@tanstack/eslint-plugin-router
Advanced tools
+22
-27
@@ -1,31 +0,26 @@ | ||
| "use strict"; | ||
| const rules = require("./rules.cjs"); | ||
| const plugin = { | ||
| meta: { | ||
| name: "@tanstack/eslint-plugin-router" | ||
| }, | ||
| configs: {}, | ||
| rules: rules.rules | ||
| //#region src/index.ts | ||
| var plugin = { | ||
| meta: { name: "@tanstack/eslint-plugin-router" }, | ||
| configs: {}, | ||
| rules: require("./rules.cjs").rules | ||
| }; | ||
| Object.assign(plugin.configs, { | ||
| recommended: { | ||
| plugins: ["@tanstack/eslint-plugin-router"], | ||
| rules: { | ||
| "@tanstack/router/create-route-property-order": "warn", | ||
| "@tanstack/router/route-param-names": "error" | ||
| } | ||
| }, | ||
| "flat/recommended": [ | ||
| { | ||
| plugins: { | ||
| "@tanstack/router": plugin | ||
| }, | ||
| rules: { | ||
| "@tanstack/router/create-route-property-order": "warn", | ||
| "@tanstack/router/route-param-names": "error" | ||
| } | ||
| } | ||
| ] | ||
| recommended: { | ||
| plugins: ["@tanstack/eslint-plugin-router"], | ||
| rules: { | ||
| "@tanstack/router/create-route-property-order": "warn", | ||
| "@tanstack/router/route-param-names": "error" | ||
| } | ||
| }, | ||
| "flat/recommended": [{ | ||
| plugins: { "@tanstack/router": plugin }, | ||
| rules: { | ||
| "@tanstack/router/create-route-property-order": "warn", | ||
| "@tanstack/router/route-param-names": "error" | ||
| } | ||
| }] | ||
| }); | ||
| //#endregion | ||
| module.exports = plugin; | ||
| //# sourceMappingURL=index.cjs.map | ||
| //# sourceMappingURL=index.cjs.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.cjs","sources":["../../src/index.ts"],"sourcesContent":["import { rules } from './rules'\nimport type { ESLint, Linter } from 'eslint'\nimport type { RuleModule } from '@typescript-eslint/utils/ts-eslint'\n\ntype RuleKey = keyof typeof rules\n\ninterface Plugin extends Omit<ESLint.Plugin, 'rules'> {\n rules: Record<RuleKey, RuleModule<any, any, any>>\n configs: {\n recommended: ESLint.ConfigData\n 'flat/recommended': Array<Linter.FlatConfig>\n }\n}\n\nconst plugin: Plugin = {\n meta: {\n name: '@tanstack/eslint-plugin-router',\n },\n configs: {} as Plugin['configs'],\n rules,\n}\n\n// Assign configs here so we can reference `plugin`\nObject.assign(plugin.configs, {\n recommended: {\n plugins: ['@tanstack/eslint-plugin-router'],\n rules: {\n '@tanstack/router/create-route-property-order': 'warn',\n '@tanstack/router/route-param-names': 'error',\n },\n },\n 'flat/recommended': [\n {\n plugins: {\n '@tanstack/router': plugin,\n },\n rules: {\n '@tanstack/router/create-route-property-order': 'warn',\n '@tanstack/router/route-param-names': 'error',\n },\n },\n ],\n})\n\nexport default plugin\n"],"names":["rules"],"mappings":";;AAcA,MAAM,SAAiB;AAAA,EACrB,MAAM;AAAA,IACJ,MAAM;AAAA,EAAA;AAAA,EAER,SAAS,CAAA;AAAA,EAAC,OACVA,MAAAA;AACF;AAGA,OAAO,OAAO,OAAO,SAAS;AAAA,EAC5B,aAAa;AAAA,IACX,SAAS,CAAC,gCAAgC;AAAA,IAC1C,OAAO;AAAA,MACL,gDAAgD;AAAA,MAChD,sCAAsC;AAAA,IAAA;AAAA,EACxC;AAAA,EAEF,oBAAoB;AAAA,IAClB;AAAA,MACE,SAAS;AAAA,QACP,oBAAoB;AAAA,MAAA;AAAA,MAEtB,OAAO;AAAA,QACL,gDAAgD;AAAA,QAChD,sCAAsC;AAAA,MAAA;AAAA,IACxC;AAAA,EACF;AAEJ,CAAC;;"} | ||
| {"version":3,"file":"index.cjs","names":[],"sources":["../../src/index.ts"],"sourcesContent":["import { rules } from './rules'\nimport type { ESLint, Linter } from 'eslint'\nimport type { RuleModule } from '@typescript-eslint/utils/ts-eslint'\n\ntype RuleKey = keyof typeof rules\n\ninterface Plugin extends Omit<ESLint.Plugin, 'rules'> {\n rules: Record<RuleKey, RuleModule<any, any, any>>\n configs: {\n recommended: ESLint.ConfigData\n 'flat/recommended': Array<Linter.FlatConfig>\n }\n}\n\nconst plugin: Plugin = {\n meta: {\n name: '@tanstack/eslint-plugin-router',\n },\n configs: {} as Plugin['configs'],\n rules,\n}\n\n// Assign configs here so we can reference `plugin`\nObject.assign(plugin.configs, {\n recommended: {\n plugins: ['@tanstack/eslint-plugin-router'],\n rules: {\n '@tanstack/router/create-route-property-order': 'warn',\n '@tanstack/router/route-param-names': 'error',\n },\n },\n 'flat/recommended': [\n {\n plugins: {\n '@tanstack/router': plugin,\n },\n rules: {\n '@tanstack/router/create-route-property-order': 'warn',\n '@tanstack/router/route-param-names': 'error',\n },\n },\n ],\n})\n\nexport default plugin\n"],"mappings":";AAcA,IAAM,SAAiB;CACrB,MAAM,EACJ,MAAM,kCACP;CACD,SAAS,EAAE;CACX,8BAAA;CACD;AAGD,OAAO,OAAO,OAAO,SAAS;CAC5B,aAAa;EACX,SAAS,CAAC,iCAAiC;EAC3C,OAAO;GACL,gDAAgD;GAChD,sCAAsC;GACvC;EACF;CACD,oBAAoB,CAClB;EACE,SAAS,EACP,oBAAoB,QACrB;EACD,OAAO;GACL,gDAAgD;GAChD,sCAAsC;GACvC;EACF,CACF;CACF,CAAC"} |
@@ -1,10 +0,11 @@ | ||
| "use strict"; | ||
| Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); | ||
| const createRoutePropertyOrder_rule = require("./rules/create-route-property-order/create-route-property-order.rule.cjs"); | ||
| const routeParamNames_rule = require("./rules/route-param-names/route-param-names.rule.cjs"); | ||
| const rules = { | ||
| [createRoutePropertyOrder_rule.name]: createRoutePropertyOrder_rule.rule, | ||
| [routeParamNames_rule.name]: routeParamNames_rule.rule | ||
| const require_create_route_property_order_rule = require("./rules/create-route-property-order/create-route-property-order.rule.cjs"); | ||
| const require_route_param_names_rule = require("./rules/route-param-names/route-param-names.rule.cjs"); | ||
| //#region src/rules.ts | ||
| var rules = { | ||
| [require_create_route_property_order_rule.name]: require_create_route_property_order_rule.rule, | ||
| [require_route_param_names_rule.name]: require_route_param_names_rule.rule | ||
| }; | ||
| //#endregion | ||
| exports.rules = rules; | ||
| //# sourceMappingURL=rules.cjs.map | ||
| //# sourceMappingURL=rules.cjs.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"rules.cjs","sources":["../../src/rules.ts"],"sourcesContent":["import * as createRoutePropertyOrder from './rules/create-route-property-order/create-route-property-order.rule'\nimport * as routeParamNames from './rules/route-param-names/route-param-names.rule'\nimport type { ESLintUtils } from '@typescript-eslint/utils'\nimport type { ExtraRuleDocs } from './types'\n\nexport const rules: Record<\n string,\n ESLintUtils.RuleModule<\n string,\n ReadonlyArray<unknown>,\n ExtraRuleDocs,\n ESLintUtils.RuleListener\n >\n> = {\n [createRoutePropertyOrder.name]: createRoutePropertyOrder.rule,\n [routeParamNames.name]: routeParamNames.rule,\n}\n"],"names":["createRoutePropertyOrder.name","createRoutePropertyOrder.rule","routeParamNames.name","routeParamNames.rule"],"mappings":";;;;AAKO,MAAM,QAQT;AAAA,EACF,CAACA,8BAAAA,IAA6B,GAAGC,8BAAAA;AAAAA,EACjC,CAACC,yBAAoB,GAAGC,qBAAAA;AAC1B;;"} | ||
| {"version":3,"file":"rules.cjs","names":[],"sources":["../../src/rules.ts"],"sourcesContent":["import * as createRoutePropertyOrder from './rules/create-route-property-order/create-route-property-order.rule'\nimport * as routeParamNames from './rules/route-param-names/route-param-names.rule'\nimport type { ESLintUtils } from '@typescript-eslint/utils'\nimport type { ExtraRuleDocs } from './types'\n\nexport const rules: Record<\n string,\n ESLintUtils.RuleModule<\n string,\n ReadonlyArray<unknown>,\n ExtraRuleDocs,\n ESLintUtils.RuleListener\n >\n> = {\n [createRoutePropertyOrder.name]: createRoutePropertyOrder.rule,\n [routeParamNames.name]: routeParamNames.rule,\n}\n"],"mappings":";;;AAKA,IAAa,QAQT;;;CAGH"} |
@@ -1,40 +0,27 @@ | ||
| "use strict"; | ||
| Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); | ||
| const createRoutePropertyOrder_utils = require("./create-route-property-order.utils.cjs"); | ||
| const createRouteFunctionsIndirect = [ | ||
| "createFileRoute", | ||
| "createRootRouteWithContext" | ||
| const require_create_route_property_order_utils = require("./create-route-property-order.utils.cjs"); | ||
| //#region src/rules/create-route-property-order/constants.ts | ||
| var createRouteFunctionsIndirect = ["createFileRoute", "createRootRouteWithContext"]; | ||
| var createRouteFunctions = [...["createRootRoute", "createRoute"], ...createRouteFunctionsIndirect]; | ||
| var sortRules = [ | ||
| [["params", "validateSearch"], ["search"]], | ||
| [["search"], ["loaderDeps", "ssr"]], | ||
| [["loaderDeps"], ["context"]], | ||
| [["context"], ["beforeLoad"]], | ||
| [["beforeLoad"], ["loader"]], | ||
| [["loader"], [ | ||
| "onEnter", | ||
| "onStay", | ||
| "onLeave", | ||
| "head", | ||
| "scripts", | ||
| "headers", | ||
| "remountDeps" | ||
| ]] | ||
| ]; | ||
| const createRouteFunctionsDirect = [ | ||
| "createRootRoute", | ||
| "createRoute" | ||
| ]; | ||
| const createRouteFunctions = [ | ||
| ...createRouteFunctionsDirect, | ||
| ...createRouteFunctionsIndirect | ||
| ]; | ||
| const sortRules = [ | ||
| [["params", "validateSearch"], ["search"]], | ||
| [["search"], ["loaderDeps", "ssr"]], | ||
| [["loaderDeps"], ["context"]], | ||
| [["context"], ["beforeLoad"]], | ||
| [["beforeLoad"], ["loader"]], | ||
| [ | ||
| ["loader"], | ||
| [ | ||
| "onEnter", | ||
| "onStay", | ||
| "onLeave", | ||
| "head", | ||
| "scripts", | ||
| "headers", | ||
| "remountDeps" | ||
| ] | ||
| ] | ||
| ]; | ||
| createRoutePropertyOrder_utils.getCheckedProperties(sortRules); | ||
| require_create_route_property_order_utils.getCheckedProperties(sortRules); | ||
| //#endregion | ||
| exports.createRouteFunctions = createRouteFunctions; | ||
| exports.createRouteFunctionsDirect = createRouteFunctionsDirect; | ||
| exports.createRouteFunctionsIndirect = createRouteFunctionsIndirect; | ||
| exports.sortRules = sortRules; | ||
| //# sourceMappingURL=constants.cjs.map | ||
| //# sourceMappingURL=constants.cjs.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"constants.cjs","sources":["../../../../src/rules/create-route-property-order/constants.ts"],"sourcesContent":["import { getCheckedProperties } from './create-route-property-order.utils'\n\nexport const createRouteFunctionsIndirect = [\n 'createFileRoute',\n 'createRootRouteWithContext',\n] as const\nexport const createRouteFunctionsDirect = [\n 'createRootRoute',\n 'createRoute',\n] as const\n\nexport const createRouteFunctions = [\n ...createRouteFunctionsDirect,\n ...createRouteFunctionsIndirect,\n] as const\n\nexport type CreateRouteFunction = (typeof createRouteFunctions)[number]\n\nexport const sortRules = [\n [['params', 'validateSearch'], ['search']],\n [['search'], ['loaderDeps', 'ssr']],\n [['loaderDeps'], ['context']],\n [['context'], ['beforeLoad']],\n [['beforeLoad'], ['loader']],\n [\n ['loader'],\n [\n 'onEnter',\n 'onStay',\n 'onLeave',\n 'head',\n 'scripts',\n 'headers',\n 'remountDeps',\n ],\n ],\n] as const\n\nexport type CheckedProperties = (typeof sortRules)[number][number][number]\nexport const checkedProperties = getCheckedProperties(sortRules)\n"],"names":["getCheckedProperties"],"mappings":";;;AAEO,MAAM,+BAA+B;AAAA,EAC1C;AAAA,EACA;AACF;AACO,MAAM,6BAA6B;AAAA,EACxC;AAAA,EACA;AACF;AAEO,MAAM,uBAAuB;AAAA,EAClC,GAAG;AAAA,EACH,GAAG;AACL;AAIO,MAAM,YAAY;AAAA,EACvB,CAAC,CAAC,UAAU,gBAAgB,GAAG,CAAC,QAAQ,CAAC;AAAA,EACzC,CAAC,CAAC,QAAQ,GAAG,CAAC,cAAc,KAAK,CAAC;AAAA,EAClC,CAAC,CAAC,YAAY,GAAG,CAAC,SAAS,CAAC;AAAA,EAC5B,CAAC,CAAC,SAAS,GAAG,CAAC,YAAY,CAAC;AAAA,EAC5B,CAAC,CAAC,YAAY,GAAG,CAAC,QAAQ,CAAC;AAAA,EAC3B;AAAA,IACE,CAAC,QAAQ;AAAA,IACT;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,EACF;AAEJ;AAGiCA,+BAAAA,qBAAqB,SAAS;;;;;"} | ||
| {"version":3,"file":"constants.cjs","names":[],"sources":["../../../../src/rules/create-route-property-order/constants.ts"],"sourcesContent":["import { getCheckedProperties } from './create-route-property-order.utils'\n\nexport const createRouteFunctionsIndirect = [\n 'createFileRoute',\n 'createRootRouteWithContext',\n] as const\nexport const createRouteFunctionsDirect = [\n 'createRootRoute',\n 'createRoute',\n] as const\n\nexport const createRouteFunctions = [\n ...createRouteFunctionsDirect,\n ...createRouteFunctionsIndirect,\n] as const\n\nexport type CreateRouteFunction = (typeof createRouteFunctions)[number]\n\nexport const sortRules = [\n [['params', 'validateSearch'], ['search']],\n [['search'], ['loaderDeps', 'ssr']],\n [['loaderDeps'], ['context']],\n [['context'], ['beforeLoad']],\n [['beforeLoad'], ['loader']],\n [\n ['loader'],\n [\n 'onEnter',\n 'onStay',\n 'onLeave',\n 'head',\n 'scripts',\n 'headers',\n 'remountDeps',\n ],\n ],\n] as const\n\nexport type CheckedProperties = (typeof sortRules)[number][number][number]\nexport const checkedProperties = getCheckedProperties(sortRules)\n"],"mappings":";;AAEA,IAAa,+BAA+B,CAC1C,mBACA,6BACD;AAMD,IAAa,uBAAuB,CAClC,GANwC,CACxC,mBACA,cACD,EAIC,GAAG,6BACJ;AAID,IAAa,YAAY;CACvB,CAAC,CAAC,UAAU,iBAAiB,EAAE,CAAC,SAAS,CAAC;CAC1C,CAAC,CAAC,SAAS,EAAE,CAAC,cAAc,MAAM,CAAC;CACnC,CAAC,CAAC,aAAa,EAAE,CAAC,UAAU,CAAC;CAC7B,CAAC,CAAC,UAAU,EAAE,CAAC,aAAa,CAAC;CAC7B,CAAC,CAAC,aAAa,EAAE,CAAC,SAAS,CAAC;CAC5B,CACE,CAAC,SAAS,EACV;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CACF;CACF;AAGgC,0CAAA,qBAAqB,UAAU"} |
@@ -1,103 +0,73 @@ | ||
| "use strict"; | ||
| Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); | ||
| const utils = require("@typescript-eslint/utils"); | ||
| const getDocsUrl = require("../../utils/get-docs-url.cjs"); | ||
| const detectRouterImports = require("../../utils/detect-router-imports.cjs"); | ||
| const createRoutePropertyOrder_utils = require("./create-route-property-order.utils.cjs"); | ||
| const constants = require("./constants.cjs"); | ||
| const createRule = utils.ESLintUtils.RuleCreator(getDocsUrl.getDocsUrl); | ||
| const createRouteFunctionSet = new Set(constants.createRouteFunctions); | ||
| const require_get_docs_url = require("../../utils/get-docs-url.cjs"); | ||
| const require_detect_router_imports = require("../../utils/detect-router-imports.cjs"); | ||
| const require_create_route_property_order_utils = require("./create-route-property-order.utils.cjs"); | ||
| const require_constants = require("./constants.cjs"); | ||
| let _typescript_eslint_utils = require("@typescript-eslint/utils"); | ||
| //#region src/rules/create-route-property-order/create-route-property-order.rule.ts | ||
| var createRule = _typescript_eslint_utils.ESLintUtils.RuleCreator(require_get_docs_url.getDocsUrl); | ||
| var createRouteFunctionSet = new Set(require_constants.createRouteFunctions); | ||
| function isCreateRouteFunction(node) { | ||
| return createRouteFunctionSet.has(node); | ||
| return createRouteFunctionSet.has(node); | ||
| } | ||
| const name = "create-route-property-order"; | ||
| const rule = createRule({ | ||
| name, | ||
| meta: { | ||
| type: "problem", | ||
| docs: { | ||
| description: "Ensure correct order of inference sensitive properties for createRoute functions", | ||
| recommended: "error" | ||
| }, | ||
| messages: { | ||
| invalidOrder: "Invalid order of properties for `{{function}}`." | ||
| }, | ||
| schema: [], | ||
| hasSuggestions: true, | ||
| fixable: "code" | ||
| }, | ||
| defaultOptions: [], | ||
| create: detectRouterImports.detectTanstackRouterImports((context) => { | ||
| return { | ||
| CallExpression(node) { | ||
| if (node.callee.type !== utils.AST_NODE_TYPES.Identifier) { | ||
| return; | ||
| } | ||
| const createRouteFunction = node.callee.name; | ||
| if (!isCreateRouteFunction(createRouteFunction)) { | ||
| return; | ||
| } | ||
| let args = node.arguments; | ||
| if (constants.createRouteFunctionsIndirect.includes(createRouteFunction)) { | ||
| if (node.parent.type === utils.AST_NODE_TYPES.CallExpression) { | ||
| args = node.parent.arguments; | ||
| } else { | ||
| return; | ||
| } | ||
| } | ||
| const argument = args[0]; | ||
| if (argument === void 0 || argument.type !== "ObjectExpression") { | ||
| return; | ||
| } | ||
| const allProperties = argument.properties; | ||
| if (allProperties.length < 2) { | ||
| return; | ||
| } | ||
| const properties = allProperties.flatMap((p) => { | ||
| if (p.type === utils.AST_NODE_TYPES.Property && p.key.type === utils.AST_NODE_TYPES.Identifier) { | ||
| return { name: p.key.name, property: p }; | ||
| } else if (p.type === utils.AST_NODE_TYPES.SpreadElement) { | ||
| if (p.argument.type === utils.AST_NODE_TYPES.Identifier) { | ||
| return { name: p.argument.name, property: p }; | ||
| } else { | ||
| throw new Error("Unsupported spread element"); | ||
| } | ||
| } | ||
| return []; | ||
| }); | ||
| const sortedProperties = createRoutePropertyOrder_utils.sortDataByOrder(properties, constants.sortRules, "name"); | ||
| if (sortedProperties === null) { | ||
| return; | ||
| } | ||
| context.report({ | ||
| node: argument, | ||
| data: { function: node.callee.name }, | ||
| messageId: "invalidOrder", | ||
| fix(fixer) { | ||
| const sourceCode = context.sourceCode; | ||
| const text = sortedProperties.reduce( | ||
| (sourceText, specifier, index) => { | ||
| let text2 = ""; | ||
| if (index < allProperties.length - 1) { | ||
| text2 = sourceCode.getText().slice( | ||
| allProperties[index].range[1], | ||
| allProperties[index + 1].range[0] | ||
| ); | ||
| } | ||
| return sourceText + sourceCode.getText(specifier.property) + text2; | ||
| }, | ||
| "" | ||
| ); | ||
| return fixer.replaceTextRange( | ||
| [allProperties[0].range[0], allProperties.at(-1).range[1]], | ||
| text | ||
| ); | ||
| } | ||
| }); | ||
| } | ||
| }; | ||
| }) | ||
| var name = "create-route-property-order"; | ||
| var rule = createRule({ | ||
| name, | ||
| meta: { | ||
| type: "problem", | ||
| docs: { | ||
| description: "Ensure correct order of inference sensitive properties for createRoute functions", | ||
| recommended: "error" | ||
| }, | ||
| messages: { invalidOrder: "Invalid order of properties for `{{function}}`." }, | ||
| schema: [], | ||
| hasSuggestions: true, | ||
| fixable: "code" | ||
| }, | ||
| defaultOptions: [], | ||
| create: require_detect_router_imports.detectTanstackRouterImports((context) => { | ||
| return { CallExpression(node) { | ||
| if (node.callee.type !== _typescript_eslint_utils.AST_NODE_TYPES.Identifier) return; | ||
| const createRouteFunction = node.callee.name; | ||
| if (!isCreateRouteFunction(createRouteFunction)) return; | ||
| let args = node.arguments; | ||
| if (require_constants.createRouteFunctionsIndirect.includes(createRouteFunction)) if (node.parent.type === _typescript_eslint_utils.AST_NODE_TYPES.CallExpression) args = node.parent.arguments; | ||
| else return; | ||
| const argument = args[0]; | ||
| if (argument === void 0 || argument.type !== "ObjectExpression") return; | ||
| const allProperties = argument.properties; | ||
| if (allProperties.length < 2) return; | ||
| const sortedProperties = require_create_route_property_order_utils.sortDataByOrder(allProperties.flatMap((p) => { | ||
| if (p.type === _typescript_eslint_utils.AST_NODE_TYPES.Property && p.key.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier) return { | ||
| name: p.key.name, | ||
| property: p | ||
| }; | ||
| else if (p.type === _typescript_eslint_utils.AST_NODE_TYPES.SpreadElement) if (p.argument.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier) return { | ||
| name: p.argument.name, | ||
| property: p | ||
| }; | ||
| else throw new Error("Unsupported spread element"); | ||
| return []; | ||
| }), require_constants.sortRules, "name"); | ||
| if (sortedProperties === null) return; | ||
| context.report({ | ||
| node: argument, | ||
| data: { function: node.callee.name }, | ||
| messageId: "invalidOrder", | ||
| fix(fixer) { | ||
| const sourceCode = context.sourceCode; | ||
| const text = sortedProperties.reduce((sourceText, specifier, index) => { | ||
| let text = ""; | ||
| if (index < allProperties.length - 1) text = sourceCode.getText().slice(allProperties[index].range[1], allProperties[index + 1].range[0]); | ||
| return sourceText + sourceCode.getText(specifier.property) + text; | ||
| }, ""); | ||
| return fixer.replaceTextRange([allProperties[0].range[0], allProperties.at(-1).range[1]], text); | ||
| } | ||
| }); | ||
| } }; | ||
| }) | ||
| }); | ||
| //#endregion | ||
| exports.name = name; | ||
| exports.rule = rule; | ||
| //# sourceMappingURL=create-route-property-order.rule.cjs.map | ||
| //# sourceMappingURL=create-route-property-order.rule.cjs.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"create-route-property-order.rule.cjs","sources":["../../../../src/rules/create-route-property-order/create-route-property-order.rule.ts"],"sourcesContent":["import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils'\n\nimport { getDocsUrl } from '../../utils/get-docs-url'\nimport { detectTanstackRouterImports } from '../../utils/detect-router-imports'\nimport { sortDataByOrder } from './create-route-property-order.utils'\nimport {\n createRouteFunctions,\n createRouteFunctionsIndirect,\n sortRules,\n} from './constants'\nimport type { CreateRouteFunction } from './constants'\nimport type { ExtraRuleDocs } from '../../types'\n\nconst createRule = ESLintUtils.RuleCreator<ExtraRuleDocs>(getDocsUrl)\n\nconst createRouteFunctionSet = new Set(createRouteFunctions)\nfunction isCreateRouteFunction(node: any): node is CreateRouteFunction {\n return createRouteFunctionSet.has(node)\n}\n\nexport const name = 'create-route-property-order'\n\nexport const rule = createRule({\n name,\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Ensure correct order of inference sensitive properties for createRoute functions',\n recommended: 'error',\n },\n messages: {\n invalidOrder: 'Invalid order of properties for `{{function}}`.',\n },\n schema: [],\n hasSuggestions: true,\n fixable: 'code',\n },\n defaultOptions: [],\n\n create: detectTanstackRouterImports((context) => {\n return {\n CallExpression(node) {\n if (node.callee.type !== AST_NODE_TYPES.Identifier) {\n return\n }\n const createRouteFunction = node.callee.name\n if (!isCreateRouteFunction(createRouteFunction)) {\n return\n }\n let args = node.arguments\n if (createRouteFunctionsIndirect.includes(createRouteFunction as any)) {\n if (node.parent.type === AST_NODE_TYPES.CallExpression) {\n args = node.parent.arguments\n } else {\n return\n }\n }\n\n const argument = args[0]\n if (argument === undefined || argument.type !== 'ObjectExpression') {\n return\n }\n\n const allProperties = argument.properties\n // no need to sort if there is at max 1 property\n if (allProperties.length < 2) {\n return\n }\n\n const properties = allProperties.flatMap((p) => {\n if (\n p.type === AST_NODE_TYPES.Property &&\n p.key.type === AST_NODE_TYPES.Identifier\n ) {\n return { name: p.key.name, property: p }\n } else if (p.type === AST_NODE_TYPES.SpreadElement) {\n if (p.argument.type === AST_NODE_TYPES.Identifier) {\n return { name: p.argument.name, property: p }\n } else {\n throw new Error('Unsupported spread element')\n }\n }\n return []\n })\n\n const sortedProperties = sortDataByOrder(properties, sortRules, 'name')\n if (sortedProperties === null) {\n return\n }\n context.report({\n node: argument,\n data: { function: node.callee.name },\n messageId: 'invalidOrder',\n fix(fixer) {\n const sourceCode = context.sourceCode\n\n const text = sortedProperties.reduce(\n (sourceText, specifier, index) => {\n let text = ''\n if (index < allProperties.length - 1) {\n text = sourceCode\n .getText()\n .slice(\n allProperties[index]!.range[1],\n allProperties[index + 1]!.range[0],\n )\n }\n return (\n sourceText + sourceCode.getText(specifier.property) + text\n )\n },\n '',\n )\n return fixer.replaceTextRange(\n [allProperties[0]!.range[0], allProperties.at(-1)!.range[1]],\n text,\n )\n },\n })\n },\n }\n }),\n})\n"],"names":["ESLintUtils","getDocsUrl","createRouteFunctions","detectTanstackRouterImports","AST_NODE_TYPES","createRouteFunctionsIndirect","sortDataByOrder","sortRules","text"],"mappings":";;;;;;;AAaA,MAAM,aAAaA,MAAAA,YAAY,YAA2BC,qBAAU;AAEpE,MAAM,yBAAyB,IAAI,IAAIC,8BAAoB;AAC3D,SAAS,sBAAsB,MAAwC;AACrE,SAAO,uBAAuB,IAAI,IAAI;AACxC;AAEO,MAAM,OAAO;AAEb,MAAM,OAAO,WAAW;AAAA,EAC7B;AAAA,EACA,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,MACF,aAAa;AAAA,IAAA;AAAA,IAEf,UAAU;AAAA,MACR,cAAc;AAAA,IAAA;AAAA,IAEhB,QAAQ,CAAA;AAAA,IACR,gBAAgB;AAAA,IAChB,SAAS;AAAA,EAAA;AAAA,EAEX,gBAAgB,CAAA;AAAA,EAEhB,QAAQC,oBAAAA,4BAA4B,CAAC,YAAY;AAC/C,WAAO;AAAA,MACL,eAAe,MAAM;AACnB,YAAI,KAAK,OAAO,SAASC,MAAAA,eAAe,YAAY;AAClD;AAAA,QACF;AACA,cAAM,sBAAsB,KAAK,OAAO;AACxC,YAAI,CAAC,sBAAsB,mBAAmB,GAAG;AAC/C;AAAA,QACF;AACA,YAAI,OAAO,KAAK;AAChB,YAAIC,UAAAA,6BAA6B,SAAS,mBAA0B,GAAG;AACrE,cAAI,KAAK,OAAO,SAASD,MAAAA,eAAe,gBAAgB;AACtD,mBAAO,KAAK,OAAO;AAAA,UACrB,OAAO;AACL;AAAA,UACF;AAAA,QACF;AAEA,cAAM,WAAW,KAAK,CAAC;AACvB,YAAI,aAAa,UAAa,SAAS,SAAS,oBAAoB;AAClE;AAAA,QACF;AAEA,cAAM,gBAAgB,SAAS;AAE/B,YAAI,cAAc,SAAS,GAAG;AAC5B;AAAA,QACF;AAEA,cAAM,aAAa,cAAc,QAAQ,CAAC,MAAM;AAC9C,cACE,EAAE,SAASA,MAAAA,eAAe,YAC1B,EAAE,IAAI,SAASA,MAAAA,eAAe,YAC9B;AACA,mBAAO,EAAE,MAAM,EAAE,IAAI,MAAM,UAAU,EAAA;AAAA,UACvC,WAAW,EAAE,SAASA,MAAAA,eAAe,eAAe;AAClD,gBAAI,EAAE,SAAS,SAASA,MAAAA,eAAe,YAAY;AACjD,qBAAO,EAAE,MAAM,EAAE,SAAS,MAAM,UAAU,EAAA;AAAA,YAC5C,OAAO;AACL,oBAAM,IAAI,MAAM,4BAA4B;AAAA,YAC9C;AAAA,UACF;AACA,iBAAO,CAAA;AAAA,QACT,CAAC;AAED,cAAM,mBAAmBE,+BAAAA,gBAAgB,YAAYC,UAAAA,WAAW,MAAM;AACtE,YAAI,qBAAqB,MAAM;AAC7B;AAAA,QACF;AACA,gBAAQ,OAAO;AAAA,UACb,MAAM;AAAA,UACN,MAAM,EAAE,UAAU,KAAK,OAAO,KAAA;AAAA,UAC9B,WAAW;AAAA,UACX,IAAI,OAAO;AACT,kBAAM,aAAa,QAAQ;AAE3B,kBAAM,OAAO,iBAAiB;AAAA,cAC5B,CAAC,YAAY,WAAW,UAAU;AAChC,oBAAIC,QAAO;AACX,oBAAI,QAAQ,cAAc,SAAS,GAAG;AACpCA,0BAAO,WACJ,QAAA,EACA;AAAA,oBACC,cAAc,KAAK,EAAG,MAAM,CAAC;AAAA,oBAC7B,cAAc,QAAQ,CAAC,EAAG,MAAM,CAAC;AAAA,kBAAA;AAAA,gBAEvC;AACA,uBACE,aAAa,WAAW,QAAQ,UAAU,QAAQ,IAAIA;AAAAA,cAE1D;AAAA,cACA;AAAA,YAAA;AAEF,mBAAO,MAAM;AAAA,cACX,CAAC,cAAc,CAAC,EAAG,MAAM,CAAC,GAAG,cAAc,GAAG,EAAE,EAAG,MAAM,CAAC,CAAC;AAAA,cAC3D;AAAA,YAAA;AAAA,UAEJ;AAAA,QAAA,CACD;AAAA,MACH;AAAA,IAAA;AAAA,EAEJ,CAAC;AACH,CAAC;;;"} | ||
| {"version":3,"file":"create-route-property-order.rule.cjs","names":[],"sources":["../../../../src/rules/create-route-property-order/create-route-property-order.rule.ts"],"sourcesContent":["import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils'\n\nimport { getDocsUrl } from '../../utils/get-docs-url'\nimport { detectTanstackRouterImports } from '../../utils/detect-router-imports'\nimport { sortDataByOrder } from './create-route-property-order.utils'\nimport {\n createRouteFunctions,\n createRouteFunctionsIndirect,\n sortRules,\n} from './constants'\nimport type { CreateRouteFunction } from './constants'\nimport type { ExtraRuleDocs } from '../../types'\n\nconst createRule = ESLintUtils.RuleCreator<ExtraRuleDocs>(getDocsUrl)\n\nconst createRouteFunctionSet = new Set(createRouteFunctions)\nfunction isCreateRouteFunction(node: any): node is CreateRouteFunction {\n return createRouteFunctionSet.has(node)\n}\n\nexport const name = 'create-route-property-order'\n\nexport const rule = createRule({\n name,\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Ensure correct order of inference sensitive properties for createRoute functions',\n recommended: 'error',\n },\n messages: {\n invalidOrder: 'Invalid order of properties for `{{function}}`.',\n },\n schema: [],\n hasSuggestions: true,\n fixable: 'code',\n },\n defaultOptions: [],\n\n create: detectTanstackRouterImports((context) => {\n return {\n CallExpression(node) {\n if (node.callee.type !== AST_NODE_TYPES.Identifier) {\n return\n }\n const createRouteFunction = node.callee.name\n if (!isCreateRouteFunction(createRouteFunction)) {\n return\n }\n let args = node.arguments\n if (createRouteFunctionsIndirect.includes(createRouteFunction as any)) {\n if (node.parent.type === AST_NODE_TYPES.CallExpression) {\n args = node.parent.arguments\n } else {\n return\n }\n }\n\n const argument = args[0]\n if (argument === undefined || argument.type !== 'ObjectExpression') {\n return\n }\n\n const allProperties = argument.properties\n // no need to sort if there is at max 1 property\n if (allProperties.length < 2) {\n return\n }\n\n const properties = allProperties.flatMap((p) => {\n if (\n p.type === AST_NODE_TYPES.Property &&\n p.key.type === AST_NODE_TYPES.Identifier\n ) {\n return { name: p.key.name, property: p }\n } else if (p.type === AST_NODE_TYPES.SpreadElement) {\n if (p.argument.type === AST_NODE_TYPES.Identifier) {\n return { name: p.argument.name, property: p }\n } else {\n throw new Error('Unsupported spread element')\n }\n }\n return []\n })\n\n const sortedProperties = sortDataByOrder(properties, sortRules, 'name')\n if (sortedProperties === null) {\n return\n }\n context.report({\n node: argument,\n data: { function: node.callee.name },\n messageId: 'invalidOrder',\n fix(fixer) {\n const sourceCode = context.sourceCode\n\n const text = sortedProperties.reduce(\n (sourceText, specifier, index) => {\n let text = ''\n if (index < allProperties.length - 1) {\n text = sourceCode\n .getText()\n .slice(\n allProperties[index]!.range[1],\n allProperties[index + 1]!.range[0],\n )\n }\n return (\n sourceText + sourceCode.getText(specifier.property) + text\n )\n },\n '',\n )\n return fixer.replaceTextRange(\n [allProperties[0]!.range[0], allProperties.at(-1)!.range[1]],\n text,\n )\n },\n })\n },\n }\n }),\n})\n"],"mappings":";;;;;;AAaA,IAAM,aAAa,yBAAA,YAAY,YAA2B,qBAAA,WAAW;AAErE,IAAM,yBAAyB,IAAI,IAAI,kBAAA,qBAAqB;AAC5D,SAAS,sBAAsB,MAAwC;AACrE,QAAO,uBAAuB,IAAI,KAAK;;AAGzC,IAAa,OAAO;AAEpB,IAAa,OAAO,WAAW;CAC7B;CACA,MAAM;EACJ,MAAM;EACN,MAAM;GACJ,aACE;GACF,aAAa;GACd;EACD,UAAU,EACR,cAAc,mDACf;EACD,QAAQ,EAAE;EACV,gBAAgB;EAChB,SAAS;EACV;CACD,gBAAgB,EAAE;CAElB,QAAQ,8BAAA,6BAA6B,YAAY;AAC/C,SAAO,EACL,eAAe,MAAM;AACnB,OAAI,KAAK,OAAO,SAAS,yBAAA,eAAe,WACtC;GAEF,MAAM,sBAAsB,KAAK,OAAO;AACxC,OAAI,CAAC,sBAAsB,oBAAoB,CAC7C;GAEF,IAAI,OAAO,KAAK;AAChB,OAAI,kBAAA,6BAA6B,SAAS,oBAA2B,CACnE,KAAI,KAAK,OAAO,SAAS,yBAAA,eAAe,eACtC,QAAO,KAAK,OAAO;OAEnB;GAIJ,MAAM,WAAW,KAAK;AACtB,OAAI,aAAa,KAAA,KAAa,SAAS,SAAS,mBAC9C;GAGF,MAAM,gBAAgB,SAAS;AAE/B,OAAI,cAAc,SAAS,EACzB;GAmBF,MAAM,mBAAmB,0CAAA,gBAhBN,cAAc,SAAS,MAAM;AAC9C,QACE,EAAE,SAAS,yBAAA,eAAe,YAC1B,EAAE,IAAI,SAAS,yBAAA,eAAe,WAE9B,QAAO;KAAE,MAAM,EAAE,IAAI;KAAM,UAAU;KAAG;aAC/B,EAAE,SAAS,yBAAA,eAAe,cACnC,KAAI,EAAE,SAAS,SAAS,yBAAA,eAAe,WACrC,QAAO;KAAE,MAAM,EAAE,SAAS;KAAM,UAAU;KAAG;QAE7C,OAAM,IAAI,MAAM,6BAA6B;AAGjD,WAAO,EAAE;KACT,EAEmD,kBAAA,WAAW,OAAO;AACvE,OAAI,qBAAqB,KACvB;AAEF,WAAQ,OAAO;IACb,MAAM;IACN,MAAM,EAAE,UAAU,KAAK,OAAO,MAAM;IACpC,WAAW;IACX,IAAI,OAAO;KACT,MAAM,aAAa,QAAQ;KAE3B,MAAM,OAAO,iBAAiB,QAC3B,YAAY,WAAW,UAAU;MAChC,IAAI,OAAO;AACX,UAAI,QAAQ,cAAc,SAAS,EACjC,QAAO,WACJ,SAAS,CACT,MACC,cAAc,OAAQ,MAAM,IAC5B,cAAc,QAAQ,GAAI,MAAM,GACjC;AAEL,aACE,aAAa,WAAW,QAAQ,UAAU,SAAS,GAAG;QAG1D,GACD;AACD,YAAO,MAAM,iBACX,CAAC,cAAc,GAAI,MAAM,IAAI,cAAc,GAAG,GAAG,CAAE,MAAM,GAAG,EAC5D,KACD;;IAEJ,CAAC;KAEL;GACD;CACH,CAAC"} |
@@ -1,50 +0,39 @@ | ||
| "use strict"; | ||
| Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); | ||
| //#region src/rules/create-route-property-order/create-route-property-order.utils.ts | ||
| function sortDataByOrder(data, orderRules, key) { | ||
| const getSubsetIndex = (item, subsets) => { | ||
| for (let i = 0; i < subsets.length; i++) { | ||
| if (subsets[i]?.includes(item)) { | ||
| return i; | ||
| } | ||
| } | ||
| return null; | ||
| }; | ||
| const orderSets = orderRules.reduce( | ||
| (sets, [A, B]) => [...sets, A, B], | ||
| [] | ||
| ); | ||
| const inOrderArray = data.filter( | ||
| (item) => getSubsetIndex(item[key], orderSets) !== null | ||
| ); | ||
| let wasResorted = false; | ||
| const sortedArray = inOrderArray.sort((a, b) => { | ||
| const aKey = a[key], bKey = b[key]; | ||
| const aSubsetIndex = getSubsetIndex(aKey, orderSets); | ||
| const bSubsetIndex = getSubsetIndex(bKey, orderSets); | ||
| if (aSubsetIndex !== null && bSubsetIndex !== null && aSubsetIndex !== bSubsetIndex) { | ||
| return aSubsetIndex - bSubsetIndex; | ||
| } | ||
| return 0; | ||
| }); | ||
| const inOrderIterator = sortedArray.values(); | ||
| const result = data.map((item) => { | ||
| if (getSubsetIndex(item[key], orderSets) !== null) { | ||
| const sortedItem = inOrderIterator.next().value; | ||
| if (sortedItem[key] !== item[key]) { | ||
| wasResorted = true; | ||
| } | ||
| return sortedItem; | ||
| } | ||
| return item; | ||
| }); | ||
| if (!wasResorted) { | ||
| return null; | ||
| } | ||
| return result; | ||
| const getSubsetIndex = (item, subsets) => { | ||
| for (let i = 0; i < subsets.length; i++) if (subsets[i]?.includes(item)) return i; | ||
| return null; | ||
| }; | ||
| const orderSets = orderRules.reduce((sets, [A, B]) => [ | ||
| ...sets, | ||
| A, | ||
| B | ||
| ], []); | ||
| const inOrderArray = data.filter((item) => getSubsetIndex(item[key], orderSets) !== null); | ||
| let wasResorted = false; | ||
| const inOrderIterator = inOrderArray.sort((a, b) => { | ||
| const aKey = a[key], bKey = b[key]; | ||
| const aSubsetIndex = getSubsetIndex(aKey, orderSets); | ||
| const bSubsetIndex = getSubsetIndex(bKey, orderSets); | ||
| if (aSubsetIndex !== null && bSubsetIndex !== null && aSubsetIndex !== bSubsetIndex) return aSubsetIndex - bSubsetIndex; | ||
| return 0; | ||
| }).values(); | ||
| const result = data.map((item) => { | ||
| if (getSubsetIndex(item[key], orderSets) !== null) { | ||
| const sortedItem = inOrderIterator.next().value; | ||
| if (sortedItem[key] !== item[key]) wasResorted = true; | ||
| return sortedItem; | ||
| } | ||
| return item; | ||
| }); | ||
| if (!wasResorted) return null; | ||
| return result; | ||
| } | ||
| function getCheckedProperties(orderRules) { | ||
| return [...new Set(orderRules.flat(2))]; | ||
| return [...new Set(orderRules.flat(2))]; | ||
| } | ||
| //#endregion | ||
| exports.getCheckedProperties = getCheckedProperties; | ||
| exports.sortDataByOrder = sortDataByOrder; | ||
| //# sourceMappingURL=create-route-property-order.utils.cjs.map | ||
| //# sourceMappingURL=create-route-property-order.utils.cjs.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"create-route-property-order.utils.cjs","sources":["../../../../src/rules/create-route-property-order/create-route-property-order.utils.ts"],"sourcesContent":["export function sortDataByOrder<T, TKey extends keyof T>(\n data: Array<T> | ReadonlyArray<T>,\n orderRules: ReadonlyArray<\n Readonly<[ReadonlyArray<T[TKey]>, ReadonlyArray<T[TKey]>]>\n >,\n key: TKey,\n): Array<T> | null {\n const getSubsetIndex = (\n item: T[TKey],\n subsets: ReadonlyArray<ReadonlyArray<T[TKey]> | Array<T[TKey]>>,\n ): number | null => {\n for (let i = 0; i < subsets.length; i++) {\n if (subsets[i]?.includes(item)) {\n return i\n }\n }\n return null\n }\n\n const orderSets = orderRules.reduce(\n (sets, [A, B]) => [...sets, A, B],\n [] as Array<ReadonlyArray<T[TKey]> | Array<T[TKey]>>,\n )\n\n const inOrderArray = data.filter(\n (item) => getSubsetIndex(item[key], orderSets) !== null,\n )\n\n let wasResorted = false as boolean\n\n // Sort by the relative order defined by the rules\n const sortedArray = inOrderArray.sort((a, b) => {\n const aKey = a[key],\n bKey = b[key]\n const aSubsetIndex = getSubsetIndex(aKey, orderSets)\n const bSubsetIndex = getSubsetIndex(bKey, orderSets)\n\n // If both items belong to different subsets, sort by their subset order\n if (\n aSubsetIndex !== null &&\n bSubsetIndex !== null &&\n aSubsetIndex !== bSubsetIndex\n ) {\n return aSubsetIndex - bSubsetIndex\n }\n\n // If both items belong to the same subset or neither is in the subset, keep their relative order\n return 0\n })\n\n const inOrderIterator = sortedArray.values()\n const result = data.map((item) => {\n if (getSubsetIndex(item[key], orderSets) !== null) {\n const sortedItem = inOrderIterator.next().value!\n if (sortedItem[key] !== item[key]) {\n wasResorted = true\n }\n return sortedItem\n }\n return item\n })\n\n if (!wasResorted) {\n return null\n }\n return result\n}\n\nexport function getCheckedProperties<T>(\n orderRules: ReadonlyArray<ReadonlyArray<ReadonlyArray<T>>>,\n): ReadonlyArray<T> {\n return [...new Set<T>(orderRules.flat(2))]\n}\n"],"names":[],"mappings":";;AAAO,SAAS,gBACd,MACA,YAGA,KACiB;AACjB,QAAM,iBAAiB,CACrB,MACA,YACkB;AAClB,aAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,UAAI,QAAQ,CAAC,GAAG,SAAS,IAAI,GAAG;AAC9B,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,WAAW;AAAA,IAC3B,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,GAAG,CAAC;AAAA,IAChC,CAAA;AAAA,EAAC;AAGH,QAAM,eAAe,KAAK;AAAA,IACxB,CAAC,SAAS,eAAe,KAAK,GAAG,GAAG,SAAS,MAAM;AAAA,EAAA;AAGrD,MAAI,cAAc;AAGlB,QAAM,cAAc,aAAa,KAAK,CAAC,GAAG,MAAM;AAC9C,UAAM,OAAO,EAAE,GAAG,GAChB,OAAO,EAAE,GAAG;AACd,UAAM,eAAe,eAAe,MAAM,SAAS;AACnD,UAAM,eAAe,eAAe,MAAM,SAAS;AAGnD,QACE,iBAAiB,QACjB,iBAAiB,QACjB,iBAAiB,cACjB;AACA,aAAO,eAAe;AAAA,IACxB;AAGA,WAAO;AAAA,EACT,CAAC;AAED,QAAM,kBAAkB,YAAY,OAAA;AACpC,QAAM,SAAS,KAAK,IAAI,CAAC,SAAS;AAChC,QAAI,eAAe,KAAK,GAAG,GAAG,SAAS,MAAM,MAAM;AACjD,YAAM,aAAa,gBAAgB,KAAA,EAAO;AAC1C,UAAI,WAAW,GAAG,MAAM,KAAK,GAAG,GAAG;AACjC,sBAAc;AAAA,MAChB;AACA,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT,CAAC;AAED,MAAI,CAAC,aAAa;AAChB,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEO,SAAS,qBACd,YACkB;AAClB,SAAO,CAAC,GAAG,IAAI,IAAO,WAAW,KAAK,CAAC,CAAC,CAAC;AAC3C;;;"} | ||
| {"version":3,"file":"create-route-property-order.utils.cjs","names":[],"sources":["../../../../src/rules/create-route-property-order/create-route-property-order.utils.ts"],"sourcesContent":["export function sortDataByOrder<T, TKey extends keyof T>(\n data: Array<T> | ReadonlyArray<T>,\n orderRules: ReadonlyArray<\n Readonly<[ReadonlyArray<T[TKey]>, ReadonlyArray<T[TKey]>]>\n >,\n key: TKey,\n): Array<T> | null {\n const getSubsetIndex = (\n item: T[TKey],\n subsets: ReadonlyArray<ReadonlyArray<T[TKey]> | Array<T[TKey]>>,\n ): number | null => {\n for (let i = 0; i < subsets.length; i++) {\n if (subsets[i]?.includes(item)) {\n return i\n }\n }\n return null\n }\n\n const orderSets = orderRules.reduce(\n (sets, [A, B]) => [...sets, A, B],\n [] as Array<ReadonlyArray<T[TKey]> | Array<T[TKey]>>,\n )\n\n const inOrderArray = data.filter(\n (item) => getSubsetIndex(item[key], orderSets) !== null,\n )\n\n let wasResorted = false as boolean\n\n // Sort by the relative order defined by the rules\n const sortedArray = inOrderArray.sort((a, b) => {\n const aKey = a[key],\n bKey = b[key]\n const aSubsetIndex = getSubsetIndex(aKey, orderSets)\n const bSubsetIndex = getSubsetIndex(bKey, orderSets)\n\n // If both items belong to different subsets, sort by their subset order\n if (\n aSubsetIndex !== null &&\n bSubsetIndex !== null &&\n aSubsetIndex !== bSubsetIndex\n ) {\n return aSubsetIndex - bSubsetIndex\n }\n\n // If both items belong to the same subset or neither is in the subset, keep their relative order\n return 0\n })\n\n const inOrderIterator = sortedArray.values()\n const result = data.map((item) => {\n if (getSubsetIndex(item[key], orderSets) !== null) {\n const sortedItem = inOrderIterator.next().value!\n if (sortedItem[key] !== item[key]) {\n wasResorted = true\n }\n return sortedItem\n }\n return item\n })\n\n if (!wasResorted) {\n return null\n }\n return result\n}\n\nexport function getCheckedProperties<T>(\n orderRules: ReadonlyArray<ReadonlyArray<ReadonlyArray<T>>>,\n): ReadonlyArray<T> {\n return [...new Set<T>(orderRules.flat(2))]\n}\n"],"mappings":";AAAA,SAAgB,gBACd,MACA,YAGA,KACiB;CACjB,MAAM,kBACJ,MACA,YACkB;AAClB,OAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,IAClC,KAAI,QAAQ,IAAI,SAAS,KAAK,CAC5B,QAAO;AAGX,SAAO;;CAGT,MAAM,YAAY,WAAW,QAC1B,MAAM,CAAC,GAAG,OAAO;EAAC,GAAG;EAAM;EAAG;EAAE,EACjC,EAAE,CACH;CAED,MAAM,eAAe,KAAK,QACvB,SAAS,eAAe,KAAK,MAAM,UAAU,KAAK,KACpD;CAED,IAAI,cAAc;CAsBlB,MAAM,kBAnBc,aAAa,MAAM,GAAG,MAAM;EAC9C,MAAM,OAAO,EAAE,MACb,OAAO,EAAE;EACX,MAAM,eAAe,eAAe,MAAM,UAAU;EACpD,MAAM,eAAe,eAAe,MAAM,UAAU;AAGpD,MACE,iBAAiB,QACjB,iBAAiB,QACjB,iBAAiB,aAEjB,QAAO,eAAe;AAIxB,SAAO;GACP,CAEkC,QAAQ;CAC5C,MAAM,SAAS,KAAK,KAAK,SAAS;AAChC,MAAI,eAAe,KAAK,MAAM,UAAU,KAAK,MAAM;GACjD,MAAM,aAAa,gBAAgB,MAAM,CAAC;AAC1C,OAAI,WAAW,SAAS,KAAK,KAC3B,eAAc;AAEhB,UAAO;;AAET,SAAO;GACP;AAEF,KAAI,CAAC,YACH,QAAO;AAET,QAAO;;AAGT,SAAgB,qBACd,YACkB;AAClB,QAAO,CAAC,GAAG,IAAI,IAAO,WAAW,KAAK,EAAE,CAAC,CAAC"} |
@@ -1,13 +0,28 @@ | ||
| "use strict"; | ||
| Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); | ||
| const pathAsFirstArgFunctions = [ | ||
| "createFileRoute", | ||
| "createLazyFileRoute", | ||
| "createLazyRoute" | ||
| //#region src/rules/route-param-names/constants.ts | ||
| /** | ||
| * Functions where the path is passed as the first argument (string literal) | ||
| * e.g., createFileRoute('/path/$param')(...) | ||
| */ | ||
| var pathAsFirstArgFunctions = [ | ||
| "createFileRoute", | ||
| "createLazyFileRoute", | ||
| "createLazyRoute" | ||
| ]; | ||
| const pathAsPropertyFunctions = ["createRoute"]; | ||
| const VALID_PARAM_NAME_REGEX = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/; | ||
| /** | ||
| * Functions where the path is a property in the options object | ||
| * e.g., createRoute({ path: '/path/$param' }) | ||
| */ | ||
| var pathAsPropertyFunctions = ["createRoute"]; | ||
| [...pathAsFirstArgFunctions, ...pathAsPropertyFunctions]; | ||
| /** | ||
| * Regex for valid JavaScript identifier (param name) | ||
| * Must start with letter, underscore, or dollar sign | ||
| * Can contain letters, numbers, underscores, or dollar signs | ||
| */ | ||
| var VALID_PARAM_NAME_REGEX = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/; | ||
| //#endregion | ||
| exports.VALID_PARAM_NAME_REGEX = VALID_PARAM_NAME_REGEX; | ||
| exports.pathAsFirstArgFunctions = pathAsFirstArgFunctions; | ||
| exports.pathAsPropertyFunctions = pathAsPropertyFunctions; | ||
| //# sourceMappingURL=constants.cjs.map | ||
| //# sourceMappingURL=constants.cjs.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"constants.cjs","sources":["../../../../src/rules/route-param-names/constants.ts"],"sourcesContent":["/**\n * Functions where the path is passed as the first argument (string literal)\n * e.g., createFileRoute('/path/$param')(...)\n */\nexport const pathAsFirstArgFunctions = [\n 'createFileRoute',\n 'createLazyFileRoute',\n 'createLazyRoute',\n] as const\n\nexport type PathAsFirstArgFunction = (typeof pathAsFirstArgFunctions)[number]\n\n/**\n * Functions where the path is a property in the options object\n * e.g., createRoute({ path: '/path/$param' })\n */\nexport const pathAsPropertyFunctions = ['createRoute'] as const\n\nexport type PathAsPropertyFunction = (typeof pathAsPropertyFunctions)[number]\n\n/**\n * All route functions that need param name validation\n */\nexport const allRouteFunctions = [\n ...pathAsFirstArgFunctions,\n ...pathAsPropertyFunctions,\n] as const\n\nexport type RouteFunction = (typeof allRouteFunctions)[number]\n\n/**\n * Regex for valid JavaScript identifier (param name)\n * Must start with letter, underscore, or dollar sign\n * Can contain letters, numbers, underscores, or dollar signs\n */\nexport const VALID_PARAM_NAME_REGEX = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/\n"],"names":[],"mappings":";;AAIO,MAAM,0BAA0B;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AACF;AAQO,MAAM,0BAA0B,CAAC,aAAa;AAmB9C,MAAM,yBAAyB;;;;"} | ||
| {"version":3,"file":"constants.cjs","names":[],"sources":["../../../../src/rules/route-param-names/constants.ts"],"sourcesContent":["/**\n * Functions where the path is passed as the first argument (string literal)\n * e.g., createFileRoute('/path/$param')(...)\n */\nexport const pathAsFirstArgFunctions = [\n 'createFileRoute',\n 'createLazyFileRoute',\n 'createLazyRoute',\n] as const\n\nexport type PathAsFirstArgFunction = (typeof pathAsFirstArgFunctions)[number]\n\n/**\n * Functions where the path is a property in the options object\n * e.g., createRoute({ path: '/path/$param' })\n */\nexport const pathAsPropertyFunctions = ['createRoute'] as const\n\nexport type PathAsPropertyFunction = (typeof pathAsPropertyFunctions)[number]\n\n/**\n * All route functions that need param name validation\n */\nexport const allRouteFunctions = [\n ...pathAsFirstArgFunctions,\n ...pathAsPropertyFunctions,\n] as const\n\nexport type RouteFunction = (typeof allRouteFunctions)[number]\n\n/**\n * Regex for valid JavaScript identifier (param name)\n * Must start with letter, underscore, or dollar sign\n * Can contain letters, numbers, underscores, or dollar signs\n */\nexport const VALID_PARAM_NAME_REGEX = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/\n"],"mappings":";;;;;AAIA,IAAa,0BAA0B;CACrC;CACA;CACA;CACD;;;;;AAQD,IAAa,0BAA0B,CAAC,cAAc;AAOrB,CAC/B,GAAG,yBACH,GAAG,wBACJ;;;;;;AASD,IAAa,yBAAyB"} |
@@ -1,98 +0,78 @@ | ||
| "use strict"; | ||
| Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); | ||
| const utils = require("@typescript-eslint/utils"); | ||
| const getDocsUrl = require("../../utils/get-docs-url.cjs"); | ||
| const detectRouterImports = require("../../utils/detect-router-imports.cjs"); | ||
| const routeParamNames_utils = require("./route-param-names.utils.cjs"); | ||
| const constants = require("./constants.cjs"); | ||
| const createRule = utils.ESLintUtils.RuleCreator(getDocsUrl.getDocsUrl); | ||
| const pathAsFirstArgSet = new Set(constants.pathAsFirstArgFunctions); | ||
| const pathAsPropertySet = new Set(constants.pathAsPropertyFunctions); | ||
| const name = "route-param-names"; | ||
| const rule = createRule({ | ||
| name, | ||
| meta: { | ||
| type: "problem", | ||
| docs: { | ||
| description: "Ensure route param names are valid JavaScript identifiers", | ||
| recommended: "error" | ||
| }, | ||
| messages: { | ||
| invalidParamName: 'Invalid param name "{{paramName}}" in route path. Param names must be valid JavaScript identifiers (match /[a-zA-Z_$][a-zA-Z0-9_$]*/).' | ||
| }, | ||
| schema: [] | ||
| }, | ||
| defaultOptions: [], | ||
| create: detectRouterImports.detectTanstackRouterImports((context, _, helpers) => { | ||
| function reportInvalidParams(node, path) { | ||
| const invalidParams = routeParamNames_utils.getInvalidParams(path); | ||
| for (const param of invalidParams) { | ||
| context.report({ | ||
| node, | ||
| messageId: "invalidParamName", | ||
| data: { paramName: param.paramName } | ||
| }); | ||
| } | ||
| } | ||
| function getStringLiteralValue(node) { | ||
| if (node.type === utils.AST_NODE_TYPES.Literal && typeof node.value === "string") { | ||
| return node.value; | ||
| } | ||
| if (node.type === utils.AST_NODE_TYPES.TemplateLiteral && node.quasis.length === 1) { | ||
| const cooked = node.quasis[0]?.value.cooked; | ||
| if (cooked != null) { | ||
| return cooked; | ||
| } | ||
| } | ||
| return null; | ||
| } | ||
| return { | ||
| CallExpression(node) { | ||
| if (node.callee.type === utils.AST_NODE_TYPES.Identifier) { | ||
| const funcName = node.callee.name; | ||
| if (!helpers.isTanstackRouterImport(node.callee)) { | ||
| return; | ||
| } | ||
| if (pathAsPropertySet.has(funcName)) { | ||
| const arg = node.arguments[0]; | ||
| if (arg?.type === utils.AST_NODE_TYPES.ObjectExpression) { | ||
| for (const prop of arg.properties) { | ||
| if (prop.type === utils.AST_NODE_TYPES.Property) { | ||
| const isPathKey = prop.key.type === utils.AST_NODE_TYPES.Identifier && prop.key.name === "path" || prop.key.type === utils.AST_NODE_TYPES.Literal && prop.key.value === "path"; | ||
| if (isPathKey) { | ||
| const pathValue = getStringLiteralValue(prop.value); | ||
| if (pathValue) { | ||
| reportInvalidParams(prop.value, pathValue); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| return; | ||
| } | ||
| } | ||
| if (node.callee.type === utils.AST_NODE_TYPES.CallExpression) { | ||
| const innerCall = node.callee; | ||
| if (innerCall.callee.type === utils.AST_NODE_TYPES.Identifier) { | ||
| const funcName = innerCall.callee.name; | ||
| if (!helpers.isTanstackRouterImport(innerCall.callee)) { | ||
| return; | ||
| } | ||
| if (pathAsFirstArgSet.has(funcName)) { | ||
| const pathArg = innerCall.arguments[0]; | ||
| if (pathArg) { | ||
| const pathValue = getStringLiteralValue(pathArg); | ||
| if (pathValue) { | ||
| reportInvalidParams(pathArg, pathValue); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| }; | ||
| }) | ||
| const require_get_docs_url = require("../../utils/get-docs-url.cjs"); | ||
| const require_detect_router_imports = require("../../utils/detect-router-imports.cjs"); | ||
| const require_constants = require("./constants.cjs"); | ||
| const require_route_param_names_utils = require("./route-param-names.utils.cjs"); | ||
| let _typescript_eslint_utils = require("@typescript-eslint/utils"); | ||
| //#region src/rules/route-param-names/route-param-names.rule.ts | ||
| var createRule = _typescript_eslint_utils.ESLintUtils.RuleCreator(require_get_docs_url.getDocsUrl); | ||
| var pathAsFirstArgSet = new Set(require_constants.pathAsFirstArgFunctions); | ||
| var pathAsPropertySet = new Set(require_constants.pathAsPropertyFunctions); | ||
| var name = "route-param-names"; | ||
| var rule = createRule({ | ||
| name, | ||
| meta: { | ||
| type: "problem", | ||
| docs: { | ||
| description: "Ensure route param names are valid JavaScript identifiers", | ||
| recommended: "error" | ||
| }, | ||
| messages: { invalidParamName: "Invalid param name \"{{paramName}}\" in route path. Param names must be valid JavaScript identifiers (match /[a-zA-Z_$][a-zA-Z0-9_$]*/)." }, | ||
| schema: [] | ||
| }, | ||
| defaultOptions: [], | ||
| create: require_detect_router_imports.detectTanstackRouterImports((context, _, helpers) => { | ||
| function reportInvalidParams(node, path) { | ||
| const invalidParams = require_route_param_names_utils.getInvalidParams(path); | ||
| for (const param of invalidParams) context.report({ | ||
| node, | ||
| messageId: "invalidParamName", | ||
| data: { paramName: param.paramName } | ||
| }); | ||
| } | ||
| function getStringLiteralValue(node) { | ||
| if (node.type === _typescript_eslint_utils.AST_NODE_TYPES.Literal && typeof node.value === "string") return node.value; | ||
| if (node.type === _typescript_eslint_utils.AST_NODE_TYPES.TemplateLiteral && node.quasis.length === 1) { | ||
| const cooked = node.quasis[0]?.value.cooked; | ||
| if (cooked != null) return cooked; | ||
| } | ||
| return null; | ||
| } | ||
| return { CallExpression(node) { | ||
| if (node.callee.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier) { | ||
| const funcName = node.callee.name; | ||
| if (!helpers.isTanstackRouterImport(node.callee)) return; | ||
| if (pathAsPropertySet.has(funcName)) { | ||
| const arg = node.arguments[0]; | ||
| if (arg?.type === _typescript_eslint_utils.AST_NODE_TYPES.ObjectExpression) { | ||
| for (const prop of arg.properties) if (prop.type === _typescript_eslint_utils.AST_NODE_TYPES.Property) { | ||
| if (prop.key.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier && prop.key.name === "path" || prop.key.type === _typescript_eslint_utils.AST_NODE_TYPES.Literal && prop.key.value === "path") { | ||
| const pathValue = getStringLiteralValue(prop.value); | ||
| if (pathValue) reportInvalidParams(prop.value, pathValue); | ||
| } | ||
| } | ||
| } | ||
| return; | ||
| } | ||
| } | ||
| if (node.callee.type === _typescript_eslint_utils.AST_NODE_TYPES.CallExpression) { | ||
| const innerCall = node.callee; | ||
| if (innerCall.callee.type === _typescript_eslint_utils.AST_NODE_TYPES.Identifier) { | ||
| const funcName = innerCall.callee.name; | ||
| if (!helpers.isTanstackRouterImport(innerCall.callee)) return; | ||
| if (pathAsFirstArgSet.has(funcName)) { | ||
| const pathArg = innerCall.arguments[0]; | ||
| if (pathArg) { | ||
| const pathValue = getStringLiteralValue(pathArg); | ||
| if (pathValue) reportInvalidParams(pathArg, pathValue); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } }; | ||
| }) | ||
| }); | ||
| //#endregion | ||
| exports.name = name; | ||
| exports.rule = rule; | ||
| //# sourceMappingURL=route-param-names.rule.cjs.map | ||
| //# sourceMappingURL=route-param-names.rule.cjs.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"route-param-names.rule.cjs","sources":["../../../../src/rules/route-param-names/route-param-names.rule.ts"],"sourcesContent":["import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils'\n\nimport { getDocsUrl } from '../../utils/get-docs-url'\nimport { detectTanstackRouterImports } from '../../utils/detect-router-imports'\nimport { getInvalidParams } from './route-param-names.utils'\nimport { pathAsFirstArgFunctions, pathAsPropertyFunctions } from './constants'\nimport type { TSESTree } from '@typescript-eslint/utils'\nimport type { ExtraRuleDocs } from '../../types'\n\nconst createRule = ESLintUtils.RuleCreator<ExtraRuleDocs>(getDocsUrl)\n\nconst pathAsFirstArgSet = new Set<string>(pathAsFirstArgFunctions)\nconst pathAsPropertySet = new Set<string>(pathAsPropertyFunctions)\n\nexport const name = 'route-param-names'\n\nexport const rule = createRule({\n name,\n meta: {\n type: 'problem',\n docs: {\n description: 'Ensure route param names are valid JavaScript identifiers',\n recommended: 'error',\n },\n messages: {\n invalidParamName:\n 'Invalid param name \"{{paramName}}\" in route path. Param names must be valid JavaScript identifiers (match /[a-zA-Z_$][a-zA-Z0-9_$]*/).',\n },\n schema: [],\n },\n defaultOptions: [],\n\n create: detectTanstackRouterImports((context, _, helpers) => {\n function reportInvalidParams(node: TSESTree.Node, path: string) {\n const invalidParams = getInvalidParams(path)\n\n for (const param of invalidParams) {\n context.report({\n node,\n messageId: 'invalidParamName',\n data: { paramName: param.paramName },\n })\n }\n }\n\n function getStringLiteralValue(node: TSESTree.Node): string | null {\n if (\n node.type === AST_NODE_TYPES.Literal &&\n typeof node.value === 'string'\n ) {\n return node.value\n }\n if (\n node.type === AST_NODE_TYPES.TemplateLiteral &&\n node.quasis.length === 1\n ) {\n const cooked = node.quasis[0]?.value.cooked\n if (cooked != null) {\n return cooked\n }\n }\n return null\n }\n\n return {\n CallExpression(node) {\n // Handle direct function call: createRoute({ path: '...' })\n if (node.callee.type === AST_NODE_TYPES.Identifier) {\n const funcName = node.callee.name\n\n // Skip if not imported from TanStack Router\n if (!helpers.isTanstackRouterImport(node.callee)) {\n return\n }\n\n // Case: createRoute({ path: '/path/$param' }) or createRoute({ 'path': '/path/$param' })\n if (pathAsPropertySet.has(funcName)) {\n const arg = node.arguments[0]\n if (arg?.type === AST_NODE_TYPES.ObjectExpression) {\n for (const prop of arg.properties) {\n if (prop.type === AST_NODE_TYPES.Property) {\n const isPathKey =\n (prop.key.type === AST_NODE_TYPES.Identifier &&\n prop.key.name === 'path') ||\n (prop.key.type === AST_NODE_TYPES.Literal &&\n prop.key.value === 'path')\n if (isPathKey) {\n const pathValue = getStringLiteralValue(prop.value)\n if (pathValue) {\n reportInvalidParams(prop.value, pathValue)\n }\n }\n }\n }\n }\n return\n }\n }\n\n // Handle curried function call: createFileRoute('/path')({ ... })\n if (node.callee.type === AST_NODE_TYPES.CallExpression) {\n const innerCall = node.callee\n\n if (innerCall.callee.type === AST_NODE_TYPES.Identifier) {\n const funcName = innerCall.callee.name\n\n // Skip if not imported from TanStack Router\n if (!helpers.isTanstackRouterImport(innerCall.callee)) {\n return\n }\n\n // Case: createFileRoute('/path/$param')(...) or similar\n if (pathAsFirstArgSet.has(funcName)) {\n const pathArg = innerCall.arguments[0]\n if (pathArg) {\n const pathValue = getStringLiteralValue(pathArg)\n if (pathValue) {\n reportInvalidParams(pathArg, pathValue)\n }\n }\n }\n }\n }\n },\n }\n }),\n})\n"],"names":["ESLintUtils","getDocsUrl","pathAsFirstArgFunctions","pathAsPropertyFunctions","detectTanstackRouterImports","getInvalidParams","AST_NODE_TYPES"],"mappings":";;;;;;;AASA,MAAM,aAAaA,MAAAA,YAAY,YAA2BC,qBAAU;AAEpE,MAAM,oBAAoB,IAAI,IAAYC,iCAAuB;AACjE,MAAM,oBAAoB,IAAI,IAAYC,iCAAuB;AAE1D,MAAM,OAAO;AAEb,MAAM,OAAO,WAAW;AAAA,EAC7B;AAAA,EACA,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aAAa;AAAA,MACb,aAAa;AAAA,IAAA;AAAA,IAEf,UAAU;AAAA,MACR,kBACE;AAAA,IAAA;AAAA,IAEJ,QAAQ,CAAA;AAAA,EAAC;AAAA,EAEX,gBAAgB,CAAA;AAAA,EAEhB,QAAQC,oBAAAA,4BAA4B,CAAC,SAAS,GAAG,YAAY;AAC3D,aAAS,oBAAoB,MAAqB,MAAc;AAC9D,YAAM,gBAAgBC,sBAAAA,iBAAiB,IAAI;AAE3C,iBAAW,SAAS,eAAe;AACjC,gBAAQ,OAAO;AAAA,UACb;AAAA,UACA,WAAW;AAAA,UACX,MAAM,EAAE,WAAW,MAAM,UAAA;AAAA,QAAU,CACpC;AAAA,MACH;AAAA,IACF;AAEA,aAAS,sBAAsB,MAAoC;AACjE,UACE,KAAK,SAASC,MAAAA,eAAe,WAC7B,OAAO,KAAK,UAAU,UACtB;AACA,eAAO,KAAK;AAAA,MACd;AACA,UACE,KAAK,SAASA,qBAAe,mBAC7B,KAAK,OAAO,WAAW,GACvB;AACA,cAAM,SAAS,KAAK,OAAO,CAAC,GAAG,MAAM;AACrC,YAAI,UAAU,MAAM;AAClB,iBAAO;AAAA,QACT;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,MACL,eAAe,MAAM;AAEnB,YAAI,KAAK,OAAO,SAASA,MAAAA,eAAe,YAAY;AAClD,gBAAM,WAAW,KAAK,OAAO;AAG7B,cAAI,CAAC,QAAQ,uBAAuB,KAAK,MAAM,GAAG;AAChD;AAAA,UACF;AAGA,cAAI,kBAAkB,IAAI,QAAQ,GAAG;AACnC,kBAAM,MAAM,KAAK,UAAU,CAAC;AAC5B,gBAAI,KAAK,SAASA,MAAAA,eAAe,kBAAkB;AACjD,yBAAW,QAAQ,IAAI,YAAY;AACjC,oBAAI,KAAK,SAASA,MAAAA,eAAe,UAAU;AACzC,wBAAM,YACH,KAAK,IAAI,SAASA,MAAAA,eAAe,cAChC,KAAK,IAAI,SAAS,UACnB,KAAK,IAAI,SAASA,MAAAA,eAAe,WAChC,KAAK,IAAI,UAAU;AACvB,sBAAI,WAAW;AACb,0BAAM,YAAY,sBAAsB,KAAK,KAAK;AAClD,wBAAI,WAAW;AACb,0CAAoB,KAAK,OAAO,SAAS;AAAA,oBAC3C;AAAA,kBACF;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AACA;AAAA,UACF;AAAA,QACF;AAGA,YAAI,KAAK,OAAO,SAASA,MAAAA,eAAe,gBAAgB;AACtD,gBAAM,YAAY,KAAK;AAEvB,cAAI,UAAU,OAAO,SAASA,MAAAA,eAAe,YAAY;AACvD,kBAAM,WAAW,UAAU,OAAO;AAGlC,gBAAI,CAAC,QAAQ,uBAAuB,UAAU,MAAM,GAAG;AACrD;AAAA,YACF;AAGA,gBAAI,kBAAkB,IAAI,QAAQ,GAAG;AACnC,oBAAM,UAAU,UAAU,UAAU,CAAC;AACrC,kBAAI,SAAS;AACX,sBAAM,YAAY,sBAAsB,OAAO;AAC/C,oBAAI,WAAW;AACb,sCAAoB,SAAS,SAAS;AAAA,gBACxC;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IAAA;AAAA,EAEJ,CAAC;AACH,CAAC;;;"} | ||
| {"version":3,"file":"route-param-names.rule.cjs","names":[],"sources":["../../../../src/rules/route-param-names/route-param-names.rule.ts"],"sourcesContent":["import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils'\n\nimport { getDocsUrl } from '../../utils/get-docs-url'\nimport { detectTanstackRouterImports } from '../../utils/detect-router-imports'\nimport { getInvalidParams } from './route-param-names.utils'\nimport { pathAsFirstArgFunctions, pathAsPropertyFunctions } from './constants'\nimport type { TSESTree } from '@typescript-eslint/utils'\nimport type { ExtraRuleDocs } from '../../types'\n\nconst createRule = ESLintUtils.RuleCreator<ExtraRuleDocs>(getDocsUrl)\n\nconst pathAsFirstArgSet = new Set<string>(pathAsFirstArgFunctions)\nconst pathAsPropertySet = new Set<string>(pathAsPropertyFunctions)\n\nexport const name = 'route-param-names'\n\nexport const rule = createRule({\n name,\n meta: {\n type: 'problem',\n docs: {\n description: 'Ensure route param names are valid JavaScript identifiers',\n recommended: 'error',\n },\n messages: {\n invalidParamName:\n 'Invalid param name \"{{paramName}}\" in route path. Param names must be valid JavaScript identifiers (match /[a-zA-Z_$][a-zA-Z0-9_$]*/).',\n },\n schema: [],\n },\n defaultOptions: [],\n\n create: detectTanstackRouterImports((context, _, helpers) => {\n function reportInvalidParams(node: TSESTree.Node, path: string) {\n const invalidParams = getInvalidParams(path)\n\n for (const param of invalidParams) {\n context.report({\n node,\n messageId: 'invalidParamName',\n data: { paramName: param.paramName },\n })\n }\n }\n\n function getStringLiteralValue(node: TSESTree.Node): string | null {\n if (\n node.type === AST_NODE_TYPES.Literal &&\n typeof node.value === 'string'\n ) {\n return node.value\n }\n if (\n node.type === AST_NODE_TYPES.TemplateLiteral &&\n node.quasis.length === 1\n ) {\n const cooked = node.quasis[0]?.value.cooked\n if (cooked != null) {\n return cooked\n }\n }\n return null\n }\n\n return {\n CallExpression(node) {\n // Handle direct function call: createRoute({ path: '...' })\n if (node.callee.type === AST_NODE_TYPES.Identifier) {\n const funcName = node.callee.name\n\n // Skip if not imported from TanStack Router\n if (!helpers.isTanstackRouterImport(node.callee)) {\n return\n }\n\n // Case: createRoute({ path: '/path/$param' }) or createRoute({ 'path': '/path/$param' })\n if (pathAsPropertySet.has(funcName)) {\n const arg = node.arguments[0]\n if (arg?.type === AST_NODE_TYPES.ObjectExpression) {\n for (const prop of arg.properties) {\n if (prop.type === AST_NODE_TYPES.Property) {\n const isPathKey =\n (prop.key.type === AST_NODE_TYPES.Identifier &&\n prop.key.name === 'path') ||\n (prop.key.type === AST_NODE_TYPES.Literal &&\n prop.key.value === 'path')\n if (isPathKey) {\n const pathValue = getStringLiteralValue(prop.value)\n if (pathValue) {\n reportInvalidParams(prop.value, pathValue)\n }\n }\n }\n }\n }\n return\n }\n }\n\n // Handle curried function call: createFileRoute('/path')({ ... })\n if (node.callee.type === AST_NODE_TYPES.CallExpression) {\n const innerCall = node.callee\n\n if (innerCall.callee.type === AST_NODE_TYPES.Identifier) {\n const funcName = innerCall.callee.name\n\n // Skip if not imported from TanStack Router\n if (!helpers.isTanstackRouterImport(innerCall.callee)) {\n return\n }\n\n // Case: createFileRoute('/path/$param')(...) or similar\n if (pathAsFirstArgSet.has(funcName)) {\n const pathArg = innerCall.arguments[0]\n if (pathArg) {\n const pathValue = getStringLiteralValue(pathArg)\n if (pathValue) {\n reportInvalidParams(pathArg, pathValue)\n }\n }\n }\n }\n }\n },\n }\n }),\n})\n"],"mappings":";;;;;;AASA,IAAM,aAAa,yBAAA,YAAY,YAA2B,qBAAA,WAAW;AAErE,IAAM,oBAAoB,IAAI,IAAY,kBAAA,wBAAwB;AAClE,IAAM,oBAAoB,IAAI,IAAY,kBAAA,wBAAwB;AAElE,IAAa,OAAO;AAEpB,IAAa,OAAO,WAAW;CAC7B;CACA,MAAM;EACJ,MAAM;EACN,MAAM;GACJ,aAAa;GACb,aAAa;GACd;EACD,UAAU,EACR,kBACE,4IACH;EACD,QAAQ,EAAE;EACX;CACD,gBAAgB,EAAE;CAElB,QAAQ,8BAAA,6BAA6B,SAAS,GAAG,YAAY;EAC3D,SAAS,oBAAoB,MAAqB,MAAc;GAC9D,MAAM,gBAAgB,gCAAA,iBAAiB,KAAK;AAE5C,QAAK,MAAM,SAAS,cAClB,SAAQ,OAAO;IACb;IACA,WAAW;IACX,MAAM,EAAE,WAAW,MAAM,WAAW;IACrC,CAAC;;EAIN,SAAS,sBAAsB,MAAoC;AACjE,OACE,KAAK,SAAS,yBAAA,eAAe,WAC7B,OAAO,KAAK,UAAU,SAEtB,QAAO,KAAK;AAEd,OACE,KAAK,SAAS,yBAAA,eAAe,mBAC7B,KAAK,OAAO,WAAW,GACvB;IACA,MAAM,SAAS,KAAK,OAAO,IAAI,MAAM;AACrC,QAAI,UAAU,KACZ,QAAO;;AAGX,UAAO;;AAGT,SAAO,EACL,eAAe,MAAM;AAEnB,OAAI,KAAK,OAAO,SAAS,yBAAA,eAAe,YAAY;IAClD,MAAM,WAAW,KAAK,OAAO;AAG7B,QAAI,CAAC,QAAQ,uBAAuB,KAAK,OAAO,CAC9C;AAIF,QAAI,kBAAkB,IAAI,SAAS,EAAE;KACnC,MAAM,MAAM,KAAK,UAAU;AAC3B,SAAI,KAAK,SAAS,yBAAA,eAAe;WAC1B,MAAM,QAAQ,IAAI,WACrB,KAAI,KAAK,SAAS,yBAAA,eAAe;WAE5B,KAAK,IAAI,SAAS,yBAAA,eAAe,cAChC,KAAK,IAAI,SAAS,UACnB,KAAK,IAAI,SAAS,yBAAA,eAAe,WAChC,KAAK,IAAI,UAAU,QACR;QACb,MAAM,YAAY,sBAAsB,KAAK,MAAM;AACnD,YAAI,UACF,qBAAoB,KAAK,OAAO,UAAU;;;;AAMpD;;;AAKJ,OAAI,KAAK,OAAO,SAAS,yBAAA,eAAe,gBAAgB;IACtD,MAAM,YAAY,KAAK;AAEvB,QAAI,UAAU,OAAO,SAAS,yBAAA,eAAe,YAAY;KACvD,MAAM,WAAW,UAAU,OAAO;AAGlC,SAAI,CAAC,QAAQ,uBAAuB,UAAU,OAAO,CACnD;AAIF,SAAI,kBAAkB,IAAI,SAAS,EAAE;MACnC,MAAM,UAAU,UAAU,UAAU;AACpC,UAAI,SAAS;OACX,MAAM,YAAY,sBAAsB,QAAQ;AAChD,WAAI,UACF,qBAAoB,SAAS,UAAU;;;;;KAOpD;GACD;CACH,CAAC"} |
@@ -1,61 +0,72 @@ | ||
| "use strict"; | ||
| Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); | ||
| const constants = require("./constants.cjs"); | ||
| const require_constants = require("./constants.cjs"); | ||
| //#region src/rules/route-param-names/route-param-names.utils.ts | ||
| /** | ||
| * Extracts param names from a route path segment. | ||
| * | ||
| * Handles these patterns: | ||
| * - $paramName -> extract "paramName" | ||
| * - {$paramName} -> extract "paramName" | ||
| * - prefix{$paramName}suffix -> extract "paramName" | ||
| * - {-$paramName} -> extract "paramName" (optional) | ||
| * - prefix{-$paramName}suffix -> extract "paramName" (optional) | ||
| * - $ or {$} -> wildcard, skip validation | ||
| */ | ||
| function extractParamsFromSegment(segment) { | ||
| const params = []; | ||
| if (!segment || !segment.includes("$")) { | ||
| return params; | ||
| } | ||
| if (segment === "$" || segment === "{$}") { | ||
| return params; | ||
| } | ||
| if (segment.startsWith("$") && !segment.includes("{")) { | ||
| const paramName = segment.slice(1); | ||
| if (paramName) { | ||
| params.push({ | ||
| fullParam: segment, | ||
| paramName, | ||
| isOptional: false, | ||
| isValid: constants.VALID_PARAM_NAME_REGEX.test(paramName) | ||
| }); | ||
| } | ||
| return params; | ||
| } | ||
| const bracePattern = /\{(-?\$)([^}]*)\}/g; | ||
| let match; | ||
| while ((match = bracePattern.exec(segment)) !== null) { | ||
| const prefix = match[1]; | ||
| const paramName = match[2]; | ||
| if (!paramName) { | ||
| continue; | ||
| } | ||
| const isOptional = prefix === "-$"; | ||
| params.push({ | ||
| fullParam: `${prefix}${paramName}`, | ||
| paramName, | ||
| isOptional, | ||
| isValid: constants.VALID_PARAM_NAME_REGEX.test(paramName) | ||
| }); | ||
| } | ||
| return params; | ||
| const params = []; | ||
| if (!segment || !segment.includes("$")) return params; | ||
| if (segment === "$" || segment === "{$}") return params; | ||
| if (segment.startsWith("$") && !segment.includes("{")) { | ||
| const paramName = segment.slice(1); | ||
| if (paramName) params.push({ | ||
| fullParam: segment, | ||
| paramName, | ||
| isOptional: false, | ||
| isValid: require_constants.VALID_PARAM_NAME_REGEX.test(paramName) | ||
| }); | ||
| return params; | ||
| } | ||
| const bracePattern = /\{(-?\$)([^}]*)\}/g; | ||
| let match; | ||
| while ((match = bracePattern.exec(segment)) !== null) { | ||
| const prefix = match[1]; | ||
| const paramName = match[2]; | ||
| if (!paramName) continue; | ||
| const isOptional = prefix === "-$"; | ||
| params.push({ | ||
| fullParam: `${prefix}${paramName}`, | ||
| paramName, | ||
| isOptional, | ||
| isValid: require_constants.VALID_PARAM_NAME_REGEX.test(paramName) | ||
| }); | ||
| } | ||
| return params; | ||
| } | ||
| /** | ||
| * Extracts all params from a route path. | ||
| * | ||
| * @param path - The route path (e.g., "/users/$userId/posts/$postId") | ||
| * @returns Array of extracted params with validation info | ||
| */ | ||
| function extractParamsFromPath(path) { | ||
| if (!path || !path.includes("$")) { | ||
| return []; | ||
| } | ||
| const segments = path.split("/"); | ||
| const allParams = []; | ||
| for (const segment of segments) { | ||
| const params = extractParamsFromSegment(segment); | ||
| allParams.push(...params); | ||
| } | ||
| return allParams; | ||
| if (!path || !path.includes("$")) return []; | ||
| const segments = path.split("/"); | ||
| const allParams = []; | ||
| for (const segment of segments) { | ||
| const params = extractParamsFromSegment(segment); | ||
| allParams.push(...params); | ||
| } | ||
| return allParams; | ||
| } | ||
| /** | ||
| * Gets all invalid params from a route path. | ||
| * | ||
| * @param path - The route path | ||
| * @returns Array of invalid param info | ||
| */ | ||
| function getInvalidParams(path) { | ||
| const params = extractParamsFromPath(path); | ||
| return params.filter((p) => !p.isValid); | ||
| return extractParamsFromPath(path).filter((p) => !p.isValid); | ||
| } | ||
| exports.extractParamsFromPath = extractParamsFromPath; | ||
| exports.extractParamsFromSegment = extractParamsFromSegment; | ||
| //#endregion | ||
| exports.getInvalidParams = getInvalidParams; | ||
| //# sourceMappingURL=route-param-names.utils.cjs.map | ||
| //# sourceMappingURL=route-param-names.utils.cjs.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"route-param-names.utils.cjs","sources":["../../../../src/rules/route-param-names/route-param-names.utils.ts"],"sourcesContent":["import { VALID_PARAM_NAME_REGEX } from './constants'\n\nexport interface ExtractedParam {\n /** The full param string including $ prefix (e.g., \"$userId\", \"-$optional\") */\n fullParam: string\n /** The param name without $ prefix (e.g., \"userId\", \"optional\") */\n paramName: string\n /** Whether this is an optional param (prefixed with -$) */\n isOptional: boolean\n /** Whether this param name is valid */\n isValid: boolean\n}\n\n/**\n * Extracts param names from a route path segment.\n *\n * Handles these patterns:\n * - $paramName -> extract \"paramName\"\n * - {$paramName} -> extract \"paramName\"\n * - prefix{$paramName}suffix -> extract \"paramName\"\n * - {-$paramName} -> extract \"paramName\" (optional)\n * - prefix{-$paramName}suffix -> extract \"paramName\" (optional)\n * - $ or {$} -> wildcard, skip validation\n */\nexport function extractParamsFromSegment(\n segment: string,\n): Array<ExtractedParam> {\n const params: Array<ExtractedParam> = []\n\n // Skip empty segments\n if (!segment || !segment.includes('$')) {\n return params\n }\n\n // Check for wildcard ($ alone or {$})\n if (segment === '$' || segment === '{$}') {\n return params // Wildcard, no param name to validate\n }\n\n // Pattern 1: Simple $paramName (entire segment starts with $)\n if (segment.startsWith('$') && !segment.includes('{')) {\n const paramName = segment.slice(1)\n if (paramName) {\n params.push({\n fullParam: segment,\n paramName,\n isOptional: false,\n isValid: VALID_PARAM_NAME_REGEX.test(paramName),\n })\n }\n return params\n }\n\n // Pattern 2: Braces pattern {$paramName} or {-$paramName} with optional prefix/suffix\n // Match patterns like: prefix{$param}suffix, {$param}, {-$param}\n const bracePattern = /\\{(-?\\$)([^}]*)\\}/g\n let match\n\n while ((match = bracePattern.exec(segment)) !== null) {\n const prefix = match[1] // \"$\" or \"-$\"\n const paramName = match[2] // The param name after $ or -$\n\n if (!paramName) {\n // This is a wildcard {$} or {-$}, skip\n continue\n }\n\n const isOptional = prefix === '-$'\n\n params.push({\n fullParam: `${prefix}${paramName}`,\n paramName,\n isOptional,\n isValid: VALID_PARAM_NAME_REGEX.test(paramName),\n })\n }\n\n return params\n}\n\n/**\n * Extracts all params from a route path.\n *\n * @param path - The route path (e.g., \"/users/$userId/posts/$postId\")\n * @returns Array of extracted params with validation info\n */\nexport function extractParamsFromPath(path: string): Array<ExtractedParam> {\n if (!path || !path.includes('$')) {\n return []\n }\n\n const segments = path.split('/')\n const allParams: Array<ExtractedParam> = []\n\n for (const segment of segments) {\n const params = extractParamsFromSegment(segment)\n allParams.push(...params)\n }\n\n return allParams\n}\n\n/**\n * Validates a single param name.\n *\n * @param paramName - The param name to validate (without $ prefix)\n * @returns Whether the param name is valid\n */\nexport function isValidParamName(paramName: string): boolean {\n return VALID_PARAM_NAME_REGEX.test(paramName)\n}\n\n/**\n * Gets all invalid params from a route path.\n *\n * @param path - The route path\n * @returns Array of invalid param info\n */\nexport function getInvalidParams(path: string): Array<ExtractedParam> {\n const params = extractParamsFromPath(path)\n return params.filter((p) => !p.isValid)\n}\n"],"names":["VALID_PARAM_NAME_REGEX"],"mappings":";;;AAwBO,SAAS,yBACd,SACuB;AACvB,QAAM,SAAgC,CAAA;AAGtC,MAAI,CAAC,WAAW,CAAC,QAAQ,SAAS,GAAG,GAAG;AACtC,WAAO;AAAA,EACT;AAGA,MAAI,YAAY,OAAO,YAAY,OAAO;AACxC,WAAO;AAAA,EACT;AAGA,MAAI,QAAQ,WAAW,GAAG,KAAK,CAAC,QAAQ,SAAS,GAAG,GAAG;AACrD,UAAM,YAAY,QAAQ,MAAM,CAAC;AACjC,QAAI,WAAW;AACb,aAAO,KAAK;AAAA,QACV,WAAW;AAAA,QACX;AAAA,QACA,YAAY;AAAA,QACZ,SAASA,UAAAA,uBAAuB,KAAK,SAAS;AAAA,MAAA,CAC/C;AAAA,IACH;AACA,WAAO;AAAA,EACT;AAIA,QAAM,eAAe;AACrB,MAAI;AAEJ,UAAQ,QAAQ,aAAa,KAAK,OAAO,OAAO,MAAM;AACpD,UAAM,SAAS,MAAM,CAAC;AACtB,UAAM,YAAY,MAAM,CAAC;AAEzB,QAAI,CAAC,WAAW;AAEd;AAAA,IACF;AAEA,UAAM,aAAa,WAAW;AAE9B,WAAO,KAAK;AAAA,MACV,WAAW,GAAG,MAAM,GAAG,SAAS;AAAA,MAChC;AAAA,MACA;AAAA,MACA,SAASA,UAAAA,uBAAuB,KAAK,SAAS;AAAA,IAAA,CAC/C;AAAA,EACH;AAEA,SAAO;AACT;AAQO,SAAS,sBAAsB,MAAqC;AACzE,MAAI,CAAC,QAAQ,CAAC,KAAK,SAAS,GAAG,GAAG;AAChC,WAAO,CAAA;AAAA,EACT;AAEA,QAAM,WAAW,KAAK,MAAM,GAAG;AAC/B,QAAM,YAAmC,CAAA;AAEzC,aAAW,WAAW,UAAU;AAC9B,UAAM,SAAS,yBAAyB,OAAO;AAC/C,cAAU,KAAK,GAAG,MAAM;AAAA,EAC1B;AAEA,SAAO;AACT;AAkBO,SAAS,iBAAiB,MAAqC;AACpE,QAAM,SAAS,sBAAsB,IAAI;AACzC,SAAO,OAAO,OAAO,CAAC,MAAM,CAAC,EAAE,OAAO;AACxC;;;;"} | ||
| {"version":3,"file":"route-param-names.utils.cjs","names":[],"sources":["../../../../src/rules/route-param-names/route-param-names.utils.ts"],"sourcesContent":["import { VALID_PARAM_NAME_REGEX } from './constants'\n\nexport interface ExtractedParam {\n /** The full param string including $ prefix (e.g., \"$userId\", \"-$optional\") */\n fullParam: string\n /** The param name without $ prefix (e.g., \"userId\", \"optional\") */\n paramName: string\n /** Whether this is an optional param (prefixed with -$) */\n isOptional: boolean\n /** Whether this param name is valid */\n isValid: boolean\n}\n\n/**\n * Extracts param names from a route path segment.\n *\n * Handles these patterns:\n * - $paramName -> extract \"paramName\"\n * - {$paramName} -> extract \"paramName\"\n * - prefix{$paramName}suffix -> extract \"paramName\"\n * - {-$paramName} -> extract \"paramName\" (optional)\n * - prefix{-$paramName}suffix -> extract \"paramName\" (optional)\n * - $ or {$} -> wildcard, skip validation\n */\nexport function extractParamsFromSegment(\n segment: string,\n): Array<ExtractedParam> {\n const params: Array<ExtractedParam> = []\n\n // Skip empty segments\n if (!segment || !segment.includes('$')) {\n return params\n }\n\n // Check for wildcard ($ alone or {$})\n if (segment === '$' || segment === '{$}') {\n return params // Wildcard, no param name to validate\n }\n\n // Pattern 1: Simple $paramName (entire segment starts with $)\n if (segment.startsWith('$') && !segment.includes('{')) {\n const paramName = segment.slice(1)\n if (paramName) {\n params.push({\n fullParam: segment,\n paramName,\n isOptional: false,\n isValid: VALID_PARAM_NAME_REGEX.test(paramName),\n })\n }\n return params\n }\n\n // Pattern 2: Braces pattern {$paramName} or {-$paramName} with optional prefix/suffix\n // Match patterns like: prefix{$param}suffix, {$param}, {-$param}\n const bracePattern = /\\{(-?\\$)([^}]*)\\}/g\n let match\n\n while ((match = bracePattern.exec(segment)) !== null) {\n const prefix = match[1] // \"$\" or \"-$\"\n const paramName = match[2] // The param name after $ or -$\n\n if (!paramName) {\n // This is a wildcard {$} or {-$}, skip\n continue\n }\n\n const isOptional = prefix === '-$'\n\n params.push({\n fullParam: `${prefix}${paramName}`,\n paramName,\n isOptional,\n isValid: VALID_PARAM_NAME_REGEX.test(paramName),\n })\n }\n\n return params\n}\n\n/**\n * Extracts all params from a route path.\n *\n * @param path - The route path (e.g., \"/users/$userId/posts/$postId\")\n * @returns Array of extracted params with validation info\n */\nexport function extractParamsFromPath(path: string): Array<ExtractedParam> {\n if (!path || !path.includes('$')) {\n return []\n }\n\n const segments = path.split('/')\n const allParams: Array<ExtractedParam> = []\n\n for (const segment of segments) {\n const params = extractParamsFromSegment(segment)\n allParams.push(...params)\n }\n\n return allParams\n}\n\n/**\n * Validates a single param name.\n *\n * @param paramName - The param name to validate (without $ prefix)\n * @returns Whether the param name is valid\n */\nexport function isValidParamName(paramName: string): boolean {\n return VALID_PARAM_NAME_REGEX.test(paramName)\n}\n\n/**\n * Gets all invalid params from a route path.\n *\n * @param path - The route path\n * @returns Array of invalid param info\n */\nexport function getInvalidParams(path: string): Array<ExtractedParam> {\n const params = extractParamsFromPath(path)\n return params.filter((p) => !p.isValid)\n}\n"],"mappings":";;;;;;;;;;;;;AAwBA,SAAgB,yBACd,SACuB;CACvB,MAAM,SAAgC,EAAE;AAGxC,KAAI,CAAC,WAAW,CAAC,QAAQ,SAAS,IAAI,CACpC,QAAO;AAIT,KAAI,YAAY,OAAO,YAAY,MACjC,QAAO;AAIT,KAAI,QAAQ,WAAW,IAAI,IAAI,CAAC,QAAQ,SAAS,IAAI,EAAE;EACrD,MAAM,YAAY,QAAQ,MAAM,EAAE;AAClC,MAAI,UACF,QAAO,KAAK;GACV,WAAW;GACX;GACA,YAAY;GACZ,SAAS,kBAAA,uBAAuB,KAAK,UAAU;GAChD,CAAC;AAEJ,SAAO;;CAKT,MAAM,eAAe;CACrB,IAAI;AAEJ,SAAQ,QAAQ,aAAa,KAAK,QAAQ,MAAM,MAAM;EACpD,MAAM,SAAS,MAAM;EACrB,MAAM,YAAY,MAAM;AAExB,MAAI,CAAC,UAEH;EAGF,MAAM,aAAa,WAAW;AAE9B,SAAO,KAAK;GACV,WAAW,GAAG,SAAS;GACvB;GACA;GACA,SAAS,kBAAA,uBAAuB,KAAK,UAAU;GAChD,CAAC;;AAGJ,QAAO;;;;;;;;AAST,SAAgB,sBAAsB,MAAqC;AACzE,KAAI,CAAC,QAAQ,CAAC,KAAK,SAAS,IAAI,CAC9B,QAAO,EAAE;CAGX,MAAM,WAAW,KAAK,MAAM,IAAI;CAChC,MAAM,YAAmC,EAAE;AAE3C,MAAK,MAAM,WAAW,UAAU;EAC9B,MAAM,SAAS,yBAAyB,QAAQ;AAChD,YAAU,KAAK,GAAG,OAAO;;AAG3B,QAAO;;;;;;;;AAmBT,SAAgB,iBAAiB,MAAqC;AAEpE,QADe,sBAAsB,KAAK,CAC5B,QAAQ,MAAM,CAAC,EAAE,QAAQ"} |
@@ -1,54 +0,38 @@ | ||
| "use strict"; | ||
| Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); | ||
| const utils = require("@typescript-eslint/utils"); | ||
| let _typescript_eslint_utils = require("@typescript-eslint/utils"); | ||
| //#region src/utils/detect-router-imports.ts | ||
| function detectTanstackRouterImports(create) { | ||
| return (context, optionsWithDefault) => { | ||
| const tanstackRouterImportSpecifiers = []; | ||
| const helpers = { | ||
| isSpecificTanstackRouterImport(node, source) { | ||
| return !!tanstackRouterImportSpecifiers.find((specifier) => { | ||
| if (specifier.type === utils.TSESTree.AST_NODE_TYPES.ImportSpecifier && specifier.parent.type === utils.TSESTree.AST_NODE_TYPES.ImportDeclaration && specifier.parent.source.value === source) { | ||
| return node.name === specifier.local.name; | ||
| } | ||
| return false; | ||
| }); | ||
| }, | ||
| isTanstackRouterImport(node) { | ||
| return !!tanstackRouterImportSpecifiers.find((specifier) => { | ||
| if (specifier.type === utils.TSESTree.AST_NODE_TYPES.ImportSpecifier) { | ||
| return node.name === specifier.local.name; | ||
| } | ||
| return false; | ||
| }); | ||
| } | ||
| }; | ||
| const detectionInstructions = { | ||
| ImportDeclaration(node) { | ||
| if (node.specifiers.length > 0 && // `importKind` is parser-dependent and can be undefined (eg. Espree) | ||
| node.importKind !== "type" && node.source.value.startsWith("@tanstack/") && node.source.value.endsWith("-router")) { | ||
| tanstackRouterImportSpecifiers.push(...node.specifiers); | ||
| } | ||
| } | ||
| }; | ||
| const ruleInstructions = create(context, optionsWithDefault, helpers); | ||
| const enhancedRuleInstructions = {}; | ||
| const allKeys = new Set( | ||
| Object.keys(detectionInstructions).concat(Object.keys(ruleInstructions)) | ||
| ); | ||
| allKeys.forEach((instruction) => { | ||
| enhancedRuleInstructions[instruction] = (node) => { | ||
| if (instruction in detectionInstructions) { | ||
| detectionInstructions[instruction]?.(node); | ||
| } | ||
| const ruleFunction = ruleInstructions[instruction]; | ||
| if (ruleFunction !== void 0) { | ||
| return ruleFunction(node); | ||
| } | ||
| return void 0; | ||
| }; | ||
| }); | ||
| return enhancedRuleInstructions; | ||
| }; | ||
| return (context, optionsWithDefault) => { | ||
| const tanstackRouterImportSpecifiers = []; | ||
| const helpers = { | ||
| isSpecificTanstackRouterImport(node, source) { | ||
| return !!tanstackRouterImportSpecifiers.find((specifier) => { | ||
| if (specifier.type === _typescript_eslint_utils.TSESTree.AST_NODE_TYPES.ImportSpecifier && specifier.parent.type === _typescript_eslint_utils.TSESTree.AST_NODE_TYPES.ImportDeclaration && specifier.parent.source.value === source) return node.name === specifier.local.name; | ||
| return false; | ||
| }); | ||
| }, | ||
| isTanstackRouterImport(node) { | ||
| return !!tanstackRouterImportSpecifiers.find((specifier) => { | ||
| if (specifier.type === _typescript_eslint_utils.TSESTree.AST_NODE_TYPES.ImportSpecifier) return node.name === specifier.local.name; | ||
| return false; | ||
| }); | ||
| } | ||
| }; | ||
| const detectionInstructions = { ImportDeclaration(node) { | ||
| if (node.specifiers.length > 0 && node.importKind !== "type" && node.source.value.startsWith("@tanstack/") && node.source.value.endsWith("-router")) tanstackRouterImportSpecifiers.push(...node.specifiers); | ||
| } }; | ||
| const ruleInstructions = create(context, optionsWithDefault, helpers); | ||
| const enhancedRuleInstructions = {}; | ||
| new Set(Object.keys(detectionInstructions).concat(Object.keys(ruleInstructions))).forEach((instruction) => { | ||
| enhancedRuleInstructions[instruction] = (node) => { | ||
| if (instruction in detectionInstructions) detectionInstructions[instruction]?.(node); | ||
| const ruleFunction = ruleInstructions[instruction]; | ||
| if (ruleFunction !== void 0) return ruleFunction(node); | ||
| }; | ||
| }); | ||
| return enhancedRuleInstructions; | ||
| }; | ||
| } | ||
| //#endregion | ||
| exports.detectTanstackRouterImports = detectTanstackRouterImports; | ||
| //# sourceMappingURL=detect-router-imports.cjs.map | ||
| //# sourceMappingURL=detect-router-imports.cjs.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"detect-router-imports.cjs","sources":["../../../src/utils/detect-router-imports.ts"],"sourcesContent":["import { TSESTree } from '@typescript-eslint/utils'\nimport type { ESLintUtils, TSESLint } from '@typescript-eslint/utils'\n\ntype Create = Parameters<\n ReturnType<typeof ESLintUtils.RuleCreator>\n>[0]['create']\n\ntype Context = Parameters<Create>[0]\ntype Options = Parameters<Create>[1]\ntype Helpers = {\n isSpecificTanstackRouterImport: (\n node: TSESTree.Identifier,\n source: string,\n ) => boolean\n isTanstackRouterImport: (node: TSESTree.Identifier) => boolean\n}\n\ntype EnhancedCreate = (\n context: Context,\n options: Options,\n helpers: Helpers,\n) => ReturnType<Create>\n\nexport function detectTanstackRouterImports(create: EnhancedCreate): Create {\n return (context, optionsWithDefault) => {\n const tanstackRouterImportSpecifiers: Array<TSESTree.ImportClause> = []\n\n const helpers: Helpers = {\n isSpecificTanstackRouterImport(node, source) {\n return !!tanstackRouterImportSpecifiers.find((specifier) => {\n if (\n specifier.type === TSESTree.AST_NODE_TYPES.ImportSpecifier &&\n specifier.parent.type ===\n TSESTree.AST_NODE_TYPES.ImportDeclaration &&\n specifier.parent.source.value === source\n ) {\n return node.name === specifier.local.name\n }\n\n return false\n })\n },\n isTanstackRouterImport(node) {\n return !!tanstackRouterImportSpecifiers.find((specifier) => {\n if (specifier.type === TSESTree.AST_NODE_TYPES.ImportSpecifier) {\n return node.name === specifier.local.name\n }\n\n return false\n })\n },\n }\n\n const detectionInstructions: TSESLint.RuleListener = {\n ImportDeclaration(node) {\n if (\n node.specifiers.length > 0 &&\n // `importKind` is parser-dependent and can be undefined (eg. Espree)\n node.importKind !== 'type' &&\n node.source.value.startsWith('@tanstack/') &&\n node.source.value.endsWith('-router')\n ) {\n tanstackRouterImportSpecifiers.push(...node.specifiers)\n }\n },\n }\n\n // Call original rule definition\n const ruleInstructions = create(context, optionsWithDefault, helpers)\n const enhancedRuleInstructions: TSESLint.RuleListener = {}\n\n const allKeys = new Set(\n Object.keys(detectionInstructions).concat(Object.keys(ruleInstructions)),\n )\n\n // Iterate over ALL instructions keys so we can override original rule instructions\n // to prevent their execution if conditions to report errors are not met.\n allKeys.forEach((instruction) => {\n enhancedRuleInstructions[instruction] = (node) => {\n if (instruction in detectionInstructions) {\n detectionInstructions[instruction]?.(node)\n }\n\n const ruleFunction = ruleInstructions[instruction]\n if (ruleFunction !== undefined) {\n return ruleFunction(node)\n }\n\n return undefined\n }\n })\n\n return enhancedRuleInstructions\n }\n}\n"],"names":["TSESTree"],"mappings":";;;AAuBO,SAAS,4BAA4B,QAAgC;AAC1E,SAAO,CAAC,SAAS,uBAAuB;AACtC,UAAM,iCAA+D,CAAA;AAErE,UAAM,UAAmB;AAAA,MACvB,+BAA+B,MAAM,QAAQ;AAC3C,eAAO,CAAC,CAAC,+BAA+B,KAAK,CAAC,cAAc;AAC1D,cACE,UAAU,SAASA,MAAAA,SAAS,eAAe,mBAC3C,UAAU,OAAO,SACfA,MAAAA,SAAS,eAAe,qBAC1B,UAAU,OAAO,OAAO,UAAU,QAClC;AACA,mBAAO,KAAK,SAAS,UAAU,MAAM;AAAA,UACvC;AAEA,iBAAO;AAAA,QACT,CAAC;AAAA,MACH;AAAA,MACA,uBAAuB,MAAM;AAC3B,eAAO,CAAC,CAAC,+BAA+B,KAAK,CAAC,cAAc;AAC1D,cAAI,UAAU,SAASA,eAAS,eAAe,iBAAiB;AAC9D,mBAAO,KAAK,SAAS,UAAU,MAAM;AAAA,UACvC;AAEA,iBAAO;AAAA,QACT,CAAC;AAAA,MACH;AAAA,IAAA;AAGF,UAAM,wBAA+C;AAAA,MACnD,kBAAkB,MAAM;AACtB,YACE,KAAK,WAAW,SAAS;AAAA,QAEzB,KAAK,eAAe,UACpB,KAAK,OAAO,MAAM,WAAW,YAAY,KACzC,KAAK,OAAO,MAAM,SAAS,SAAS,GACpC;AACA,yCAA+B,KAAK,GAAG,KAAK,UAAU;AAAA,QACxD;AAAA,MACF;AAAA,IAAA;AAIF,UAAM,mBAAmB,OAAO,SAAS,oBAAoB,OAAO;AACpE,UAAM,2BAAkD,CAAA;AAExD,UAAM,UAAU,IAAI;AAAA,MAClB,OAAO,KAAK,qBAAqB,EAAE,OAAO,OAAO,KAAK,gBAAgB,CAAC;AAAA,IAAA;AAKzE,YAAQ,QAAQ,CAAC,gBAAgB;AAC/B,+BAAyB,WAAW,IAAI,CAAC,SAAS;AAChD,YAAI,eAAe,uBAAuB;AACxC,gCAAsB,WAAW,IAAI,IAAI;AAAA,QAC3C;AAEA,cAAM,eAAe,iBAAiB,WAAW;AACjD,YAAI,iBAAiB,QAAW;AAC9B,iBAAO,aAAa,IAAI;AAAA,QAC1B;AAEA,eAAO;AAAA,MACT;AAAA,IACF,CAAC;AAED,WAAO;AAAA,EACT;AACF;;"} | ||
| {"version":3,"file":"detect-router-imports.cjs","names":[],"sources":["../../../src/utils/detect-router-imports.ts"],"sourcesContent":["import { TSESTree } from '@typescript-eslint/utils'\nimport type { ESLintUtils, TSESLint } from '@typescript-eslint/utils'\n\ntype Create = Parameters<\n ReturnType<typeof ESLintUtils.RuleCreator>\n>[0]['create']\n\ntype Context = Parameters<Create>[0]\ntype Options = Parameters<Create>[1]\ntype Helpers = {\n isSpecificTanstackRouterImport: (\n node: TSESTree.Identifier,\n source: string,\n ) => boolean\n isTanstackRouterImport: (node: TSESTree.Identifier) => boolean\n}\n\ntype EnhancedCreate = (\n context: Context,\n options: Options,\n helpers: Helpers,\n) => ReturnType<Create>\n\nexport function detectTanstackRouterImports(create: EnhancedCreate): Create {\n return (context, optionsWithDefault) => {\n const tanstackRouterImportSpecifiers: Array<TSESTree.ImportClause> = []\n\n const helpers: Helpers = {\n isSpecificTanstackRouterImport(node, source) {\n return !!tanstackRouterImportSpecifiers.find((specifier) => {\n if (\n specifier.type === TSESTree.AST_NODE_TYPES.ImportSpecifier &&\n specifier.parent.type ===\n TSESTree.AST_NODE_TYPES.ImportDeclaration &&\n specifier.parent.source.value === source\n ) {\n return node.name === specifier.local.name\n }\n\n return false\n })\n },\n isTanstackRouterImport(node) {\n return !!tanstackRouterImportSpecifiers.find((specifier) => {\n if (specifier.type === TSESTree.AST_NODE_TYPES.ImportSpecifier) {\n return node.name === specifier.local.name\n }\n\n return false\n })\n },\n }\n\n const detectionInstructions: TSESLint.RuleListener = {\n ImportDeclaration(node) {\n if (\n node.specifiers.length > 0 &&\n // `importKind` is parser-dependent and can be undefined (eg. Espree)\n node.importKind !== 'type' &&\n node.source.value.startsWith('@tanstack/') &&\n node.source.value.endsWith('-router')\n ) {\n tanstackRouterImportSpecifiers.push(...node.specifiers)\n }\n },\n }\n\n // Call original rule definition\n const ruleInstructions = create(context, optionsWithDefault, helpers)\n const enhancedRuleInstructions: TSESLint.RuleListener = {}\n\n const allKeys = new Set(\n Object.keys(detectionInstructions).concat(Object.keys(ruleInstructions)),\n )\n\n // Iterate over ALL instructions keys so we can override original rule instructions\n // to prevent their execution if conditions to report errors are not met.\n allKeys.forEach((instruction) => {\n enhancedRuleInstructions[instruction] = (node) => {\n if (instruction in detectionInstructions) {\n detectionInstructions[instruction]?.(node)\n }\n\n const ruleFunction = ruleInstructions[instruction]\n if (ruleFunction !== undefined) {\n return ruleFunction(node)\n }\n\n return undefined\n }\n })\n\n return enhancedRuleInstructions\n }\n}\n"],"mappings":";;AAuBA,SAAgB,4BAA4B,QAAgC;AAC1E,SAAQ,SAAS,uBAAuB;EACtC,MAAM,iCAA+D,EAAE;EAEvE,MAAM,UAAmB;GACvB,+BAA+B,MAAM,QAAQ;AAC3C,WAAO,CAAC,CAAC,+BAA+B,MAAM,cAAc;AAC1D,SACE,UAAU,SAAS,yBAAA,SAAS,eAAe,mBAC3C,UAAU,OAAO,SACf,yBAAA,SAAS,eAAe,qBAC1B,UAAU,OAAO,OAAO,UAAU,OAElC,QAAO,KAAK,SAAS,UAAU,MAAM;AAGvC,YAAO;MACP;;GAEJ,uBAAuB,MAAM;AAC3B,WAAO,CAAC,CAAC,+BAA+B,MAAM,cAAc;AAC1D,SAAI,UAAU,SAAS,yBAAA,SAAS,eAAe,gBAC7C,QAAO,KAAK,SAAS,UAAU,MAAM;AAGvC,YAAO;MACP;;GAEL;EAED,MAAM,wBAA+C,EACnD,kBAAkB,MAAM;AACtB,OACE,KAAK,WAAW,SAAS,KAEzB,KAAK,eAAe,UACpB,KAAK,OAAO,MAAM,WAAW,aAAa,IAC1C,KAAK,OAAO,MAAM,SAAS,UAAU,CAErC,gCAA+B,KAAK,GAAG,KAAK,WAAW;KAG5D;EAGD,MAAM,mBAAmB,OAAO,SAAS,oBAAoB,QAAQ;EACrE,MAAM,2BAAkD,EAAE;AAE1C,MAAI,IAClB,OAAO,KAAK,sBAAsB,CAAC,OAAO,OAAO,KAAK,iBAAiB,CAAC,CACzE,CAIO,SAAS,gBAAgB;AAC/B,4BAAyB,gBAAgB,SAAS;AAChD,QAAI,eAAe,sBACjB,uBAAsB,eAAe,KAAK;IAG5C,MAAM,eAAe,iBAAiB;AACtC,QAAI,iBAAiB,KAAA,EACnB,QAAO,aAAa,KAAK;;IAK7B;AAEF,SAAO"} |
@@ -1,5 +0,6 @@ | ||
| "use strict"; | ||
| Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); | ||
| const getDocsUrl = (ruleName) => `https://tanstack.com/router/latest/docs/eslint/${ruleName}`; | ||
| //#region src/utils/get-docs-url.ts | ||
| var getDocsUrl = (ruleName) => `https://tanstack.com/router/latest/docs/eslint/${ruleName}`; | ||
| //#endregion | ||
| exports.getDocsUrl = getDocsUrl; | ||
| //# sourceMappingURL=get-docs-url.cjs.map | ||
| //# sourceMappingURL=get-docs-url.cjs.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"get-docs-url.cjs","sources":["../../../src/utils/get-docs-url.ts"],"sourcesContent":["export const getDocsUrl = (ruleName: string): string =>\n `https://tanstack.com/router/latest/docs/eslint/${ruleName}`\n"],"names":[],"mappings":";;AAAO,MAAM,aAAa,CAAC,aACzB,kDAAkD,QAAQ;;"} | ||
| {"version":3,"file":"get-docs-url.cjs","names":[],"sources":["../../../src/utils/get-docs-url.ts"],"sourcesContent":["export const getDocsUrl = (ruleName: string): string =>\n `https://tanstack.com/router/latest/docs/eslint/${ruleName}`\n"],"mappings":";AAAA,IAAa,cAAc,aACzB,kDAAkD"} |
+23
-28
| import { rules } from "./rules.js"; | ||
| const plugin = { | ||
| meta: { | ||
| name: "@tanstack/eslint-plugin-router" | ||
| }, | ||
| configs: {}, | ||
| rules | ||
| //#region src/index.ts | ||
| var plugin = { | ||
| meta: { name: "@tanstack/eslint-plugin-router" }, | ||
| configs: {}, | ||
| rules | ||
| }; | ||
| Object.assign(plugin.configs, { | ||
| recommended: { | ||
| plugins: ["@tanstack/eslint-plugin-router"], | ||
| rules: { | ||
| "@tanstack/router/create-route-property-order": "warn", | ||
| "@tanstack/router/route-param-names": "error" | ||
| } | ||
| }, | ||
| "flat/recommended": [ | ||
| { | ||
| plugins: { | ||
| "@tanstack/router": plugin | ||
| }, | ||
| rules: { | ||
| "@tanstack/router/create-route-property-order": "warn", | ||
| "@tanstack/router/route-param-names": "error" | ||
| } | ||
| } | ||
| ] | ||
| recommended: { | ||
| plugins: ["@tanstack/eslint-plugin-router"], | ||
| rules: { | ||
| "@tanstack/router/create-route-property-order": "warn", | ||
| "@tanstack/router/route-param-names": "error" | ||
| } | ||
| }, | ||
| "flat/recommended": [{ | ||
| plugins: { "@tanstack/router": plugin }, | ||
| rules: { | ||
| "@tanstack/router/create-route-property-order": "warn", | ||
| "@tanstack/router/route-param-names": "error" | ||
| } | ||
| }] | ||
| }); | ||
| export { | ||
| plugin as default | ||
| }; | ||
| //# sourceMappingURL=index.js.map | ||
| //#endregion | ||
| export { plugin as default }; | ||
| //# sourceMappingURL=index.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.js","sources":["../../src/index.ts"],"sourcesContent":["import { rules } from './rules'\nimport type { ESLint, Linter } from 'eslint'\nimport type { RuleModule } from '@typescript-eslint/utils/ts-eslint'\n\ntype RuleKey = keyof typeof rules\n\ninterface Plugin extends Omit<ESLint.Plugin, 'rules'> {\n rules: Record<RuleKey, RuleModule<any, any, any>>\n configs: {\n recommended: ESLint.ConfigData\n 'flat/recommended': Array<Linter.FlatConfig>\n }\n}\n\nconst plugin: Plugin = {\n meta: {\n name: '@tanstack/eslint-plugin-router',\n },\n configs: {} as Plugin['configs'],\n rules,\n}\n\n// Assign configs here so we can reference `plugin`\nObject.assign(plugin.configs, {\n recommended: {\n plugins: ['@tanstack/eslint-plugin-router'],\n rules: {\n '@tanstack/router/create-route-property-order': 'warn',\n '@tanstack/router/route-param-names': 'error',\n },\n },\n 'flat/recommended': [\n {\n plugins: {\n '@tanstack/router': plugin,\n },\n rules: {\n '@tanstack/router/create-route-property-order': 'warn',\n '@tanstack/router/route-param-names': 'error',\n },\n },\n ],\n})\n\nexport default plugin\n"],"names":[],"mappings":";AAcA,MAAM,SAAiB;AAAA,EACrB,MAAM;AAAA,IACJ,MAAM;AAAA,EAAA;AAAA,EAER,SAAS,CAAA;AAAA,EACT;AACF;AAGA,OAAO,OAAO,OAAO,SAAS;AAAA,EAC5B,aAAa;AAAA,IACX,SAAS,CAAC,gCAAgC;AAAA,IAC1C,OAAO;AAAA,MACL,gDAAgD;AAAA,MAChD,sCAAsC;AAAA,IAAA;AAAA,EACxC;AAAA,EAEF,oBAAoB;AAAA,IAClB;AAAA,MACE,SAAS;AAAA,QACP,oBAAoB;AAAA,MAAA;AAAA,MAEtB,OAAO;AAAA,QACL,gDAAgD;AAAA,QAChD,sCAAsC;AAAA,MAAA;AAAA,IACxC;AAAA,EACF;AAEJ,CAAC;"} | ||
| {"version":3,"file":"index.js","names":[],"sources":["../../src/index.ts"],"sourcesContent":["import { rules } from './rules'\nimport type { ESLint, Linter } from 'eslint'\nimport type { RuleModule } from '@typescript-eslint/utils/ts-eslint'\n\ntype RuleKey = keyof typeof rules\n\ninterface Plugin extends Omit<ESLint.Plugin, 'rules'> {\n rules: Record<RuleKey, RuleModule<any, any, any>>\n configs: {\n recommended: ESLint.ConfigData\n 'flat/recommended': Array<Linter.FlatConfig>\n }\n}\n\nconst plugin: Plugin = {\n meta: {\n name: '@tanstack/eslint-plugin-router',\n },\n configs: {} as Plugin['configs'],\n rules,\n}\n\n// Assign configs here so we can reference `plugin`\nObject.assign(plugin.configs, {\n recommended: {\n plugins: ['@tanstack/eslint-plugin-router'],\n rules: {\n '@tanstack/router/create-route-property-order': 'warn',\n '@tanstack/router/route-param-names': 'error',\n },\n },\n 'flat/recommended': [\n {\n plugins: {\n '@tanstack/router': plugin,\n },\n rules: {\n '@tanstack/router/create-route-property-order': 'warn',\n '@tanstack/router/route-param-names': 'error',\n },\n },\n ],\n})\n\nexport default plugin\n"],"mappings":";;AAcA,IAAM,SAAiB;CACrB,MAAM,EACJ,MAAM,kCACP;CACD,SAAS,EAAE;CACX;CACD;AAGD,OAAO,OAAO,OAAO,SAAS;CAC5B,aAAa;EACX,SAAS,CAAC,iCAAiC;EAC3C,OAAO;GACL,gDAAgD;GAChD,sCAAsC;GACvC;EACF;CACD,oBAAoB,CAClB;EACE,SAAS,EACP,oBAAoB,QACrB;EACD,OAAO;GACL,gDAAgD;GAChD,sCAAsC;GACvC;EACF,CACF;CACF,CAAC"} |
+10
-9
@@ -1,10 +0,11 @@ | ||
| import { rule as rule$1, name as name$1 } from "./rules/create-route-property-order/create-route-property-order.rule.js"; | ||
| import { rule, name } from "./rules/route-param-names/route-param-names.rule.js"; | ||
| const rules = { | ||
| [name$1]: rule$1, | ||
| [name]: rule | ||
| import { name, rule } from "./rules/create-route-property-order/create-route-property-order.rule.js"; | ||
| import { name as name$1, rule as rule$1 } from "./rules/route-param-names/route-param-names.rule.js"; | ||
| //#region src/rules.ts | ||
| var rules = { | ||
| [name]: rule, | ||
| [name$1]: rule$1 | ||
| }; | ||
| export { | ||
| rules | ||
| }; | ||
| //# sourceMappingURL=rules.js.map | ||
| //#endregion | ||
| export { rules }; | ||
| //# sourceMappingURL=rules.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"rules.js","sources":["../../src/rules.ts"],"sourcesContent":["import * as createRoutePropertyOrder from './rules/create-route-property-order/create-route-property-order.rule'\nimport * as routeParamNames from './rules/route-param-names/route-param-names.rule'\nimport type { ESLintUtils } from '@typescript-eslint/utils'\nimport type { ExtraRuleDocs } from './types'\n\nexport const rules: Record<\n string,\n ESLintUtils.RuleModule<\n string,\n ReadonlyArray<unknown>,\n ExtraRuleDocs,\n ESLintUtils.RuleListener\n >\n> = {\n [createRoutePropertyOrder.name]: createRoutePropertyOrder.rule,\n [routeParamNames.name]: routeParamNames.rule,\n}\n"],"names":["createRoutePropertyOrder.name","createRoutePropertyOrder.rule","routeParamNames.name","routeParamNames.rule"],"mappings":";;AAKO,MAAM,QAQT;AAAA,EACF,CAACA,MAA6B,GAAGC;AAAAA,EACjC,CAACC,IAAoB,GAAGC;AAC1B;"} | ||
| {"version":3,"file":"rules.js","names":[],"sources":["../../src/rules.ts"],"sourcesContent":["import * as createRoutePropertyOrder from './rules/create-route-property-order/create-route-property-order.rule'\nimport * as routeParamNames from './rules/route-param-names/route-param-names.rule'\nimport type { ESLintUtils } from '@typescript-eslint/utils'\nimport type { ExtraRuleDocs } from './types'\n\nexport const rules: Record<\n string,\n ESLintUtils.RuleModule<\n string,\n ReadonlyArray<unknown>,\n ExtraRuleDocs,\n ESLintUtils.RuleListener\n >\n> = {\n [createRoutePropertyOrder.name]: createRoutePropertyOrder.rule,\n [routeParamNames.name]: routeParamNames.rule,\n}\n"],"mappings":";;;AAKA,IAAa,QAQT;EACD,OAAgC;EAChC,SAAuB;CACzB"} |
| import { getCheckedProperties } from "./create-route-property-order.utils.js"; | ||
| const createRouteFunctionsIndirect = [ | ||
| "createFileRoute", | ||
| "createRootRouteWithContext" | ||
| //#region src/rules/create-route-property-order/constants.ts | ||
| var createRouteFunctionsIndirect = ["createFileRoute", "createRootRouteWithContext"]; | ||
| var createRouteFunctions = [...["createRootRoute", "createRoute"], ...createRouteFunctionsIndirect]; | ||
| var sortRules = [ | ||
| [["params", "validateSearch"], ["search"]], | ||
| [["search"], ["loaderDeps", "ssr"]], | ||
| [["loaderDeps"], ["context"]], | ||
| [["context"], ["beforeLoad"]], | ||
| [["beforeLoad"], ["loader"]], | ||
| [["loader"], [ | ||
| "onEnter", | ||
| "onStay", | ||
| "onLeave", | ||
| "head", | ||
| "scripts", | ||
| "headers", | ||
| "remountDeps" | ||
| ]] | ||
| ]; | ||
| const createRouteFunctionsDirect = [ | ||
| "createRootRoute", | ||
| "createRoute" | ||
| ]; | ||
| const createRouteFunctions = [ | ||
| ...createRouteFunctionsDirect, | ||
| ...createRouteFunctionsIndirect | ||
| ]; | ||
| const sortRules = [ | ||
| [["params", "validateSearch"], ["search"]], | ||
| [["search"], ["loaderDeps", "ssr"]], | ||
| [["loaderDeps"], ["context"]], | ||
| [["context"], ["beforeLoad"]], | ||
| [["beforeLoad"], ["loader"]], | ||
| [ | ||
| ["loader"], | ||
| [ | ||
| "onEnter", | ||
| "onStay", | ||
| "onLeave", | ||
| "head", | ||
| "scripts", | ||
| "headers", | ||
| "remountDeps" | ||
| ] | ||
| ] | ||
| ]; | ||
| getCheckedProperties(sortRules); | ||
| export { | ||
| createRouteFunctions, | ||
| createRouteFunctionsDirect, | ||
| createRouteFunctionsIndirect, | ||
| sortRules | ||
| }; | ||
| //# sourceMappingURL=constants.js.map | ||
| //#endregion | ||
| export { createRouteFunctions, createRouteFunctionsIndirect, sortRules }; | ||
| //# sourceMappingURL=constants.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"constants.js","sources":["../../../../src/rules/create-route-property-order/constants.ts"],"sourcesContent":["import { getCheckedProperties } from './create-route-property-order.utils'\n\nexport const createRouteFunctionsIndirect = [\n 'createFileRoute',\n 'createRootRouteWithContext',\n] as const\nexport const createRouteFunctionsDirect = [\n 'createRootRoute',\n 'createRoute',\n] as const\n\nexport const createRouteFunctions = [\n ...createRouteFunctionsDirect,\n ...createRouteFunctionsIndirect,\n] as const\n\nexport type CreateRouteFunction = (typeof createRouteFunctions)[number]\n\nexport const sortRules = [\n [['params', 'validateSearch'], ['search']],\n [['search'], ['loaderDeps', 'ssr']],\n [['loaderDeps'], ['context']],\n [['context'], ['beforeLoad']],\n [['beforeLoad'], ['loader']],\n [\n ['loader'],\n [\n 'onEnter',\n 'onStay',\n 'onLeave',\n 'head',\n 'scripts',\n 'headers',\n 'remountDeps',\n ],\n ],\n] as const\n\nexport type CheckedProperties = (typeof sortRules)[number][number][number]\nexport const checkedProperties = getCheckedProperties(sortRules)\n"],"names":[],"mappings":";AAEO,MAAM,+BAA+B;AAAA,EAC1C;AAAA,EACA;AACF;AACO,MAAM,6BAA6B;AAAA,EACxC;AAAA,EACA;AACF;AAEO,MAAM,uBAAuB;AAAA,EAClC,GAAG;AAAA,EACH,GAAG;AACL;AAIO,MAAM,YAAY;AAAA,EACvB,CAAC,CAAC,UAAU,gBAAgB,GAAG,CAAC,QAAQ,CAAC;AAAA,EACzC,CAAC,CAAC,QAAQ,GAAG,CAAC,cAAc,KAAK,CAAC;AAAA,EAClC,CAAC,CAAC,YAAY,GAAG,CAAC,SAAS,CAAC;AAAA,EAC5B,CAAC,CAAC,SAAS,GAAG,CAAC,YAAY,CAAC;AAAA,EAC5B,CAAC,CAAC,YAAY,GAAG,CAAC,QAAQ,CAAC;AAAA,EAC3B;AAAA,IACE,CAAC,QAAQ;AAAA,IACT;AAAA,MACE;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAAA,EACF;AAEJ;AAGiC,qBAAqB,SAAS;"} | ||
| {"version":3,"file":"constants.js","names":[],"sources":["../../../../src/rules/create-route-property-order/constants.ts"],"sourcesContent":["import { getCheckedProperties } from './create-route-property-order.utils'\n\nexport const createRouteFunctionsIndirect = [\n 'createFileRoute',\n 'createRootRouteWithContext',\n] as const\nexport const createRouteFunctionsDirect = [\n 'createRootRoute',\n 'createRoute',\n] as const\n\nexport const createRouteFunctions = [\n ...createRouteFunctionsDirect,\n ...createRouteFunctionsIndirect,\n] as const\n\nexport type CreateRouteFunction = (typeof createRouteFunctions)[number]\n\nexport const sortRules = [\n [['params', 'validateSearch'], ['search']],\n [['search'], ['loaderDeps', 'ssr']],\n [['loaderDeps'], ['context']],\n [['context'], ['beforeLoad']],\n [['beforeLoad'], ['loader']],\n [\n ['loader'],\n [\n 'onEnter',\n 'onStay',\n 'onLeave',\n 'head',\n 'scripts',\n 'headers',\n 'remountDeps',\n ],\n ],\n] as const\n\nexport type CheckedProperties = (typeof sortRules)[number][number][number]\nexport const checkedProperties = getCheckedProperties(sortRules)\n"],"mappings":";;AAEA,IAAa,+BAA+B,CAC1C,mBACA,6BACD;AAMD,IAAa,uBAAuB,CAClC,GANwC,CACxC,mBACA,cACD,EAIC,GAAG,6BACJ;AAID,IAAa,YAAY;CACvB,CAAC,CAAC,UAAU,iBAAiB,EAAE,CAAC,SAAS,CAAC;CAC1C,CAAC,CAAC,SAAS,EAAE,CAAC,cAAc,MAAM,CAAC;CACnC,CAAC,CAAC,aAAa,EAAE,CAAC,UAAU,CAAC;CAC7B,CAAC,CAAC,UAAU,EAAE,CAAC,aAAa,CAAC;CAC7B,CAAC,CAAC,aAAa,EAAE,CAAC,SAAS,CAAC;CAC5B,CACE,CAAC,SAAS,EACV;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACD,CACF;CACF;AAGgC,qBAAqB,UAAU"} |
@@ -1,2 +0,1 @@ | ||
| import { ESLintUtils, AST_NODE_TYPES } from "@typescript-eslint/utils"; | ||
| import { getDocsUrl } from "../../utils/get-docs-url.js"; | ||
@@ -6,99 +5,69 @@ import { detectTanstackRouterImports } from "../../utils/detect-router-imports.js"; | ||
| import { createRouteFunctions, createRouteFunctionsIndirect, sortRules } from "./constants.js"; | ||
| const createRule = ESLintUtils.RuleCreator(getDocsUrl); | ||
| const createRouteFunctionSet = new Set(createRouteFunctions); | ||
| import { AST_NODE_TYPES, ESLintUtils } from "@typescript-eslint/utils"; | ||
| //#region src/rules/create-route-property-order/create-route-property-order.rule.ts | ||
| var createRule = ESLintUtils.RuleCreator(getDocsUrl); | ||
| var createRouteFunctionSet = new Set(createRouteFunctions); | ||
| function isCreateRouteFunction(node) { | ||
| return createRouteFunctionSet.has(node); | ||
| return createRouteFunctionSet.has(node); | ||
| } | ||
| const name = "create-route-property-order"; | ||
| const rule = createRule({ | ||
| name, | ||
| meta: { | ||
| type: "problem", | ||
| docs: { | ||
| description: "Ensure correct order of inference sensitive properties for createRoute functions", | ||
| recommended: "error" | ||
| }, | ||
| messages: { | ||
| invalidOrder: "Invalid order of properties for `{{function}}`." | ||
| }, | ||
| schema: [], | ||
| hasSuggestions: true, | ||
| fixable: "code" | ||
| }, | ||
| defaultOptions: [], | ||
| create: detectTanstackRouterImports((context) => { | ||
| return { | ||
| CallExpression(node) { | ||
| if (node.callee.type !== AST_NODE_TYPES.Identifier) { | ||
| return; | ||
| } | ||
| const createRouteFunction = node.callee.name; | ||
| if (!isCreateRouteFunction(createRouteFunction)) { | ||
| return; | ||
| } | ||
| let args = node.arguments; | ||
| if (createRouteFunctionsIndirect.includes(createRouteFunction)) { | ||
| if (node.parent.type === AST_NODE_TYPES.CallExpression) { | ||
| args = node.parent.arguments; | ||
| } else { | ||
| return; | ||
| } | ||
| } | ||
| const argument = args[0]; | ||
| if (argument === void 0 || argument.type !== "ObjectExpression") { | ||
| return; | ||
| } | ||
| const allProperties = argument.properties; | ||
| if (allProperties.length < 2) { | ||
| return; | ||
| } | ||
| const properties = allProperties.flatMap((p) => { | ||
| if (p.type === AST_NODE_TYPES.Property && p.key.type === AST_NODE_TYPES.Identifier) { | ||
| return { name: p.key.name, property: p }; | ||
| } else if (p.type === AST_NODE_TYPES.SpreadElement) { | ||
| if (p.argument.type === AST_NODE_TYPES.Identifier) { | ||
| return { name: p.argument.name, property: p }; | ||
| } else { | ||
| throw new Error("Unsupported spread element"); | ||
| } | ||
| } | ||
| return []; | ||
| }); | ||
| const sortedProperties = sortDataByOrder(properties, sortRules, "name"); | ||
| if (sortedProperties === null) { | ||
| return; | ||
| } | ||
| context.report({ | ||
| node: argument, | ||
| data: { function: node.callee.name }, | ||
| messageId: "invalidOrder", | ||
| fix(fixer) { | ||
| const sourceCode = context.sourceCode; | ||
| const text = sortedProperties.reduce( | ||
| (sourceText, specifier, index) => { | ||
| let text2 = ""; | ||
| if (index < allProperties.length - 1) { | ||
| text2 = sourceCode.getText().slice( | ||
| allProperties[index].range[1], | ||
| allProperties[index + 1].range[0] | ||
| ); | ||
| } | ||
| return sourceText + sourceCode.getText(specifier.property) + text2; | ||
| }, | ||
| "" | ||
| ); | ||
| return fixer.replaceTextRange( | ||
| [allProperties[0].range[0], allProperties.at(-1).range[1]], | ||
| text | ||
| ); | ||
| } | ||
| }); | ||
| } | ||
| }; | ||
| }) | ||
| var name = "create-route-property-order"; | ||
| var rule = createRule({ | ||
| name, | ||
| meta: { | ||
| type: "problem", | ||
| docs: { | ||
| description: "Ensure correct order of inference sensitive properties for createRoute functions", | ||
| recommended: "error" | ||
| }, | ||
| messages: { invalidOrder: "Invalid order of properties for `{{function}}`." }, | ||
| schema: [], | ||
| hasSuggestions: true, | ||
| fixable: "code" | ||
| }, | ||
| defaultOptions: [], | ||
| create: detectTanstackRouterImports((context) => { | ||
| return { CallExpression(node) { | ||
| if (node.callee.type !== AST_NODE_TYPES.Identifier) return; | ||
| const createRouteFunction = node.callee.name; | ||
| if (!isCreateRouteFunction(createRouteFunction)) return; | ||
| let args = node.arguments; | ||
| if (createRouteFunctionsIndirect.includes(createRouteFunction)) if (node.parent.type === AST_NODE_TYPES.CallExpression) args = node.parent.arguments; | ||
| else return; | ||
| const argument = args[0]; | ||
| if (argument === void 0 || argument.type !== "ObjectExpression") return; | ||
| const allProperties = argument.properties; | ||
| if (allProperties.length < 2) return; | ||
| const sortedProperties = sortDataByOrder(allProperties.flatMap((p) => { | ||
| if (p.type === AST_NODE_TYPES.Property && p.key.type === AST_NODE_TYPES.Identifier) return { | ||
| name: p.key.name, | ||
| property: p | ||
| }; | ||
| else if (p.type === AST_NODE_TYPES.SpreadElement) if (p.argument.type === AST_NODE_TYPES.Identifier) return { | ||
| name: p.argument.name, | ||
| property: p | ||
| }; | ||
| else throw new Error("Unsupported spread element"); | ||
| return []; | ||
| }), sortRules, "name"); | ||
| if (sortedProperties === null) return; | ||
| context.report({ | ||
| node: argument, | ||
| data: { function: node.callee.name }, | ||
| messageId: "invalidOrder", | ||
| fix(fixer) { | ||
| const sourceCode = context.sourceCode; | ||
| const text = sortedProperties.reduce((sourceText, specifier, index) => { | ||
| let text = ""; | ||
| if (index < allProperties.length - 1) text = sourceCode.getText().slice(allProperties[index].range[1], allProperties[index + 1].range[0]); | ||
| return sourceText + sourceCode.getText(specifier.property) + text; | ||
| }, ""); | ||
| return fixer.replaceTextRange([allProperties[0].range[0], allProperties.at(-1).range[1]], text); | ||
| } | ||
| }); | ||
| } }; | ||
| }) | ||
| }); | ||
| export { | ||
| name, | ||
| rule | ||
| }; | ||
| //# sourceMappingURL=create-route-property-order.rule.js.map | ||
| //#endregion | ||
| export { name, rule }; | ||
| //# sourceMappingURL=create-route-property-order.rule.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"create-route-property-order.rule.js","sources":["../../../../src/rules/create-route-property-order/create-route-property-order.rule.ts"],"sourcesContent":["import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils'\n\nimport { getDocsUrl } from '../../utils/get-docs-url'\nimport { detectTanstackRouterImports } from '../../utils/detect-router-imports'\nimport { sortDataByOrder } from './create-route-property-order.utils'\nimport {\n createRouteFunctions,\n createRouteFunctionsIndirect,\n sortRules,\n} from './constants'\nimport type { CreateRouteFunction } from './constants'\nimport type { ExtraRuleDocs } from '../../types'\n\nconst createRule = ESLintUtils.RuleCreator<ExtraRuleDocs>(getDocsUrl)\n\nconst createRouteFunctionSet = new Set(createRouteFunctions)\nfunction isCreateRouteFunction(node: any): node is CreateRouteFunction {\n return createRouteFunctionSet.has(node)\n}\n\nexport const name = 'create-route-property-order'\n\nexport const rule = createRule({\n name,\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Ensure correct order of inference sensitive properties for createRoute functions',\n recommended: 'error',\n },\n messages: {\n invalidOrder: 'Invalid order of properties for `{{function}}`.',\n },\n schema: [],\n hasSuggestions: true,\n fixable: 'code',\n },\n defaultOptions: [],\n\n create: detectTanstackRouterImports((context) => {\n return {\n CallExpression(node) {\n if (node.callee.type !== AST_NODE_TYPES.Identifier) {\n return\n }\n const createRouteFunction = node.callee.name\n if (!isCreateRouteFunction(createRouteFunction)) {\n return\n }\n let args = node.arguments\n if (createRouteFunctionsIndirect.includes(createRouteFunction as any)) {\n if (node.parent.type === AST_NODE_TYPES.CallExpression) {\n args = node.parent.arguments\n } else {\n return\n }\n }\n\n const argument = args[0]\n if (argument === undefined || argument.type !== 'ObjectExpression') {\n return\n }\n\n const allProperties = argument.properties\n // no need to sort if there is at max 1 property\n if (allProperties.length < 2) {\n return\n }\n\n const properties = allProperties.flatMap((p) => {\n if (\n p.type === AST_NODE_TYPES.Property &&\n p.key.type === AST_NODE_TYPES.Identifier\n ) {\n return { name: p.key.name, property: p }\n } else if (p.type === AST_NODE_TYPES.SpreadElement) {\n if (p.argument.type === AST_NODE_TYPES.Identifier) {\n return { name: p.argument.name, property: p }\n } else {\n throw new Error('Unsupported spread element')\n }\n }\n return []\n })\n\n const sortedProperties = sortDataByOrder(properties, sortRules, 'name')\n if (sortedProperties === null) {\n return\n }\n context.report({\n node: argument,\n data: { function: node.callee.name },\n messageId: 'invalidOrder',\n fix(fixer) {\n const sourceCode = context.sourceCode\n\n const text = sortedProperties.reduce(\n (sourceText, specifier, index) => {\n let text = ''\n if (index < allProperties.length - 1) {\n text = sourceCode\n .getText()\n .slice(\n allProperties[index]!.range[1],\n allProperties[index + 1]!.range[0],\n )\n }\n return (\n sourceText + sourceCode.getText(specifier.property) + text\n )\n },\n '',\n )\n return fixer.replaceTextRange(\n [allProperties[0]!.range[0], allProperties.at(-1)!.range[1]],\n text,\n )\n },\n })\n },\n }\n }),\n})\n"],"names":["text"],"mappings":";;;;;AAaA,MAAM,aAAa,YAAY,YAA2B,UAAU;AAEpE,MAAM,yBAAyB,IAAI,IAAI,oBAAoB;AAC3D,SAAS,sBAAsB,MAAwC;AACrE,SAAO,uBAAuB,IAAI,IAAI;AACxC;AAEO,MAAM,OAAO;AAEb,MAAM,OAAO,WAAW;AAAA,EAC7B;AAAA,EACA,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,MACF,aAAa;AAAA,IAAA;AAAA,IAEf,UAAU;AAAA,MACR,cAAc;AAAA,IAAA;AAAA,IAEhB,QAAQ,CAAA;AAAA,IACR,gBAAgB;AAAA,IAChB,SAAS;AAAA,EAAA;AAAA,EAEX,gBAAgB,CAAA;AAAA,EAEhB,QAAQ,4BAA4B,CAAC,YAAY;AAC/C,WAAO;AAAA,MACL,eAAe,MAAM;AACnB,YAAI,KAAK,OAAO,SAAS,eAAe,YAAY;AAClD;AAAA,QACF;AACA,cAAM,sBAAsB,KAAK,OAAO;AACxC,YAAI,CAAC,sBAAsB,mBAAmB,GAAG;AAC/C;AAAA,QACF;AACA,YAAI,OAAO,KAAK;AAChB,YAAI,6BAA6B,SAAS,mBAA0B,GAAG;AACrE,cAAI,KAAK,OAAO,SAAS,eAAe,gBAAgB;AACtD,mBAAO,KAAK,OAAO;AAAA,UACrB,OAAO;AACL;AAAA,UACF;AAAA,QACF;AAEA,cAAM,WAAW,KAAK,CAAC;AACvB,YAAI,aAAa,UAAa,SAAS,SAAS,oBAAoB;AAClE;AAAA,QACF;AAEA,cAAM,gBAAgB,SAAS;AAE/B,YAAI,cAAc,SAAS,GAAG;AAC5B;AAAA,QACF;AAEA,cAAM,aAAa,cAAc,QAAQ,CAAC,MAAM;AAC9C,cACE,EAAE,SAAS,eAAe,YAC1B,EAAE,IAAI,SAAS,eAAe,YAC9B;AACA,mBAAO,EAAE,MAAM,EAAE,IAAI,MAAM,UAAU,EAAA;AAAA,UACvC,WAAW,EAAE,SAAS,eAAe,eAAe;AAClD,gBAAI,EAAE,SAAS,SAAS,eAAe,YAAY;AACjD,qBAAO,EAAE,MAAM,EAAE,SAAS,MAAM,UAAU,EAAA;AAAA,YAC5C,OAAO;AACL,oBAAM,IAAI,MAAM,4BAA4B;AAAA,YAC9C;AAAA,UACF;AACA,iBAAO,CAAA;AAAA,QACT,CAAC;AAED,cAAM,mBAAmB,gBAAgB,YAAY,WAAW,MAAM;AACtE,YAAI,qBAAqB,MAAM;AAC7B;AAAA,QACF;AACA,gBAAQ,OAAO;AAAA,UACb,MAAM;AAAA,UACN,MAAM,EAAE,UAAU,KAAK,OAAO,KAAA;AAAA,UAC9B,WAAW;AAAA,UACX,IAAI,OAAO;AACT,kBAAM,aAAa,QAAQ;AAE3B,kBAAM,OAAO,iBAAiB;AAAA,cAC5B,CAAC,YAAY,WAAW,UAAU;AAChC,oBAAIA,QAAO;AACX,oBAAI,QAAQ,cAAc,SAAS,GAAG;AACpCA,0BAAO,WACJ,QAAA,EACA;AAAA,oBACC,cAAc,KAAK,EAAG,MAAM,CAAC;AAAA,oBAC7B,cAAc,QAAQ,CAAC,EAAG,MAAM,CAAC;AAAA,kBAAA;AAAA,gBAEvC;AACA,uBACE,aAAa,WAAW,QAAQ,UAAU,QAAQ,IAAIA;AAAAA,cAE1D;AAAA,cACA;AAAA,YAAA;AAEF,mBAAO,MAAM;AAAA,cACX,CAAC,cAAc,CAAC,EAAG,MAAM,CAAC,GAAG,cAAc,GAAG,EAAE,EAAG,MAAM,CAAC,CAAC;AAAA,cAC3D;AAAA,YAAA;AAAA,UAEJ;AAAA,QAAA,CACD;AAAA,MACH;AAAA,IAAA;AAAA,EAEJ,CAAC;AACH,CAAC;"} | ||
| {"version":3,"file":"create-route-property-order.rule.js","names":[],"sources":["../../../../src/rules/create-route-property-order/create-route-property-order.rule.ts"],"sourcesContent":["import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils'\n\nimport { getDocsUrl } from '../../utils/get-docs-url'\nimport { detectTanstackRouterImports } from '../../utils/detect-router-imports'\nimport { sortDataByOrder } from './create-route-property-order.utils'\nimport {\n createRouteFunctions,\n createRouteFunctionsIndirect,\n sortRules,\n} from './constants'\nimport type { CreateRouteFunction } from './constants'\nimport type { ExtraRuleDocs } from '../../types'\n\nconst createRule = ESLintUtils.RuleCreator<ExtraRuleDocs>(getDocsUrl)\n\nconst createRouteFunctionSet = new Set(createRouteFunctions)\nfunction isCreateRouteFunction(node: any): node is CreateRouteFunction {\n return createRouteFunctionSet.has(node)\n}\n\nexport const name = 'create-route-property-order'\n\nexport const rule = createRule({\n name,\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Ensure correct order of inference sensitive properties for createRoute functions',\n recommended: 'error',\n },\n messages: {\n invalidOrder: 'Invalid order of properties for `{{function}}`.',\n },\n schema: [],\n hasSuggestions: true,\n fixable: 'code',\n },\n defaultOptions: [],\n\n create: detectTanstackRouterImports((context) => {\n return {\n CallExpression(node) {\n if (node.callee.type !== AST_NODE_TYPES.Identifier) {\n return\n }\n const createRouteFunction = node.callee.name\n if (!isCreateRouteFunction(createRouteFunction)) {\n return\n }\n let args = node.arguments\n if (createRouteFunctionsIndirect.includes(createRouteFunction as any)) {\n if (node.parent.type === AST_NODE_TYPES.CallExpression) {\n args = node.parent.arguments\n } else {\n return\n }\n }\n\n const argument = args[0]\n if (argument === undefined || argument.type !== 'ObjectExpression') {\n return\n }\n\n const allProperties = argument.properties\n // no need to sort if there is at max 1 property\n if (allProperties.length < 2) {\n return\n }\n\n const properties = allProperties.flatMap((p) => {\n if (\n p.type === AST_NODE_TYPES.Property &&\n p.key.type === AST_NODE_TYPES.Identifier\n ) {\n return { name: p.key.name, property: p }\n } else if (p.type === AST_NODE_TYPES.SpreadElement) {\n if (p.argument.type === AST_NODE_TYPES.Identifier) {\n return { name: p.argument.name, property: p }\n } else {\n throw new Error('Unsupported spread element')\n }\n }\n return []\n })\n\n const sortedProperties = sortDataByOrder(properties, sortRules, 'name')\n if (sortedProperties === null) {\n return\n }\n context.report({\n node: argument,\n data: { function: node.callee.name },\n messageId: 'invalidOrder',\n fix(fixer) {\n const sourceCode = context.sourceCode\n\n const text = sortedProperties.reduce(\n (sourceText, specifier, index) => {\n let text = ''\n if (index < allProperties.length - 1) {\n text = sourceCode\n .getText()\n .slice(\n allProperties[index]!.range[1],\n allProperties[index + 1]!.range[0],\n )\n }\n return (\n sourceText + sourceCode.getText(specifier.property) + text\n )\n },\n '',\n )\n return fixer.replaceTextRange(\n [allProperties[0]!.range[0], allProperties.at(-1)!.range[1]],\n text,\n )\n },\n })\n },\n }\n }),\n})\n"],"mappings":";;;;;;AAaA,IAAM,aAAa,YAAY,YAA2B,WAAW;AAErE,IAAM,yBAAyB,IAAI,IAAI,qBAAqB;AAC5D,SAAS,sBAAsB,MAAwC;AACrE,QAAO,uBAAuB,IAAI,KAAK;;AAGzC,IAAa,OAAO;AAEpB,IAAa,OAAO,WAAW;CAC7B;CACA,MAAM;EACJ,MAAM;EACN,MAAM;GACJ,aACE;GACF,aAAa;GACd;EACD,UAAU,EACR,cAAc,mDACf;EACD,QAAQ,EAAE;EACV,gBAAgB;EAChB,SAAS;EACV;CACD,gBAAgB,EAAE;CAElB,QAAQ,6BAA6B,YAAY;AAC/C,SAAO,EACL,eAAe,MAAM;AACnB,OAAI,KAAK,OAAO,SAAS,eAAe,WACtC;GAEF,MAAM,sBAAsB,KAAK,OAAO;AACxC,OAAI,CAAC,sBAAsB,oBAAoB,CAC7C;GAEF,IAAI,OAAO,KAAK;AAChB,OAAI,6BAA6B,SAAS,oBAA2B,CACnE,KAAI,KAAK,OAAO,SAAS,eAAe,eACtC,QAAO,KAAK,OAAO;OAEnB;GAIJ,MAAM,WAAW,KAAK;AACtB,OAAI,aAAa,KAAA,KAAa,SAAS,SAAS,mBAC9C;GAGF,MAAM,gBAAgB,SAAS;AAE/B,OAAI,cAAc,SAAS,EACzB;GAmBF,MAAM,mBAAmB,gBAhBN,cAAc,SAAS,MAAM;AAC9C,QACE,EAAE,SAAS,eAAe,YAC1B,EAAE,IAAI,SAAS,eAAe,WAE9B,QAAO;KAAE,MAAM,EAAE,IAAI;KAAM,UAAU;KAAG;aAC/B,EAAE,SAAS,eAAe,cACnC,KAAI,EAAE,SAAS,SAAS,eAAe,WACrC,QAAO;KAAE,MAAM,EAAE,SAAS;KAAM,UAAU;KAAG;QAE7C,OAAM,IAAI,MAAM,6BAA6B;AAGjD,WAAO,EAAE;KACT,EAEmD,WAAW,OAAO;AACvE,OAAI,qBAAqB,KACvB;AAEF,WAAQ,OAAO;IACb,MAAM;IACN,MAAM,EAAE,UAAU,KAAK,OAAO,MAAM;IACpC,WAAW;IACX,IAAI,OAAO;KACT,MAAM,aAAa,QAAQ;KAE3B,MAAM,OAAO,iBAAiB,QAC3B,YAAY,WAAW,UAAU;MAChC,IAAI,OAAO;AACX,UAAI,QAAQ,cAAc,SAAS,EACjC,QAAO,WACJ,SAAS,CACT,MACC,cAAc,OAAQ,MAAM,IAC5B,cAAc,QAAQ,GAAI,MAAM,GACjC;AAEL,aACE,aAAa,WAAW,QAAQ,UAAU,SAAS,GAAG;QAG1D,GACD;AACD,YAAO,MAAM,iBACX,CAAC,cAAc,GAAI,MAAM,IAAI,cAAc,GAAG,GAAG,CAAE,MAAM,GAAG,EAC5D,KACD;;IAEJ,CAAC;KAEL;GACD;CACH,CAAC"} |
@@ -0,50 +1,38 @@ | ||
| //#region src/rules/create-route-property-order/create-route-property-order.utils.ts | ||
| function sortDataByOrder(data, orderRules, key) { | ||
| const getSubsetIndex = (item, subsets) => { | ||
| for (let i = 0; i < subsets.length; i++) { | ||
| if (subsets[i]?.includes(item)) { | ||
| return i; | ||
| } | ||
| } | ||
| return null; | ||
| }; | ||
| const orderSets = orderRules.reduce( | ||
| (sets, [A, B]) => [...sets, A, B], | ||
| [] | ||
| ); | ||
| const inOrderArray = data.filter( | ||
| (item) => getSubsetIndex(item[key], orderSets) !== null | ||
| ); | ||
| let wasResorted = false; | ||
| const sortedArray = inOrderArray.sort((a, b) => { | ||
| const aKey = a[key], bKey = b[key]; | ||
| const aSubsetIndex = getSubsetIndex(aKey, orderSets); | ||
| const bSubsetIndex = getSubsetIndex(bKey, orderSets); | ||
| if (aSubsetIndex !== null && bSubsetIndex !== null && aSubsetIndex !== bSubsetIndex) { | ||
| return aSubsetIndex - bSubsetIndex; | ||
| } | ||
| return 0; | ||
| }); | ||
| const inOrderIterator = sortedArray.values(); | ||
| const result = data.map((item) => { | ||
| if (getSubsetIndex(item[key], orderSets) !== null) { | ||
| const sortedItem = inOrderIterator.next().value; | ||
| if (sortedItem[key] !== item[key]) { | ||
| wasResorted = true; | ||
| } | ||
| return sortedItem; | ||
| } | ||
| return item; | ||
| }); | ||
| if (!wasResorted) { | ||
| return null; | ||
| } | ||
| return result; | ||
| const getSubsetIndex = (item, subsets) => { | ||
| for (let i = 0; i < subsets.length; i++) if (subsets[i]?.includes(item)) return i; | ||
| return null; | ||
| }; | ||
| const orderSets = orderRules.reduce((sets, [A, B]) => [ | ||
| ...sets, | ||
| A, | ||
| B | ||
| ], []); | ||
| const inOrderArray = data.filter((item) => getSubsetIndex(item[key], orderSets) !== null); | ||
| let wasResorted = false; | ||
| const inOrderIterator = inOrderArray.sort((a, b) => { | ||
| const aKey = a[key], bKey = b[key]; | ||
| const aSubsetIndex = getSubsetIndex(aKey, orderSets); | ||
| const bSubsetIndex = getSubsetIndex(bKey, orderSets); | ||
| if (aSubsetIndex !== null && bSubsetIndex !== null && aSubsetIndex !== bSubsetIndex) return aSubsetIndex - bSubsetIndex; | ||
| return 0; | ||
| }).values(); | ||
| const result = data.map((item) => { | ||
| if (getSubsetIndex(item[key], orderSets) !== null) { | ||
| const sortedItem = inOrderIterator.next().value; | ||
| if (sortedItem[key] !== item[key]) wasResorted = true; | ||
| return sortedItem; | ||
| } | ||
| return item; | ||
| }); | ||
| if (!wasResorted) return null; | ||
| return result; | ||
| } | ||
| function getCheckedProperties(orderRules) { | ||
| return [...new Set(orderRules.flat(2))]; | ||
| return [...new Set(orderRules.flat(2))]; | ||
| } | ||
| export { | ||
| getCheckedProperties, | ||
| sortDataByOrder | ||
| }; | ||
| //# sourceMappingURL=create-route-property-order.utils.js.map | ||
| //#endregion | ||
| export { getCheckedProperties, sortDataByOrder }; | ||
| //# sourceMappingURL=create-route-property-order.utils.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"create-route-property-order.utils.js","sources":["../../../../src/rules/create-route-property-order/create-route-property-order.utils.ts"],"sourcesContent":["export function sortDataByOrder<T, TKey extends keyof T>(\n data: Array<T> | ReadonlyArray<T>,\n orderRules: ReadonlyArray<\n Readonly<[ReadonlyArray<T[TKey]>, ReadonlyArray<T[TKey]>]>\n >,\n key: TKey,\n): Array<T> | null {\n const getSubsetIndex = (\n item: T[TKey],\n subsets: ReadonlyArray<ReadonlyArray<T[TKey]> | Array<T[TKey]>>,\n ): number | null => {\n for (let i = 0; i < subsets.length; i++) {\n if (subsets[i]?.includes(item)) {\n return i\n }\n }\n return null\n }\n\n const orderSets = orderRules.reduce(\n (sets, [A, B]) => [...sets, A, B],\n [] as Array<ReadonlyArray<T[TKey]> | Array<T[TKey]>>,\n )\n\n const inOrderArray = data.filter(\n (item) => getSubsetIndex(item[key], orderSets) !== null,\n )\n\n let wasResorted = false as boolean\n\n // Sort by the relative order defined by the rules\n const sortedArray = inOrderArray.sort((a, b) => {\n const aKey = a[key],\n bKey = b[key]\n const aSubsetIndex = getSubsetIndex(aKey, orderSets)\n const bSubsetIndex = getSubsetIndex(bKey, orderSets)\n\n // If both items belong to different subsets, sort by their subset order\n if (\n aSubsetIndex !== null &&\n bSubsetIndex !== null &&\n aSubsetIndex !== bSubsetIndex\n ) {\n return aSubsetIndex - bSubsetIndex\n }\n\n // If both items belong to the same subset or neither is in the subset, keep their relative order\n return 0\n })\n\n const inOrderIterator = sortedArray.values()\n const result = data.map((item) => {\n if (getSubsetIndex(item[key], orderSets) !== null) {\n const sortedItem = inOrderIterator.next().value!\n if (sortedItem[key] !== item[key]) {\n wasResorted = true\n }\n return sortedItem\n }\n return item\n })\n\n if (!wasResorted) {\n return null\n }\n return result\n}\n\nexport function getCheckedProperties<T>(\n orderRules: ReadonlyArray<ReadonlyArray<ReadonlyArray<T>>>,\n): ReadonlyArray<T> {\n return [...new Set<T>(orderRules.flat(2))]\n}\n"],"names":[],"mappings":"AAAO,SAAS,gBACd,MACA,YAGA,KACiB;AACjB,QAAM,iBAAiB,CACrB,MACA,YACkB;AAClB,aAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,UAAI,QAAQ,CAAC,GAAG,SAAS,IAAI,GAAG;AAC9B,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,QAAM,YAAY,WAAW;AAAA,IAC3B,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,GAAG,CAAC;AAAA,IAChC,CAAA;AAAA,EAAC;AAGH,QAAM,eAAe,KAAK;AAAA,IACxB,CAAC,SAAS,eAAe,KAAK,GAAG,GAAG,SAAS,MAAM;AAAA,EAAA;AAGrD,MAAI,cAAc;AAGlB,QAAM,cAAc,aAAa,KAAK,CAAC,GAAG,MAAM;AAC9C,UAAM,OAAO,EAAE,GAAG,GAChB,OAAO,EAAE,GAAG;AACd,UAAM,eAAe,eAAe,MAAM,SAAS;AACnD,UAAM,eAAe,eAAe,MAAM,SAAS;AAGnD,QACE,iBAAiB,QACjB,iBAAiB,QACjB,iBAAiB,cACjB;AACA,aAAO,eAAe;AAAA,IACxB;AAGA,WAAO;AAAA,EACT,CAAC;AAED,QAAM,kBAAkB,YAAY,OAAA;AACpC,QAAM,SAAS,KAAK,IAAI,CAAC,SAAS;AAChC,QAAI,eAAe,KAAK,GAAG,GAAG,SAAS,MAAM,MAAM;AACjD,YAAM,aAAa,gBAAgB,KAAA,EAAO;AAC1C,UAAI,WAAW,GAAG,MAAM,KAAK,GAAG,GAAG;AACjC,sBAAc;AAAA,MAChB;AACA,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT,CAAC;AAED,MAAI,CAAC,aAAa;AAChB,WAAO;AAAA,EACT;AACA,SAAO;AACT;AAEO,SAAS,qBACd,YACkB;AAClB,SAAO,CAAC,GAAG,IAAI,IAAO,WAAW,KAAK,CAAC,CAAC,CAAC;AAC3C;"} | ||
| {"version":3,"file":"create-route-property-order.utils.js","names":[],"sources":["../../../../src/rules/create-route-property-order/create-route-property-order.utils.ts"],"sourcesContent":["export function sortDataByOrder<T, TKey extends keyof T>(\n data: Array<T> | ReadonlyArray<T>,\n orderRules: ReadonlyArray<\n Readonly<[ReadonlyArray<T[TKey]>, ReadonlyArray<T[TKey]>]>\n >,\n key: TKey,\n): Array<T> | null {\n const getSubsetIndex = (\n item: T[TKey],\n subsets: ReadonlyArray<ReadonlyArray<T[TKey]> | Array<T[TKey]>>,\n ): number | null => {\n for (let i = 0; i < subsets.length; i++) {\n if (subsets[i]?.includes(item)) {\n return i\n }\n }\n return null\n }\n\n const orderSets = orderRules.reduce(\n (sets, [A, B]) => [...sets, A, B],\n [] as Array<ReadonlyArray<T[TKey]> | Array<T[TKey]>>,\n )\n\n const inOrderArray = data.filter(\n (item) => getSubsetIndex(item[key], orderSets) !== null,\n )\n\n let wasResorted = false as boolean\n\n // Sort by the relative order defined by the rules\n const sortedArray = inOrderArray.sort((a, b) => {\n const aKey = a[key],\n bKey = b[key]\n const aSubsetIndex = getSubsetIndex(aKey, orderSets)\n const bSubsetIndex = getSubsetIndex(bKey, orderSets)\n\n // If both items belong to different subsets, sort by their subset order\n if (\n aSubsetIndex !== null &&\n bSubsetIndex !== null &&\n aSubsetIndex !== bSubsetIndex\n ) {\n return aSubsetIndex - bSubsetIndex\n }\n\n // If both items belong to the same subset or neither is in the subset, keep their relative order\n return 0\n })\n\n const inOrderIterator = sortedArray.values()\n const result = data.map((item) => {\n if (getSubsetIndex(item[key], orderSets) !== null) {\n const sortedItem = inOrderIterator.next().value!\n if (sortedItem[key] !== item[key]) {\n wasResorted = true\n }\n return sortedItem\n }\n return item\n })\n\n if (!wasResorted) {\n return null\n }\n return result\n}\n\nexport function getCheckedProperties<T>(\n orderRules: ReadonlyArray<ReadonlyArray<ReadonlyArray<T>>>,\n): ReadonlyArray<T> {\n return [...new Set<T>(orderRules.flat(2))]\n}\n"],"mappings":";AAAA,SAAgB,gBACd,MACA,YAGA,KACiB;CACjB,MAAM,kBACJ,MACA,YACkB;AAClB,OAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,IAClC,KAAI,QAAQ,IAAI,SAAS,KAAK,CAC5B,QAAO;AAGX,SAAO;;CAGT,MAAM,YAAY,WAAW,QAC1B,MAAM,CAAC,GAAG,OAAO;EAAC,GAAG;EAAM;EAAG;EAAE,EACjC,EAAE,CACH;CAED,MAAM,eAAe,KAAK,QACvB,SAAS,eAAe,KAAK,MAAM,UAAU,KAAK,KACpD;CAED,IAAI,cAAc;CAsBlB,MAAM,kBAnBc,aAAa,MAAM,GAAG,MAAM;EAC9C,MAAM,OAAO,EAAE,MACb,OAAO,EAAE;EACX,MAAM,eAAe,eAAe,MAAM,UAAU;EACpD,MAAM,eAAe,eAAe,MAAM,UAAU;AAGpD,MACE,iBAAiB,QACjB,iBAAiB,QACjB,iBAAiB,aAEjB,QAAO,eAAe;AAIxB,SAAO;GACP,CAEkC,QAAQ;CAC5C,MAAM,SAAS,KAAK,KAAK,SAAS;AAChC,MAAI,eAAe,KAAK,MAAM,UAAU,KAAK,MAAM;GACjD,MAAM,aAAa,gBAAgB,MAAM,CAAC;AAC1C,OAAI,WAAW,SAAS,KAAK,KAC3B,eAAc;AAEhB,UAAO;;AAET,SAAO;GACP;AAEF,KAAI,CAAC,YACH,QAAO;AAET,QAAO;;AAGT,SAAgB,qBACd,YACkB;AAClB,QAAO,CAAC,GAAG,IAAI,IAAO,WAAW,KAAK,EAAE,CAAC,CAAC"} |
@@ -1,13 +0,26 @@ | ||
| const pathAsFirstArgFunctions = [ | ||
| "createFileRoute", | ||
| "createLazyFileRoute", | ||
| "createLazyRoute" | ||
| //#region src/rules/route-param-names/constants.ts | ||
| /** | ||
| * Functions where the path is passed as the first argument (string literal) | ||
| * e.g., createFileRoute('/path/$param')(...) | ||
| */ | ||
| var pathAsFirstArgFunctions = [ | ||
| "createFileRoute", | ||
| "createLazyFileRoute", | ||
| "createLazyRoute" | ||
| ]; | ||
| const pathAsPropertyFunctions = ["createRoute"]; | ||
| const VALID_PARAM_NAME_REGEX = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/; | ||
| export { | ||
| VALID_PARAM_NAME_REGEX, | ||
| pathAsFirstArgFunctions, | ||
| pathAsPropertyFunctions | ||
| }; | ||
| //# sourceMappingURL=constants.js.map | ||
| /** | ||
| * Functions where the path is a property in the options object | ||
| * e.g., createRoute({ path: '/path/$param' }) | ||
| */ | ||
| var pathAsPropertyFunctions = ["createRoute"]; | ||
| [...pathAsFirstArgFunctions, ...pathAsPropertyFunctions]; | ||
| /** | ||
| * Regex for valid JavaScript identifier (param name) | ||
| * Must start with letter, underscore, or dollar sign | ||
| * Can contain letters, numbers, underscores, or dollar signs | ||
| */ | ||
| var VALID_PARAM_NAME_REGEX = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/; | ||
| //#endregion | ||
| export { VALID_PARAM_NAME_REGEX, pathAsFirstArgFunctions, pathAsPropertyFunctions }; | ||
| //# sourceMappingURL=constants.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"constants.js","sources":["../../../../src/rules/route-param-names/constants.ts"],"sourcesContent":["/**\n * Functions where the path is passed as the first argument (string literal)\n * e.g., createFileRoute('/path/$param')(...)\n */\nexport const pathAsFirstArgFunctions = [\n 'createFileRoute',\n 'createLazyFileRoute',\n 'createLazyRoute',\n] as const\n\nexport type PathAsFirstArgFunction = (typeof pathAsFirstArgFunctions)[number]\n\n/**\n * Functions where the path is a property in the options object\n * e.g., createRoute({ path: '/path/$param' })\n */\nexport const pathAsPropertyFunctions = ['createRoute'] as const\n\nexport type PathAsPropertyFunction = (typeof pathAsPropertyFunctions)[number]\n\n/**\n * All route functions that need param name validation\n */\nexport const allRouteFunctions = [\n ...pathAsFirstArgFunctions,\n ...pathAsPropertyFunctions,\n] as const\n\nexport type RouteFunction = (typeof allRouteFunctions)[number]\n\n/**\n * Regex for valid JavaScript identifier (param name)\n * Must start with letter, underscore, or dollar sign\n * Can contain letters, numbers, underscores, or dollar signs\n */\nexport const VALID_PARAM_NAME_REGEX = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/\n"],"names":[],"mappings":"AAIO,MAAM,0BAA0B;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AACF;AAQO,MAAM,0BAA0B,CAAC,aAAa;AAmB9C,MAAM,yBAAyB;"} | ||
| {"version":3,"file":"constants.js","names":[],"sources":["../../../../src/rules/route-param-names/constants.ts"],"sourcesContent":["/**\n * Functions where the path is passed as the first argument (string literal)\n * e.g., createFileRoute('/path/$param')(...)\n */\nexport const pathAsFirstArgFunctions = [\n 'createFileRoute',\n 'createLazyFileRoute',\n 'createLazyRoute',\n] as const\n\nexport type PathAsFirstArgFunction = (typeof pathAsFirstArgFunctions)[number]\n\n/**\n * Functions where the path is a property in the options object\n * e.g., createRoute({ path: '/path/$param' })\n */\nexport const pathAsPropertyFunctions = ['createRoute'] as const\n\nexport type PathAsPropertyFunction = (typeof pathAsPropertyFunctions)[number]\n\n/**\n * All route functions that need param name validation\n */\nexport const allRouteFunctions = [\n ...pathAsFirstArgFunctions,\n ...pathAsPropertyFunctions,\n] as const\n\nexport type RouteFunction = (typeof allRouteFunctions)[number]\n\n/**\n * Regex for valid JavaScript identifier (param name)\n * Must start with letter, underscore, or dollar sign\n * Can contain letters, numbers, underscores, or dollar signs\n */\nexport const VALID_PARAM_NAME_REGEX = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/\n"],"mappings":";;;;;AAIA,IAAa,0BAA0B;CACrC;CACA;CACA;CACD;;;;;AAQD,IAAa,0BAA0B,CAAC,cAAc;AAOrB,CAC/B,GAAG,yBACH,GAAG,wBACJ;;;;;;AASD,IAAa,yBAAyB"} |
@@ -1,98 +0,77 @@ | ||
| import { ESLintUtils, AST_NODE_TYPES } from "@typescript-eslint/utils"; | ||
| import { getDocsUrl } from "../../utils/get-docs-url.js"; | ||
| import { detectTanstackRouterImports } from "../../utils/detect-router-imports.js"; | ||
| import { pathAsFirstArgFunctions, pathAsPropertyFunctions } from "./constants.js"; | ||
| import { getInvalidParams } from "./route-param-names.utils.js"; | ||
| import { pathAsFirstArgFunctions, pathAsPropertyFunctions } from "./constants.js"; | ||
| const createRule = ESLintUtils.RuleCreator(getDocsUrl); | ||
| const pathAsFirstArgSet = new Set(pathAsFirstArgFunctions); | ||
| const pathAsPropertySet = new Set(pathAsPropertyFunctions); | ||
| const name = "route-param-names"; | ||
| const rule = createRule({ | ||
| name, | ||
| meta: { | ||
| type: "problem", | ||
| docs: { | ||
| description: "Ensure route param names are valid JavaScript identifiers", | ||
| recommended: "error" | ||
| }, | ||
| messages: { | ||
| invalidParamName: 'Invalid param name "{{paramName}}" in route path. Param names must be valid JavaScript identifiers (match /[a-zA-Z_$][a-zA-Z0-9_$]*/).' | ||
| }, | ||
| schema: [] | ||
| }, | ||
| defaultOptions: [], | ||
| create: detectTanstackRouterImports((context, _, helpers) => { | ||
| function reportInvalidParams(node, path) { | ||
| const invalidParams = getInvalidParams(path); | ||
| for (const param of invalidParams) { | ||
| context.report({ | ||
| node, | ||
| messageId: "invalidParamName", | ||
| data: { paramName: param.paramName } | ||
| }); | ||
| } | ||
| } | ||
| function getStringLiteralValue(node) { | ||
| if (node.type === AST_NODE_TYPES.Literal && typeof node.value === "string") { | ||
| return node.value; | ||
| } | ||
| if (node.type === AST_NODE_TYPES.TemplateLiteral && node.quasis.length === 1) { | ||
| const cooked = node.quasis[0]?.value.cooked; | ||
| if (cooked != null) { | ||
| return cooked; | ||
| } | ||
| } | ||
| return null; | ||
| } | ||
| return { | ||
| CallExpression(node) { | ||
| if (node.callee.type === AST_NODE_TYPES.Identifier) { | ||
| const funcName = node.callee.name; | ||
| if (!helpers.isTanstackRouterImport(node.callee)) { | ||
| return; | ||
| } | ||
| if (pathAsPropertySet.has(funcName)) { | ||
| const arg = node.arguments[0]; | ||
| if (arg?.type === AST_NODE_TYPES.ObjectExpression) { | ||
| for (const prop of arg.properties) { | ||
| if (prop.type === AST_NODE_TYPES.Property) { | ||
| const isPathKey = prop.key.type === AST_NODE_TYPES.Identifier && prop.key.name === "path" || prop.key.type === AST_NODE_TYPES.Literal && prop.key.value === "path"; | ||
| if (isPathKey) { | ||
| const pathValue = getStringLiteralValue(prop.value); | ||
| if (pathValue) { | ||
| reportInvalidParams(prop.value, pathValue); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| return; | ||
| } | ||
| } | ||
| if (node.callee.type === AST_NODE_TYPES.CallExpression) { | ||
| const innerCall = node.callee; | ||
| if (innerCall.callee.type === AST_NODE_TYPES.Identifier) { | ||
| const funcName = innerCall.callee.name; | ||
| if (!helpers.isTanstackRouterImport(innerCall.callee)) { | ||
| return; | ||
| } | ||
| if (pathAsFirstArgSet.has(funcName)) { | ||
| const pathArg = innerCall.arguments[0]; | ||
| if (pathArg) { | ||
| const pathValue = getStringLiteralValue(pathArg); | ||
| if (pathValue) { | ||
| reportInvalidParams(pathArg, pathValue); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } | ||
| }; | ||
| }) | ||
| import { AST_NODE_TYPES, ESLintUtils } from "@typescript-eslint/utils"; | ||
| //#region src/rules/route-param-names/route-param-names.rule.ts | ||
| var createRule = ESLintUtils.RuleCreator(getDocsUrl); | ||
| var pathAsFirstArgSet = new Set(pathAsFirstArgFunctions); | ||
| var pathAsPropertySet = new Set(pathAsPropertyFunctions); | ||
| var name = "route-param-names"; | ||
| var rule = createRule({ | ||
| name, | ||
| meta: { | ||
| type: "problem", | ||
| docs: { | ||
| description: "Ensure route param names are valid JavaScript identifiers", | ||
| recommended: "error" | ||
| }, | ||
| messages: { invalidParamName: "Invalid param name \"{{paramName}}\" in route path. Param names must be valid JavaScript identifiers (match /[a-zA-Z_$][a-zA-Z0-9_$]*/)." }, | ||
| schema: [] | ||
| }, | ||
| defaultOptions: [], | ||
| create: detectTanstackRouterImports((context, _, helpers) => { | ||
| function reportInvalidParams(node, path) { | ||
| const invalidParams = getInvalidParams(path); | ||
| for (const param of invalidParams) context.report({ | ||
| node, | ||
| messageId: "invalidParamName", | ||
| data: { paramName: param.paramName } | ||
| }); | ||
| } | ||
| function getStringLiteralValue(node) { | ||
| if (node.type === AST_NODE_TYPES.Literal && typeof node.value === "string") return node.value; | ||
| if (node.type === AST_NODE_TYPES.TemplateLiteral && node.quasis.length === 1) { | ||
| const cooked = node.quasis[0]?.value.cooked; | ||
| if (cooked != null) return cooked; | ||
| } | ||
| return null; | ||
| } | ||
| return { CallExpression(node) { | ||
| if (node.callee.type === AST_NODE_TYPES.Identifier) { | ||
| const funcName = node.callee.name; | ||
| if (!helpers.isTanstackRouterImport(node.callee)) return; | ||
| if (pathAsPropertySet.has(funcName)) { | ||
| const arg = node.arguments[0]; | ||
| if (arg?.type === AST_NODE_TYPES.ObjectExpression) { | ||
| for (const prop of arg.properties) if (prop.type === AST_NODE_TYPES.Property) { | ||
| if (prop.key.type === AST_NODE_TYPES.Identifier && prop.key.name === "path" || prop.key.type === AST_NODE_TYPES.Literal && prop.key.value === "path") { | ||
| const pathValue = getStringLiteralValue(prop.value); | ||
| if (pathValue) reportInvalidParams(prop.value, pathValue); | ||
| } | ||
| } | ||
| } | ||
| return; | ||
| } | ||
| } | ||
| if (node.callee.type === AST_NODE_TYPES.CallExpression) { | ||
| const innerCall = node.callee; | ||
| if (innerCall.callee.type === AST_NODE_TYPES.Identifier) { | ||
| const funcName = innerCall.callee.name; | ||
| if (!helpers.isTanstackRouterImport(innerCall.callee)) return; | ||
| if (pathAsFirstArgSet.has(funcName)) { | ||
| const pathArg = innerCall.arguments[0]; | ||
| if (pathArg) { | ||
| const pathValue = getStringLiteralValue(pathArg); | ||
| if (pathValue) reportInvalidParams(pathArg, pathValue); | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } }; | ||
| }) | ||
| }); | ||
| export { | ||
| name, | ||
| rule | ||
| }; | ||
| //# sourceMappingURL=route-param-names.rule.js.map | ||
| //#endregion | ||
| export { name, rule }; | ||
| //# sourceMappingURL=route-param-names.rule.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"route-param-names.rule.js","sources":["../../../../src/rules/route-param-names/route-param-names.rule.ts"],"sourcesContent":["import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils'\n\nimport { getDocsUrl } from '../../utils/get-docs-url'\nimport { detectTanstackRouterImports } from '../../utils/detect-router-imports'\nimport { getInvalidParams } from './route-param-names.utils'\nimport { pathAsFirstArgFunctions, pathAsPropertyFunctions } from './constants'\nimport type { TSESTree } from '@typescript-eslint/utils'\nimport type { ExtraRuleDocs } from '../../types'\n\nconst createRule = ESLintUtils.RuleCreator<ExtraRuleDocs>(getDocsUrl)\n\nconst pathAsFirstArgSet = new Set<string>(pathAsFirstArgFunctions)\nconst pathAsPropertySet = new Set<string>(pathAsPropertyFunctions)\n\nexport const name = 'route-param-names'\n\nexport const rule = createRule({\n name,\n meta: {\n type: 'problem',\n docs: {\n description: 'Ensure route param names are valid JavaScript identifiers',\n recommended: 'error',\n },\n messages: {\n invalidParamName:\n 'Invalid param name \"{{paramName}}\" in route path. Param names must be valid JavaScript identifiers (match /[a-zA-Z_$][a-zA-Z0-9_$]*/).',\n },\n schema: [],\n },\n defaultOptions: [],\n\n create: detectTanstackRouterImports((context, _, helpers) => {\n function reportInvalidParams(node: TSESTree.Node, path: string) {\n const invalidParams = getInvalidParams(path)\n\n for (const param of invalidParams) {\n context.report({\n node,\n messageId: 'invalidParamName',\n data: { paramName: param.paramName },\n })\n }\n }\n\n function getStringLiteralValue(node: TSESTree.Node): string | null {\n if (\n node.type === AST_NODE_TYPES.Literal &&\n typeof node.value === 'string'\n ) {\n return node.value\n }\n if (\n node.type === AST_NODE_TYPES.TemplateLiteral &&\n node.quasis.length === 1\n ) {\n const cooked = node.quasis[0]?.value.cooked\n if (cooked != null) {\n return cooked\n }\n }\n return null\n }\n\n return {\n CallExpression(node) {\n // Handle direct function call: createRoute({ path: '...' })\n if (node.callee.type === AST_NODE_TYPES.Identifier) {\n const funcName = node.callee.name\n\n // Skip if not imported from TanStack Router\n if (!helpers.isTanstackRouterImport(node.callee)) {\n return\n }\n\n // Case: createRoute({ path: '/path/$param' }) or createRoute({ 'path': '/path/$param' })\n if (pathAsPropertySet.has(funcName)) {\n const arg = node.arguments[0]\n if (arg?.type === AST_NODE_TYPES.ObjectExpression) {\n for (const prop of arg.properties) {\n if (prop.type === AST_NODE_TYPES.Property) {\n const isPathKey =\n (prop.key.type === AST_NODE_TYPES.Identifier &&\n prop.key.name === 'path') ||\n (prop.key.type === AST_NODE_TYPES.Literal &&\n prop.key.value === 'path')\n if (isPathKey) {\n const pathValue = getStringLiteralValue(prop.value)\n if (pathValue) {\n reportInvalidParams(prop.value, pathValue)\n }\n }\n }\n }\n }\n return\n }\n }\n\n // Handle curried function call: createFileRoute('/path')({ ... })\n if (node.callee.type === AST_NODE_TYPES.CallExpression) {\n const innerCall = node.callee\n\n if (innerCall.callee.type === AST_NODE_TYPES.Identifier) {\n const funcName = innerCall.callee.name\n\n // Skip if not imported from TanStack Router\n if (!helpers.isTanstackRouterImport(innerCall.callee)) {\n return\n }\n\n // Case: createFileRoute('/path/$param')(...) or similar\n if (pathAsFirstArgSet.has(funcName)) {\n const pathArg = innerCall.arguments[0]\n if (pathArg) {\n const pathValue = getStringLiteralValue(pathArg)\n if (pathValue) {\n reportInvalidParams(pathArg, pathValue)\n }\n }\n }\n }\n }\n },\n }\n }),\n})\n"],"names":[],"mappings":";;;;;AASA,MAAM,aAAa,YAAY,YAA2B,UAAU;AAEpE,MAAM,oBAAoB,IAAI,IAAY,uBAAuB;AACjE,MAAM,oBAAoB,IAAI,IAAY,uBAAuB;AAE1D,MAAM,OAAO;AAEb,MAAM,OAAO,WAAW;AAAA,EAC7B;AAAA,EACA,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aAAa;AAAA,MACb,aAAa;AAAA,IAAA;AAAA,IAEf,UAAU;AAAA,MACR,kBACE;AAAA,IAAA;AAAA,IAEJ,QAAQ,CAAA;AAAA,EAAC;AAAA,EAEX,gBAAgB,CAAA;AAAA,EAEhB,QAAQ,4BAA4B,CAAC,SAAS,GAAG,YAAY;AAC3D,aAAS,oBAAoB,MAAqB,MAAc;AAC9D,YAAM,gBAAgB,iBAAiB,IAAI;AAE3C,iBAAW,SAAS,eAAe;AACjC,gBAAQ,OAAO;AAAA,UACb;AAAA,UACA,WAAW;AAAA,UACX,MAAM,EAAE,WAAW,MAAM,UAAA;AAAA,QAAU,CACpC;AAAA,MACH;AAAA,IACF;AAEA,aAAS,sBAAsB,MAAoC;AACjE,UACE,KAAK,SAAS,eAAe,WAC7B,OAAO,KAAK,UAAU,UACtB;AACA,eAAO,KAAK;AAAA,MACd;AACA,UACE,KAAK,SAAS,eAAe,mBAC7B,KAAK,OAAO,WAAW,GACvB;AACA,cAAM,SAAS,KAAK,OAAO,CAAC,GAAG,MAAM;AACrC,YAAI,UAAU,MAAM;AAClB,iBAAO;AAAA,QACT;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,MACL,eAAe,MAAM;AAEnB,YAAI,KAAK,OAAO,SAAS,eAAe,YAAY;AAClD,gBAAM,WAAW,KAAK,OAAO;AAG7B,cAAI,CAAC,QAAQ,uBAAuB,KAAK,MAAM,GAAG;AAChD;AAAA,UACF;AAGA,cAAI,kBAAkB,IAAI,QAAQ,GAAG;AACnC,kBAAM,MAAM,KAAK,UAAU,CAAC;AAC5B,gBAAI,KAAK,SAAS,eAAe,kBAAkB;AACjD,yBAAW,QAAQ,IAAI,YAAY;AACjC,oBAAI,KAAK,SAAS,eAAe,UAAU;AACzC,wBAAM,YACH,KAAK,IAAI,SAAS,eAAe,cAChC,KAAK,IAAI,SAAS,UACnB,KAAK,IAAI,SAAS,eAAe,WAChC,KAAK,IAAI,UAAU;AACvB,sBAAI,WAAW;AACb,0BAAM,YAAY,sBAAsB,KAAK,KAAK;AAClD,wBAAI,WAAW;AACb,0CAAoB,KAAK,OAAO,SAAS;AAAA,oBAC3C;AAAA,kBACF;AAAA,gBACF;AAAA,cACF;AAAA,YACF;AACA;AAAA,UACF;AAAA,QACF;AAGA,YAAI,KAAK,OAAO,SAAS,eAAe,gBAAgB;AACtD,gBAAM,YAAY,KAAK;AAEvB,cAAI,UAAU,OAAO,SAAS,eAAe,YAAY;AACvD,kBAAM,WAAW,UAAU,OAAO;AAGlC,gBAAI,CAAC,QAAQ,uBAAuB,UAAU,MAAM,GAAG;AACrD;AAAA,YACF;AAGA,gBAAI,kBAAkB,IAAI,QAAQ,GAAG;AACnC,oBAAM,UAAU,UAAU,UAAU,CAAC;AACrC,kBAAI,SAAS;AACX,sBAAM,YAAY,sBAAsB,OAAO;AAC/C,oBAAI,WAAW;AACb,sCAAoB,SAAS,SAAS;AAAA,gBACxC;AAAA,cACF;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IAAA;AAAA,EAEJ,CAAC;AACH,CAAC;"} | ||
| {"version":3,"file":"route-param-names.rule.js","names":[],"sources":["../../../../src/rules/route-param-names/route-param-names.rule.ts"],"sourcesContent":["import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils'\n\nimport { getDocsUrl } from '../../utils/get-docs-url'\nimport { detectTanstackRouterImports } from '../../utils/detect-router-imports'\nimport { getInvalidParams } from './route-param-names.utils'\nimport { pathAsFirstArgFunctions, pathAsPropertyFunctions } from './constants'\nimport type { TSESTree } from '@typescript-eslint/utils'\nimport type { ExtraRuleDocs } from '../../types'\n\nconst createRule = ESLintUtils.RuleCreator<ExtraRuleDocs>(getDocsUrl)\n\nconst pathAsFirstArgSet = new Set<string>(pathAsFirstArgFunctions)\nconst pathAsPropertySet = new Set<string>(pathAsPropertyFunctions)\n\nexport const name = 'route-param-names'\n\nexport const rule = createRule({\n name,\n meta: {\n type: 'problem',\n docs: {\n description: 'Ensure route param names are valid JavaScript identifiers',\n recommended: 'error',\n },\n messages: {\n invalidParamName:\n 'Invalid param name \"{{paramName}}\" in route path. Param names must be valid JavaScript identifiers (match /[a-zA-Z_$][a-zA-Z0-9_$]*/).',\n },\n schema: [],\n },\n defaultOptions: [],\n\n create: detectTanstackRouterImports((context, _, helpers) => {\n function reportInvalidParams(node: TSESTree.Node, path: string) {\n const invalidParams = getInvalidParams(path)\n\n for (const param of invalidParams) {\n context.report({\n node,\n messageId: 'invalidParamName',\n data: { paramName: param.paramName },\n })\n }\n }\n\n function getStringLiteralValue(node: TSESTree.Node): string | null {\n if (\n node.type === AST_NODE_TYPES.Literal &&\n typeof node.value === 'string'\n ) {\n return node.value\n }\n if (\n node.type === AST_NODE_TYPES.TemplateLiteral &&\n node.quasis.length === 1\n ) {\n const cooked = node.quasis[0]?.value.cooked\n if (cooked != null) {\n return cooked\n }\n }\n return null\n }\n\n return {\n CallExpression(node) {\n // Handle direct function call: createRoute({ path: '...' })\n if (node.callee.type === AST_NODE_TYPES.Identifier) {\n const funcName = node.callee.name\n\n // Skip if not imported from TanStack Router\n if (!helpers.isTanstackRouterImport(node.callee)) {\n return\n }\n\n // Case: createRoute({ path: '/path/$param' }) or createRoute({ 'path': '/path/$param' })\n if (pathAsPropertySet.has(funcName)) {\n const arg = node.arguments[0]\n if (arg?.type === AST_NODE_TYPES.ObjectExpression) {\n for (const prop of arg.properties) {\n if (prop.type === AST_NODE_TYPES.Property) {\n const isPathKey =\n (prop.key.type === AST_NODE_TYPES.Identifier &&\n prop.key.name === 'path') ||\n (prop.key.type === AST_NODE_TYPES.Literal &&\n prop.key.value === 'path')\n if (isPathKey) {\n const pathValue = getStringLiteralValue(prop.value)\n if (pathValue) {\n reportInvalidParams(prop.value, pathValue)\n }\n }\n }\n }\n }\n return\n }\n }\n\n // Handle curried function call: createFileRoute('/path')({ ... })\n if (node.callee.type === AST_NODE_TYPES.CallExpression) {\n const innerCall = node.callee\n\n if (innerCall.callee.type === AST_NODE_TYPES.Identifier) {\n const funcName = innerCall.callee.name\n\n // Skip if not imported from TanStack Router\n if (!helpers.isTanstackRouterImport(innerCall.callee)) {\n return\n }\n\n // Case: createFileRoute('/path/$param')(...) or similar\n if (pathAsFirstArgSet.has(funcName)) {\n const pathArg = innerCall.arguments[0]\n if (pathArg) {\n const pathValue = getStringLiteralValue(pathArg)\n if (pathValue) {\n reportInvalidParams(pathArg, pathValue)\n }\n }\n }\n }\n }\n },\n }\n }),\n})\n"],"mappings":";;;;;;AASA,IAAM,aAAa,YAAY,YAA2B,WAAW;AAErE,IAAM,oBAAoB,IAAI,IAAY,wBAAwB;AAClE,IAAM,oBAAoB,IAAI,IAAY,wBAAwB;AAElE,IAAa,OAAO;AAEpB,IAAa,OAAO,WAAW;CAC7B;CACA,MAAM;EACJ,MAAM;EACN,MAAM;GACJ,aAAa;GACb,aAAa;GACd;EACD,UAAU,EACR,kBACE,4IACH;EACD,QAAQ,EAAE;EACX;CACD,gBAAgB,EAAE;CAElB,QAAQ,6BAA6B,SAAS,GAAG,YAAY;EAC3D,SAAS,oBAAoB,MAAqB,MAAc;GAC9D,MAAM,gBAAgB,iBAAiB,KAAK;AAE5C,QAAK,MAAM,SAAS,cAClB,SAAQ,OAAO;IACb;IACA,WAAW;IACX,MAAM,EAAE,WAAW,MAAM,WAAW;IACrC,CAAC;;EAIN,SAAS,sBAAsB,MAAoC;AACjE,OACE,KAAK,SAAS,eAAe,WAC7B,OAAO,KAAK,UAAU,SAEtB,QAAO,KAAK;AAEd,OACE,KAAK,SAAS,eAAe,mBAC7B,KAAK,OAAO,WAAW,GACvB;IACA,MAAM,SAAS,KAAK,OAAO,IAAI,MAAM;AACrC,QAAI,UAAU,KACZ,QAAO;;AAGX,UAAO;;AAGT,SAAO,EACL,eAAe,MAAM;AAEnB,OAAI,KAAK,OAAO,SAAS,eAAe,YAAY;IAClD,MAAM,WAAW,KAAK,OAAO;AAG7B,QAAI,CAAC,QAAQ,uBAAuB,KAAK,OAAO,CAC9C;AAIF,QAAI,kBAAkB,IAAI,SAAS,EAAE;KACnC,MAAM,MAAM,KAAK,UAAU;AAC3B,SAAI,KAAK,SAAS,eAAe;WAC1B,MAAM,QAAQ,IAAI,WACrB,KAAI,KAAK,SAAS,eAAe;WAE5B,KAAK,IAAI,SAAS,eAAe,cAChC,KAAK,IAAI,SAAS,UACnB,KAAK,IAAI,SAAS,eAAe,WAChC,KAAK,IAAI,UAAU,QACR;QACb,MAAM,YAAY,sBAAsB,KAAK,MAAM;AACnD,YAAI,UACF,qBAAoB,KAAK,OAAO,UAAU;;;;AAMpD;;;AAKJ,OAAI,KAAK,OAAO,SAAS,eAAe,gBAAgB;IACtD,MAAM,YAAY,KAAK;AAEvB,QAAI,UAAU,OAAO,SAAS,eAAe,YAAY;KACvD,MAAM,WAAW,UAAU,OAAO;AAGlC,SAAI,CAAC,QAAQ,uBAAuB,UAAU,OAAO,CACnD;AAIF,SAAI,kBAAkB,IAAI,SAAS,EAAE;MACnC,MAAM,UAAU,UAAU,UAAU;AACpC,UAAI,SAAS;OACX,MAAM,YAAY,sBAAsB,QAAQ;AAChD,WAAI,UACF,qBAAoB,SAAS,UAAU;;;;;KAOpD;GACD;CACH,CAAC"} |
| import { VALID_PARAM_NAME_REGEX } from "./constants.js"; | ||
| //#region src/rules/route-param-names/route-param-names.utils.ts | ||
| /** | ||
| * Extracts param names from a route path segment. | ||
| * | ||
| * Handles these patterns: | ||
| * - $paramName -> extract "paramName" | ||
| * - {$paramName} -> extract "paramName" | ||
| * - prefix{$paramName}suffix -> extract "paramName" | ||
| * - {-$paramName} -> extract "paramName" (optional) | ||
| * - prefix{-$paramName}suffix -> extract "paramName" (optional) | ||
| * - $ or {$} -> wildcard, skip validation | ||
| */ | ||
| function extractParamsFromSegment(segment) { | ||
| const params = []; | ||
| if (!segment || !segment.includes("$")) { | ||
| return params; | ||
| } | ||
| if (segment === "$" || segment === "{$}") { | ||
| return params; | ||
| } | ||
| if (segment.startsWith("$") && !segment.includes("{")) { | ||
| const paramName = segment.slice(1); | ||
| if (paramName) { | ||
| params.push({ | ||
| fullParam: segment, | ||
| paramName, | ||
| isOptional: false, | ||
| isValid: VALID_PARAM_NAME_REGEX.test(paramName) | ||
| }); | ||
| } | ||
| return params; | ||
| } | ||
| const bracePattern = /\{(-?\$)([^}]*)\}/g; | ||
| let match; | ||
| while ((match = bracePattern.exec(segment)) !== null) { | ||
| const prefix = match[1]; | ||
| const paramName = match[2]; | ||
| if (!paramName) { | ||
| continue; | ||
| } | ||
| const isOptional = prefix === "-$"; | ||
| params.push({ | ||
| fullParam: `${prefix}${paramName}`, | ||
| paramName, | ||
| isOptional, | ||
| isValid: VALID_PARAM_NAME_REGEX.test(paramName) | ||
| }); | ||
| } | ||
| return params; | ||
| const params = []; | ||
| if (!segment || !segment.includes("$")) return params; | ||
| if (segment === "$" || segment === "{$}") return params; | ||
| if (segment.startsWith("$") && !segment.includes("{")) { | ||
| const paramName = segment.slice(1); | ||
| if (paramName) params.push({ | ||
| fullParam: segment, | ||
| paramName, | ||
| isOptional: false, | ||
| isValid: VALID_PARAM_NAME_REGEX.test(paramName) | ||
| }); | ||
| return params; | ||
| } | ||
| const bracePattern = /\{(-?\$)([^}]*)\}/g; | ||
| let match; | ||
| while ((match = bracePattern.exec(segment)) !== null) { | ||
| const prefix = match[1]; | ||
| const paramName = match[2]; | ||
| if (!paramName) continue; | ||
| const isOptional = prefix === "-$"; | ||
| params.push({ | ||
| fullParam: `${prefix}${paramName}`, | ||
| paramName, | ||
| isOptional, | ||
| isValid: VALID_PARAM_NAME_REGEX.test(paramName) | ||
| }); | ||
| } | ||
| return params; | ||
| } | ||
| /** | ||
| * Extracts all params from a route path. | ||
| * | ||
| * @param path - The route path (e.g., "/users/$userId/posts/$postId") | ||
| * @returns Array of extracted params with validation info | ||
| */ | ||
| function extractParamsFromPath(path) { | ||
| if (!path || !path.includes("$")) { | ||
| return []; | ||
| } | ||
| const segments = path.split("/"); | ||
| const allParams = []; | ||
| for (const segment of segments) { | ||
| const params = extractParamsFromSegment(segment); | ||
| allParams.push(...params); | ||
| } | ||
| return allParams; | ||
| if (!path || !path.includes("$")) return []; | ||
| const segments = path.split("/"); | ||
| const allParams = []; | ||
| for (const segment of segments) { | ||
| const params = extractParamsFromSegment(segment); | ||
| allParams.push(...params); | ||
| } | ||
| return allParams; | ||
| } | ||
| /** | ||
| * Gets all invalid params from a route path. | ||
| * | ||
| * @param path - The route path | ||
| * @returns Array of invalid param info | ||
| */ | ||
| function getInvalidParams(path) { | ||
| const params = extractParamsFromPath(path); | ||
| return params.filter((p) => !p.isValid); | ||
| return extractParamsFromPath(path).filter((p) => !p.isValid); | ||
| } | ||
| export { | ||
| extractParamsFromPath, | ||
| extractParamsFromSegment, | ||
| getInvalidParams | ||
| }; | ||
| //# sourceMappingURL=route-param-names.utils.js.map | ||
| //#endregion | ||
| export { getInvalidParams }; | ||
| //# sourceMappingURL=route-param-names.utils.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"route-param-names.utils.js","sources":["../../../../src/rules/route-param-names/route-param-names.utils.ts"],"sourcesContent":["import { VALID_PARAM_NAME_REGEX } from './constants'\n\nexport interface ExtractedParam {\n /** The full param string including $ prefix (e.g., \"$userId\", \"-$optional\") */\n fullParam: string\n /** The param name without $ prefix (e.g., \"userId\", \"optional\") */\n paramName: string\n /** Whether this is an optional param (prefixed with -$) */\n isOptional: boolean\n /** Whether this param name is valid */\n isValid: boolean\n}\n\n/**\n * Extracts param names from a route path segment.\n *\n * Handles these patterns:\n * - $paramName -> extract \"paramName\"\n * - {$paramName} -> extract \"paramName\"\n * - prefix{$paramName}suffix -> extract \"paramName\"\n * - {-$paramName} -> extract \"paramName\" (optional)\n * - prefix{-$paramName}suffix -> extract \"paramName\" (optional)\n * - $ or {$} -> wildcard, skip validation\n */\nexport function extractParamsFromSegment(\n segment: string,\n): Array<ExtractedParam> {\n const params: Array<ExtractedParam> = []\n\n // Skip empty segments\n if (!segment || !segment.includes('$')) {\n return params\n }\n\n // Check for wildcard ($ alone or {$})\n if (segment === '$' || segment === '{$}') {\n return params // Wildcard, no param name to validate\n }\n\n // Pattern 1: Simple $paramName (entire segment starts with $)\n if (segment.startsWith('$') && !segment.includes('{')) {\n const paramName = segment.slice(1)\n if (paramName) {\n params.push({\n fullParam: segment,\n paramName,\n isOptional: false,\n isValid: VALID_PARAM_NAME_REGEX.test(paramName),\n })\n }\n return params\n }\n\n // Pattern 2: Braces pattern {$paramName} or {-$paramName} with optional prefix/suffix\n // Match patterns like: prefix{$param}suffix, {$param}, {-$param}\n const bracePattern = /\\{(-?\\$)([^}]*)\\}/g\n let match\n\n while ((match = bracePattern.exec(segment)) !== null) {\n const prefix = match[1] // \"$\" or \"-$\"\n const paramName = match[2] // The param name after $ or -$\n\n if (!paramName) {\n // This is a wildcard {$} or {-$}, skip\n continue\n }\n\n const isOptional = prefix === '-$'\n\n params.push({\n fullParam: `${prefix}${paramName}`,\n paramName,\n isOptional,\n isValid: VALID_PARAM_NAME_REGEX.test(paramName),\n })\n }\n\n return params\n}\n\n/**\n * Extracts all params from a route path.\n *\n * @param path - The route path (e.g., \"/users/$userId/posts/$postId\")\n * @returns Array of extracted params with validation info\n */\nexport function extractParamsFromPath(path: string): Array<ExtractedParam> {\n if (!path || !path.includes('$')) {\n return []\n }\n\n const segments = path.split('/')\n const allParams: Array<ExtractedParam> = []\n\n for (const segment of segments) {\n const params = extractParamsFromSegment(segment)\n allParams.push(...params)\n }\n\n return allParams\n}\n\n/**\n * Validates a single param name.\n *\n * @param paramName - The param name to validate (without $ prefix)\n * @returns Whether the param name is valid\n */\nexport function isValidParamName(paramName: string): boolean {\n return VALID_PARAM_NAME_REGEX.test(paramName)\n}\n\n/**\n * Gets all invalid params from a route path.\n *\n * @param path - The route path\n * @returns Array of invalid param info\n */\nexport function getInvalidParams(path: string): Array<ExtractedParam> {\n const params = extractParamsFromPath(path)\n return params.filter((p) => !p.isValid)\n}\n"],"names":[],"mappings":";AAwBO,SAAS,yBACd,SACuB;AACvB,QAAM,SAAgC,CAAA;AAGtC,MAAI,CAAC,WAAW,CAAC,QAAQ,SAAS,GAAG,GAAG;AACtC,WAAO;AAAA,EACT;AAGA,MAAI,YAAY,OAAO,YAAY,OAAO;AACxC,WAAO;AAAA,EACT;AAGA,MAAI,QAAQ,WAAW,GAAG,KAAK,CAAC,QAAQ,SAAS,GAAG,GAAG;AACrD,UAAM,YAAY,QAAQ,MAAM,CAAC;AACjC,QAAI,WAAW;AACb,aAAO,KAAK;AAAA,QACV,WAAW;AAAA,QACX;AAAA,QACA,YAAY;AAAA,QACZ,SAAS,uBAAuB,KAAK,SAAS;AAAA,MAAA,CAC/C;AAAA,IACH;AACA,WAAO;AAAA,EACT;AAIA,QAAM,eAAe;AACrB,MAAI;AAEJ,UAAQ,QAAQ,aAAa,KAAK,OAAO,OAAO,MAAM;AACpD,UAAM,SAAS,MAAM,CAAC;AACtB,UAAM,YAAY,MAAM,CAAC;AAEzB,QAAI,CAAC,WAAW;AAEd;AAAA,IACF;AAEA,UAAM,aAAa,WAAW;AAE9B,WAAO,KAAK;AAAA,MACV,WAAW,GAAG,MAAM,GAAG,SAAS;AAAA,MAChC;AAAA,MACA;AAAA,MACA,SAAS,uBAAuB,KAAK,SAAS;AAAA,IAAA,CAC/C;AAAA,EACH;AAEA,SAAO;AACT;AAQO,SAAS,sBAAsB,MAAqC;AACzE,MAAI,CAAC,QAAQ,CAAC,KAAK,SAAS,GAAG,GAAG;AAChC,WAAO,CAAA;AAAA,EACT;AAEA,QAAM,WAAW,KAAK,MAAM,GAAG;AAC/B,QAAM,YAAmC,CAAA;AAEzC,aAAW,WAAW,UAAU;AAC9B,UAAM,SAAS,yBAAyB,OAAO;AAC/C,cAAU,KAAK,GAAG,MAAM;AAAA,EAC1B;AAEA,SAAO;AACT;AAkBO,SAAS,iBAAiB,MAAqC;AACpE,QAAM,SAAS,sBAAsB,IAAI;AACzC,SAAO,OAAO,OAAO,CAAC,MAAM,CAAC,EAAE,OAAO;AACxC;"} | ||
| {"version":3,"file":"route-param-names.utils.js","names":[],"sources":["../../../../src/rules/route-param-names/route-param-names.utils.ts"],"sourcesContent":["import { VALID_PARAM_NAME_REGEX } from './constants'\n\nexport interface ExtractedParam {\n /** The full param string including $ prefix (e.g., \"$userId\", \"-$optional\") */\n fullParam: string\n /** The param name without $ prefix (e.g., \"userId\", \"optional\") */\n paramName: string\n /** Whether this is an optional param (prefixed with -$) */\n isOptional: boolean\n /** Whether this param name is valid */\n isValid: boolean\n}\n\n/**\n * Extracts param names from a route path segment.\n *\n * Handles these patterns:\n * - $paramName -> extract \"paramName\"\n * - {$paramName} -> extract \"paramName\"\n * - prefix{$paramName}suffix -> extract \"paramName\"\n * - {-$paramName} -> extract \"paramName\" (optional)\n * - prefix{-$paramName}suffix -> extract \"paramName\" (optional)\n * - $ or {$} -> wildcard, skip validation\n */\nexport function extractParamsFromSegment(\n segment: string,\n): Array<ExtractedParam> {\n const params: Array<ExtractedParam> = []\n\n // Skip empty segments\n if (!segment || !segment.includes('$')) {\n return params\n }\n\n // Check for wildcard ($ alone or {$})\n if (segment === '$' || segment === '{$}') {\n return params // Wildcard, no param name to validate\n }\n\n // Pattern 1: Simple $paramName (entire segment starts with $)\n if (segment.startsWith('$') && !segment.includes('{')) {\n const paramName = segment.slice(1)\n if (paramName) {\n params.push({\n fullParam: segment,\n paramName,\n isOptional: false,\n isValid: VALID_PARAM_NAME_REGEX.test(paramName),\n })\n }\n return params\n }\n\n // Pattern 2: Braces pattern {$paramName} or {-$paramName} with optional prefix/suffix\n // Match patterns like: prefix{$param}suffix, {$param}, {-$param}\n const bracePattern = /\\{(-?\\$)([^}]*)\\}/g\n let match\n\n while ((match = bracePattern.exec(segment)) !== null) {\n const prefix = match[1] // \"$\" or \"-$\"\n const paramName = match[2] // The param name after $ or -$\n\n if (!paramName) {\n // This is a wildcard {$} or {-$}, skip\n continue\n }\n\n const isOptional = prefix === '-$'\n\n params.push({\n fullParam: `${prefix}${paramName}`,\n paramName,\n isOptional,\n isValid: VALID_PARAM_NAME_REGEX.test(paramName),\n })\n }\n\n return params\n}\n\n/**\n * Extracts all params from a route path.\n *\n * @param path - The route path (e.g., \"/users/$userId/posts/$postId\")\n * @returns Array of extracted params with validation info\n */\nexport function extractParamsFromPath(path: string): Array<ExtractedParam> {\n if (!path || !path.includes('$')) {\n return []\n }\n\n const segments = path.split('/')\n const allParams: Array<ExtractedParam> = []\n\n for (const segment of segments) {\n const params = extractParamsFromSegment(segment)\n allParams.push(...params)\n }\n\n return allParams\n}\n\n/**\n * Validates a single param name.\n *\n * @param paramName - The param name to validate (without $ prefix)\n * @returns Whether the param name is valid\n */\nexport function isValidParamName(paramName: string): boolean {\n return VALID_PARAM_NAME_REGEX.test(paramName)\n}\n\n/**\n * Gets all invalid params from a route path.\n *\n * @param path - The route path\n * @returns Array of invalid param info\n */\nexport function getInvalidParams(path: string): Array<ExtractedParam> {\n const params = extractParamsFromPath(path)\n return params.filter((p) => !p.isValid)\n}\n"],"mappings":";;;;;;;;;;;;;AAwBA,SAAgB,yBACd,SACuB;CACvB,MAAM,SAAgC,EAAE;AAGxC,KAAI,CAAC,WAAW,CAAC,QAAQ,SAAS,IAAI,CACpC,QAAO;AAIT,KAAI,YAAY,OAAO,YAAY,MACjC,QAAO;AAIT,KAAI,QAAQ,WAAW,IAAI,IAAI,CAAC,QAAQ,SAAS,IAAI,EAAE;EACrD,MAAM,YAAY,QAAQ,MAAM,EAAE;AAClC,MAAI,UACF,QAAO,KAAK;GACV,WAAW;GACX;GACA,YAAY;GACZ,SAAS,uBAAuB,KAAK,UAAU;GAChD,CAAC;AAEJ,SAAO;;CAKT,MAAM,eAAe;CACrB,IAAI;AAEJ,SAAQ,QAAQ,aAAa,KAAK,QAAQ,MAAM,MAAM;EACpD,MAAM,SAAS,MAAM;EACrB,MAAM,YAAY,MAAM;AAExB,MAAI,CAAC,UAEH;EAGF,MAAM,aAAa,WAAW;AAE9B,SAAO,KAAK;GACV,WAAW,GAAG,SAAS;GACvB;GACA;GACA,SAAS,uBAAuB,KAAK,UAAU;GAChD,CAAC;;AAGJ,QAAO;;;;;;;;AAST,SAAgB,sBAAsB,MAAqC;AACzE,KAAI,CAAC,QAAQ,CAAC,KAAK,SAAS,IAAI,CAC9B,QAAO,EAAE;CAGX,MAAM,WAAW,KAAK,MAAM,IAAI;CAChC,MAAM,YAAmC,EAAE;AAE3C,MAAK,MAAM,WAAW,UAAU;EAC9B,MAAM,SAAS,yBAAyB,QAAQ;AAChD,YAAU,KAAK,GAAG,OAAO;;AAG3B,QAAO;;;;;;;;AAmBT,SAAgB,iBAAiB,MAAqC;AAEpE,QADe,sBAAsB,KAAK,CAC5B,QAAQ,MAAM,CAAC,EAAE,QAAQ"} |
| import { TSESTree } from "@typescript-eslint/utils"; | ||
| //#region src/utils/detect-router-imports.ts | ||
| function detectTanstackRouterImports(create) { | ||
| return (context, optionsWithDefault) => { | ||
| const tanstackRouterImportSpecifiers = []; | ||
| const helpers = { | ||
| isSpecificTanstackRouterImport(node, source) { | ||
| return !!tanstackRouterImportSpecifiers.find((specifier) => { | ||
| if (specifier.type === TSESTree.AST_NODE_TYPES.ImportSpecifier && specifier.parent.type === TSESTree.AST_NODE_TYPES.ImportDeclaration && specifier.parent.source.value === source) { | ||
| return node.name === specifier.local.name; | ||
| } | ||
| return false; | ||
| }); | ||
| }, | ||
| isTanstackRouterImport(node) { | ||
| return !!tanstackRouterImportSpecifiers.find((specifier) => { | ||
| if (specifier.type === TSESTree.AST_NODE_TYPES.ImportSpecifier) { | ||
| return node.name === specifier.local.name; | ||
| } | ||
| return false; | ||
| }); | ||
| } | ||
| }; | ||
| const detectionInstructions = { | ||
| ImportDeclaration(node) { | ||
| if (node.specifiers.length > 0 && // `importKind` is parser-dependent and can be undefined (eg. Espree) | ||
| node.importKind !== "type" && node.source.value.startsWith("@tanstack/") && node.source.value.endsWith("-router")) { | ||
| tanstackRouterImportSpecifiers.push(...node.specifiers); | ||
| } | ||
| } | ||
| }; | ||
| const ruleInstructions = create(context, optionsWithDefault, helpers); | ||
| const enhancedRuleInstructions = {}; | ||
| const allKeys = new Set( | ||
| Object.keys(detectionInstructions).concat(Object.keys(ruleInstructions)) | ||
| ); | ||
| allKeys.forEach((instruction) => { | ||
| enhancedRuleInstructions[instruction] = (node) => { | ||
| if (instruction in detectionInstructions) { | ||
| detectionInstructions[instruction]?.(node); | ||
| } | ||
| const ruleFunction = ruleInstructions[instruction]; | ||
| if (ruleFunction !== void 0) { | ||
| return ruleFunction(node); | ||
| } | ||
| return void 0; | ||
| }; | ||
| }); | ||
| return enhancedRuleInstructions; | ||
| }; | ||
| return (context, optionsWithDefault) => { | ||
| const tanstackRouterImportSpecifiers = []; | ||
| const helpers = { | ||
| isSpecificTanstackRouterImport(node, source) { | ||
| return !!tanstackRouterImportSpecifiers.find((specifier) => { | ||
| if (specifier.type === TSESTree.AST_NODE_TYPES.ImportSpecifier && specifier.parent.type === TSESTree.AST_NODE_TYPES.ImportDeclaration && specifier.parent.source.value === source) return node.name === specifier.local.name; | ||
| return false; | ||
| }); | ||
| }, | ||
| isTanstackRouterImport(node) { | ||
| return !!tanstackRouterImportSpecifiers.find((specifier) => { | ||
| if (specifier.type === TSESTree.AST_NODE_TYPES.ImportSpecifier) return node.name === specifier.local.name; | ||
| return false; | ||
| }); | ||
| } | ||
| }; | ||
| const detectionInstructions = { ImportDeclaration(node) { | ||
| if (node.specifiers.length > 0 && node.importKind !== "type" && node.source.value.startsWith("@tanstack/") && node.source.value.endsWith("-router")) tanstackRouterImportSpecifiers.push(...node.specifiers); | ||
| } }; | ||
| const ruleInstructions = create(context, optionsWithDefault, helpers); | ||
| const enhancedRuleInstructions = {}; | ||
| new Set(Object.keys(detectionInstructions).concat(Object.keys(ruleInstructions))).forEach((instruction) => { | ||
| enhancedRuleInstructions[instruction] = (node) => { | ||
| if (instruction in detectionInstructions) detectionInstructions[instruction]?.(node); | ||
| const ruleFunction = ruleInstructions[instruction]; | ||
| if (ruleFunction !== void 0) return ruleFunction(node); | ||
| }; | ||
| }); | ||
| return enhancedRuleInstructions; | ||
| }; | ||
| } | ||
| export { | ||
| detectTanstackRouterImports | ||
| }; | ||
| //# sourceMappingURL=detect-router-imports.js.map | ||
| //#endregion | ||
| export { detectTanstackRouterImports }; | ||
| //# sourceMappingURL=detect-router-imports.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"detect-router-imports.js","sources":["../../../src/utils/detect-router-imports.ts"],"sourcesContent":["import { TSESTree } from '@typescript-eslint/utils'\nimport type { ESLintUtils, TSESLint } from '@typescript-eslint/utils'\n\ntype Create = Parameters<\n ReturnType<typeof ESLintUtils.RuleCreator>\n>[0]['create']\n\ntype Context = Parameters<Create>[0]\ntype Options = Parameters<Create>[1]\ntype Helpers = {\n isSpecificTanstackRouterImport: (\n node: TSESTree.Identifier,\n source: string,\n ) => boolean\n isTanstackRouterImport: (node: TSESTree.Identifier) => boolean\n}\n\ntype EnhancedCreate = (\n context: Context,\n options: Options,\n helpers: Helpers,\n) => ReturnType<Create>\n\nexport function detectTanstackRouterImports(create: EnhancedCreate): Create {\n return (context, optionsWithDefault) => {\n const tanstackRouterImportSpecifiers: Array<TSESTree.ImportClause> = []\n\n const helpers: Helpers = {\n isSpecificTanstackRouterImport(node, source) {\n return !!tanstackRouterImportSpecifiers.find((specifier) => {\n if (\n specifier.type === TSESTree.AST_NODE_TYPES.ImportSpecifier &&\n specifier.parent.type ===\n TSESTree.AST_NODE_TYPES.ImportDeclaration &&\n specifier.parent.source.value === source\n ) {\n return node.name === specifier.local.name\n }\n\n return false\n })\n },\n isTanstackRouterImport(node) {\n return !!tanstackRouterImportSpecifiers.find((specifier) => {\n if (specifier.type === TSESTree.AST_NODE_TYPES.ImportSpecifier) {\n return node.name === specifier.local.name\n }\n\n return false\n })\n },\n }\n\n const detectionInstructions: TSESLint.RuleListener = {\n ImportDeclaration(node) {\n if (\n node.specifiers.length > 0 &&\n // `importKind` is parser-dependent and can be undefined (eg. Espree)\n node.importKind !== 'type' &&\n node.source.value.startsWith('@tanstack/') &&\n node.source.value.endsWith('-router')\n ) {\n tanstackRouterImportSpecifiers.push(...node.specifiers)\n }\n },\n }\n\n // Call original rule definition\n const ruleInstructions = create(context, optionsWithDefault, helpers)\n const enhancedRuleInstructions: TSESLint.RuleListener = {}\n\n const allKeys = new Set(\n Object.keys(detectionInstructions).concat(Object.keys(ruleInstructions)),\n )\n\n // Iterate over ALL instructions keys so we can override original rule instructions\n // to prevent their execution if conditions to report errors are not met.\n allKeys.forEach((instruction) => {\n enhancedRuleInstructions[instruction] = (node) => {\n if (instruction in detectionInstructions) {\n detectionInstructions[instruction]?.(node)\n }\n\n const ruleFunction = ruleInstructions[instruction]\n if (ruleFunction !== undefined) {\n return ruleFunction(node)\n }\n\n return undefined\n }\n })\n\n return enhancedRuleInstructions\n }\n}\n"],"names":[],"mappings":";AAuBO,SAAS,4BAA4B,QAAgC;AAC1E,SAAO,CAAC,SAAS,uBAAuB;AACtC,UAAM,iCAA+D,CAAA;AAErE,UAAM,UAAmB;AAAA,MACvB,+BAA+B,MAAM,QAAQ;AAC3C,eAAO,CAAC,CAAC,+BAA+B,KAAK,CAAC,cAAc;AAC1D,cACE,UAAU,SAAS,SAAS,eAAe,mBAC3C,UAAU,OAAO,SACf,SAAS,eAAe,qBAC1B,UAAU,OAAO,OAAO,UAAU,QAClC;AACA,mBAAO,KAAK,SAAS,UAAU,MAAM;AAAA,UACvC;AAEA,iBAAO;AAAA,QACT,CAAC;AAAA,MACH;AAAA,MACA,uBAAuB,MAAM;AAC3B,eAAO,CAAC,CAAC,+BAA+B,KAAK,CAAC,cAAc;AAC1D,cAAI,UAAU,SAAS,SAAS,eAAe,iBAAiB;AAC9D,mBAAO,KAAK,SAAS,UAAU,MAAM;AAAA,UACvC;AAEA,iBAAO;AAAA,QACT,CAAC;AAAA,MACH;AAAA,IAAA;AAGF,UAAM,wBAA+C;AAAA,MACnD,kBAAkB,MAAM;AACtB,YACE,KAAK,WAAW,SAAS;AAAA,QAEzB,KAAK,eAAe,UACpB,KAAK,OAAO,MAAM,WAAW,YAAY,KACzC,KAAK,OAAO,MAAM,SAAS,SAAS,GACpC;AACA,yCAA+B,KAAK,GAAG,KAAK,UAAU;AAAA,QACxD;AAAA,MACF;AAAA,IAAA;AAIF,UAAM,mBAAmB,OAAO,SAAS,oBAAoB,OAAO;AACpE,UAAM,2BAAkD,CAAA;AAExD,UAAM,UAAU,IAAI;AAAA,MAClB,OAAO,KAAK,qBAAqB,EAAE,OAAO,OAAO,KAAK,gBAAgB,CAAC;AAAA,IAAA;AAKzE,YAAQ,QAAQ,CAAC,gBAAgB;AAC/B,+BAAyB,WAAW,IAAI,CAAC,SAAS;AAChD,YAAI,eAAe,uBAAuB;AACxC,gCAAsB,WAAW,IAAI,IAAI;AAAA,QAC3C;AAEA,cAAM,eAAe,iBAAiB,WAAW;AACjD,YAAI,iBAAiB,QAAW;AAC9B,iBAAO,aAAa,IAAI;AAAA,QAC1B;AAEA,eAAO;AAAA,MACT;AAAA,IACF,CAAC;AAED,WAAO;AAAA,EACT;AACF;"} | ||
| {"version":3,"file":"detect-router-imports.js","names":[],"sources":["../../../src/utils/detect-router-imports.ts"],"sourcesContent":["import { TSESTree } from '@typescript-eslint/utils'\nimport type { ESLintUtils, TSESLint } from '@typescript-eslint/utils'\n\ntype Create = Parameters<\n ReturnType<typeof ESLintUtils.RuleCreator>\n>[0]['create']\n\ntype Context = Parameters<Create>[0]\ntype Options = Parameters<Create>[1]\ntype Helpers = {\n isSpecificTanstackRouterImport: (\n node: TSESTree.Identifier,\n source: string,\n ) => boolean\n isTanstackRouterImport: (node: TSESTree.Identifier) => boolean\n}\n\ntype EnhancedCreate = (\n context: Context,\n options: Options,\n helpers: Helpers,\n) => ReturnType<Create>\n\nexport function detectTanstackRouterImports(create: EnhancedCreate): Create {\n return (context, optionsWithDefault) => {\n const tanstackRouterImportSpecifiers: Array<TSESTree.ImportClause> = []\n\n const helpers: Helpers = {\n isSpecificTanstackRouterImport(node, source) {\n return !!tanstackRouterImportSpecifiers.find((specifier) => {\n if (\n specifier.type === TSESTree.AST_NODE_TYPES.ImportSpecifier &&\n specifier.parent.type ===\n TSESTree.AST_NODE_TYPES.ImportDeclaration &&\n specifier.parent.source.value === source\n ) {\n return node.name === specifier.local.name\n }\n\n return false\n })\n },\n isTanstackRouterImport(node) {\n return !!tanstackRouterImportSpecifiers.find((specifier) => {\n if (specifier.type === TSESTree.AST_NODE_TYPES.ImportSpecifier) {\n return node.name === specifier.local.name\n }\n\n return false\n })\n },\n }\n\n const detectionInstructions: TSESLint.RuleListener = {\n ImportDeclaration(node) {\n if (\n node.specifiers.length > 0 &&\n // `importKind` is parser-dependent and can be undefined (eg. Espree)\n node.importKind !== 'type' &&\n node.source.value.startsWith('@tanstack/') &&\n node.source.value.endsWith('-router')\n ) {\n tanstackRouterImportSpecifiers.push(...node.specifiers)\n }\n },\n }\n\n // Call original rule definition\n const ruleInstructions = create(context, optionsWithDefault, helpers)\n const enhancedRuleInstructions: TSESLint.RuleListener = {}\n\n const allKeys = new Set(\n Object.keys(detectionInstructions).concat(Object.keys(ruleInstructions)),\n )\n\n // Iterate over ALL instructions keys so we can override original rule instructions\n // to prevent their execution if conditions to report errors are not met.\n allKeys.forEach((instruction) => {\n enhancedRuleInstructions[instruction] = (node) => {\n if (instruction in detectionInstructions) {\n detectionInstructions[instruction]?.(node)\n }\n\n const ruleFunction = ruleInstructions[instruction]\n if (ruleFunction !== undefined) {\n return ruleFunction(node)\n }\n\n return undefined\n }\n })\n\n return enhancedRuleInstructions\n }\n}\n"],"mappings":";;AAuBA,SAAgB,4BAA4B,QAAgC;AAC1E,SAAQ,SAAS,uBAAuB;EACtC,MAAM,iCAA+D,EAAE;EAEvE,MAAM,UAAmB;GACvB,+BAA+B,MAAM,QAAQ;AAC3C,WAAO,CAAC,CAAC,+BAA+B,MAAM,cAAc;AAC1D,SACE,UAAU,SAAS,SAAS,eAAe,mBAC3C,UAAU,OAAO,SACf,SAAS,eAAe,qBAC1B,UAAU,OAAO,OAAO,UAAU,OAElC,QAAO,KAAK,SAAS,UAAU,MAAM;AAGvC,YAAO;MACP;;GAEJ,uBAAuB,MAAM;AAC3B,WAAO,CAAC,CAAC,+BAA+B,MAAM,cAAc;AAC1D,SAAI,UAAU,SAAS,SAAS,eAAe,gBAC7C,QAAO,KAAK,SAAS,UAAU,MAAM;AAGvC,YAAO;MACP;;GAEL;EAED,MAAM,wBAA+C,EACnD,kBAAkB,MAAM;AACtB,OACE,KAAK,WAAW,SAAS,KAEzB,KAAK,eAAe,UACpB,KAAK,OAAO,MAAM,WAAW,aAAa,IAC1C,KAAK,OAAO,MAAM,SAAS,UAAU,CAErC,gCAA+B,KAAK,GAAG,KAAK,WAAW;KAG5D;EAGD,MAAM,mBAAmB,OAAO,SAAS,oBAAoB,QAAQ;EACrE,MAAM,2BAAkD,EAAE;AAE1C,MAAI,IAClB,OAAO,KAAK,sBAAsB,CAAC,OAAO,OAAO,KAAK,iBAAiB,CAAC,CACzE,CAIO,SAAS,gBAAgB;AAC/B,4BAAyB,gBAAgB,SAAS;AAChD,QAAI,eAAe,sBACjB,uBAAsB,eAAe,KAAK;IAG5C,MAAM,eAAe,iBAAiB;AACtC,QAAI,iBAAiB,KAAA,EACnB,QAAO,aAAa,KAAK;;IAK7B;AAEF,SAAO"} |
@@ -1,5 +0,6 @@ | ||
| const getDocsUrl = (ruleName) => `https://tanstack.com/router/latest/docs/eslint/${ruleName}`; | ||
| export { | ||
| getDocsUrl | ||
| }; | ||
| //# sourceMappingURL=get-docs-url.js.map | ||
| //#region src/utils/get-docs-url.ts | ||
| var getDocsUrl = (ruleName) => `https://tanstack.com/router/latest/docs/eslint/${ruleName}`; | ||
| //#endregion | ||
| export { getDocsUrl }; | ||
| //# sourceMappingURL=get-docs-url.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"get-docs-url.js","sources":["../../../src/utils/get-docs-url.ts"],"sourcesContent":["export const getDocsUrl = (ruleName: string): string =>\n `https://tanstack.com/router/latest/docs/eslint/${ruleName}`\n"],"names":[],"mappings":"AAAO,MAAM,aAAa,CAAC,aACzB,kDAAkD,QAAQ;"} | ||
| {"version":3,"file":"get-docs-url.js","names":[],"sources":["../../../src/utils/get-docs-url.ts"],"sourcesContent":["export const getDocsUrl = (ruleName: string): string =>\n `https://tanstack.com/router/latest/docs/eslint/${ruleName}`\n"],"mappings":";AAAA,IAAa,cAAc,aACzB,kDAAkD"} |
+1
-1
| { | ||
| "name": "@tanstack/eslint-plugin-router", | ||
| "version": "1.161.5", | ||
| "version": "1.161.6", | ||
| "description": "ESLint plugin for TanStack Router", | ||
@@ -5,0 +5,0 @@ "author": "Manuel Schiller", |
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
153507
-3.4%2418
-6.96%