@tanstack/router-generator 1.121.0-alpha.27 → 1.121.0-alpha.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/dist/cjs/config.cjs +1 -3
  2. package/dist/cjs/config.cjs.map +1 -1
  3. package/dist/cjs/config.d.cts +3 -3
  4. package/dist/cjs/filesystem/physical/getRouteNodes.cjs +18 -4
  5. package/dist/cjs/filesystem/physical/getRouteNodes.cjs.map +1 -1
  6. package/dist/cjs/filesystem/physical/getRouteNodes.d.cts +1 -0
  7. package/dist/cjs/filesystem/virtual/config.cjs.map +1 -1
  8. package/dist/cjs/filesystem/virtual/getRouteNodes.cjs +18 -12
  9. package/dist/cjs/filesystem/virtual/getRouteNodes.cjs.map +1 -1
  10. package/dist/cjs/filesystem/virtual/getRouteNodes.d.cts +4 -1
  11. package/dist/cjs/filesystem/virtual/loadConfigFile.cjs.map +1 -1
  12. package/dist/cjs/generator.cjs +144 -97
  13. package/dist/cjs/generator.cjs.map +1 -1
  14. package/dist/cjs/generator.d.cts +11 -9
  15. package/dist/cjs/index.d.cts +1 -1
  16. package/dist/cjs/logger.cjs.map +1 -1
  17. package/dist/cjs/plugin/default-generator-plugin.cjs +16 -10
  18. package/dist/cjs/plugin/default-generator-plugin.cjs.map +1 -1
  19. package/dist/cjs/template.cjs.map +1 -1
  20. package/dist/cjs/transform/default-transform-plugin.cjs +6 -4
  21. package/dist/cjs/transform/default-transform-plugin.cjs.map +1 -1
  22. package/dist/cjs/transform/transform.cjs +41 -20
  23. package/dist/cjs/transform/transform.cjs.map +1 -1
  24. package/dist/cjs/transform/utils.cjs.map +1 -1
  25. package/dist/cjs/types.d.cts +5 -0
  26. package/dist/cjs/utils.cjs +43 -24
  27. package/dist/cjs/utils.cjs.map +1 -1
  28. package/dist/cjs/utils.d.cts +6 -0
  29. package/dist/esm/config.d.ts +3 -3
  30. package/dist/esm/config.js +2 -4
  31. package/dist/esm/config.js.map +1 -1
  32. package/dist/esm/filesystem/physical/getRouteNodes.d.ts +1 -0
  33. package/dist/esm/filesystem/physical/getRouteNodes.js +19 -5
  34. package/dist/esm/filesystem/physical/getRouteNodes.js.map +1 -1
  35. package/dist/esm/filesystem/virtual/config.js.map +1 -1
  36. package/dist/esm/filesystem/virtual/getRouteNodes.d.ts +4 -1
  37. package/dist/esm/filesystem/virtual/getRouteNodes.js +19 -13
  38. package/dist/esm/filesystem/virtual/getRouteNodes.js.map +1 -1
  39. package/dist/esm/filesystem/virtual/loadConfigFile.js.map +1 -1
  40. package/dist/esm/generator.d.ts +11 -9
  41. package/dist/esm/generator.js +147 -100
  42. package/dist/esm/generator.js.map +1 -1
  43. package/dist/esm/index.d.ts +1 -1
  44. package/dist/esm/logger.js.map +1 -1
  45. package/dist/esm/plugin/default-generator-plugin.js +16 -10
  46. package/dist/esm/plugin/default-generator-plugin.js.map +1 -1
  47. package/dist/esm/template.js.map +1 -1
  48. package/dist/esm/transform/default-transform-plugin.js +6 -4
  49. package/dist/esm/transform/default-transform-plugin.js.map +1 -1
  50. package/dist/esm/transform/transform.js +41 -20
  51. package/dist/esm/transform/transform.js.map +1 -1
  52. package/dist/esm/transform/utils.js.map +1 -1
  53. package/dist/esm/types.d.ts +5 -0
  54. package/dist/esm/utils.d.ts +6 -0
  55. package/dist/esm/utils.js +43 -24
  56. package/dist/esm/utils.js.map +1 -1
  57. package/package.json +5 -5
  58. package/src/config.ts +1 -2
  59. package/src/filesystem/physical/getRouteNodes.ts +31 -11
  60. package/src/filesystem/virtual/getRouteNodes.ts +32 -23
  61. package/src/generator.ts +193 -71
  62. package/src/index.ts +2 -0
  63. package/src/plugin/default-generator-plugin.ts +16 -3
  64. package/src/transform/default-transform-plugin.ts +5 -2
  65. package/src/transform/transform.ts +59 -25
  66. package/src/types.ts +7 -0
  67. package/src/utils.ts +79 -31
@@ -3,9 +3,10 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
3
3
  const recast = require("recast");
4
4
  const utils = require("./utils.cjs");
5
5
  const b = recast.types.builders;
