UNPKG

eslint-plugin-regexp

Version:

ESLint plugin for finding RegExp mistakes and RegExp style guide violations.

201 lines (200 loc) 8.94 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const utils_1 = require("../utils"); const unicode_alias_1 = require("../utils/unicode-alias"); function isGeneralCategory(key) { return unicode_alias_1.UNICODE_CATEGORY_ALIAS.toShort(key) === "gc"; } exports.default = (0, utils_1.createRule)("unicode-property", { meta: { docs: { description: "enforce consistent naming of unicode properties", category: "Stylistic Issues", recommended: false, }, schema: [ { type: "object", properties: { generalCategory: { enum: ["always", "never", "ignore"], }, key: { enum: ["short", "long", "ignore"], }, property: { anyOf: [ { enum: ["short", "long", "ignore"], }, { type: "object", properties: { binary: { enum: ["short", "long", "ignore"], }, generalCategory: { enum: ["short", "long", "ignore"], }, script: { enum: ["short", "long", "ignore"], }, }, additionalProperties: false, }, ], }, }, additionalProperties: false, }, ], messages: { unnecessaryGc: "Unnecessary '{{ gc }}=' in Unicode property.", missingGc: "Missing '{{ gc }}=' in Unicode property.", expectedKey: "Excepted {{ len }} key. Use '{{ key }}' instead.", expectedProperty: "Excepted {{ len }} {{ type }} property. Use '{{ prop }}' instead.", }, type: "suggestion", fixable: "code", }, create(context) { const { generalCategory = "never", key: keyFormat = "ignore", property = { binary: "ignore", generalCategory: "ignore", script: "long", }, } = (context.options[0] || {}); let defaultPropertyFormat = "long"; if (typeof property === "string") { defaultPropertyFormat = property; } const { binary: binaryFormat = defaultPropertyFormat, generalCategory: generalCategoryFormat = defaultPropertyFormat, script: scriptFormat = defaultPropertyFormat, } = typeof property === "string" ? {} : property; function createVisitor(regexpContext) { const { node, getRegexpLocation, fixReplaceNode } = regexpContext; function onUnicodeProperty(cs) { const keyValueSyntax = cs.raw.includes("="); function fixReplace(inner) { return fixReplaceNode(cs, `${cs.raw.slice(0, 2)}{${inner}}`); } function getKeyLocation() { const offset = "\\p{".length; if (keyValueSyntax) { return getRegexpLocation({ start: cs.start + offset, end: cs.start + offset + cs.key.length, }); } return getRegexpLocation({ start: cs.start + offset, end: cs.end - 1, }); } function getValueLocation() { return getRegexpLocation({ start: cs.end - 1 - (cs.value || cs.key).length, end: cs.end - 1, }); } const { key, value } = cs; if (value === null) { if (binaryFormat !== "ignore") { const expected = binaryFormat === "short" ? unicode_alias_1.UNICODE_BINARY_PROPERTY_ALIAS.toShort(key) : unicode_alias_1.UNICODE_BINARY_PROPERTY_ALIAS.toLong(key); if (key !== expected) { context.report({ node, loc: getKeyLocation(), messageId: "expectedProperty", data: { len: binaryFormat, type: "binary", prop: expected, }, fix: fixReplace(expected), }); } } } else { const isGC = isGeneralCategory(key); let handledKey = false; if (isGC) { if (keyValueSyntax && generalCategory === "never") { context.report({ node, loc: getKeyLocation(), messageId: "unnecessaryGc", data: { gc: key }, fix: fixReplace(value), }); handledKey = true; } if (!keyValueSyntax && generalCategory === "always") { const missing = keyFormat === "long" ? "General_Category" : "gc"; context.report({ node, loc: getRegexpLocation(cs), messageId: "missingGc", data: { gc: missing }, fix: fixReplace(`${missing}=${value}`), }); handledKey = true; } } if (!handledKey && keyValueSyntax && keyFormat !== "ignore") { const expected = keyFormat === "short" ? unicode_alias_1.UNICODE_CATEGORY_ALIAS.toShort(key) : unicode_alias_1.UNICODE_CATEGORY_ALIAS.toLong(key); if (key !== expected) { context.report({ node, loc: getKeyLocation(), messageId: "expectedKey", data: { len: keyFormat, key: expected }, fix: fixReplace(`${expected}=${value}`), }); } } const valueFormat = isGC ? generalCategoryFormat : scriptFormat; if (valueFormat !== "ignore") { const aliasMap = isGC ? unicode_alias_1.UNICODE_GENERAL_CATEGORY_ALIAS : unicode_alias_1.UNICODE_SCRIPT_ALIAS; const expected = valueFormat === "short" ? aliasMap.toShort(value) : aliasMap.toLong(value); if (value !== expected) { const prefix = keyValueSyntax ? `${key}=` : ""; const type = isGC ? "General_Category" : "Script"; context.report({ node, loc: getValueLocation(), messageId: "expectedProperty", data: { len: valueFormat, type, prop: expected, }, fix: fixReplace(`${prefix}${expected}`), }); } } } } return { onCharacterSetEnter(cs) { if (cs.kind === "property") { onUnicodeProperty(cs); } }, }; } return (0, utils_1.defineRegexpVisitor)(context, { createVisitor, }); }, });