UNPKG

@vrcd-community/zhlint

Version:

A linting tool for Chinese language.

105 lines (104 loc) 5.27 kB
/** * @fileoverview * * This rule is checking spaces besides normal punctuations. * Usually, for full-width punctuations, we don't need any spaces around. * For half-width punctuations, we need a space after that. * * Options * - noSpaceBeforePunctuation: boolean | undefined * - `true`: remove spaces before a half-width punctuation (default) * - `false` or `undefined`: do nothing, just keep the original format * - spaceAfterHalfWidthPunctuation: boolean | undefined * - `true`: ensure one space after a half-width punctuation (default) * - `false` or `undefined`: do nothing, just keep the original format * - noSpaceAfterFullWidthPunctuation: boolean | undefined * - `true`: remove spaces around a full-width punctuation (default) * - `false` or `undefined`: do nothing, just keep the original format * * Details: * - noSpaceBeforePunctuation: * content/right-quotation/right-bracket/code x punctuation * - spaceAfterHalfWidthPunctuation: * half x content/left-quotation/left-bracket/code * - noSpaceAfterFullWidthPunctuation: * full x content/left-quotation/left-bracket/code * * - skip half-width punctuations between half-width content without space * - skip successive multiple half-width punctuations */ import { GroupTokenType, isLetterType, isPauseOrStopType, MarkSideType, HyperTokenType, isFullwidthPunctuationType, isHalfwidthPunctuationType } from '../parser/index.js'; import { checkSpaceAfter, findVisibleTokenAfter, findVisibleTokenBefore, findWrappersBetween, isHalfwidthPunctuationWithoutSpaceAround, isSuccessiveHalfwidthPunctuation } from './util.js'; import { PUNCTUATION_NOSPACE_AFTER, PUNCTUATION_NOSPACE_BEFORE, PUNCTUATION_SPACE_AFTER } from './messages.js'; const generateHandler = (options) => { const noBeforePunctuationOption = options === null || options === void 0 ? void 0 : options.noSpaceBeforePauseOrStop; const oneAfterHalfWidthPunctuationOption = options === null || options === void 0 ? void 0 : options.spaceAfterHalfwidthPauseOrStop; const noAfterFullWidthPunctuationOption = options === null || options === void 0 ? void 0 : options.noSpaceAfterFullwidthPauseOrStop; return (token, _, group) => { // skip non-punctuation tokens and non-normal punctuations if (!isPauseOrStopType(token.type)) { return; } // skip half-width punctuations between half-width content without space if (isHalfwidthPunctuationWithoutSpaceAround(group, token)) { return; } // skip successive multiple half-width punctuations if (isSuccessiveHalfwidthPunctuation(group, token)) { return; } // 1. content/right-quotation/right-bracket/code x punctuation if (noBeforePunctuationOption) { const contentTokenBefore = findVisibleTokenBefore(group, token); if (contentTokenBefore && // content (isLetterType(contentTokenBefore.type) || // right-quotation contentTokenBefore.type === GroupTokenType.GROUP || // right-bracket (contentTokenBefore.type === HyperTokenType.BRACKET_MARK && contentTokenBefore.markSide === MarkSideType.RIGHT) || // code contentTokenBefore.type === HyperTokenType.CODE_CONTENT)) { const { spaceHost } = findWrappersBetween(group, contentTokenBefore, token); if (spaceHost) { checkSpaceAfter(spaceHost, '', PUNCTUATION_NOSPACE_BEFORE); } } } // 2. half/full x content/left-quotation/left-bracket/code if ((isFullwidthPunctuationType(token.modifiedType) && noAfterFullWidthPunctuationOption) || (isHalfwidthPunctuationType(token.modifiedType) && oneAfterHalfWidthPunctuationOption)) { const spaceAfter = isHalfwidthPunctuationType(token.modifiedType) ? ' ' : ''; const message = isHalfwidthPunctuationType(token.modifiedType) ? PUNCTUATION_SPACE_AFTER : PUNCTUATION_NOSPACE_AFTER; const contentTokenAfter = findVisibleTokenAfter(group, token); if (contentTokenAfter && // content (isLetterType(contentTokenAfter.type) || // left-quotation contentTokenAfter.type === GroupTokenType.GROUP || // left-bracket (contentTokenAfter.type === HyperTokenType.BRACKET_MARK && contentTokenAfter.markSide === MarkSideType.LEFT) || // code contentTokenAfter.type === HyperTokenType.CODE_CONTENT)) { const { spaceHost } = findWrappersBetween(group, token, contentTokenAfter); if (spaceHost) { checkSpaceAfter(spaceHost, spaceAfter, message); } } } }; }; export const defaultConfig = { noSpaceBeforePunctuation: true, spaceAfterHalfWidthPunctuation: true, noSpaceAfterFullWidthPunctuation: true }; export default generateHandler;