eslint-plugin-react-naming-convention
Advanced tools
Comparing version
@@ -52,3 +52,3 @@ 'use strict'; | ||
var name2 = "eslint-plugin-react-naming-convention"; | ||
var version = "1.34.0-next.0"; | ||
var version = "1.34.0-next.1"; | ||
var createRule = shared.createRuleForPlugin("naming-convention"); | ||
@@ -121,40 +121,41 @@ | ||
name: RULE_NAME, | ||
create(context) { | ||
const options = normalizeOptions(context.options); | ||
const { rule } = options; | ||
const collector = core.useComponentCollector(context); | ||
const collectorLegacy = core.useComponentCollectorLegacy(); | ||
return { | ||
...collector.listeners, | ||
...collectorLegacy.listeners, | ||
"Program:exit"(node) { | ||
const functionComponents = collector.ctx.getAllComponents(node); | ||
const classComponents = collectorLegacy.ctx.getAllComponents(node); | ||
for (const { node: component } of functionComponents.values()) { | ||
const id = AST__namespace.getFunctionIdentifier(component); | ||
if (id?.name == null) continue; | ||
const name3 = id.name; | ||
if (isValidName(name3, options)) return; | ||
context.report({ | ||
messageId: "invalid", | ||
node: id, | ||
data: { name: name3, rule } | ||
}); | ||
} | ||
for (const { node: component } of classComponents.values()) { | ||
const id = AST__namespace.getClassIdentifier(component); | ||
if (id?.name == null) continue; | ||
const name3 = id.name; | ||
if (isValidName(name3, options)) continue; | ||
context.report({ | ||
messageId: "invalid", | ||
node: id, | ||
data: { name: name3, rule } | ||
}); | ||
} | ||
} | ||
}; | ||
}, | ||
create, | ||
defaultOptions | ||
}); | ||
function create(context) { | ||
const options = normalizeOptions(context.options); | ||
const { rule } = options; | ||
const collector = core.useComponentCollector(context); | ||
const collectorLegacy = core.useComponentCollectorLegacy(); | ||
return { | ||
...collector.listeners, | ||
...collectorLegacy.listeners, | ||
"Program:exit"(node) { | ||
const functionComponents = collector.ctx.getAllComponents(node); | ||
const classComponents = collectorLegacy.ctx.getAllComponents(node); | ||
for (const { node: component } of functionComponents.values()) { | ||
const id = AST__namespace.getFunctionIdentifier(component); | ||
if (id?.name == null) continue; | ||
const name3 = id.name; | ||
if (isValidName(name3, options)) return; | ||
context.report({ | ||
messageId: "invalid", | ||
node: id, | ||
data: { name: name3, rule } | ||
}); | ||
} | ||
for (const { node: component } of classComponents.values()) { | ||
const id = AST__namespace.getClassIdentifier(component); | ||
if (id?.name == null) continue; | ||
const name3 = id.name; | ||
if (isValidName(name3, options)) continue; | ||
context.report({ | ||
messageId: "invalid", | ||
node: id, | ||
data: { name: name3, rule } | ||
}); | ||
} | ||
} | ||
}; | ||
} | ||
function normalizeOptions(options) { | ||
@@ -199,20 +200,21 @@ const opts = options[0]; | ||
name: RULE_NAME2, | ||
create(context) { | ||
if (!context.sourceCode.text.includes("createContext")) return {}; | ||
return { | ||
CallExpression(node) { | ||
if (!core.isCreateContextCall(context, node)) return; | ||
const id = core.getInstanceId(node); | ||
if (id == null) return; | ||
const name3 = tsPattern.match(id).with({ type: types.AST_NODE_TYPES.Identifier, name: tsPattern.P.select() }, eff.identity).with({ type: types.AST_NODE_TYPES.MemberExpression, property: { name: tsPattern.P.select(tsPattern.P.string) } }, eff.identity).otherwise(() => eff._); | ||
if (name3 != null && core.isComponentName(name3) && name3.endsWith("Context")) return; | ||
context.report({ | ||
messageId: "invalid", | ||
node: id | ||
}); | ||
} | ||
}; | ||
}, | ||
create: create2, | ||
defaultOptions: [] | ||
}); | ||
function create2(context) { | ||
if (!context.sourceCode.text.includes("createContext")) return {}; | ||
return { | ||
CallExpression(node) { | ||
if (!core.isCreateContextCall(context, node)) return; | ||
const id = core.getInstanceId(node); | ||
if (id == null) return; | ||
const name3 = tsPattern.match(id).with({ type: types.AST_NODE_TYPES.Identifier, name: tsPattern.P.select() }, eff.identity).with({ type: types.AST_NODE_TYPES.MemberExpression, property: { name: tsPattern.P.select(tsPattern.P.string) } }, eff.identity).otherwise(() => eff._); | ||
if (name3 != null && core.isComponentName(name3) && name3.endsWith("Context")) return; | ||
context.report({ | ||
messageId: "invalid", | ||
node: id | ||
}); | ||
} | ||
}; | ||
} | ||
var RULE_NAME3 = "filename"; | ||
@@ -269,38 +271,39 @@ var defaultOptions2 = [ | ||
name: RULE_NAME3, | ||
create(context) { | ||
const options = context.options[0] ?? defaultOptions2[0]; | ||
const rule = typeof options === "string" ? options : options.rule ?? "PascalCase"; | ||
const excepts = typeof options === "string" ? [] : options.excepts ?? []; | ||
function validate(name3, casing = rule, ignores = excepts) { | ||
const shouldIgnore = ignores.map(toRegExp).some((pattern) => pattern.test(name3)); | ||
if (shouldIgnore) return true; | ||
return tsPattern.match(casing).with("PascalCase", () => shared.RE_PASCAL_CASE.test(name3)).with("camelCase", () => shared.RE_CAMEL_CASE.test(name3)).with("kebab-case", () => shared.RE_KEBAB_CASE.test(name3)).with("snake_case", () => shared.RE_SNAKE_CASE.test(name3)).exhaustive(); | ||
} | ||
function getSuggestion(name3, casing = rule) { | ||
return tsPattern.match(casing).with("PascalCase", () => stringTs.pascalCase(name3)).with("camelCase", () => stringTs.camelCase(name3)).with("kebab-case", () => stringTs.kebabCase(name3)).with("snake_case", () => stringTs.snakeCase(name3)).exhaustive(); | ||
} | ||
return { | ||
Program(node) { | ||
const [basename = "", ...rest] = path__default.default.basename(context.filename).split("."); | ||
if (basename.length === 0) { | ||
context.report({ messageId: "filenameEmpty", node }); | ||
return; | ||
} | ||
if (validate(basename)) { | ||
return; | ||
} | ||
context.report({ | ||
messageId: "filenameInvalid", | ||
node, | ||
data: { | ||
name: context.filename, | ||
rule, | ||
suggestion: [getSuggestion(basename), ...rest].join(".") | ||
} | ||
}); | ||
} | ||
}; | ||
}, | ||
create: create3, | ||
defaultOptions: defaultOptions2 | ||
}); | ||
function create3(context) { | ||
const options = context.options[0] ?? defaultOptions2[0]; | ||
const rule = typeof options === "string" ? options : options.rule ?? "PascalCase"; | ||
const excepts = typeof options === "string" ? [] : options.excepts ?? []; | ||
function validate(name3, casing = rule, ignores = excepts) { | ||
const shouldIgnore = ignores.map(toRegExp).some((pattern) => pattern.test(name3)); | ||
if (shouldIgnore) return true; | ||
return tsPattern.match(casing).with("PascalCase", () => shared.RE_PASCAL_CASE.test(name3)).with("camelCase", () => shared.RE_CAMEL_CASE.test(name3)).with("kebab-case", () => shared.RE_KEBAB_CASE.test(name3)).with("snake_case", () => shared.RE_SNAKE_CASE.test(name3)).exhaustive(); | ||
} | ||
function getSuggestion(name3, casing = rule) { | ||
return tsPattern.match(casing).with("PascalCase", () => stringTs.pascalCase(name3)).with("camelCase", () => stringTs.camelCase(name3)).with("kebab-case", () => stringTs.kebabCase(name3)).with("snake_case", () => stringTs.snakeCase(name3)).exhaustive(); | ||
} | ||
return { | ||
Program(node) { | ||
const [basename = "", ...rest] = path__default.default.basename(context.filename).split("."); | ||
if (basename.length === 0) { | ||
context.report({ messageId: "filenameEmpty", node }); | ||
return; | ||
} | ||
if (validate(basename)) { | ||
return; | ||
} | ||
context.report({ | ||
messageId: "filenameInvalid", | ||
node, | ||
data: { | ||
name: context.filename, | ||
rule, | ||
suggestion: [getSuggestion(basename), ...rest].join(".") | ||
} | ||
}); | ||
} | ||
}; | ||
} | ||
var RULE_NAME4 = "filename-extension"; | ||
@@ -356,48 +359,49 @@ var defaultOptions3 = [{ | ||
name: RULE_NAME4, | ||
create(context) { | ||
const options = context.options[0] ?? defaultOptions3[0]; | ||
const allow = eff.isObject(options) ? options.allow : options; | ||
const extensions = eff.isObject(options) && "extensions" in options ? options.extensions : defaultOptions3[0].extensions; | ||
const extensionsString = extensions.map((ext) => `'${ext}'`).join(", "); | ||
const filename = context.filename; | ||
let hasJSXNode = false; | ||
return { | ||
JSXElement() { | ||
hasJSXNode = true; | ||
}, | ||
JSXFragment() { | ||
hasJSXNode = true; | ||
}, | ||
"Program:exit"(node) { | ||
const fileNameExt = filename.slice(filename.lastIndexOf(".")); | ||
const isJSXExt = extensions.includes(fileNameExt); | ||
if (hasJSXNode && !isJSXExt) { | ||
context.report({ | ||
messageId: "useJsxFileExtension", | ||
node, | ||
data: { | ||
extensions: extensionsString | ||
} | ||
}); | ||
return; | ||
} | ||
const hasCode = node.body.length > 0; | ||
const ignoreFilesWithoutCode = eff.isObject(options) && options.ignoreFilesWithoutCode === true; | ||
if (!hasCode && ignoreFilesWithoutCode) { | ||
return; | ||
} | ||
if (!hasJSXNode && isJSXExt && allow === "as-needed") { | ||
context.report({ | ||
messageId: "useNonJsxFileExtension", | ||
node, | ||
data: { | ||
extensions: extensionsString | ||
} | ||
}); | ||
} | ||
} | ||
}; | ||
}, | ||
create: create4, | ||
defaultOptions: defaultOptions3 | ||
}); | ||
function create4(context) { | ||
const options = context.options[0] ?? defaultOptions3[0]; | ||
const allow = eff.isObject(options) ? options.allow : options; | ||
const extensions = eff.isObject(options) && "extensions" in options ? options.extensions : defaultOptions3[0].extensions; | ||
const extensionsString = extensions.map((ext) => `'${ext}'`).join(", "); | ||
const filename = context.filename; | ||
let hasJSXNode = false; | ||
return { | ||
JSXElement() { | ||
hasJSXNode = true; | ||
}, | ||
JSXFragment() { | ||
hasJSXNode = true; | ||
}, | ||
"Program:exit"(node) { | ||
const fileNameExt = filename.slice(filename.lastIndexOf(".")); | ||
const isJSXExt = extensions.includes(fileNameExt); | ||
if (hasJSXNode && !isJSXExt) { | ||
context.report({ | ||
messageId: "useJsxFileExtension", | ||
node, | ||
data: { | ||
extensions: extensionsString | ||
} | ||
}); | ||
return; | ||
} | ||
const hasCode = node.body.length > 0; | ||
const ignoreFilesWithoutCode = eff.isObject(options) && options.ignoreFilesWithoutCode === true; | ||
if (!hasCode && ignoreFilesWithoutCode) { | ||
return; | ||
} | ||
if (!hasJSXNode && isJSXExt && allow === "as-needed") { | ||
context.report({ | ||
messageId: "useNonJsxFileExtension", | ||
node, | ||
data: { | ||
extensions: extensionsString | ||
} | ||
}); | ||
} | ||
} | ||
}; | ||
} | ||
var RULE_NAME5 = "use-state"; | ||
@@ -420,41 +424,42 @@ var RULE_FEATURES = [ | ||
name: RULE_NAME5, | ||
create(context) { | ||
return { | ||
"CallExpression[callee.name='useState']"(node) { | ||
if (node.parent.type !== types.AST_NODE_TYPES.VariableDeclarator) { | ||
context.report({ messageId: "invalid", node }); | ||
} | ||
const id = core.getInstanceId(node); | ||
if (id?.type !== types.AST_NODE_TYPES.ArrayPattern) { | ||
context.report({ messageId: "invalid", node }); | ||
return; | ||
} | ||
const [value, setter] = id.elements; | ||
if (value == null || setter == null) { | ||
context.report({ messageId: "invalid", node }); | ||
return; | ||
} | ||
const setterName = tsPattern.match(setter).with({ type: types.AST_NODE_TYPES.Identifier }, (id2) => id2.name).otherwise(() => eff._); | ||
if (setterName == null || !setterName.startsWith("set")) { | ||
context.report({ messageId: "invalid", node }); | ||
return; | ||
} | ||
const valueName = tsPattern.match(value).with({ type: types.AST_NODE_TYPES.Identifier }, ({ name: name3 }) => stringTs.snakeCase(name3)).with({ type: types.AST_NODE_TYPES.ObjectPattern }, ({ properties }) => { | ||
const values = properties.reduce((acc, prop) => { | ||
if (prop.type === types.AST_NODE_TYPES.Property && prop.key.type === types.AST_NODE_TYPES.Identifier) { | ||
return [...acc, prop.key.name]; | ||
} | ||
return acc; | ||
}, []); | ||
return values.join("_"); | ||
}).otherwise(() => eff._); | ||
if (valueName == null || `set_${valueName}` !== stringTs.snakeCase(setterName)) { | ||
context.report({ messageId: "invalid", node }); | ||
return; | ||
} | ||
} | ||
}; | ||
}, | ||
create: create5, | ||
defaultOptions: [] | ||
}); | ||
function create5(context) { | ||
return { | ||
"CallExpression[callee.name='useState']"(node) { | ||
if (node.parent.type !== types.AST_NODE_TYPES.VariableDeclarator) { | ||
context.report({ messageId: "invalid", node }); | ||
} | ||
const id = core.getInstanceId(node); | ||
if (id?.type !== types.AST_NODE_TYPES.ArrayPattern) { | ||
context.report({ messageId: "invalid", node }); | ||
return; | ||
} | ||
const [value, setter] = id.elements; | ||
if (value == null || setter == null) { | ||
context.report({ messageId: "invalid", node }); | ||
return; | ||
} | ||
const setterName = tsPattern.match(setter).with({ type: types.AST_NODE_TYPES.Identifier }, (id2) => id2.name).otherwise(() => eff._); | ||
if (setterName == null || !setterName.startsWith("set")) { | ||
context.report({ messageId: "invalid", node }); | ||
return; | ||
} | ||
const valueName = tsPattern.match(value).with({ type: types.AST_NODE_TYPES.Identifier }, ({ name: name3 }) => stringTs.snakeCase(name3)).with({ type: types.AST_NODE_TYPES.ObjectPattern }, ({ properties }) => { | ||
const values = properties.reduce((acc, prop) => { | ||
if (prop.type === types.AST_NODE_TYPES.Property && prop.key.type === types.AST_NODE_TYPES.Identifier) { | ||
return [...acc, prop.key.name]; | ||
} | ||
return acc; | ||
}, []); | ||
return values.join("_"); | ||
}).otherwise(() => eff._); | ||
if (valueName == null || `set_${valueName}` !== stringTs.snakeCase(setterName)) { | ||
context.report({ messageId: "invalid", node }); | ||
return; | ||
} | ||
} | ||
}; | ||
} | ||
@@ -461,0 +466,0 @@ // src/plugin.ts |
{ | ||
"name": "eslint-plugin-react-naming-convention", | ||
"version": "1.34.0-next.0", | ||
"version": "1.34.0-next.1", | ||
"description": "ESLint React's ESLint plugin for naming convention related rules.", | ||
@@ -52,8 +52,8 @@ "keywords": [ | ||
"ts-pattern": "^5.6.2", | ||
"@eslint-react/ast": "1.34.0-next.0", | ||
"@eslint-react/core": "1.34.0-next.0", | ||
"@eslint-react/jsx": "1.34.0-next.0", | ||
"@eslint-react/shared": "1.34.0-next.0", | ||
"@eslint-react/eff": "1.34.0-next.0", | ||
"@eslint-react/var": "1.34.0-next.0" | ||
"@eslint-react/ast": "1.34.0-next.1", | ||
"@eslint-react/core": "1.34.0-next.1", | ||
"@eslint-react/eff": "1.34.0-next.1", | ||
"@eslint-react/jsx": "1.34.0-next.1", | ||
"@eslint-react/shared": "1.34.0-next.1", | ||
"@eslint-react/var": "1.34.0-next.1" | ||
}, | ||
@@ -60,0 +60,0 @@ "devDependencies": { |
Sorry, the diff of this file is not supported yet
1023
0.99%41429
-0.98%+ Added
+ Added
+ Added
+ Added
+ Added
+ Added
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed