@vrcd-community/zhlint
Version:
A linting tool for Chinese language.
107 lines (106 loc) • 3.7 kB
JavaScript
/**
* @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;