6
+ const EXPORT_NAME = "Route";
6
7
  const defaultTransformPlugin = {
7
8
  name: "default-transform",
8
- exportName: "Route",
9
+ exportName: EXPORT_NAME,
9
10
  imports: (ctx) => {
10
11
  const imports = {};
11
12
  const targetModule = `@tanstack/${ctx.target}-router`;
@@ -51,9 +52,8 @@ const defaultTransformPlugin = {
51
52
  return imports;
52
53
  },
53
54
  onExportFound: ({ decl, ctx }) => {
54
- var _a;
55
55
  let appliedChanges = false;
56
- if (((_a = decl.init) == null ? void 0 : _a.type) === "CallExpression") {
56
+ if (decl.init?.type === "CallExpression") {
57
57
  const callExpression = decl.init;
58
58
  let identifier;
59
59
  if (callExpression.callee.type === "Identifier") {
@@ -78,7 +78,9 @@ const defaultTransformPlugin = {
78
78
  }
79
79
  }
80
80
  if (identifier === void 0) {
81
- throw new Error(`expected identifier to be present`);
81
+ throw new Error(
82
+ `expected identifier to be present in ${ctx.routeId} for export ${EXPORT_NAME}`
83
+ );
82
84
  }
83
85
  if (identifier.name === "createFileRoute" && ctx.lazy) {
84
86
  identifier.name = "createLazyFileRoute";
@@ -1 +1 @@
1
- {"version":3,"file":"default-transform-plugin.cjs","sources":["../../../src/transform/default-transform-plugin.ts"],"sourcesContent":["import { types } from 'recast'\nimport { ensureStringArgument } from './utils'\nimport type { TransformImportsConfig, TransformPlugin } from './types'\n\nconst b = types.builders\n\nexport const defaultTransformPlugin: TransformPlugin = {\n name: 'default-transform',\n exportName: 'Route',\n imports: (ctx) => {\n const imports: TransformImportsConfig = {}\n const targetModule = `@tanstack/${ctx.target}-router`\n if (ctx.verboseFileRoutes === false) {\n imports.banned = [\n {\n source: targetModule,\n specifiers: [\n { imported: 'createLazyFileRoute' },\n { imported: 'createFileRoute' },\n ],\n },\n ]\n } else {\n if (ctx.lazy) {\n imports.required = [\n {\n source: targetModule,\n specifiers: [{ imported: 'createLazyFileRoute' }],\n },\n ]\n imports.banned = [\n {\n source: targetModule,\n specifiers: [{ imported: 'createFileRoute' }],\n },\n ]\n } else {\n imports.required = [\n {\n source: targetModule,\n specifiers: [{ imported: 'createFileRoute' }],\n },\n ]\n imports.banned = [\n {\n source: targetModule,\n specifiers: [{ imported: 'createLazyFileRoute' }],\n },\n ]\n }\n }\n return imports\n },\n onExportFound: ({ decl, ctx }) => {\n let appliedChanges = false\n if (decl.init?.type === 'CallExpression') {\n const callExpression = decl.init\n let identifier: types.namedTypes.Identifier | undefined\n // `const Route = createFileRoute({ ... })`\n if (callExpression.callee.type === 'Identifier') {\n identifier = callExpression.callee\n if (ctx.verboseFileRoutes) {\n // we need to add the string literal via another CallExpression\n callExpression.callee = b.callExpression(identifier, [\n b.stringLiteral(ctx.routeId),\n ])\n appliedChanges = true\n }\n }\n // `const Route = createFileRoute('/path')({ ... })`\n else if (\n callExpression.callee.type === 'CallExpression' &&\n callExpression.callee.callee.type === 'Identifier'\n ) {\n identifier = callExpression.callee.callee\n if (!ctx.verboseFileRoutes) {\n // we need to remove the route id\n callExpression.callee = identifier\n appliedChanges = true\n } else {\n // check if the route id is correct\n appliedChanges = ensureStringArgument(\n callExpression.callee,\n ctx.routeId,\n ctx.preferredQuote,\n )\n }\n }\n if (identifier === undefined) {\n throw new Error(`expected identifier to be present`)\n }\n if (identifier.name === 'createFileRoute' && ctx.lazy) {\n identifier.name = 'createLazyFileRoute'\n appliedChanges = true\n } else if (identifier.name === 'createLazyFileRoute' && !ctx.lazy) {\n identifier.name = 'createFileRoute'\n appliedChanges = true\n }\n }\n\n return appliedChanges\n },\n}\n"],"names":["types","ensureStringArgument"],"mappings":";;;;AAIA,MAAM,IAAIA,OAAM,MAAA;AAET,MAAM,yBAA0C;AAAA,EACrD,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,SAAS,CAAC,QAAQ;AAChB,UAAM,UAAkC,CAAC;AACnC,UAAA,eAAe,aAAa,IAAI,MAAM;AACxC,QAAA,IAAI,sBAAsB,OAAO;AACnC,cAAQ,SAAS;AAAA,QACf;AAAA,UACE,QAAQ;AAAA,UACR,YAAY;AAAA,YACV,EAAE,UAAU,sBAAsB;AAAA,YAClC,EAAE,UAAU,kBAAkB;AAAA,UAAA;AAAA,QAChC;AAAA,MAEJ;AAAA,IAAA,OACK;AACL,UAAI,IAAI,MAAM;AACZ,gBAAQ,WAAW;AAAA,UACjB;AAAA,YACE,QAAQ;AAAA,YACR,YAAY,CAAC,EAAE,UAAU,sBAAuB,CAAA;AAAA,UAAA;AAAA,QAEpD;AACA,gBAAQ,SAAS;AAAA,UACf;AAAA,YACE,QAAQ;AAAA,YACR,YAAY,CAAC,EAAE,UAAU,kBAAmB,CAAA;AAAA,UAAA;AAAA,QAEhD;AAAA,MAAA,OACK;AACL,gBAAQ,WAAW;AAAA,UACjB;AAAA,YACE,QAAQ;AAAA,YACR,YAAY,CAAC,EAAE,UAAU,kBAAmB,CAAA;AAAA,UAAA;AAAA,QAEhD;AACA,gBAAQ,SAAS;AAAA,UACf;AAAA,YACE,QAAQ;AAAA,YACR,YAAY,CAAC,EAAE,UAAU,sBAAuB,CAAA;AAAA,UAAA;AAAA,QAEpD;AAAA,MAAA;AAAA,IACF;AAEK,WAAA;AAAA,EACT;AAAA,EACA,eAAe,CAAC,EAAE,MAAM,UAAU;;AAChC,QAAI,iBAAiB;AACjB,UAAA,UAAK,SAAL,mBAAW,UAAS,kBAAkB;AACxC,YAAM,iBAAiB,KAAK;AACxB,UAAA;AAEA,UAAA,eAAe,OAAO,SAAS,cAAc;AAC/C,qBAAa,eAAe;AAC5B,YAAI,IAAI,mBAAmB;AAEV,yBAAA,SAAS,EAAE,eAAe,YAAY;AAAA,YACnD,EAAE,cAAc,IAAI,OAAO;AAAA,UAAA,CAC5B;AACgB,2BAAA;AAAA,QAAA;AAAA,MACnB,WAIA,eAAe,OAAO,SAAS,oBAC/B,eAAe,OAAO,OAAO,SAAS,cACtC;AACA,qBAAa,eAAe,OAAO;AAC/B,YAAA,CAAC,IAAI,mBAAmB;AAE1B,yBAAe,SAAS;AACP,2BAAA;AAAA,QAAA,OACZ;AAEY,2BAAAC,MAAA;AAAA,YACf,eAAe;AAAA,YACf,IAAI;AAAA,YACJ,IAAI;AAAA,UACN;AAAA,QAAA;AAAA,MACF;AAEF,UAAI,eAAe,QAAW;AACtB,cAAA,IAAI,MAAM,mCAAmC;AAAA,MAAA;AAErD,UAAI,WAAW,SAAS,qBAAqB,IAAI,MAAM;AACrD,mBAAW,OAAO;AACD,yBAAA;AAAA,MAAA,WACR,WAAW,SAAS,yBAAyB,CAAC,IAAI,MAAM;AACjE,mBAAW,OAAO;AACD,yBAAA;AAAA,MAAA;AAAA,IACnB;AAGK,WAAA;AAAA,EAAA;AAEX;;"}
1
+ {"version":3,"file":"default-transform-plugin.cjs","sources":["../../../src/transform/default-transform-plugin.ts"],"sourcesContent":["import { types } from 'recast'\nimport { ensureStringArgument } from './utils'\nimport type { TransformImportsConfig, TransformPlugin } from './types'\n\nconst b = types.builders\n\nconst EXPORT_NAME = 'Route'\nexport const defaultTransformPlugin: TransformPlugin = {\n name: 'default-transform',\n exportName: EXPORT_NAME,\n imports: (ctx) => {\n const imports: TransformImportsConfig = {}\n const targetModule = `@tanstack/${ctx.target}-router`\n if (ctx.verboseFileRoutes === false) {\n imports.banned = [\n {\n source: targetModule,\n specifiers: [\n { imported: 'createLazyFileRoute' },\n { imported: 'createFileRoute' },\n ],\n },\n ]\n } else {\n if (ctx.lazy) {\n imports.required = [\n {\n source: targetModule,\n specifiers: [{ imported: 'createLazyFileRoute' }],\n },\n ]\n imports.banned = [\n {\n source: targetModule,\n specifiers: [{ imported: 'createFileRoute' }],\n },\n ]\n } else {\n imports.required = [\n {\n source: targetModule,\n specifiers: [{ imported: 'createFileRoute' }],\n },\n ]\n imports.banned = [\n {\n source: targetModule,\n specifiers: [{ imported: 'createLazyFileRoute' }],\n },\n ]\n }\n }\n return imports\n },\n onExportFound: ({ decl, ctx }) => {\n let appliedChanges = false\n if (decl.init?.type === 'CallExpression') {\n const callExpression = decl.init\n let identifier: types.namedTypes.Identifier | undefined\n // `const Route = createFileRoute({ ... })`\n if (callExpression.callee.type === 'Identifier') {\n identifier = callExpression.callee\n if (ctx.verboseFileRoutes) {\n // we need to add the string literal via another CallExpression\n callExpression.callee = b.callExpression(identifier, [\n b.stringLiteral(ctx.routeId),\n ])\n appliedChanges = true\n }\n }\n // `const Route = createFileRoute('/path')({ ... })`\n else if (\n callExpression.callee.type === 'CallExpression' &&\n callExpression.callee.callee.type === 'Identifier'\n ) {\n identifier = callExpression.callee.callee\n if (!ctx.verboseFileRoutes) {\n // we need to remove the route id\n callExpression.callee = identifier\n appliedChanges = true\n } else {\n // check if the route id is correct\n appliedChanges = ensureStringArgument(\n callExpression.callee,\n ctx.routeId,\n ctx.preferredQuote,\n )\n }\n }\n if (identifier === undefined) {\n throw new Error(\n `expected identifier to be present in ${ctx.routeId} for export ${EXPORT_NAME}`,\n )\n }\n if (identifier.name === 'createFileRoute' && ctx.lazy) {\n identifier.name = 'createLazyFileRoute'\n appliedChanges = true\n } else if (identifier.name === 'createLazyFileRoute' && !ctx.lazy) {\n identifier.name = 'createFileRoute'\n appliedChanges = true\n }\n }\n\n return appliedChanges\n },\n}\n"],"names":["types","ensureStringArgument"],"mappings":";;;;AAIA,MAAM,IAAIA,OAAAA,MAAM;AAEhB,MAAM,cAAc;AACb,MAAM,yBAA0C;AAAA,EACrD,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,SAAS,CAAC,QAAQ;AAChB,UAAM,UAAkC,CAAA;AACxC,UAAM,eAAe,aAAa,IAAI,MAAM;AAC5C,QAAI,IAAI,sBAAsB,OAAO;AACnC,cAAQ,SAAS;AAAA,QACf;AAAA,UACE,QAAQ;AAAA,UACR,YAAY;AAAA,YACV,EAAE,UAAU,sBAAA;AAAA,YACZ,EAAE,UAAU,kBAAA;AAAA,UAAkB;AAAA,QAChC;AAAA,MACF;AAAA,IAEJ,OAAO;AACL,UAAI,IAAI,MAAM;AACZ,gBAAQ,WAAW;AAAA,UACjB;AAAA,YACE,QAAQ;AAAA,YACR,YAAY,CAAC,EAAE,UAAU,uBAAuB;AAAA,UAAA;AAAA,QAClD;AAEF,gBAAQ,SAAS;AAAA,UACf;AAAA,YACE,QAAQ;AAAA,YACR,YAAY,CAAC,EAAE,UAAU,mBAAmB;AAAA,UAAA;AAAA,QAC9C;AAAA,MAEJ,OAAO;AACL,gBAAQ,WAAW;AAAA,UACjB;AAAA,YACE,QAAQ;AAAA,YACR,YAAY,CAAC,EAAE,UAAU,mBAAmB;AAAA,UAAA;AAAA,QAC9C;AAEF,gBAAQ,SAAS;AAAA,UACf;AAAA,YACE,QAAQ;AAAA,YACR,YAAY,CAAC,EAAE,UAAU,uBAAuB;AAAA,UAAA;AAAA,QAClD;AAAA,MAEJ;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EACA,eAAe,CAAC,EAAE,MAAM,UAAU;AAChC,QAAI,iBAAiB;AACrB,QAAI,KAAK,MAAM,SAAS,kBAAkB;AACxC,YAAM,iBAAiB,KAAK;AAC5B,UAAI;AAEJ,UAAI,eAAe,OAAO,SAAS,cAAc;AAC/C,qBAAa,eAAe;AAC5B,YAAI,IAAI,mBAAmB;AAEzB,yBAAe,SAAS,EAAE,eAAe,YAAY;AAAA,YACnD,EAAE,cAAc,IAAI,OAAO;AAAA,UAAA,CAC5B;AACD,2BAAiB;AAAA,QACnB;AAAA,MACF,WAGE,eAAe,OAAO,SAAS,oBAC/B,eAAe,OAAO,OAAO,SAAS,cACtC;AACA,qBAAa,eAAe,OAAO;AACnC,YAAI,CAAC,IAAI,mBAAmB;AAE1B,yBAAe,SAAS;AACxB,2BAAiB;AAAA,QACnB,OAAO;AAEL,2BAAiBC,MAAAA;AAAAA,YACf,eAAe;AAAA,YACf,IAAI;AAAA,YACJ,IAAI;AAAA,UAAA;AAAA,QAER;AAAA,MACF;AACA,UAAI,eAAe,QAAW;AAC5B,cAAM,IAAI;AAAA,UACR,wCAAwC,IAAI,OAAO,eAAe,WAAW;AAAA,QAAA;AAAA,MAEjF;AACA,UAAI,WAAW,SAAS,qBAAqB,IAAI,MAAM;AACrD,mBAAW,OAAO;AAClB,yBAAiB;AAAA,MACnB,WAAW,WAAW,SAAS,yBAAyB,CAAC,IAAI,MAAM;AACjE,mBAAW,OAAO;AAClB,yBAAiB;AAAA,MACnB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;;"}
@@ -10,7 +10,6 @@ async function transform({
10
10
  source,
11
11
  plugins
12
12
  }) {
13
- var _a, _b, _c;
14
13
  let appliedChanges = false;
15
14
  let ast;
16
15
  const foundExports = [];
@@ -41,27 +40,50 @@ async function transform({
41
40
  const exportName = plugin.exportName;
42
41
  if (registeredExports.has(exportName)) {
43
42
  throw new Error(
44
- `Export ${exportName} is already registered by plugin ${(_a = registeredExports.get(exportName)) == null ? void 0 : _a.name}`
43
+ `Export ${exportName} is already registered by plugin ${registeredExports.get(exportName)?.name}`
45
44
  );
46
45
  }
47
46
  registeredExports.set(exportName, plugin);
48
47
  }
48
+ function onExportFound(decl, exportName, plugin) {
49
+ const pluginAppliedChanges = plugin.onExportFound({
50
+ decl,
51
+ ctx: { ...ctx, preferredQuote }
52
+ });
53
+ if (pluginAppliedChanges) {
54
+ appliedChanges = true;
55
+ }
56
+ registeredExports.delete(exportName);
57
+ foundExports.push(exportName);
58
+ }
49
59
  const program = ast.program;
50
60
  for (const n of program.body) {
51
- if (registeredExports.size > 0 && n.type === "ExportNamedDeclaration" && ((_b = n.declaration) == null ? void 0 : _b.type) === "VariableDeclaration") {
52
- const decl = n.declaration.declarations[0];
53
- if (decl && decl.type === "VariableDeclarator" && decl.id.type === "Identifier") {
54
- const plugin = registeredExports.get(decl.id.name);
55
- if (plugin) {
56
- const pluginAppliedChanges = plugin.onExportFound({
57
- decl,
58
- ctx: { ...ctx, preferredQuote }
59
- });
60
- if (pluginAppliedChanges) {
61
- appliedChanges = true;
61
+ if (registeredExports.size > 0 && n.type === "ExportNamedDeclaration") {
62
+ if (n.declaration?.type === "VariableDeclaration") {
63
+ const decl = n.declaration.declarations[0];
64
+ if (decl && decl.type === "VariableDeclarator" && decl.id.type === "Identifier") {
65
+ const plugin = registeredExports.get(decl.id.name);
66
+ if (plugin) {
67
+ onExportFound(decl, decl.id.name, plugin);
68
+ }
69
+ }
70
+ } else if (n.declaration === null && n.specifiers) {
71
+ for (const spec of n.specifiers) {
72
+ if (typeof spec.exported.name === "string") {
73
+ const plugin = registeredExports.get(spec.exported.name);
74
+ if (plugin) {
75
+ const variableName = spec.local?.name || spec.exported.name;
76
+ for (const decl of program.body) {
77
+ if (decl.type === "VariableDeclaration" && decl.declarations[0]) {
78
+ const variable = decl.declarations[0];
79
+ if (variable.type === "VariableDeclarator" && variable.id.type === "Identifier" && variable.id.name === variableName) {
80
+ onExportFound(variable, spec.exported.name, plugin);
81
+ break;
82
+ }
83
+ }
84
+ }
85
+ }
62
86
  }
63
- registeredExports.delete(decl.id.name);
64
- foundExports.push(decl.id.name);
65
87
  }
66
88
  }
67
89
  }
@@ -197,7 +219,7 @@ async function transform({
197
219
  if (importDeclarationsToRemove.length > 0) {
198
220
  appliedChanges = true;
199
221
  for (const importDeclaration of importDeclarationsToRemove) {
200
- if (((_c = importDeclaration.specifiers) == null ? void 0 : _c.length) === 0) {
222
+ if (importDeclaration.specifiers?.length === 0) {
201
223
  const index = program.body.indexOf(importDeclaration);
202
224
  if (index !== -1) {
203
225
  program.body.splice(index, 1);
@@ -332,11 +354,10 @@ function detectPreferredQuoteStyle(ast) {
332
354
  let double = 0;
333
355
  recast.visit(ast, {
334
356
  visitStringLiteral(path) {
335
- var _a;
336
357
  if (path.parent.node.type !== "JSXAttribute") {
337
- const raw = (_a = path.node.extra) == null ? void 0 : _a.raw;
338
- if (raw == null ? void 0 : raw.startsWith("'")) single++;
339
- else if (raw == null ? void 0 : raw.startsWith('"')) double++;
358
+ const raw = path.node.extra?.raw;
359
+ if (raw?.startsWith("'")) single++;
360
+ else if (raw?.startsWith('"')) double++;
340
361
  }
341
362
  return false;
342
363
  }
@@ -1 +1 @@
1
- {"version":3,"file":"transform.cjs","sources":["../../../src/transform/transform.ts"],"sourcesContent":["import { parseAst } from '@tanstack/router-utils'\nimport { parse, print, types, visit } from 'recast'\nimport { SourceMapConsumer } from 'source-map'\nimport { mergeImportDeclarations } from '../utils'\nimport type { ImportDeclaration } from '../types'\nimport type { RawSourceMap } from 'source-map'\nimport type {\n TransformOptions,\n TransformPlugin,\n TransformResult,\n} from './types'\n\nconst b = types.builders\n\nexport async function transform({\n ctx,\n source,\n plugins,\n}: TransformOptions): Promise<TransformResult> {\n let appliedChanges = false as boolean\n let ast: types.namedTypes.File\n const foundExports: Array<string> = []\n try {\n ast = parse(source, {\n sourceFileName: 'output.ts',\n parser: {\n parse(code: string) {\n return parseAst({\n code,\n // we need to instruct babel to produce tokens,\n // otherwise recast will try to generate the tokens via its own parser and will fail\n tokens: true,\n })\n },\n },\n })\n } catch (e) {\n console.error('Error parsing code', ctx.routeId, source, e)\n return {\n result: 'error',\n error: e,\n }\n }\n\n const preferredQuote = detectPreferredQuoteStyle(ast)\n\n const registeredExports = new Map</* export name */ string, TransformPlugin>()\n\n for (const plugin of plugins ?? []) {\n const exportName = plugin.exportName\n if (registeredExports.has(exportName)) {\n throw new Error(\n `Export ${exportName} is already registered by plugin ${registeredExports.get(exportName)?.name}`,\n )\n }\n registeredExports.set(exportName, plugin)\n }\n\n const program: types.namedTypes.Program = ast.program\n // first pass: find registered exports\n for (const n of program.body) {\n if (\n registeredExports.size > 0 &&\n n.type === 'ExportNamedDeclaration' &&\n n.declaration?.type === 'VariableDeclaration'\n ) {\n const decl = n.declaration.declarations[0]\n if (\n decl &&\n decl.type === 'VariableDeclarator' &&\n decl.id.type === 'Identifier'\n ) {\n const plugin = registeredExports.get(decl.id.name)\n if (plugin) {\n const pluginAppliedChanges = plugin.onExportFound({\n decl,\n ctx: { ...ctx, preferredQuote },\n })\n\n if (pluginAppliedChanges) {\n appliedChanges = true\n }\n\n // export is handled, remove it from the registered exports\n registeredExports.delete(decl.id.name)\n // store the export so we can later return it once the file is transformed\n foundExports.push(decl.id.name)\n }\n }\n }\n }\n\n const imports: {\n required: Array<ImportDeclaration>\n banned: Array<ImportDeclaration>\n } = {\n required: [],\n banned: [],\n }\n\n for (const plugin of plugins ?? []) {\n const exportName = plugin.exportName\n if (foundExports.includes(exportName)) {\n const pluginImports = plugin.imports(ctx)\n if (pluginImports.required) {\n imports.required.push(...pluginImports.required)\n }\n if (pluginImports.banned) {\n imports.banned.push(...pluginImports.banned)\n }\n }\n }\n\n imports.required = mergeImportDeclarations(imports.required)\n imports.banned = mergeImportDeclarations(imports.banned)\n\n const importStatementCandidates: Array<types.namedTypes.ImportDeclaration> =\n []\n const importDeclarationsToRemove: Array<types.namedTypes.ImportDeclaration> =\n []\n\n // second pass: apply import rules, but only if a matching export for the plugin was found\n for (const n of program.body) {\n const findImport =\n (opts: { source: string; importKind?: 'type' | 'value' | 'typeof' }) =>\n (i: ImportDeclaration) => {\n if (i.source === opts.source) {\n const importKind = i.importKind || 'value'\n const expectedImportKind = opts.importKind || 'value'\n return expectedImportKind === importKind\n }\n return false\n }\n if (n.type === 'ImportDeclaration' && typeof n.source.value === 'string') {\n const filterImport = findImport({\n source: n.source.value,\n importKind: n.importKind,\n })\n let requiredImports = imports.required.filter(filterImport)[0]\n\n const bannedImports = imports.banned.filter(filterImport)[0]\n if (!requiredImports && !bannedImports) {\n continue\n }\n const importSpecifiersToRemove: types.namedTypes.ImportDeclaration['specifiers'] =\n []\n if (n.specifiers) {\n for (const spec of n.specifiers) {\n if (!requiredImports && !bannedImports) {\n break\n }\n if (\n spec.type === 'ImportSpecifier' &&\n typeof spec.imported.name === 'string'\n ) {\n if (requiredImports) {\n const requiredImportIndex = requiredImports.specifiers.findIndex(\n (imp) => imp.imported === spec.imported.name,\n )\n if (requiredImportIndex !== -1) {\n // import is already present, remove it from requiredImports\n requiredImports.specifiers.splice(requiredImportIndex, 1)\n if (requiredImports.specifiers.length === 0) {\n imports.required = imports.required.splice(\n imports.required.indexOf(requiredImports),\n 1,\n )\n requiredImports = undefined\n }\n } else {\n // add the import statement to the candidates\n importStatementCandidates.push(n)\n }\n }\n if (bannedImports) {\n const bannedImportIndex = bannedImports.specifiers.findIndex(\n (imp) => imp.imported === spec.imported.name,\n )\n if (bannedImportIndex !== -1) {\n importSpecifiersToRemove.push(spec)\n }\n }\n }\n }\n if (importSpecifiersToRemove.length > 0) {\n appliedChanges = true\n n.specifiers = n.specifiers.filter(\n (spec) => !importSpecifiersToRemove.includes(spec),\n )\n\n // mark the import statement as to be deleted if it is now empty\n if (n.specifiers.length === 0) {\n importDeclarationsToRemove.push(n)\n }\n }\n }\n }\n }\n imports.required.forEach((requiredImport) => {\n if (requiredImport.specifiers.length > 0) {\n appliedChanges = true\n if (importStatementCandidates.length > 0) {\n // find the first import statement that matches both the module and the import kind\n const importStatement = importStatementCandidates.find(\n (importStatement) => {\n if (importStatement.source.value === requiredImport.source) {\n const importKind = importStatement.importKind || 'value'\n const requiredImportKind = requiredImport.importKind || 'value'\n return importKind === requiredImportKind\n }\n return false\n },\n )\n if (importStatement) {\n if (importStatement.specifiers === undefined) {\n importStatement.specifiers = []\n }\n const importSpecifiersToAdd = requiredImport.specifiers.map((spec) =>\n b.importSpecifier(\n b.identifier(spec.imported),\n b.identifier(spec.imported),\n ),\n )\n importStatement.specifiers = [\n ...importStatement.specifiers,\n ...importSpecifiersToAdd,\n ]\n return\n }\n }\n const importStatement = b.importDeclaration(\n requiredImport.specifiers.map((spec) =>\n b.importSpecifier(\n b.identifier(spec.imported),\n spec.local ? b.identifier(spec.local) : null,\n ),\n ),\n b.stringLiteral(requiredImport.source),\n )\n program.body.unshift(importStatement)\n }\n })\n if (importDeclarationsToRemove.length > 0) {\n appliedChanges = true\n for (const importDeclaration of importDeclarationsToRemove) {\n // check if the import declaration is still empty\n if (importDeclaration.specifiers?.length === 0) {\n const index = program.body.indexOf(importDeclaration)\n if (index !== -1) {\n program.body.splice(index, 1)\n }\n }\n }\n }\n\n if (!appliedChanges) {\n return {\n exports: foundExports,\n result: 'not-modified',\n }\n }\n\n const printResult = print(ast, {\n reuseWhitespace: true,\n sourceMapName: 'output.map',\n })\n let transformedCode = printResult.code\n if (printResult.map) {\n const fixedOutput = await fixTransformedOutputText({\n originalCode: source,\n transformedCode,\n sourceMap: printResult.map as RawSourceMap,\n preferredQuote,\n })\n transformedCode = fixedOutput\n }\n return {\n result: 'modified',\n exports: foundExports,\n output: transformedCode,\n }\n}\n\nasync function fixTransformedOutputText({\n originalCode,\n transformedCode,\n sourceMap,\n preferredQuote,\n}: {\n originalCode: string\n transformedCode: string\n sourceMap: RawSourceMap\n preferredQuote: '\"' | \"'\"\n}) {\n const originalLines = originalCode.split('\\n')\n const transformedLines = transformedCode.split('\\n')\n\n const defaultUsesSemicolons = detectSemicolonUsage(originalCode)\n\n const consumer = await new SourceMapConsumer(sourceMap)\n\n const fixedLines = transformedLines.map((line, i) => {\n const transformedLineNum = i + 1\n\n let origLineText: string | undefined = undefined\n\n for (let col = 0; col < line.length; col++) {\n const mapped = consumer.originalPositionFor({\n line: transformedLineNum,\n column: col,\n })\n if (mapped.line != null && mapped.line > 0) {\n origLineText = originalLines[mapped.line - 1]\n break\n }\n }\n\n if (origLineText !== undefined) {\n if (origLineText === line) {\n return origLineText\n }\n return fixLine(line, {\n originalLine: origLineText,\n useOriginalSemicolon: true,\n useOriginalQuotes: true,\n fallbackQuote: preferredQuote,\n })\n } else {\n return fixLine(line, {\n originalLine: null,\n useOriginalSemicolon: false,\n useOriginalQuotes: false,\n fallbackQuote: preferredQuote,\n fallbackSemicolon: defaultUsesSemicolons,\n })\n }\n })\n\n return fixedLines.join('\\n')\n}\n\nfunction fixLine(\n line: string,\n {\n originalLine,\n useOriginalSemicolon,\n useOriginalQuotes,\n fallbackQuote,\n fallbackSemicolon = true,\n }: {\n originalLine: string | null\n useOriginalSemicolon: boolean\n useOriginalQuotes: boolean\n fallbackQuote: string\n fallbackSemicolon?: boolean\n },\n) {\n let result = line\n\n if (useOriginalQuotes && originalLine) {\n result = fixQuotes(result, originalLine, fallbackQuote)\n } else if (!useOriginalQuotes && fallbackQuote) {\n result = fixQuotesToPreferred(result, fallbackQuote)\n }\n\n if (useOriginalSemicolon && originalLine) {\n const hadSemicolon = originalLine.trimEnd().endsWith(';')\n const hasSemicolon = result.trimEnd().endsWith(';')\n if (hadSemicolon && !hasSemicolon) result += ';'\n if (!hadSemicolon && hasSemicolon) result = result.replace(/;\\s*$/, '')\n } else if (!useOriginalSemicolon) {\n const hasSemicolon = result.trimEnd().endsWith(';')\n if (!fallbackSemicolon && hasSemicolon) result = result.replace(/;\\s*$/, '')\n if (fallbackSemicolon && !hasSemicolon && result.trim()) result += ';'\n }\n\n return result\n}\n\nfunction fixQuotes(line: string, originalLine: string, fallbackQuote: string) {\n let originalQuote = detectQuoteFromLine(originalLine)\n if (!originalQuote) {\n originalQuote = fallbackQuote\n }\n return fixQuotesToPreferred(line, originalQuote)\n}\n\nfunction fixQuotesToPreferred(line: string, quote: string) {\n // Replace existing quotes with preferred quote\n return line.replace(\n /(['\"`])([^'\"`\\\\]*(?:\\\\.[^'\"`\\\\]*)*)\\1/g,\n (_, q, content) => {\n const escaped = content.replaceAll(quote, `\\\\${quote}`)\n return `${quote}${escaped}${quote}`\n },\n )\n}\n\nfunction detectQuoteFromLine(line: string) {\n const match = line.match(/(['\"`])(?:\\\\.|[^\\\\])*?\\1/)\n return match ? match[1] : null\n}\n\nfunction detectSemicolonUsage(code: string) {\n const lines = code.split('\\n').map((l) => l.trim())\n const total = lines.length\n const withSemis = lines.filter((l) => l.endsWith(';')).length\n return withSemis > total / 2\n}\n\nexport function detectPreferredQuoteStyle(ast: types.ASTNode): \"'\" | '\"' {\n let single = 0\n let double = 0\n\n visit(ast, {\n visitStringLiteral(path) {\n if (path.parent.node.type !== 'JSXAttribute') {\n const raw = path.node.extra?.raw\n if (raw?.startsWith(\"'\")) single++\n else if (raw?.startsWith('\"')) double++\n }\n return false\n },\n })\n\n if (single >= double) {\n return \"'\"\n }\n return '\"'\n}\n"],"names":["types","parse","parseAst","mergeImportDeclarations","importStatement","print","sourceMap","SourceMapConsumer","visit"],"mappings":";;;;;;AAYA,MAAM,IAAIA,OAAM,MAAA;AAEhB,eAAsB,UAAU;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AACF,GAA+C;;AAC7C,MAAI,iBAAiB;AACjB,MAAA;AACJ,QAAM,eAA8B,CAAC;AACjC,MAAA;AACF,UAAMC,aAAM,QAAQ;AAAA,MAClB,gBAAgB;AAAA,MAChB,QAAQ;AAAA,QACN,MAAM,MAAc;AAClB,iBAAOC,qBAAS;AAAA,YACd;AAAA;AAAA;AAAA,YAGA,QAAQ;AAAA,UAAA,CACT;AAAA,QAAA;AAAA,MACH;AAAA,IACF,CACD;AAAA,WACM,GAAG;AACV,YAAQ,MAAM,sBAAsB,IAAI,SAAS,QAAQ,CAAC;AACnD,WAAA;AAAA,MACL,QAAQ;AAAA,MACR,OAAO;AAAA,IACT;AAAA,EAAA;AAGI,QAAA,iBAAiB,0BAA0B,GAAG;AAE9C,QAAA,wCAAwB,IAA+C;AAElE,aAAA,UAAU,WAAW,IAAI;AAClC,UAAM,aAAa,OAAO;AACtB,QAAA,kBAAkB,IAAI,UAAU,GAAG;AACrC,YAAM,IAAI;AAAA,QACR,UAAU,UAAU,qCAAoC,uBAAkB,IAAI,UAAU,MAAhC,mBAAmC,IAAI;AAAA,MACjG;AAAA,IAAA;AAEgB,sBAAA,IAAI,YAAY,MAAM;AAAA,EAAA;AAG1C,QAAM,UAAoC,IAAI;AAEnC,aAAA,KAAK,QAAQ,MAAM;AAE1B,QAAA,kBAAkB,OAAO,KACzB,EAAE,SAAS,8BACX,OAAE,gBAAF,mBAAe,UAAS,uBACxB;AACA,YAAM,OAAO,EAAE,YAAY,aAAa,CAAC;AACzC,UACE,QACA,KAAK,SAAS,wBACd,KAAK,GAAG,SAAS,cACjB;AACA,cAAM,SAAS,kBAAkB,IAAI,KAAK,GAAG,IAAI;AACjD,YAAI,QAAQ;AACJ,gBAAA,uBAAuB,OAAO,cAAc;AAAA,YAChD;AAAA,YACA,KAAK,EAAE,GAAG,KAAK,eAAe;AAAA,UAAA,CAC/B;AAED,cAAI,sBAAsB;AACP,6BAAA;AAAA,UAAA;AAID,4BAAA,OAAO,KAAK,GAAG,IAAI;AAExB,uBAAA,KAAK,KAAK,GAAG,IAAI;AAAA,QAAA;AAAA,MAChC;AAAA,IACF;AAAA,EACF;AAGF,QAAM,UAGF;AAAA,IACF,UAAU,CAAC;AAAA,IACX,QAAQ,CAAA;AAAA,EACV;AAEW,aAAA,UAAU,WAAW,IAAI;AAClC,UAAM,aAAa,OAAO;AACtB,QAAA,aAAa,SAAS,UAAU,GAAG;AAC/B,YAAA,gBAAgB,OAAO,QAAQ,GAAG;AACxC,UAAI,cAAc,UAAU;AAC1B,gBAAQ,SAAS,KAAK,GAAG,cAAc,QAAQ;AAAA,MAAA;AAEjD,UAAI,cAAc,QAAQ;AACxB,gBAAQ,OAAO,KAAK,GAAG,cAAc,MAAM;AAAA,MAAA;AAAA,IAC7C;AAAA,EACF;AAGM,UAAA,WAAWC,8BAAwB,QAAQ,QAAQ;AACnD,UAAA,SAASA,8BAAwB,QAAQ,MAAM;AAEvD,QAAM,4BACJ,CAAC;AACH,QAAM,6BACJ,CAAC;AAGQ,aAAA,KAAK,QAAQ,MAAM;AAC5B,UAAM,aACJ,CAAC,SACD,CAAC,MAAyB;AACpB,UAAA,EAAE,WAAW,KAAK,QAAQ;AACtB,cAAA,aAAa,EAAE,cAAc;AAC7B,cAAA,qBAAqB,KAAK,cAAc;AAC9C,eAAO,uBAAuB;AAAA,MAAA;AAEzB,aAAA;AAAA,IACT;AACF,QAAI,EAAE,SAAS,uBAAuB,OAAO,EAAE,OAAO,UAAU,UAAU;AACxE,YAAM,eAAe,WAAW;AAAA,QAC9B,QAAQ,EAAE,OAAO;AAAA,QACjB,YAAY,EAAE;AAAA,MAAA,CACf;AACD,UAAI,kBAAkB,QAAQ,SAAS,OAAO,YAAY,EAAE,CAAC;AAE7D,YAAM,gBAAgB,QAAQ,OAAO,OAAO,YAAY,EAAE,CAAC;AACvD,UAAA,CAAC,mBAAmB,CAAC,eAAe;AACtC;AAAA,MAAA;AAEF,YAAM,2BACJ,CAAC;AACH,UAAI,EAAE,YAAY;AACL,mBAAA,QAAQ,EAAE,YAAY;AAC3B,cAAA,CAAC,mBAAmB,CAAC,eAAe;AACtC;AAAA,UAAA;AAEF,cACE,KAAK,SAAS,qBACd,OAAO,KAAK,SAAS,SAAS,UAC9B;AACA,gBAAI,iBAAiB;AACb,oBAAA,sBAAsB,gBAAgB,WAAW;AAAA,gBACrD,CAAC,QAAQ,IAAI,aAAa,KAAK,SAAS;AAAA,cAC1C;AACA,kBAAI,wBAAwB,IAAI;AAEd,gCAAA,WAAW,OAAO,qBAAqB,CAAC;AACpD,oBAAA,gBAAgB,WAAW,WAAW,GAAG;AACnC,0BAAA,WAAW,QAAQ,SAAS;AAAA,oBAClC,QAAQ,SAAS,QAAQ,eAAe;AAAA,oBACxC;AAAA,kBACF;AACkB,oCAAA;AAAA,gBAAA;AAAA,cACpB,OACK;AAEL,0CAA0B,KAAK,CAAC;AAAA,cAAA;AAAA,YAClC;AAEF,gBAAI,eAAe;AACX,oBAAA,oBAAoB,cAAc,WAAW;AAAA,gBACjD,CAAC,QAAQ,IAAI,aAAa,KAAK,SAAS;AAAA,cAC1C;AACA,kBAAI,sBAAsB,IAAI;AAC5B,yCAAyB,KAAK,IAAI;AAAA,cAAA;AAAA,YACpC;AAAA,UACF;AAAA,QACF;AAEE,YAAA,yBAAyB,SAAS,GAAG;AACtB,2BAAA;AACf,YAAA,aAAa,EAAE,WAAW;AAAA,YAC1B,CAAC,SAAS,CAAC,yBAAyB,SAAS,IAAI;AAAA,UACnD;AAGI,cAAA,EAAE,WAAW,WAAW,GAAG;AAC7B,uCAA2B,KAAK,CAAC;AAAA,UAAA;AAAA,QACnC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEM,UAAA,SAAS,QAAQ,CAAC,mBAAmB;AACvC,QAAA,eAAe,WAAW,SAAS,GAAG;AACvB,uBAAA;AACb,UAAA,0BAA0B,SAAS,GAAG;AAExC,cAAMC,mBAAkB,0BAA0B;AAAA,UAChD,CAACA,qBAAoB;AACnB,gBAAIA,iBAAgB,OAAO,UAAU,eAAe,QAAQ;AACpD,oBAAA,aAAaA,iBAAgB,cAAc;AAC3C,oBAAA,qBAAqB,eAAe,cAAc;AACxD,qBAAO,eAAe;AAAA,YAAA;AAEjB,mBAAA;AAAA,UAAA;AAAA,QAEX;AACA,YAAIA,kBAAiB;AACfA,cAAAA,iBAAgB,eAAe,QAAW;AAC5CA,6BAAgB,aAAa,CAAC;AAAA,UAAA;AAE1B,gBAAA,wBAAwB,eAAe,WAAW;AAAA,YAAI,CAAC,SAC3D,EAAE;AAAA,cACA,EAAE,WAAW,KAAK,QAAQ;AAAA,cAC1B,EAAE,WAAW,KAAK,QAAQ;AAAA,YAAA;AAAA,UAE9B;AACAA,2BAAgB,aAAa;AAAA,YAC3B,GAAGA,iBAAgB;AAAA,YACnB,GAAG;AAAA,UACL;AACA;AAAA,QAAA;AAAA,MACF;AAEF,YAAM,kBAAkB,EAAE;AAAA,QACxB,eAAe,WAAW;AAAA,UAAI,CAAC,SAC7B,EAAE;AAAA,YACA,EAAE,WAAW,KAAK,QAAQ;AAAA,YAC1B,KAAK,QAAQ,EAAE,WAAW,KAAK,KAAK,IAAI;AAAA,UAAA;AAAA,QAE5C;AAAA,QACA,EAAE,cAAc,eAAe,MAAM;AAAA,MACvC;AACQ,cAAA,KAAK,QAAQ,eAAe;AAAA,IAAA;AAAA,EACtC,CACD;AACG,MAAA,2BAA2B,SAAS,GAAG;AACxB,qBAAA;AACjB,eAAW,qBAAqB,4BAA4B;AAEtD,YAAA,uBAAkB,eAAlB,mBAA8B,YAAW,GAAG;AAC9C,cAAM,QAAQ,QAAQ,KAAK,QAAQ,iBAAiB;AACpD,YAAI,UAAU,IAAI;AACR,kBAAA,KAAK,OAAO,OAAO,CAAC;AAAA,QAAA;AAAA,MAC9B;AAAA,IACF;AAAA,EACF;AAGF,MAAI,CAAC,gBAAgB;AACZ,WAAA;AAAA,MACL,SAAS;AAAA,MACT,QAAQ;AAAA,IACV;AAAA,EAAA;AAGI,QAAA,cAAcC,aAAM,KAAK;AAAA,IAC7B,iBAAiB;AAAA,IACjB,eAAe;AAAA,EAAA,CAChB;AACD,MAAI,kBAAkB,YAAY;AAClC,MAAI,YAAY,KAAK;AACb,UAAA,cAAc,MAAM,yBAAyB;AAAA,MACjD,cAAc;AAAA,MACd;AAAA,MACA,WAAW,YAAY;AAAA,MACvB;AAAA,IAAA,CACD;AACiB,sBAAA;AAAA,EAAA;AAEb,SAAA;AAAA,IACL,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,QAAQ;AAAA,EACV;AACF;AAEA,eAAe,yBAAyB;AAAA,EACtC;AAAA,EACA;AAAA,EAAA,WACAC;AAAAA,EACA;AACF,GAKG;AACK,QAAA,gBAAgB,aAAa,MAAM,IAAI;AACvC,QAAA,mBAAmB,gBAAgB,MAAM,IAAI;AAE7C,QAAA,wBAAwB,qBAAqB,YAAY;AAE/D,QAAM,WAAW,MAAM,IAAIC,UAAA,kBAAkBD,WAAS;AAEtD,QAAM,aAAa,iBAAiB,IAAI,CAAC,MAAM,MAAM;AACnD,UAAM,qBAAqB,IAAI;AAE/B,QAAI,eAAmC;AAEvC,aAAS,MAAM,GAAG,MAAM,KAAK,QAAQ,OAAO;AACpC,YAAA,SAAS,SAAS,oBAAoB;AAAA,QAC1C,MAAM;AAAA,QACN,QAAQ;AAAA,MAAA,CACT;AACD,UAAI,OAAO,QAAQ,QAAQ,OAAO,OAAO,GAAG;AAC3B,uBAAA,cAAc,OAAO,OAAO,CAAC;AAC5C;AAAA,MAAA;AAAA,IACF;AAGF,QAAI,iBAAiB,QAAW;AAC9B,UAAI,iBAAiB,MAAM;AAClB,eAAA;AAAA,MAAA;AAET,aAAO,QAAQ,MAAM;AAAA,QACnB,cAAc;AAAA,QACd,sBAAsB;AAAA,QACtB,mBAAmB;AAAA,QACnB,eAAe;AAAA,MAAA,CAChB;AAAA,IAAA,OACI;AACL,aAAO,QAAQ,MAAM;AAAA,QACnB,cAAc;AAAA,QACd,sBAAsB;AAAA,QACtB,mBAAmB;AAAA,QACnB,eAAe;AAAA,QACf,mBAAmB;AAAA,MAAA,CACpB;AAAA,IAAA;AAAA,EACH,CACD;AAEM,SAAA,WAAW,KAAK,IAAI;AAC7B;AAEA,SAAS,QACP,MACA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,oBAAoB;AACtB,GAOA;AACA,MAAI,SAAS;AAEb,MAAI,qBAAqB,cAAc;AAC5B,aAAA,UAAU,QAAQ,cAAc,aAAa;AAAA,EAAA,WAC7C,CAAC,qBAAqB,eAAe;AACrC,aAAA,qBAAqB,QAAQ,aAAa;AAAA,EAAA;AAGrD,MAAI,wBAAwB,cAAc;AACxC,UAAM,eAAe,aAAa,QAAQ,EAAE,SAAS,GAAG;AACxD,UAAM,eAAe,OAAO,QAAQ,EAAE,SAAS,GAAG;AAC9C,QAAA,gBAAgB,CAAC,aAAwB,WAAA;AAC7C,QAAI,CAAC,gBAAgB,uBAAuB,OAAO,QAAQ,SAAS,EAAE;AAAA,EAAA,WAC7D,CAAC,sBAAsB;AAChC,UAAM,eAAe,OAAO,QAAQ,EAAE,SAAS,GAAG;AAClD,QAAI,CAAC,qBAAqB,uBAAuB,OAAO,QAAQ,SAAS,EAAE;AAC3E,QAAI,qBAAqB,CAAC,gBAAgB,OAAO,KAAA,EAAkB,WAAA;AAAA,EAAA;AAG9D,SAAA;AACT;AAEA,SAAS,UAAU,MAAc,cAAsB,eAAuB;AACxE,MAAA,gBAAgB,oBAAoB,YAAY;AACpD,MAAI,CAAC,eAAe;AACF,oBAAA;AAAA,EAAA;AAEX,SAAA,qBAAqB,MAAM,aAAa;AACjD;AAEA,SAAS,qBAAqB,MAAc,OAAe;AAEzD,SAAO,KAAK;AAAA,IACV;AAAA,IACA,CAAC,GAAG,GAAG,YAAY;AACjB,YAAM,UAAU,QAAQ,WAAW,OAAO,KAAK,KAAK,EAAE;AACtD,aAAO,GAAG,KAAK,GAAG,OAAO,GAAG,KAAK;AAAA,IAAA;AAAA,EAErC;AACF;AAEA,SAAS,oBAAoB,MAAc;AACnC,QAAA,QAAQ,KAAK,MAAM,0BAA0B;AAC5C,SAAA,QAAQ,MAAM,CAAC,IAAI;AAC5B;AAEA,SAAS,qBAAqB,MAAc;AACpC,QAAA,QAAQ,KAAK,MAAM,IAAI,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM;AAClD,QAAM,QAAQ,MAAM;AACd,QAAA,YAAY,MAAM,OAAO,CAAC,MAAM,EAAE,SAAS,GAAG,CAAC,EAAE;AACvD,SAAO,YAAY,QAAQ;AAC7B;AAEO,SAAS,0BAA0B,KAA+B;AACvE,MAAI,SAAS;AACb,MAAI,SAAS;AAEbE,SAAAA,MAAM,KAAK;AAAA,IACT,mBAAmB,MAAM;;AACvB,UAAI,KAAK,OAAO,KAAK,SAAS,gBAAgB;AACtC,cAAA,OAAM,UAAK,KAAK,UAAV,mBAAiB;AACzB,YAAA,2BAAK,WAAW,KAAM;AAAA,iBACjB,2BAAK,WAAW,KAAM;AAAA,MAAA;AAE1B,aAAA;AAAA,IAAA;AAAA,EACT,CACD;AAED,MAAI,UAAU,QAAQ;AACb,WAAA;AAAA,EAAA;AAEF,SAAA;AACT;;;"}
1
+ {"version":3,"file":"transform.cjs","sources":["../../../src/transform/transform.ts"],"sourcesContent":["import { parseAst } from '@tanstack/router-utils'\nimport { parse, print, types, visit } from 'recast'\nimport { SourceMapConsumer } from 'source-map'\nimport { mergeImportDeclarations } from '../utils'\nimport type { ImportDeclaration } from '../types'\nimport type { RawSourceMap } from 'source-map'\nimport type {\n TransformOptions,\n TransformPlugin,\n TransformResult,\n} from './types'\n\nconst b = types.builders\n\nexport async function transform({\n ctx,\n source,\n plugins,\n}: TransformOptions): Promise<TransformResult> {\n let appliedChanges = false as boolean\n let ast: types.namedTypes.File\n const foundExports: Array<string> = []\n try {\n ast = parse(source, {\n sourceFileName: 'output.ts',\n parser: {\n parse(code: string) {\n return parseAst({\n code,\n // we need to instruct babel to produce tokens,\n // otherwise recast will try to generate the tokens via its own parser and will fail\n tokens: true,\n })\n },\n },\n })\n } catch (e) {\n console.error('Error parsing code', ctx.routeId, source, e)\n return {\n result: 'error',\n error: e,\n }\n }\n\n const preferredQuote = detectPreferredQuoteStyle(ast)\n\n const registeredExports = new Map</* export name */ string, TransformPlugin>()\n\n for (const plugin of plugins ?? []) {\n const exportName = plugin.exportName\n if (registeredExports.has(exportName)) {\n throw new Error(\n `Export ${exportName} is already registered by plugin ${registeredExports.get(exportName)?.name}`,\n )\n }\n registeredExports.set(exportName, plugin)\n }\n\n function onExportFound(\n decl: types.namedTypes.VariableDeclarator,\n exportName: string,\n plugin: TransformPlugin,\n ) {\n const pluginAppliedChanges = plugin.onExportFound({\n decl,\n ctx: { ...ctx, preferredQuote },\n })\n if (pluginAppliedChanges) {\n appliedChanges = true\n }\n\n // export is handled, remove it from the registered exports\n registeredExports.delete(exportName)\n // store the export so we can later return it once the file is transformed\n foundExports.push(exportName)\n }\n\n const program: types.namedTypes.Program = ast.program\n // first pass: find registered exports\n for (const n of program.body) {\n if (registeredExports.size > 0 && n.type === 'ExportNamedDeclaration') {\n // direct export of a variable declaration, e.g. `export const Route = createFileRoute('/path')`\n if (n.declaration?.type === 'VariableDeclaration') {\n const decl = n.declaration.declarations[0]\n if (\n decl &&\n decl.type === 'VariableDeclarator' &&\n decl.id.type === 'Identifier'\n ) {\n const plugin = registeredExports.get(decl.id.name)\n if (plugin) {\n onExportFound(decl, decl.id.name, plugin)\n }\n }\n }\n // this is an export without a declaration, e.g. `export { Route }`\n else if (n.declaration === null && n.specifiers) {\n for (const spec of n.specifiers) {\n if (typeof spec.exported.name === 'string') {\n const plugin = registeredExports.get(spec.exported.name)\n if (plugin) {\n const variableName = spec.local?.name || spec.exported.name\n // find the matching variable declaration by iterating over the top-level declarations\n for (const decl of program.body) {\n if (\n decl.type === 'VariableDeclaration' &&\n decl.declarations[0]\n ) {\n const variable = decl.declarations[0]\n if (\n variable.type === 'VariableDeclarator' &&\n variable.id.type === 'Identifier' &&\n variable.id.name === variableName\n ) {\n onExportFound(variable, spec.exported.name, plugin)\n break\n }\n }\n }\n }\n }\n }\n }\n }\n }\n\n const imports: {\n required: Array<ImportDeclaration>\n banned: Array<ImportDeclaration>\n } = {\n required: [],\n banned: [],\n }\n\n for (const plugin of plugins ?? []) {\n const exportName = plugin.exportName\n if (foundExports.includes(exportName)) {\n const pluginImports = plugin.imports(ctx)\n if (pluginImports.required) {\n imports.required.push(...pluginImports.required)\n }\n if (pluginImports.banned) {\n imports.banned.push(...pluginImports.banned)\n }\n }\n }\n\n imports.required = mergeImportDeclarations(imports.required)\n imports.banned = mergeImportDeclarations(imports.banned)\n\n const importStatementCandidates: Array<types.namedTypes.ImportDeclaration> =\n []\n const importDeclarationsToRemove: Array<types.namedTypes.ImportDeclaration> =\n []\n\n // second pass: apply import rules, but only if a matching export for the plugin was found\n for (const n of program.body) {\n const findImport =\n (opts: { source: string; importKind?: 'type' | 'value' | 'typeof' }) =>\n (i: ImportDeclaration) => {\n if (i.source === opts.source) {\n const importKind = i.importKind || 'value'\n const expectedImportKind = opts.importKind || 'value'\n return expectedImportKind === importKind\n }\n return false\n }\n if (n.type === 'ImportDeclaration' && typeof n.source.value === 'string') {\n const filterImport = findImport({\n source: n.source.value,\n importKind: n.importKind,\n })\n let requiredImports = imports.required.filter(filterImport)[0]\n\n const bannedImports = imports.banned.filter(filterImport)[0]\n if (!requiredImports && !bannedImports) {\n continue\n }\n const importSpecifiersToRemove: types.namedTypes.ImportDeclaration['specifiers'] =\n []\n if (n.specifiers) {\n for (const spec of n.specifiers) {\n if (!requiredImports && !bannedImports) {\n break\n }\n if (\n spec.type === 'ImportSpecifier' &&\n typeof spec.imported.name === 'string'\n ) {\n if (requiredImports) {\n const requiredImportIndex = requiredImports.specifiers.findIndex(\n (imp) => imp.imported === spec.imported.name,\n )\n if (requiredImportIndex !== -1) {\n // import is already present, remove it from requiredImports\n requiredImports.specifiers.splice(requiredImportIndex, 1)\n if (requiredImports.specifiers.length === 0) {\n imports.required = imports.required.splice(\n imports.required.indexOf(requiredImports),\n 1,\n )\n requiredImports = undefined\n }\n } else {\n // add the import statement to the candidates\n importStatementCandidates.push(n)\n }\n }\n if (bannedImports) {\n const bannedImportIndex = bannedImports.specifiers.findIndex(\n (imp) => imp.imported === spec.imported.name,\n )\n if (bannedImportIndex !== -1) {\n importSpecifiersToRemove.push(spec)\n }\n }\n }\n }\n if (importSpecifiersToRemove.length > 0) {\n appliedChanges = true\n n.specifiers = n.specifiers.filter(\n (spec) => !importSpecifiersToRemove.includes(spec),\n )\n\n // mark the import statement as to be deleted if it is now empty\n if (n.specifiers.length === 0) {\n importDeclarationsToRemove.push(n)\n }\n }\n }\n }\n }\n imports.required.forEach((requiredImport) => {\n if (requiredImport.specifiers.length > 0) {\n appliedChanges = true\n if (importStatementCandidates.length > 0) {\n // find the first import statement that matches both the module and the import kind\n const importStatement = importStatementCandidates.find(\n (importStatement) => {\n if (importStatement.source.value === requiredImport.source) {\n const importKind = importStatement.importKind || 'value'\n const requiredImportKind = requiredImport.importKind || 'value'\n return importKind === requiredImportKind\n }\n return false\n },\n )\n if (importStatement) {\n if (importStatement.specifiers === undefined) {\n importStatement.specifiers = []\n }\n const importSpecifiersToAdd = requiredImport.specifiers.map((spec) =>\n b.importSpecifier(\n b.identifier(spec.imported),\n b.identifier(spec.imported),\n ),\n )\n importStatement.specifiers = [\n ...importStatement.specifiers,\n ...importSpecifiersToAdd,\n ]\n return\n }\n }\n const importStatement = b.importDeclaration(\n requiredImport.specifiers.map((spec) =>\n b.importSpecifier(\n b.identifier(spec.imported),\n spec.local ? b.identifier(spec.local) : null,\n ),\n ),\n b.stringLiteral(requiredImport.source),\n )\n program.body.unshift(importStatement)\n }\n })\n if (importDeclarationsToRemove.length > 0) {\n appliedChanges = true\n for (const importDeclaration of importDeclarationsToRemove) {\n // check if the import declaration is still empty\n if (importDeclaration.specifiers?.length === 0) {\n const index = program.body.indexOf(importDeclaration)\n if (index !== -1) {\n program.body.splice(index, 1)\n }\n }\n }\n }\n\n if (!appliedChanges) {\n return {\n exports: foundExports,\n result: 'not-modified',\n }\n }\n\n const printResult = print(ast, {\n reuseWhitespace: true,\n sourceMapName: 'output.map',\n })\n let transformedCode = printResult.code\n if (printResult.map) {\n const fixedOutput = await fixTransformedOutputText({\n originalCode: source,\n transformedCode,\n sourceMap: printResult.map as RawSourceMap,\n preferredQuote,\n })\n transformedCode = fixedOutput\n }\n return {\n result: 'modified',\n exports: foundExports,\n output: transformedCode,\n }\n}\n\nasync function fixTransformedOutputText({\n originalCode,\n transformedCode,\n sourceMap,\n preferredQuote,\n}: {\n originalCode: string\n transformedCode: string\n sourceMap: RawSourceMap\n preferredQuote: '\"' | \"'\"\n}) {\n const originalLines = originalCode.split('\\n')\n const transformedLines = transformedCode.split('\\n')\n\n const defaultUsesSemicolons = detectSemicolonUsage(originalCode)\n\n const consumer = await new SourceMapConsumer(sourceMap)\n\n const fixedLines = transformedLines.map((line, i) => {\n const transformedLineNum = i + 1\n\n let origLineText: string | undefined = undefined\n\n for (let col = 0; col < line.length; col++) {\n const mapped = consumer.originalPositionFor({\n line: transformedLineNum,\n column: col,\n })\n if (mapped.line != null && mapped.line > 0) {\n origLineText = originalLines[mapped.line - 1]\n break\n }\n }\n\n if (origLineText !== undefined) {\n if (origLineText === line) {\n return origLineText\n }\n return fixLine(line, {\n originalLine: origLineText,\n useOriginalSemicolon: true,\n useOriginalQuotes: true,\n fallbackQuote: preferredQuote,\n })\n } else {\n return fixLine(line, {\n originalLine: null,\n useOriginalSemicolon: false,\n useOriginalQuotes: false,\n fallbackQuote: preferredQuote,\n fallbackSemicolon: defaultUsesSemicolons,\n })\n }\n })\n\n return fixedLines.join('\\n')\n}\n\nfunction fixLine(\n line: string,\n {\n originalLine,\n useOriginalSemicolon,\n useOriginalQuotes,\n fallbackQuote,\n fallbackSemicolon = true,\n }: {\n originalLine: string | null\n useOriginalSemicolon: boolean\n useOriginalQuotes: boolean\n fallbackQuote: string\n fallbackSemicolon?: boolean\n },\n) {\n let result = line\n\n if (useOriginalQuotes && originalLine) {\n result = fixQuotes(result, originalLine, fallbackQuote)\n } else if (!useOriginalQuotes && fallbackQuote) {\n result = fixQuotesToPreferred(result, fallbackQuote)\n }\n\n if (useOriginalSemicolon && originalLine) {\n const hadSemicolon = originalLine.trimEnd().endsWith(';')\n const hasSemicolon = result.trimEnd().endsWith(';')\n if (hadSemicolon && !hasSemicolon) result += ';'\n if (!hadSemicolon && hasSemicolon) result = result.replace(/;\\s*$/, '')\n } else if (!useOriginalSemicolon) {\n const hasSemicolon = result.trimEnd().endsWith(';')\n if (!fallbackSemicolon && hasSemicolon) result = result.replace(/;\\s*$/, '')\n if (fallbackSemicolon && !hasSemicolon && result.trim()) result += ';'\n }\n\n return result\n}\n\nfunction fixQuotes(line: string, originalLine: string, fallbackQuote: string) {\n let originalQuote = detectQuoteFromLine(originalLine)\n if (!originalQuote) {\n originalQuote = fallbackQuote\n }\n return fixQuotesToPreferred(line, originalQuote)\n}\n\nfunction fixQuotesToPreferred(line: string, quote: string) {\n // Replace existing quotes with preferred quote\n return line.replace(\n /(['\"`])([^'\"`\\\\]*(?:\\\\.[^'\"`\\\\]*)*)\\1/g,\n (_, q, content) => {\n const escaped = content.replaceAll(quote, `\\\\${quote}`)\n return `${quote}${escaped}${quote}`\n },\n )\n}\n\nfunction detectQuoteFromLine(line: string) {\n const match = line.match(/(['\"`])(?:\\\\.|[^\\\\])*?\\1/)\n return match ? match[1] : null\n}\n\nfunction detectSemicolonUsage(code: string) {\n const lines = code.split('\\n').map((l) => l.trim())\n const total = lines.length\n const withSemis = lines.filter((l) => l.endsWith(';')).length\n return withSemis > total / 2\n}\n\nexport function detectPreferredQuoteStyle(ast: types.ASTNode): \"'\" | '\"' {\n let single = 0\n let double = 0\n\n visit(ast, {\n visitStringLiteral(path) {\n if (path.parent.node.type !== 'JSXAttribute') {\n const raw = path.node.extra?.raw\n if (raw?.startsWith(\"'\")) single++\n else if (raw?.startsWith('\"')) double++\n }\n return false\n },\n })\n\n if (single >= double) {\n return \"'\"\n }\n return '\"'\n}\n"],"names":["types","parse","parseAst","mergeImportDeclarations","importStatement","print","sourceMap","SourceMapConsumer","visit"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"utils.cjs","sources":["../../../src/transform/utils.ts"],"sourcesContent":["import { types } from 'recast'\n\nconst b = types.builders\n\nexport function ensureStringArgument(\n callExpression: types.namedTypes.CallExpression,\n value: string,\n preferredQuote?: \"'\" | '\"',\n) {\n const argument = callExpression.arguments[0]\n if (!argument) {\n let stringLiteral: types.namedTypes.StringLiteral\n if (!preferredQuote) {\n stringLiteral = b.stringLiteral.from({ value })\n } else {\n stringLiteral = b.stringLiteral.from({\n value,\n extra: {\n rawValue: value,\n raw: `${preferredQuote}${value}${preferredQuote}`,\n },\n })\n }\n callExpression.arguments.push(stringLiteral)\n return true\n } else if (argument.type === 'StringLiteral') {\n if (argument.value !== value) {\n argument.value = value\n return true\n }\n } else if (argument.type === 'TemplateLiteral') {\n if (\n argument.quasis.length === 1 &&\n argument.quasis[0] &&\n argument.quasis[0].value.raw !== value\n ) {\n argument.quasis[0].value.raw = value\n return true\n }\n }\n return false\n}\n"],"names":["types"],"mappings":";;;AAEA,MAAM,IAAIA,OAAM,MAAA;AAEA,SAAA,qBACd,gBACA,OACA,gBACA;AACM,QAAA,WAAW,eAAe,UAAU,CAAC;AAC3C,MAAI,CAAC,UAAU;AACT,QAAA;AACJ,QAAI,CAAC,gBAAgB;AACnB,sBAAgB,EAAE,cAAc,KAAK,EAAE,OAAO;AAAA,IAAA,OACzC;AACW,sBAAA,EAAE,cAAc,KAAK;AAAA,QACnC;AAAA,QACA,OAAO;AAAA,UACL,UAAU;AAAA,UACV,KAAK,GAAG,cAAc,GAAG,KAAK,GAAG,cAAc;AAAA,QAAA;AAAA,MACjD,CACD;AAAA,IAAA;AAEY,mBAAA,UAAU,KAAK,aAAa;AACpC,WAAA;AAAA,EAAA,WACE,SAAS,SAAS,iBAAiB;AACxC,QAAA,SAAS,UAAU,OAAO;AAC5B,eAAS,QAAQ;AACV,aAAA;AAAA,IAAA;AAAA,EACT,WACS,SAAS,SAAS,mBAAmB;AAC9C,QACE,SAAS,OAAO,WAAW,KAC3B,SAAS,OAAO,CAAC,KACjB,SAAS,OAAO,CAAC,EAAE,MAAM,QAAQ,OACjC;AACA,eAAS,OAAO,CAAC,EAAE,MAAM,MAAM;AACxB,aAAA;AAAA,IAAA;AAAA,EACT;AAEK,SAAA;AACT;;"}
1
+ {"version":3,"file":"utils.cjs","sources":["../../../src/transform/utils.ts"],"sourcesContent":["import { types } from 'recast'\n\nconst b = types.builders\n\nexport function ensureStringArgument(\n callExpression: types.namedTypes.CallExpression,\n value: string,\n preferredQuote?: \"'\" | '\"',\n) {\n const argument = callExpression.arguments[0]\n if (!argument) {\n let stringLiteral: types.namedTypes.StringLiteral\n if (!preferredQuote) {\n stringLiteral = b.stringLiteral.from({ value })\n } else {\n stringLiteral = b.stringLiteral.from({\n value,\n extra: {\n rawValue: value,\n raw: `${preferredQuote}${value}${preferredQuote}`,\n },\n })\n }\n callExpression.arguments.push(stringLiteral)\n return true\n } else if (argument.type === 'StringLiteral') {\n if (argument.value !== value) {\n argument.value = value\n return true\n }\n } else if (argument.type === 'TemplateLiteral') {\n if (\n argument.quasis.length === 1 &&\n argument.quasis[0] &&\n argument.quasis[0].value.raw !== value\n ) {\n argument.quasis[0].value.raw = value\n return true\n }\n }\n return false\n}\n"],"names":["types"],"mappings":";;;AAEA,MAAM,IAAIA,OAAAA,MAAM;AAET,SAAS,qBACd,gBACA,OACA,gBACA;AACA,QAAM,WAAW,eAAe,UAAU,CAAC;AAC3C,MAAI,CAAC,UAAU;AACb,QAAI;AACJ,QAAI,CAAC,gBAAgB;AACnB,sBAAgB,EAAE,cAAc,KAAK,EAAE,OAAO;AAAA,IAChD,OAAO;AACL,sBAAgB,EAAE,cAAc,KAAK;AAAA,QACnC;AAAA,QACA,OAAO;AAAA,UACL,UAAU;AAAA,UACV,KAAK,GAAG,cAAc,GAAG,KAAK,GAAG,cAAc;AAAA,QAAA;AAAA,MACjD,CACD;AAAA,IACH;AACA,mBAAe,UAAU,KAAK,aAAa;AAC3C,WAAO;AAAA,EACT,WAAW,SAAS,SAAS,iBAAiB;AAC5C,QAAI,SAAS,UAAU,OAAO;AAC5B,eAAS,QAAQ;AACjB,aAAO;AAAA,IACT;AAAA,EACF,WAAW,SAAS,SAAS,mBAAmB;AAC9C,QACE,SAAS,OAAO,WAAW,KAC3B,SAAS,OAAO,CAAC,KACjB,SAAS,OAAO,CAAC,EAAE,MAAM,QAAQ,OACjC;AACA,eAAS,OAAO,CAAC,EAAE,MAAM,MAAM;AAC/B,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;;"}
@@ -17,6 +17,7 @@ export type RouteNode = {
17
17
  export interface GetRouteNodesResult {
18
18
  rootRouteNode?: RouteNode;
19
19
  routeNodes: Array<RouteNode>;
20
+ physicalDirectories: Array<string>;
20
21
  }
21
22
  export type FsRouteType = '__root' | 'static' | 'layout' | 'pathless_layout' | 'lazy' | 'loader' | 'component' | 'pendingComponent' | 'errorComponent';
22
23
  export type RouteSubNode = {
@@ -40,3 +41,7 @@ export type HandleNodeAccumulator = {
40
41
  routePiecesByPath: Record<string, RouteSubNode>;
41
42
  routeNodes: Array<RouteNode>;
42
43
  };
44
+ export type GetRoutesByFileMapResultValue = {
45
+ routePath: string;
46
+ };
47
+ export type GetRoutesByFileMapResult = Map<string, GetRoutesByFileMapResultValue>;
@@ -95,7 +95,6 @@ function replaceBackslash(s) {
95
95
  return s.replaceAll(/\\/gi, "/");
96
96
  }
97
97
  function routePathToVariable(routePath) {
98
- var _a;
99
98
  const toVariableSafeChar = (char) => {
100
99
  if (/[a-zA-Z0-9_]/.test(char)) {
101
100
  return char;
@@ -120,10 +119,10 @@ function routePathToVariable(routePath) {
120
119
  return `Char${char.charCodeAt(0)}`;
121
120
  }
122
121
  };
123
- return ((_a = removeUnderscores(routePath)) == null ? void 0 : _a.replace(/\/\$\//g, "/splat/").replace(/\$$/g, "splat").replace(/\$\{\$\}/g, "splat").replace(/\$/g, "").split(/[/-]/g).map((d, i) => i > 0 ? capitalize(d) : d).join("").split("").map(toVariableSafeChar).join("").replace(/^(\d)/g, "R$1")) ?? "";
122
+ return removeUnderscores(routePath)?.replace(/\/\$\//g, "/splat/").replace(/\$$/g, "splat").replace(/\$\{\$\}/g, "splat").replace(/\$/g, "").split(/[/-]/g).map((d, i) => i > 0 ? capitalize(d) : d).join("").split("").map(toVariableSafeChar).join("").replace(/^(\d)/g, "R$1") ?? "";
124
123
  }
125
124
  function removeUnderscores(s) {
126
- return s == null ? void 0 : s.replaceAll(/(^_|_$)/gi, "").replaceAll(/(\/_|_\/)/gi, "/");
125
+ return s?.replaceAll(/(^_|_$)/gi, "").replaceAll(/(\/_|_\/)/gi, "/");
127
126
  }
128
127
  function capitalize(s) {
129
128
  if (typeof s !== "string") return "";
@@ -133,11 +132,10 @@ function removeExt(d, keepExtension = false) {
133
132
  return keepExtension ? d : d.substring(0, d.lastIndexOf(".")) || d;
134
133
  }
135
134
  async function writeIfDifferent(filepath, content, incomingContent, callbacks) {
136
- var _a, _b;
137
135
  if (content !== incomingContent) {
138
- (_a = callbacks == null ? void 0 : callbacks.beforeWrite) == null ? void 0 : _a.call(callbacks);
136
+ callbacks?.beforeWrite?.();
139
137
  await fsp__namespace.writeFile(filepath, incomingContent);
140
- (_b = callbacks == null ? void 0 : callbacks.afterWrite) == null ? void 0 : _b.call(callbacks);
138
+ callbacks?.afterWrite?.();
141
139
  return true;
142
140
  }
143
141
  return false;
@@ -172,8 +170,7 @@ function removeLayoutSegments(routePath = "/") {
172
170
  return newSegments.join("/");
173
171
  }
174
172
  function determineNodePath(node) {
175
- var _a;
176
- return node.path = node.parent ? ((_a = node.routePath) == null ? void 0 : _a.replace(node.parent.routePath ?? "", "")) || "/" : node.routePath;
173
+ return node.path = node.parent ? node.routePath?.replace(node.parent.routePath ?? "", "") || "/" : node.routePath;
177
174
  }
178
175
  function removeLastSegmentFromPath(routePath = "/") {
179
176
  const segments = routePath.split("/");
@@ -200,8 +197,7 @@ function hasParentRoute(routes, node, routePathToCheck) {
200
197
  return hasParentRoute(routes, node, parentRoutePath);
201
198
  }
202
199
  const getResolvedRouteNodeVariableName = (routeNode, variableNameSuffix) => {
203
- var _a;
204
- return ((_a = routeNode.children) == null ? void 0 : _a.length) ? `${routeNode.variableName}${variableNameSuffix}WithChildren` : `${routeNode.variableName}${variableNameSuffix}`;
200
+ return routeNode.children?.length ? `${routeNode.variableName}${variableNameSuffix}WithChildren` : `${routeNode.variableName}${variableNameSuffix}`;
205
201
  };
206
202
  function isRouteNodeValidForAugmentation(routeNode) {
207
203
  if (!routeNode || routeNode.isVirtual) {
@@ -210,8 +206,7 @@ function isRouteNodeValidForAugmentation(routeNode) {
210
206
  return true;
211
207
  }
212
208
  const inferPath = (routeNode) => {
213
- var _a;
214
- return routeNode.cleanedPath === "/" ? routeNode.cleanedPath : ((_a = routeNode.cleanedPath) == null ? void 0 : _a.replace(/\/$/, "")) ?? "";
209
+ return routeNode.cleanedPath === "/" ? routeNode.cleanedPath : routeNode.cleanedPath?.replace(/\/$/, "") ?? "";
215
210
  };
216
211
  const inferFullPath = (routeNode) => {
217
212
  const fullPath = removeGroups(
@@ -247,8 +242,7 @@ const inferTo = (routeNode) => {
247
242
  };
248
243
  const dedupeBranchesAndIndexRoutes = (routes) => {
249
244
  return routes.filter((route) => {
250
- var _a;
251
- if ((_a = route.children) == null ? void 0 : _a.find((child) => child.cleanedPath === "/")) return false;
245
+ if (route.children?.find((child) => child.cleanedPath === "/")) return false;
252
246
  return true;
253
247
  });
254
248
  };
@@ -280,16 +274,15 @@ Conflicting files:
280
274
  }
281
275
  }
282
276
  function buildRouteTreeConfig(nodes, exportName, disableTypes, depth = 1) {
283
- const children = nodes.map((node) => {
284
- var _a, _b;
277
+ const children = nodes.filter((n) => n.exports?.includes(exportName)).map((node) => {
285
278
  if (node._fsRouteType === "__root") {
286
279
  return;
287
280
  }
288
- if (node._fsRouteType === "pathless_layout" && !((_a = node.children) == null ? void 0 : _a.length)) {
281
+ if (node._fsRouteType === "pathless_layout" && !node.children?.length) {
289
282
  return;
290
283
  }
291
284
  const route = `${node.variableName}`;
292
- if ((_b = node.children) == null ? void 0 : _b.length) {
285
+ if (node.children?.length) {
293
286
  const childConfigs = buildRouteTreeConfig(
294
287
  node.children,
295
288
  exportName,
@@ -297,10 +290,14 @@ function buildRouteTreeConfig(nodes, exportName, disableTypes, depth = 1) {
297
290
  depth + 1
298
291
  );
299
292
  const childrenDeclaration = disableTypes ? "" : `interface ${route}${exportName}Children {
300
- ${node.children.map((child) => `${child.variableName}${exportName}: typeof ${getResolvedRouteNodeVariableName(child, exportName)}`).join(",")}
293
+ ${node.children.filter((n) => n.exports?.includes(exportName)).map(
294
+ (child) => `${child.variableName}${exportName}: typeof ${getResolvedRouteNodeVariableName(child, exportName)}`
295
+ ).join(",")}
301
296
  }`;
302
297
  const children2 = `const ${route}${exportName}Children${disableTypes ? "" : `: ${route}${exportName}Children`} = {
303
- ${node.children.map((child) => `${child.variableName}${exportName}: ${getResolvedRouteNodeVariableName(child, exportName)}`).join(",")}
298
+ ${node.children.filter((n) => n.exports?.includes(exportName)).map(
299
+ (child) => `${child.variableName}${exportName}: ${getResolvedRouteNodeVariableName(child, exportName)}`
300
+ ).join(",")}
304
301
  }`;
305
302
  const routeWithChildren = `const ${route}${exportName}WithChildren = ${route}${exportName}._addFileChildren(${route}${exportName}Children)`;
306
303
  return [
@@ -342,16 +339,14 @@ function mergeImportDeclarations(imports) {
342
339
  return Object.values(merged);
343
340
  }
344
341
  function hasChildWithExport(node, exportName) {
345
- var _a;
346
- return ((_a = node.children) == null ? void 0 : _a.some((child) => hasChildWithExport(child))) ?? false;
342
+ return node.children?.some((child) => hasChildWithExport(child)) ?? false;
347
343
  }
348
344
  const findParent = (node, exportName) => {
349
- var _a;
350
345
  if (!node) {
351
346
  return `root${exportName}Import`;
352
347
  }
353
348
  if (node.parent) {
354
- if ((_a = node.parent.exports) == null ? void 0 : _a.includes(exportName)) {
349
+ if (node.parent.exports?.includes(exportName)) {
355
350
  if (node.isVirtualParentRequired) {
356
351
  return `${node.parent.variableName}${exportName}`;
357
352
  } else {
@@ -361,6 +356,30 @@ const findParent = (node, exportName) => {
361
356
  }
362
357
  return findParent(node.parent, exportName);
363
358
  };
359
+ function buildFileRoutesByPathInterface(opts) {
360
+ return `declare module '${opts.module}' {
361
+ interface ${opts.interfaceName} {
362
+ ${opts.routeNodes.map((routeNode) => {
363
+ const filePathId = routeNode.routePath;
364
+ let preloaderRoute = "";
365
+ if (routeNode.exports?.includes(opts.exportName)) {
366
+ preloaderRoute = `typeof ${routeNode.variableName}${opts.exportName}Import`;
367
+ } else {
368
+ preloaderRoute = "unknown";
369
+ }
370
+ const parent = findParent(routeNode, opts.exportName);
371
+ return `'${filePathId}': {
372
+ id: '${filePathId}'
373
+ path: '${inferPath(routeNode)}'
374
+ fullPath: '${inferFullPath(routeNode)}'
375
+ preLoaderRoute: ${preloaderRoute}
376
+ parentRoute: typeof ${parent}
377
+ }`;
378
+ }).join("\n")}
379
+ }
380
+ }`;
381
+ }
382
+ exports.buildFileRoutesByPathInterface = buildFileRoutesByPathInterface;
364
383
  exports.buildImportString = buildImportString;
365
384
  exports.buildRouteTreeConfig = buildRouteTreeConfig;
366
385
  exports.capitalize = capitalize;
@@ -1 +1 @@
1
- {"version":3,"file":"utils.cjs","sources":["../../src/utils.ts"],"sourcesContent":["import * as fsp from 'node:fs/promises'\nimport path from 'node:path'\nimport * as prettier from 'prettier'\nimport { rootPathId } from './filesystem/physical/rootPathId'\nimport type { Config } from './config'\nimport type { ImportDeclaration, RouteNode } from './types'\n\nexport function multiSortBy<T>(\n arr: Array<T>,\n accessors: Array<(item: T) => any> = [(d) => d],\n): Array<T> {\n return arr\n .map((d, i) => [d, i] as const)\n .sort(([a, ai], [b, bi]) => {\n for (const accessor of accessors) {\n const ao = accessor(a)\n const bo = accessor(b)\n\n if (typeof ao === 'undefined') {\n if (typeof bo === 'undefined') {\n continue\n }\n return 1\n }\n\n if (ao === bo) {\n continue\n }\n\n return ao > bo ? 1 : -1\n }\n\n return ai - bi\n })\n .map(([d]) => d)\n}\n\nexport function cleanPath(path: string) {\n // remove double slashes\n return path.replace(/\\/{2,}/g, '/')\n}\n\nexport function trimPathLeft(path: string) {\n return path === '/' ? path : path.replace(/^\\/{1,}/, '')\n}\n\nexport function removeLeadingSlash(path: string): string {\n return path.replace(/^\\//, '')\n}\n\nexport function removeTrailingSlash(s: string) {\n return s.replace(/\\/$/, '')\n}\n\nexport function determineInitialRoutePath(routePath: string) {\n const DISALLOWED_ESCAPE_CHARS = new Set([\n '/',\n '\\\\',\n '?',\n '#',\n ':',\n '*',\n '<',\n '>',\n '|',\n '!',\n '$',\n '%',\n ])\n\n const parts = routePath.split(/(?<!\\[)\\.(?!\\])/g)\n\n // Escape any characters that in square brackets\n const escapedParts = parts.map((part) => {\n // Check if any disallowed characters are used in brackets\n const BRACKET_CONTENT_RE = /\\[(.*?)\\]/g\n\n let match\n while ((match = BRACKET_CONTENT_RE.exec(part)) !== null) {\n const character = match[1]\n if (character === undefined) continue\n if (DISALLOWED_ESCAPE_CHARS.has(character)) {\n console.error(\n `Error: Disallowed character \"${character}\" found in square brackets in route path \"${routePath}\".\\nYou cannot use any of the following characters in square brackets: ${Array.from(\n DISALLOWED_ESCAPE_CHARS,\n ).join(', ')}\\nPlease remove and/or replace them.`,\n )\n process.exit(1)\n }\n }\n\n // Since this split segment is safe at this point, we can\n // remove the brackets and replace them with the content inside\n return part.replace(/\\[(.)\\]/g, '$1')\n })\n\n // If the syntax for prefix/suffix is different, from the path\n // matching internals of router-core, we'd perform those changes here\n // on the `escapedParts` array before it is joined back together in\n // `final`\n\n const final = cleanPath(`/${escapedParts.join('/')}`) || ''\n\n return final\n}\n\nexport function replaceBackslash(s: string) {\n return s.replaceAll(/\\\\/gi, '/')\n}\n\nexport function routePathToVariable(routePath: string): string {\n const toVariableSafeChar = (char: string): string => {\n if (/[a-zA-Z0-9_]/.test(char)) {\n return char // Keep alphanumeric characters and underscores as is\n }\n\n // Replace special characters with meaningful text equivalents\n switch (char) {\n case '.':\n return 'Dot'\n case '-':\n return 'Dash'\n case '@':\n return 'At'\n case '(':\n return '' // Removed since route groups use parentheses\n case ')':\n return '' // Removed since route groups use parentheses\n case ' ':\n return '' // Remove spaces\n default:\n return `Char${char.charCodeAt(0)}` // For any other characters\n }\n }\n\n return (\n removeUnderscores(routePath)\n ?.replace(/\\/\\$\\//g, '/splat/')\n .replace(/\\$$/g, 'splat')\n .replace(/\\$\\{\\$\\}/g, 'splat')\n .replace(/\\$/g, '')\n .split(/[/-]/g)\n .map((d, i) => (i > 0 ? capitalize(d) : d))\n .join('')\n .split('')\n .map(toVariableSafeChar)\n .join('')\n // .replace(/([^a-zA-Z0-9]|[.])/gm, '')\n .replace(/^(\\d)/g, 'R$1') ?? ''\n )\n}\n\nexport function removeUnderscores(s?: string) {\n return s?.replaceAll(/(^_|_$)/gi, '').replaceAll(/(\\/_|_\\/)/gi, '/')\n}\n\nexport function capitalize(s: string) {\n if (typeof s !== 'string') return ''\n return s.charAt(0).toUpperCase() + s.slice(1)\n}\n\nexport function removeExt(d: string, keepExtension: boolean = false) {\n return keepExtension ? d : d.substring(0, d.lastIndexOf('.')) || d\n}\n\n/**\n * This function writes to a file if the content is different.\n *\n * @param filepath The path to the file\n * @param content Original content\n * @param incomingContent New content\n * @param callbacks Callbacks to run before and after writing\n * @returns Whether the file was written\n */\nexport async function writeIfDifferent(\n filepath: string,\n content: string,\n incomingContent: string,\n callbacks?: { beforeWrite?: () => void; afterWrite?: () => void },\n): Promise<boolean> {\n if (content !== incomingContent) {\n callbacks?.beforeWrite?.()\n await fsp.writeFile(filepath, incomingContent)\n callbacks?.afterWrite?.()\n return true\n }\n return false\n}\n\n/**\n * This function formats the source code using the default formatter (Prettier).\n *\n * @param source The content to format\n * @param config The configuration object\n * @returns The formatted content\n */\nexport async function format(\n source: string,\n config: {\n quoteStyle: 'single' | 'double'\n semicolons: boolean\n },\n): Promise<string> {\n const prettierOptions: prettier.Config = {\n semi: config.semicolons,\n singleQuote: config.quoteStyle === 'single',\n parser: 'typescript',\n }\n return prettier.format(source, prettierOptions)\n}\n\n/**\n * This function resets the regex index to 0 so that it can be reused\n * without having to create a new regex object or worry about the last\n * state when using the global flag.\n *\n * @param regex The regex object to reset\n * @returns\n */\nexport function resetRegex(regex: RegExp) {\n regex.lastIndex = 0\n return\n}\n\n/**\n * This function checks if a file exists.\n *\n * @param file The path to the file\n * @returns Whether the file exists\n */\nexport async function checkFileExists(file: string) {\n try {\n await fsp.access(file, fsp.constants.F_OK)\n return true\n } catch {\n return false\n }\n}\n\nconst possiblyNestedRouteGroupPatternRegex = /\\([^/]+\\)\\/?/g\nexport function removeGroups(s: string) {\n return s.replace(possiblyNestedRouteGroupPatternRegex, '')\n}\n\n/**\n * Removes all segments from a given path that start with an underscore ('_').\n *\n * @param {string} routePath - The path from which to remove segments. Defaults to '/'.\n * @returns {string} The path with all underscore-prefixed segments removed.\n * @example\n * removeLayoutSegments('/workspace/_auth/foo') // '/workspace/foo'\n */\nexport function removeLayoutSegments(routePath: string = '/'): string {\n const segments = routePath.split('/')\n const newSegments = segments.filter((segment) => !segment.startsWith('_'))\n return newSegments.join('/')\n}\n\n/**\n * The `node.path` is used as the `id` in the route definition.\n * This function checks if the given node has a parent and if so, it determines the correct path for the given node.\n * @param node - The node to determine the path for.\n * @returns The correct path for the given node.\n */\nexport function determineNodePath(node: RouteNode) {\n return (node.path = node.parent\n ? node.routePath?.replace(node.parent.routePath ?? '', '') || '/'\n : node.routePath)\n}\n\n/**\n * Removes the last segment from a given path. Segments are considered to be separated by a '/'.\n *\n * @param {string} routePath - The path from which to remove the last segment. Defaults to '/'.\n * @returns {string} The path with the last segment removed.\n * @example\n * removeLastSegmentFromPath('/workspace/_auth/foo') // '/workspace/_auth'\n */\nexport function removeLastSegmentFromPath(routePath: string = '/'): string {\n const segments = routePath.split('/')\n segments.pop() // Remove the last segment\n return segments.join('/')\n}\n\nexport function hasParentRoute(\n routes: Array<RouteNode>,\n node: RouteNode,\n routePathToCheck: string | undefined,\n): RouteNode | null {\n if (!routePathToCheck || routePathToCheck === '/') {\n return null\n }\n\n const sortedNodes = multiSortBy(routes, [\n (d) => d.routePath!.length * -1,\n (d) => d.variableName,\n ]).filter((d) => d.routePath !== `/${rootPathId}`)\n\n for (const route of sortedNodes) {\n if (route.routePath === '/') continue\n\n if (\n routePathToCheck.startsWith(`${route.routePath}/`) &&\n route.routePath !== routePathToCheck\n ) {\n return route\n }\n }\n\n const segments = routePathToCheck.split('/')\n segments.pop() // Remove the last segment\n const parentRoutePath = segments.join('/')\n\n return hasParentRoute(routes, node, parentRoutePath)\n}\n\n/**\n * Gets the final variable name for a route\n */\nexport const getResolvedRouteNodeVariableName = (\n routeNode: RouteNode,\n variableNameSuffix: string,\n): string => {\n return routeNode.children?.length\n ? `${routeNode.variableName}${variableNameSuffix}WithChildren`\n : `${routeNode.variableName}${variableNameSuffix}`\n}\n\n/**\n * Checks if a given RouteNode is valid for augmenting it with typing based on conditions.\n * Also asserts that the RouteNode is defined.\n *\n * @param routeNode - The RouteNode to check.\n * @returns A boolean indicating whether the RouteNode is defined.\n */\nexport function isRouteNodeValidForAugmentation(\n routeNode?: RouteNode,\n): routeNode is RouteNode {\n if (!routeNode || routeNode.isVirtual) {\n return false\n }\n return true\n}\n\n/**\n * Infers the path for use by TS\n */\nexport const inferPath = (routeNode: RouteNode): string => {\n return routeNode.cleanedPath === '/'\n ? routeNode.cleanedPath\n : (routeNode.cleanedPath?.replace(/\\/$/, '') ?? '')\n}\n\n/**\n * Infers the full path for use by TS\n */\nexport const inferFullPath = (routeNode: RouteNode): string => {\n const fullPath = removeGroups(\n removeUnderscores(removeLayoutSegments(routeNode.routePath)) ?? '',\n )\n\n return routeNode.cleanedPath === '/' ? fullPath : fullPath.replace(/\\/$/, '')\n}\n\n/**\n * Creates a map from fullPath to routeNode\n */\nexport const createRouteNodesByFullPath = (\n routeNodes: Array<RouteNode>,\n): Map<string, RouteNode> => {\n return new Map(\n routeNodes.map((routeNode) => [inferFullPath(routeNode), routeNode]),\n )\n}\n\n/**\n * Create a map from 'to' to a routeNode\n */\nexport const createRouteNodesByTo = (\n routeNodes: Array<RouteNode>,\n): Map<string, RouteNode> => {\n return new Map(\n dedupeBranchesAndIndexRoutes(routeNodes).map((routeNode) => [\n inferTo(routeNode),\n routeNode,\n ]),\n )\n}\n\n/**\n * Create a map from 'id' to a routeNode\n */\nexport const createRouteNodesById = (\n routeNodes: Array<RouteNode>,\n): Map<string, RouteNode> => {\n return new Map(\n routeNodes.map((routeNode) => {\n const id = routeNode.routePath ?? ''\n return [id, routeNode]\n }),\n )\n}\n\n/**\n * Infers to path\n */\nexport const inferTo = (routeNode: RouteNode): string => {\n const fullPath = inferFullPath(routeNode)\n\n if (fullPath === '/') return fullPath\n\n return fullPath.replace(/\\/$/, '')\n}\n\n/**\n * Dedupes branches and index routes\n */\nexport const dedupeBranchesAndIndexRoutes = (\n routes: Array<RouteNode>,\n): Array<RouteNode> => {\n return routes.filter((route) => {\n if (route.children?.find((child) => child.cleanedPath === '/')) return false\n return true\n })\n}\n\nfunction checkUnique<TElement>(routes: Array<TElement>, key: keyof TElement) {\n // Check no two routes have the same `key`\n // if they do, throw an error with the conflicting filePaths\n const keys = routes.map((d) => d[key])\n const uniqueKeys = new Set(keys)\n if (keys.length !== uniqueKeys.size) {\n const duplicateKeys = keys.filter((d, i) => keys.indexOf(d) !== i)\n const conflictingFiles = routes.filter((d) =>\n duplicateKeys.includes(d[key]),\n )\n return conflictingFiles\n }\n return undefined\n}\n\nexport function checkRouteFullPathUniqueness(\n _routes: Array<RouteNode>,\n config: Config,\n) {\n const routes = _routes.map((d) => {\n const inferredFullPath = inferFullPath(d)\n return { ...d, inferredFullPath }\n })\n\n const conflictingFiles = checkUnique(routes, 'inferredFullPath')\n\n if (conflictingFiles !== undefined) {\n const errorMessage = `Conflicting configuration paths were found for the following route${conflictingFiles.length > 1 ? 's' : ''}: ${conflictingFiles\n .map((p) => `\"${p.inferredFullPath}\"`)\n .join(', ')}.\nPlease ensure each Route has a unique full path.\nConflicting files: \\n ${conflictingFiles.map((d) => path.resolve(config.routesDirectory, d.filePath)).join('\\n ')}\\n`\n throw new Error(errorMessage)\n }\n}\n\nexport function buildRouteTreeConfig(\n nodes: Array<RouteNode>,\n exportName: string,\n disableTypes: boolean,\n depth = 1,\n): Array<string> {\n const children = nodes.map((node) => {\n if (node._fsRouteType === '__root') {\n return\n }\n\n if (node._fsRouteType === 'pathless_layout' && !node.children?.length) {\n return\n }\n\n const route = `${node.variableName}`\n\n if (node.children?.length) {\n const childConfigs = buildRouteTreeConfig(\n node.children,\n exportName,\n disableTypes,\n depth + 1,\n )\n\n const childrenDeclaration = disableTypes\n ? ''\n : `interface ${route}${exportName}Children {\n ${node.children.map((child) => `${child.variableName}${exportName}: typeof ${getResolvedRouteNodeVariableName(child, exportName)}`).join(',')}\n}`\n\n const children = `const ${route}${exportName}Children${disableTypes ? '' : `: ${route}${exportName}Children`} = {\n ${node.children.map((child) => `${child.variableName}${exportName}: ${getResolvedRouteNodeVariableName(child, exportName)}`).join(',')}\n}`\n\n const routeWithChildren = `const ${route}${exportName}WithChildren = ${route}${exportName}._addFileChildren(${route}${exportName}Children)`\n\n return [\n childConfigs.join('\\n'),\n childrenDeclaration,\n children,\n routeWithChildren,\n ].join('\\n\\n')\n }\n\n return undefined\n })\n\n return children.filter((x) => x !== undefined)\n}\n\nexport function buildImportString(\n importDeclaration: ImportDeclaration,\n): string {\n const { source, specifiers, importKind } = importDeclaration\n return specifiers.length\n ? `import ${importKind === 'type' ? 'type ' : ''}{ ${specifiers.map((s) => (s.local ? `${s.imported} as ${s.local}` : s.imported)).join(', ')} } from '${source}'`\n : ''\n}\n\nexport function lowerCaseFirstChar(value: string) {\n if (!value[0]) {\n return value\n }\n\n return value[0].toLowerCase() + value.slice(1)\n}\n\nexport function mergeImportDeclarations(\n imports: Array<ImportDeclaration>,\n): Array<ImportDeclaration> {\n const merged: Record<string, ImportDeclaration> = {}\n\n for (const imp of imports) {\n const key = `${imp.source}-${imp.importKind}`\n if (!merged[key]) {\n merged[key] = { ...imp, specifiers: [] }\n }\n for (const specifier of imp.specifiers) {\n // check if the specifier already exists in the merged import\n if (\n !merged[key].specifiers.some(\n (existing) =>\n existing.imported === specifier.imported &&\n existing.local === specifier.local,\n )\n ) {\n merged[key].specifiers.push(specifier)\n }\n }\n }\n\n return Object.values(merged)\n}\n\nexport function hasChildWithExport(\n node: RouteNode,\n exportName: string,\n): boolean {\n return (\n node.children?.some((child) => hasChildWithExport(child, exportName)) ??\n false\n )\n}\n\nexport const findParent = (\n node: RouteNode | undefined,\n exportName: string,\n): string => {\n if (!node) {\n return `root${exportName}Import`\n }\n if (node.parent) {\n if (node.parent.exports?.includes(exportName)) {\n if (node.isVirtualParentRequired) {\n return `${node.parent.variableName}${exportName}`\n } else {\n return `${node.parent.variableName}${exportName}`\n }\n }\n }\n return findParent(node.parent, exportName)\n}\n"],"names":["path","fsp","prettier","rootPathId","children"],"mappings":"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"}
1
+ {"version":3,"file":"utils.cjs","sources":["../../src/utils.ts"],"sourcesContent":["import * as fsp from 'node:fs/promises'\nimport path from 'node:path'\nimport * as prettier from 'prettier'\nimport { rootPathId } from './filesystem/physical/rootPathId'\nimport type { Config } from './config'\nimport type { ImportDeclaration, RouteNode } from './types'\n\nexport function multiSortBy<T>(\n arr: Array<T>,\n accessors: Array<(item: T) => any> = [(d) => d],\n): Array<T> {\n return arr\n .map((d, i) => [d, i] as const)\n .sort(([a, ai], [b, bi]) => {\n for (const accessor of accessors) {\n const ao = accessor(a)\n const bo = accessor(b)\n\n if (typeof ao === 'undefined') {\n if (typeof bo === 'undefined') {\n continue\n }\n return 1\n }\n\n if (ao === bo) {\n continue\n }\n\n return ao > bo ? 1 : -1\n }\n\n return ai - bi\n })\n .map(([d]) => d)\n}\n\nexport function cleanPath(path: string) {\n // remove double slashes\n return path.replace(/\\/{2,}/g, '/')\n}\n\nexport function trimPathLeft(path: string) {\n return path === '/' ? path : path.replace(/^\\/{1,}/, '')\n}\n\nexport function removeLeadingSlash(path: string): string {\n return path.replace(/^\\//, '')\n}\n\nexport function removeTrailingSlash(s: string) {\n return s.replace(/\\/$/, '')\n}\n\nexport function determineInitialRoutePath(routePath: string) {\n const DISALLOWED_ESCAPE_CHARS = new Set([\n '/',\n '\\\\',\n '?',\n '#',\n ':',\n '*',\n '<',\n '>',\n '|',\n '!',\n '$',\n '%',\n ])\n\n const parts = routePath.split(/(?<!\\[)\\.(?!\\])/g)\n\n // Escape any characters that in square brackets\n const escapedParts = parts.map((part) => {\n // Check if any disallowed characters are used in brackets\n const BRACKET_CONTENT_RE = /\\[(.*?)\\]/g\n\n let match\n while ((match = BRACKET_CONTENT_RE.exec(part)) !== null) {\n const character = match[1]\n if (character === undefined) continue\n if (DISALLOWED_ESCAPE_CHARS.has(character)) {\n console.error(\n `Error: Disallowed character \"${character}\" found in square brackets in route path \"${routePath}\".\\nYou cannot use any of the following characters in square brackets: ${Array.from(\n DISALLOWED_ESCAPE_CHARS,\n ).join(', ')}\\nPlease remove and/or replace them.`,\n )\n process.exit(1)\n }\n }\n\n // Since this split segment is safe at this point, we can\n // remove the brackets and replace them with the content inside\n return part.replace(/\\[(.)\\]/g, '$1')\n })\n\n // If the syntax for prefix/suffix is different, from the path\n // matching internals of router-core, we'd perform those changes here\n // on the `escapedParts` array before it is joined back together in\n // `final`\n\n const final = cleanPath(`/${escapedParts.join('/')}`) || ''\n\n return final\n}\n\nexport function replaceBackslash(s: string) {\n return s.replaceAll(/\\\\/gi, '/')\n}\n\nexport function routePathToVariable(routePath: string): string {\n const toVariableSafeChar = (char: string): string => {\n if (/[a-zA-Z0-9_]/.test(char)) {\n return char // Keep alphanumeric characters and underscores as is\n }\n\n // Replace special characters with meaningful text equivalents\n switch (char) {\n case '.':\n return 'Dot'\n case '-':\n return 'Dash'\n case '@':\n return 'At'\n case '(':\n return '' // Removed since route groups use parentheses\n case ')':\n return '' // Removed since route groups use parentheses\n case ' ':\n return '' // Remove spaces\n default:\n return `Char${char.charCodeAt(0)}` // For any other characters\n }\n }\n\n return (\n removeUnderscores(routePath)\n ?.replace(/\\/\\$\\//g, '/splat/')\n .replace(/\\$$/g, 'splat')\n .replace(/\\$\\{\\$\\}/g, 'splat')\n .replace(/\\$/g, '')\n .split(/[/-]/g)\n .map((d, i) => (i > 0 ? capitalize(d) : d))\n .join('')\n .split('')\n .map(toVariableSafeChar)\n .join('')\n // .replace(/([^a-zA-Z0-9]|[.])/gm, '')\n .replace(/^(\\d)/g, 'R$1') ?? ''\n )\n}\n\nexport function removeUnderscores(s?: string) {\n return s?.replaceAll(/(^_|_$)/gi, '').replaceAll(/(\\/_|_\\/)/gi, '/')\n}\n\nexport function capitalize(s: string) {\n if (typeof s !== 'string') return ''\n return s.charAt(0).toUpperCase() + s.slice(1)\n}\n\nexport function removeExt(d: string, keepExtension: boolean = false) {\n return keepExtension ? d : d.substring(0, d.lastIndexOf('.')) || d\n}\n\n/**\n * This function writes to a file if the content is different.\n *\n * @param filepath The path to the file\n * @param content Original content\n * @param incomingContent New content\n * @param callbacks Callbacks to run before and after writing\n * @returns Whether the file was written\n */\nexport async function writeIfDifferent(\n filepath: string,\n content: string,\n incomingContent: string,\n callbacks?: { beforeWrite?: () => void; afterWrite?: () => void },\n): Promise<boolean> {\n if (content !== incomingContent) {\n callbacks?.beforeWrite?.()\n await fsp.writeFile(filepath, incomingContent)\n callbacks?.afterWrite?.()\n return true\n }\n return false\n}\n\n/**\n * This function formats the source code using the default formatter (Prettier).\n *\n * @param source The content to format\n * @param config The configuration object\n * @returns The formatted content\n */\nexport async function format(\n source: string,\n config: {\n quoteStyle: 'single' | 'double'\n semicolons: boolean\n },\n): Promise<string> {\n const prettierOptions: prettier.Config = {\n semi: config.semicolons,\n singleQuote: config.quoteStyle === 'single',\n parser: 'typescript',\n }\n return prettier.format(source, prettierOptions)\n}\n\n/**\n * This function resets the regex index to 0 so that it can be reused\n * without having to create a new regex object or worry about the last\n * state when using the global flag.\n *\n * @param regex The regex object to reset\n * @returns\n */\nexport function resetRegex(regex: RegExp) {\n regex.lastIndex = 0\n return\n}\n\n/**\n * This function checks if a file exists.\n *\n * @param file The path to the file\n * @returns Whether the file exists\n */\nexport async function checkFileExists(file: string) {\n try {\n await fsp.access(file, fsp.constants.F_OK)\n return true\n } catch {\n return false\n }\n}\n\nconst possiblyNestedRouteGroupPatternRegex = /\\([^/]+\\)\\/?/g\nexport function removeGroups(s: string) {\n return s.replace(possiblyNestedRouteGroupPatternRegex, '')\n}\n\n/**\n * Removes all segments from a given path that start with an underscore ('_').\n *\n * @param {string} routePath - The path from which to remove segments. Defaults to '/'.\n * @returns {string} The path with all underscore-prefixed segments removed.\n * @example\n * removeLayoutSegments('/workspace/_auth/foo') // '/workspace/foo'\n */\nexport function removeLayoutSegments(routePath: string = '/'): string {\n const segments = routePath.split('/')\n const newSegments = segments.filter((segment) => !segment.startsWith('_'))\n return newSegments.join('/')\n}\n\n/**\n * The `node.path` is used as the `id` in the route definition.\n * This function checks if the given node has a parent and if so, it determines the correct path for the given node.\n * @param node - The node to determine the path for.\n * @returns The correct path for the given node.\n */\nexport function determineNodePath(node: RouteNode) {\n return (node.path = node.parent\n ? node.routePath?.replace(node.parent.routePath ?? '', '') || '/'\n : node.routePath)\n}\n\n/**\n * Removes the last segment from a given path. Segments are considered to be separated by a '/'.\n *\n * @param {string} routePath - The path from which to remove the last segment. Defaults to '/'.\n * @returns {string} The path with the last segment removed.\n * @example\n * removeLastSegmentFromPath('/workspace/_auth/foo') // '/workspace/_auth'\n */\nexport function removeLastSegmentFromPath(routePath: string = '/'): string {\n const segments = routePath.split('/')\n segments.pop() // Remove the last segment\n return segments.join('/')\n}\n\nexport function hasParentRoute(\n routes: Array<RouteNode>,\n node: RouteNode,\n routePathToCheck: string | undefined,\n): RouteNode | null {\n if (!routePathToCheck || routePathToCheck === '/') {\n return null\n }\n\n const sortedNodes = multiSortBy(routes, [\n (d) => d.routePath!.length * -1,\n (d) => d.variableName,\n ]).filter((d) => d.routePath !== `/${rootPathId}`)\n\n for (const route of sortedNodes) {\n if (route.routePath === '/') continue\n\n if (\n routePathToCheck.startsWith(`${route.routePath}/`) &&\n route.routePath !== routePathToCheck\n ) {\n return route\n }\n }\n\n const segments = routePathToCheck.split('/')\n segments.pop() // Remove the last segment\n const parentRoutePath = segments.join('/')\n\n return hasParentRoute(routes, node, parentRoutePath)\n}\n\n/**\n * Gets the final variable name for a route\n */\nexport const getResolvedRouteNodeVariableName = (\n routeNode: RouteNode,\n variableNameSuffix: string,\n): string => {\n return routeNode.children?.length\n ? `${routeNode.variableName}${variableNameSuffix}WithChildren`\n : `${routeNode.variableName}${variableNameSuffix}`\n}\n\n/**\n * Checks if a given RouteNode is valid for augmenting it with typing based on conditions.\n * Also asserts that the RouteNode is defined.\n *\n * @param routeNode - The RouteNode to check.\n * @returns A boolean indicating whether the RouteNode is defined.\n */\nexport function isRouteNodeValidForAugmentation(\n routeNode?: RouteNode,\n): routeNode is RouteNode {\n if (!routeNode || routeNode.isVirtual) {\n return false\n }\n return true\n}\n\n/**\n * Infers the path for use by TS\n */\nexport const inferPath = (routeNode: RouteNode): string => {\n return routeNode.cleanedPath === '/'\n ? routeNode.cleanedPath\n : (routeNode.cleanedPath?.replace(/\\/$/, '') ?? '')\n}\n\n/**\n * Infers the full path for use by TS\n */\nexport const inferFullPath = (routeNode: RouteNode): string => {\n const fullPath = removeGroups(\n removeUnderscores(removeLayoutSegments(routeNode.routePath)) ?? '',\n )\n\n return routeNode.cleanedPath === '/' ? fullPath : fullPath.replace(/\\/$/, '')\n}\n\n/**\n * Creates a map from fullPath to routeNode\n */\nexport const createRouteNodesByFullPath = (\n routeNodes: Array<RouteNode>,\n): Map<string, RouteNode> => {\n return new Map(\n routeNodes.map((routeNode) => [inferFullPath(routeNode), routeNode]),\n )\n}\n\n/**\n * Create a map from 'to' to a routeNode\n */\nexport const createRouteNodesByTo = (\n routeNodes: Array<RouteNode>,\n): Map<string, RouteNode> => {\n return new Map(\n dedupeBranchesAndIndexRoutes(routeNodes).map((routeNode) => [\n inferTo(routeNode),\n routeNode,\n ]),\n )\n}\n\n/**\n * Create a map from 'id' to a routeNode\n */\nexport const createRouteNodesById = (\n routeNodes: Array<RouteNode>,\n): Map<string, RouteNode> => {\n return new Map(\n routeNodes.map((routeNode) => {\n const id = routeNode.routePath ?? ''\n return [id, routeNode]\n }),\n )\n}\n\n/**\n * Infers to path\n */\nexport const inferTo = (routeNode: RouteNode): string => {\n const fullPath = inferFullPath(routeNode)\n\n if (fullPath === '/') return fullPath\n\n return fullPath.replace(/\\/$/, '')\n}\n\n/**\n * Dedupes branches and index routes\n */\nexport const dedupeBranchesAndIndexRoutes = (\n routes: Array<RouteNode>,\n): Array<RouteNode> => {\n return routes.filter((route) => {\n if (route.children?.find((child) => child.cleanedPath === '/')) return false\n return true\n })\n}\n\nfunction checkUnique<TElement>(routes: Array<TElement>, key: keyof TElement) {\n // Check no two routes have the same `key`\n // if they do, throw an error with the conflicting filePaths\n const keys = routes.map((d) => d[key])\n const uniqueKeys = new Set(keys)\n if (keys.length !== uniqueKeys.size) {\n const duplicateKeys = keys.filter((d, i) => keys.indexOf(d) !== i)\n const conflictingFiles = routes.filter((d) =>\n duplicateKeys.includes(d[key]),\n )\n return conflictingFiles\n }\n return undefined\n}\n\nexport function checkRouteFullPathUniqueness(\n _routes: Array<RouteNode>,\n config: Config,\n) {\n const routes = _routes.map((d) => {\n const inferredFullPath = inferFullPath(d)\n return { ...d, inferredFullPath }\n })\n\n const conflictingFiles = checkUnique(routes, 'inferredFullPath')\n\n if (conflictingFiles !== undefined) {\n const errorMessage = `Conflicting configuration paths were found for the following route${conflictingFiles.length > 1 ? 's' : ''}: ${conflictingFiles\n .map((p) => `\"${p.inferredFullPath}\"`)\n .join(', ')}.\nPlease ensure each Route has a unique full path.\nConflicting files: \\n ${conflictingFiles.map((d) => path.resolve(config.routesDirectory, d.filePath)).join('\\n ')}\\n`\n throw new Error(errorMessage)\n }\n}\n\nexport function buildRouteTreeConfig(\n nodes: Array<RouteNode>,\n exportName: string,\n disableTypes: boolean,\n depth = 1,\n): Array<string> {\n const children = nodes\n .filter((n) => n.exports?.includes(exportName))\n .map((node) => {\n if (node._fsRouteType === '__root') {\n return\n }\n\n if (node._fsRouteType === 'pathless_layout' && !node.children?.length) {\n return\n }\n\n const route = `${node.variableName}`\n\n if (node.children?.length) {\n const childConfigs = buildRouteTreeConfig(\n node.children,\n exportName,\n disableTypes,\n depth + 1,\n )\n\n const childrenDeclaration = disableTypes\n ? ''\n : `interface ${route}${exportName}Children {\n ${node.children\n .filter((n) => n.exports?.includes(exportName))\n .map(\n (child) =>\n `${child.variableName}${exportName}: typeof ${getResolvedRouteNodeVariableName(child, exportName)}`,\n )\n .join(',')}\n}`\n\n const children = `const ${route}${exportName}Children${disableTypes ? '' : `: ${route}${exportName}Children`} = {\n ${node.children\n .filter((n) => n.exports?.includes(exportName))\n .map(\n (child) =>\n `${child.variableName}${exportName}: ${getResolvedRouteNodeVariableName(child, exportName)}`,\n )\n .join(',')}\n}`\n\n const routeWithChildren = `const ${route}${exportName}WithChildren = ${route}${exportName}._addFileChildren(${route}${exportName}Children)`\n\n return [\n childConfigs.join('\\n'),\n childrenDeclaration,\n children,\n routeWithChildren,\n ].join('\\n\\n')\n }\n\n return undefined\n })\n\n return children.filter((x) => x !== undefined)\n}\n\nexport function buildImportString(\n importDeclaration: ImportDeclaration,\n): string {\n const { source, specifiers, importKind } = importDeclaration\n return specifiers.length\n ? `import ${importKind === 'type' ? 'type ' : ''}{ ${specifiers.map((s) => (s.local ? `${s.imported} as ${s.local}` : s.imported)).join(', ')} } from '${source}'`\n : ''\n}\n\nexport function lowerCaseFirstChar(value: string) {\n if (!value[0]) {\n return value\n }\n\n return value[0].toLowerCase() + value.slice(1)\n}\n\nexport function mergeImportDeclarations(\n imports: Array<ImportDeclaration>,\n): Array<ImportDeclaration> {\n const merged: Record<string, ImportDeclaration> = {}\n\n for (const imp of imports) {\n const key = `${imp.source}-${imp.importKind}`\n if (!merged[key]) {\n merged[key] = { ...imp, specifiers: [] }\n }\n for (const specifier of imp.specifiers) {\n // check if the specifier already exists in the merged import\n if (\n !merged[key].specifiers.some(\n (existing) =>\n existing.imported === specifier.imported &&\n existing.local === specifier.local,\n )\n ) {\n merged[key].specifiers.push(specifier)\n }\n }\n }\n\n return Object.values(merged)\n}\n\nexport function hasChildWithExport(\n node: RouteNode,\n exportName: string,\n): boolean {\n return (\n node.children?.some((child) => hasChildWithExport(child, exportName)) ??\n false\n )\n}\n\nexport const findParent = (\n node: RouteNode | undefined,\n exportName: string,\n): string => {\n if (!node) {\n return `root${exportName}Import`\n }\n if (node.parent) {\n if (node.parent.exports?.includes(exportName)) {\n if (node.isVirtualParentRequired) {\n return `${node.parent.variableName}${exportName}`\n } else {\n return `${node.parent.variableName}${exportName}`\n }\n }\n }\n return findParent(node.parent, exportName)\n}\n\nexport function buildFileRoutesByPathInterface(opts: {\n routeNodes: Array<RouteNode>\n module: string\n interfaceName: string\n exportName: string\n}): string {\n return `declare module '${opts.module}' {\n interface ${opts.interfaceName} {\n ${opts.routeNodes\n .map((routeNode) => {\n const filePathId = routeNode.routePath\n let preloaderRoute = ''\n\n if (routeNode.exports?.includes(opts.exportName)) {\n preloaderRoute = `typeof ${routeNode.variableName}${opts.exportName}Import`\n } else {\n preloaderRoute = 'unknown'\n }\n\n const parent = findParent(routeNode, opts.exportName)\n\n return `'${filePathId}': {\n id: '${filePathId}'\n path: '${inferPath(routeNode)}'\n fullPath: '${inferFullPath(routeNode)}'\n preLoaderRoute: ${preloaderRoute}\n parentRoute: typeof ${parent}\n }`\n })\n .join('\\n')}\n }\n}`\n}\n"],"names":["path","fsp","prettier","rootPathId","children"],"mappings":"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"}
@@ -125,3 +125,9 @@ export declare function lowerCaseFirstChar(value: string): string;
125
125
  export declare function mergeImportDeclarations(imports: Array<ImportDeclaration>): Array<ImportDeclaration>;
126
126
  export declare function hasChildWithExport(node: RouteNode, exportName: string): boolean;
127
127
  export declare const findParent: (node: RouteNode | undefined, exportName: string) => string;
128
+ export declare function buildFileRoutesByPathInterface(opts: {
129
+ routeNodes: Array<RouteNode>;
130
+ module: string;
131
+ interfaceName: string;
132
+ exportName: string;
133
+ }): string;