UNPKG

@vrcd-community/zhlint

Version:

A linting tool for Chinese language.

107 lines (106 loc) 3.7 kB
/** * @fileoverview * * This rule will unify similar punctuations into the same one. * Usually, it's just about Chinese quotations. * * Options: * - unifiedPunctuation: "traditional" | "simplified" | Record<string, boolean | string[]> & { default: boolean } */ import { GroupTokenType } from '../parser/index.js'; import { PUNCTUATION_UNIFICATION } from './messages.js'; import { checkEndValue, checkStartValue, checkValue } from './util.js'; const defaultUnifiedMap = { // U+2047 DOUBLE QUESTION MARK, U+203C DOUBLE EXCLAMATION MARK // U+2048 QUESTION EXCLAMATION MARK, U+2049 EXCLAMATION QUESTION MARK '??': ['⁇'], '!!': ['‼'], '?!': ['⁈'], '!?': ['⁉'], // U+002F SOLIDUS, U+FF0F FULLWIDTH SOLIDUS '/': ['/', '/'], // U+FF5E FULLWIDTH TILDE '~': ['~', '~'], // U+2026 HORIZONTAL ELLIPSIS, U+22EF MIDLINE HORIZONTAL ELLIPSIS '…': ['…', '⋯'], // U+25CF BLACK CIRCLE, U+2022 BULLET, U+00B7 MIDDLE DOT, // U+2027 HYPHENATION POINT, U+30FB KATAKANA MIDDLE DOT '·': ['●', '•', '·', '‧', '・'] }; const simplifiedUnifiedMap = { '“': ['「'], '”': ['」'], '‘': ['『'], '’': ['』'] }; const traditionalUnifiedMap = { '「': ['“'], '」': ['”'], '『': ['‘'], '』': ['’'] }; const revertUnifiedMap = (unifiedMap) => { const result = {}; for (const key in unifiedMap) { const value = unifiedMap[key]; value.forEach((v) => { result[v] = key; }); } return result; }; const getRevertedUnifiedMap = (options) => { const unifiedOption = options === null || options === void 0 ? void 0 : options.unifiedPunctuation; const langType = typeof unifiedOption === 'string' ? unifiedOption : undefined; const unifiedMap = {}; if (langType) { Object.assign(unifiedMap, defaultUnifiedMap); if (langType === 'simplified') { Object.assign(unifiedMap, simplifiedUnifiedMap); } else if (langType === 'traditional') { Object.assign(unifiedMap, traditionalUnifiedMap); } } else if (typeof unifiedOption === 'object') { if (unifiedOption.default) { Object.assign(unifiedMap, defaultUnifiedMap); } Object.entries(unifiedOption).forEach(([key, value]) => { if (value === true) { unifiedMap[key] = defaultUnifiedMap[key]; } else if (value === false) { delete unifiedMap[key]; } else { unifiedMap[key] = value; } }); } return revertUnifiedMap(unifiedMap); }; const generateHandler = (options) => { const charMap = getRevertedUnifiedMap(options); const handlerPunctuationUnified = (token) => { if (token.type === GroupTokenType.GROUP) { if (Object.prototype.hasOwnProperty.call(charMap, token.modifiedStartValue)) { checkStartValue(token, charMap[token.modifiedStartValue], PUNCTUATION_UNIFICATION); } if (Object.prototype.hasOwnProperty.call(charMap, token.modifiedEndValue)) { checkEndValue(token, charMap[token.modifiedEndValue], PUNCTUATION_UNIFICATION); } return; } else { if (Object.prototype.hasOwnProperty.call(charMap, token.modifiedValue)) { checkValue(token, charMap[token.modifiedValue], undefined, PUNCTUATION_UNIFICATION); } } }; return handlerPunctuationUnified; }; export const defaultConfig = { unifiedPunctuation: 'simplified' }; export default generateHandler;