@tanstack/router-generator 1.166.29 → 1.166.30

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 (47) hide show
  1. package/dist/cjs/config.cjs +0 -1
  2. package/dist/cjs/config.cjs.map +1 -1
  3. package/dist/cjs/config.d.cts +0 -3
  4. package/dist/cjs/generator.cjs +1 -44
  5. package/dist/cjs/generator.cjs.map +1 -1
  6. package/dist/cjs/index.cjs +0 -2
  7. package/dist/cjs/index.d.cts +1 -2
  8. package/dist/cjs/template.cjs +15 -12
  9. package/dist/cjs/template.cjs.map +1 -1
  10. package/dist/cjs/transform/transform.cjs +283 -266
  11. package/dist/cjs/transform/transform.cjs.map +1 -1
  12. package/dist/cjs/transform/transform.d.cts +1 -3
  13. package/dist/cjs/transform/types.d.cts +1 -7
  14. package/dist/cjs/utils.cjs +0 -16
  15. package/dist/cjs/utils.cjs.map +1 -1
  16. package/dist/cjs/utils.d.cts +0 -24
  17. package/dist/esm/config.d.ts +0 -3
  18. package/dist/esm/config.js +0 -1
  19. package/dist/esm/config.js.map +1 -1
  20. package/dist/esm/generator.js +2 -45
  21. package/dist/esm/generator.js.map +1 -1
  22. package/dist/esm/index.d.ts +1 -2
  23. package/dist/esm/index.js +1 -2
  24. package/dist/esm/template.js +15 -12
  25. package/dist/esm/template.js.map +1 -1
  26. package/dist/esm/transform/transform.d.ts +1 -3
  27. package/dist/esm/transform/transform.js +280 -265
  28. package/dist/esm/transform/transform.js.map +1 -1
  29. package/dist/esm/transform/types.d.ts +1 -7
  30. package/dist/esm/utils.d.ts +0 -24
  31. package/dist/esm/utils.js +1 -15
  32. package/dist/esm/utils.js.map +1 -1
  33. package/package.json +4 -4
  34. package/src/config.ts +0 -1
  35. package/src/generator.ts +0 -66
  36. package/src/index.ts +1 -7
  37. package/src/template.ts +16 -36
  38. package/src/transform/transform.ts +633 -446
  39. package/src/transform/types.ts +1 -8
  40. package/src/utils.ts +5 -43
  41. package/dist/cjs/transform/utils.cjs +0 -34
  42. package/dist/cjs/transform/utils.cjs.map +0 -1
  43. package/dist/cjs/transform/utils.d.cts +0 -2
  44. package/dist/esm/transform/utils.d.ts +0 -2
  45. package/dist/esm/transform/utils.js +0 -34
  46. package/dist/esm/transform/utils.js.map +0 -1
  47. package/src/transform/utils.ts +0 -42
@@ -1 +1 @@
1
- {"version":3,"file":"template.js","names":[],"sources":["../../src/template.ts"],"sourcesContent":["import { format } from './utils'\nimport type { Config } from './config'\n\ntype TemplateTag = 'tsrImports' | 'tsrPath' | 'tsrExportStart' | 'tsrExportEnd'\n\nexport function fillTemplate(\n config: Config,\n template: string,\n values: Record<TemplateTag, string>,\n) {\n const replaced = template.replace(\n /%%(\\w+)%%/g,\n (_, key) => values[key as TemplateTag] || '',\n )\n return format(replaced, config)\n}\n\nexport type TargetTemplate = {\n fullPkg: string\n subPkg: string\n rootRoute: {\n template: () => string\n imports: {\n tsrImports: () => string\n tsrExportStart: () => string\n tsrExportEnd: () => string\n }\n }\n route: {\n template: () => string\n imports: {\n tsrImports: () => string\n tsrExportStart: (routePath: string) => string\n tsrExportEnd: () => string\n }\n }\n lazyRoute: {\n template: () => string\n imports: {\n tsrImports: () => string\n tsrExportStart: (routePath: string) => string\n tsrExportEnd: () => string\n }\n }\n}\n\nexport function getTargetTemplate(config: Config): TargetTemplate {\n const target = config.target\n switch (target) {\n case 'react':\n return {\n fullPkg: '@tanstack/react-router',\n subPkg: 'react-router',\n rootRoute: {\n template: () =>\n [\n 'import * as React from \"react\"\\n',\n '%%tsrImports%%',\n '\\n\\n',\n '%%tsrExportStart%%{\\n component: RootComponent\\n }%%tsrExportEnd%%\\n\\n',\n 'function RootComponent() { return (<React.Fragment><div>Hello \"%%tsrPath%%\"!</div><Outlet /></React.Fragment>) };\\n',\n ].join(''),\n imports: {\n tsrImports: () =>\n \"import { Outlet, createRootRoute } from '@tanstack/react-router';\",\n tsrExportStart: () => 'export const Route = createRootRoute(',\n tsrExportEnd: () => ');',\n },\n },\n route: {\n template: () =>\n [\n '%%tsrImports%%',\n '\\n\\n',\n '%%tsrExportStart%%{\\n component: RouteComponent\\n }%%tsrExportEnd%%\\n\\n',\n 'function RouteComponent() { return <div>Hello \"%%tsrPath%%\"!</div> };\\n',\n ].join(''),\n imports: {\n tsrImports: () =>\n config.verboseFileRoutes === false\n ? ''\n : \"import { createFileRoute } from '@tanstack/react-router';\",\n tsrExportStart: (routePath) =>\n config.verboseFileRoutes === false\n ? 'export const Route = createFileRoute('\n : `export const Route = createFileRoute('${routePath}')(`,\n tsrExportEnd: () => ');',\n },\n },\n lazyRoute: {\n template: () =>\n [\n '%%tsrImports%%',\n '\\n\\n',\n '%%tsrExportStart%%{\\n component: RouteComponent\\n }%%tsrExportEnd%%\\n\\n',\n 'function RouteComponent() { return <div>Hello \"%%tsrPath%%\"!</div> };\\n',\n ].join(''),\n imports: {\n tsrImports: () =>\n config.verboseFileRoutes === false\n ? ''\n : \"import { createLazyFileRoute } from '@tanstack/react-router';\",\n tsrExportStart: (routePath) =>\n config.verboseFileRoutes === false\n ? 'export const Route = createLazyFileRoute('\n : `export const Route = createLazyFileRoute('${routePath}')(`,\n tsrExportEnd: () => ');',\n },\n },\n }\n case 'solid':\n return {\n fullPkg: '@tanstack/solid-router',\n subPkg: 'solid-router',\n rootRoute: {\n template: () =>\n [\n 'import * as Solid from \"solid-js\"\\n',\n '%%tsrImports%%',\n '\\n\\n',\n '%%tsrExportStart%%{\\n component: RootComponent\\n }%%tsrExportEnd%%\\n\\n',\n 'function RootComponent() { return (<><div>Hello \"%%tsrPath%%\"!</div><Outlet /></>) };\\n',\n ].join(''),\n imports: {\n tsrImports: () =>\n \"import { Outlet, createRootRoute } from '@tanstack/solid-router';\",\n tsrExportStart: () => 'export const Route = createRootRoute(',\n tsrExportEnd: () => ');',\n },\n },\n route: {\n template: () =>\n [\n '%%tsrImports%%',\n '\\n\\n',\n '%%tsrExportStart%%{\\n component: RouteComponent\\n }%%tsrExportEnd%%\\n\\n',\n 'function RouteComponent() { return <div>Hello \"%%tsrPath%%\"!</div> };\\n',\n ].join(''),\n imports: {\n tsrImports: () =>\n config.verboseFileRoutes === false\n ? ''\n : \"import { createFileRoute } from '@tanstack/solid-router';\",\n tsrExportStart: (routePath) =>\n config.verboseFileRoutes === false\n ? 'export const Route = createFileRoute('\n : `export const Route = createFileRoute('${routePath}')(`,\n tsrExportEnd: () => ');',\n },\n },\n lazyRoute: {\n template: () =>\n [\n '%%tsrImports%%',\n '\\n\\n',\n '%%tsrExportStart%%{\\n component: RouteComponent\\n }%%tsrExportEnd%%\\n\\n',\n 'function RouteComponent() { return <div>Hello \"%%tsrPath%%\"!</div> };\\n',\n ].join(''),\n imports: {\n tsrImports: () =>\n config.verboseFileRoutes === false\n ? ''\n : \"import { createLazyFileRoute } from '@tanstack/solid-router';\",\n\n tsrExportStart: (routePath) =>\n config.verboseFileRoutes === false\n ? 'export const Route = createLazyFileRoute('\n : `export const Route = createLazyFileRoute('${routePath}')(`,\n\n tsrExportEnd: () => ');',\n },\n },\n }\n case 'vue':\n return {\n fullPkg: '@tanstack/vue-router',\n subPkg: 'vue-router',\n rootRoute: {\n template: () =>\n [\n 'import { h } from \"vue\"\\n',\n '%%tsrImports%%',\n '\\n\\n',\n '%%tsrExportStart%%{\\n component: RootComponent\\n }%%tsrExportEnd%%\\n\\n',\n 'function RootComponent() { return h(\"div\", {}, [\"Hello \\\\\"%%tsrPath%%\\\\\"!\", h(Outlet)]) };\\n',\n ].join(''),\n imports: {\n tsrImports: () =>\n \"import { Outlet, createRootRoute } from '@tanstack/vue-router';\",\n tsrExportStart: () => 'export const Route = createRootRoute(',\n tsrExportEnd: () => ');',\n },\n },\n route: {\n template: () =>\n [\n 'import { h } from \"vue\"\\n',\n '%%tsrImports%%',\n '\\n\\n',\n '%%tsrExportStart%%{\\n component: RouteComponent\\n }%%tsrExportEnd%%\\n\\n',\n 'function RouteComponent() { return h(\"div\", {}, \"Hello \\\\\"%%tsrPath%%\\\\\"!\") };\\n',\n ].join(''),\n imports: {\n tsrImports: () =>\n config.verboseFileRoutes === false\n ? ''\n : \"import { createFileRoute } from '@tanstack/vue-router';\",\n tsrExportStart: (routePath) =>\n config.verboseFileRoutes === false\n ? 'export const Route = createFileRoute('\n : `export const Route = createFileRoute('${routePath}')(`,\n tsrExportEnd: () => ');',\n },\n },\n lazyRoute: {\n template: () =>\n [\n 'import { h } from \"vue\"\\n',\n '%%tsrImports%%',\n '\\n\\n',\n '%%tsrExportStart%%{\\n component: RouteComponent\\n }%%tsrExportEnd%%\\n\\n',\n 'function RouteComponent() { return h(\"div\", {}, \"Hello \\\\\"%%tsrPath%%\\\\\"!\") };\\n',\n ].join(''),\n imports: {\n tsrImports: () =>\n config.verboseFileRoutes === false\n ? ''\n : \"import { createLazyFileRoute } from '@tanstack/vue-router';\",\n\n tsrExportStart: (routePath) =>\n config.verboseFileRoutes === false\n ? 'export const Route = createLazyFileRoute('\n : `export const Route = createLazyFileRoute('${routePath}')(`,\n\n tsrExportEnd: () => ');',\n },\n },\n }\n default:\n throw new Error(`router-generator: Unknown target type: ${target}`)\n }\n}\n"],"mappings":";;AAKA,SAAgB,aACd,QACA,UACA,QACA;AAKA,QAAO,OAJU,SAAS,QACxB,eACC,GAAG,QAAQ,OAAO,QAAuB,GAC3C,EACuB,OAAO;;AAgCjC,SAAgB,kBAAkB,QAAgC;CAChE,MAAM,SAAS,OAAO;AACtB,SAAQ,QAAR;EACE,KAAK,QACH,QAAO;GACL,SAAS;GACT,QAAQ;GACR,WAAW;IACT,gBACE;KACE;KACA;KACA;KACA;KACA;KACD,CAAC,KAAK,GAAG;IACZ,SAAS;KACP,kBACE;KACF,sBAAsB;KACtB,oBAAoB;KACrB;IACF;GACD,OAAO;IACL,gBACE;KACE;KACA;KACA;KACA;KACD,CAAC,KAAK,GAAG;IACZ,SAAS;KACP,kBACE,OAAO,sBAAsB,QACzB,KACA;KACN,iBAAiB,cACf,OAAO,sBAAsB,QACzB,0CACA,yCAAyC,UAAU;KACzD,oBAAoB;KACrB;IACF;GACD,WAAW;IACT,gBACE;KACE;KACA;KACA;KACA;KACD,CAAC,KAAK,GAAG;IACZ,SAAS;KACP,kBACE,OAAO,sBAAsB,QACzB,KACA;KACN,iBAAiB,cACf,OAAO,sBAAsB,QACzB,8CACA,6CAA6C,UAAU;KAC7D,oBAAoB;KACrB;IACF;GACF;EACH,KAAK,QACH,QAAO;GACL,SAAS;GACT,QAAQ;GACR,WAAW;IACT,gBACE;KACE;KACA;KACA;KACA;KACA;KACD,CAAC,KAAK,GAAG;IACZ,SAAS;KACP,kBACE;KACF,sBAAsB;KACtB,oBAAoB;KACrB;IACF;GACD,OAAO;IACL,gBACE;KACE;KACA;KACA;KACA;KACD,CAAC,KAAK,GAAG;IACZ,SAAS;KACP,kBACE,OAAO,sBAAsB,QACzB,KACA;KACN,iBAAiB,cACf,OAAO,sBAAsB,QACzB,0CACA,yCAAyC,UAAU;KACzD,oBAAoB;KACrB;IACF;GACD,WAAW;IACT,gBACE;KACE;KACA;KACA;KACA;KACD,CAAC,KAAK,GAAG;IACZ,SAAS;KACP,kBACE,OAAO,sBAAsB,QACzB,KACA;KAEN,iBAAiB,cACf,OAAO,sBAAsB,QACzB,8CACA,6CAA6C,UAAU;KAE7D,oBAAoB;KACrB;IACF;GACF;EACH,KAAK,MACH,QAAO;GACL,SAAS;GACT,QAAQ;GACR,WAAW;IACT,gBACE;KACE;KACA;KACA;KACA;KACA;KACD,CAAC,KAAK,GAAG;IACZ,SAAS;KACP,kBACE;KACF,sBAAsB;KACtB,oBAAoB;KACrB;IACF;GACD,OAAO;IACL,gBACE;KACE;KACA;KACA;KACA;KACA;KACD,CAAC,KAAK,GAAG;IACZ,SAAS;KACP,kBACE,OAAO,sBAAsB,QACzB,KACA;KACN,iBAAiB,cACf,OAAO,sBAAsB,QACzB,0CACA,yCAAyC,UAAU;KACzD,oBAAoB;KACrB;IACF;GACD,WAAW;IACT,gBACE;KACE;KACA;KACA;KACA;KACA;KACD,CAAC,KAAK,GAAG;IACZ,SAAS;KACP,kBACE,OAAO,sBAAsB,QACzB,KACA;KAEN,iBAAiB,cACf,OAAO,sBAAsB,QACzB,8CACA,6CAA6C,UAAU;KAE7D,oBAAoB;KACrB;IACF;GACF;EACH,QACE,OAAM,IAAI,MAAM,0CAA0C,SAAS"}
1
+ {"version":3,"file":"template.js","names":[],"sources":["../../src/template.ts"],"sourcesContent":["import { format } from './utils'\nimport type { Config } from './config'\n\ntype TemplateTag = 'tsrImports' | 'tsrPath' | 'tsrExportStart' | 'tsrExportEnd'\n\nexport function fillTemplate(\n config: Config,\n template: string,\n values: Record<TemplateTag, string>,\n) {\n const replaced = template.replace(\n /%%(\\w+)%%/g,\n (_, key) => values[key as TemplateTag] || '',\n )\n return format(replaced, config)\n}\n\nexport type TargetTemplate = {\n fullPkg: string\n subPkg: string\n rootRoute: {\n template: () => string\n imports: {\n tsrImports: () => string\n tsrExportStart: () => string\n tsrExportEnd: () => string\n }\n }\n route: {\n template: () => string\n imports: {\n tsrImports: () => string\n tsrExportStart: (routePath: string) => string\n tsrExportEnd: () => string\n }\n }\n lazyRoute: {\n template: () => string\n imports: {\n tsrImports: () => string\n tsrExportStart: (routePath: string) => string\n tsrExportEnd: () => string\n }\n }\n}\n\nfunction serializeRoutePath(routePath: string) {\n return JSON.stringify(routePath)\n}\n\nexport function getTargetTemplate(config: Config): TargetTemplate {\n const target = config.target\n switch (target) {\n case 'react':\n return {\n fullPkg: '@tanstack/react-router',\n subPkg: 'react-router',\n rootRoute: {\n template: () =>\n [\n 'import * as React from \"react\"\\n',\n '%%tsrImports%%',\n '\\n\\n',\n '%%tsrExportStart%%{\\n component: RootComponent\\n }%%tsrExportEnd%%\\n\\n',\n 'function RootComponent() { return (<React.Fragment><div>Hello \"%%tsrPath%%\"!</div><Outlet /></React.Fragment>) };\\n',\n ].join(''),\n imports: {\n tsrImports: () =>\n \"import { Outlet, createRootRoute } from '@tanstack/react-router';\",\n tsrExportStart: () => 'export const Route = createRootRoute(',\n tsrExportEnd: () => ');',\n },\n },\n route: {\n template: () =>\n [\n '%%tsrImports%%',\n '\\n\\n',\n '%%tsrExportStart%%{\\n component: RouteComponent\\n }%%tsrExportEnd%%\\n\\n',\n 'function RouteComponent() { return <div>Hello \"%%tsrPath%%\"!</div> };\\n',\n ].join(''),\n imports: {\n tsrImports: () =>\n \"import { createFileRoute } from '@tanstack/react-router';\",\n tsrExportStart: (routePath) =>\n `export const Route = createFileRoute(${serializeRoutePath(routePath)})(`,\n tsrExportEnd: () => ');',\n },\n },\n lazyRoute: {\n template: () =>\n [\n '%%tsrImports%%',\n '\\n\\n',\n '%%tsrExportStart%%{\\n component: RouteComponent\\n }%%tsrExportEnd%%\\n\\n',\n 'function RouteComponent() { return <div>Hello \"%%tsrPath%%\"!</div> };\\n',\n ].join(''),\n imports: {\n tsrImports: () =>\n \"import { createLazyFileRoute } from '@tanstack/react-router';\",\n tsrExportStart: (routePath) =>\n `export const Route = createLazyFileRoute(${serializeRoutePath(routePath)})(`,\n tsrExportEnd: () => ');',\n },\n },\n }\n case 'solid':\n return {\n fullPkg: '@tanstack/solid-router',\n subPkg: 'solid-router',\n rootRoute: {\n template: () =>\n [\n 'import * as Solid from \"solid-js\"\\n',\n '%%tsrImports%%',\n '\\n\\n',\n '%%tsrExportStart%%{\\n component: RootComponent\\n }%%tsrExportEnd%%\\n\\n',\n 'function RootComponent() { return (<><div>Hello \"%%tsrPath%%\"!</div><Outlet /></>) };\\n',\n ].join(''),\n imports: {\n tsrImports: () =>\n \"import { Outlet, createRootRoute } from '@tanstack/solid-router';\",\n tsrExportStart: () => 'export const Route = createRootRoute(',\n tsrExportEnd: () => ');',\n },\n },\n route: {\n template: () =>\n [\n '%%tsrImports%%',\n '\\n\\n',\n '%%tsrExportStart%%{\\n component: RouteComponent\\n }%%tsrExportEnd%%\\n\\n',\n 'function RouteComponent() { return <div>Hello \"%%tsrPath%%\"!</div> };\\n',\n ].join(''),\n imports: {\n tsrImports: () =>\n \"import { createFileRoute } from '@tanstack/solid-router';\",\n tsrExportStart: (routePath) =>\n `export const Route = createFileRoute(${serializeRoutePath(routePath)})(`,\n tsrExportEnd: () => ');',\n },\n },\n lazyRoute: {\n template: () =>\n [\n '%%tsrImports%%',\n '\\n\\n',\n '%%tsrExportStart%%{\\n component: RouteComponent\\n }%%tsrExportEnd%%\\n\\n',\n 'function RouteComponent() { return <div>Hello \"%%tsrPath%%\"!</div> };\\n',\n ].join(''),\n imports: {\n tsrImports: () =>\n \"import { createLazyFileRoute } from '@tanstack/solid-router';\",\n\n tsrExportStart: (routePath) =>\n `export const Route = createLazyFileRoute(${serializeRoutePath(routePath)})(`,\n\n tsrExportEnd: () => ');',\n },\n },\n }\n case 'vue':\n return {\n fullPkg: '@tanstack/vue-router',\n subPkg: 'vue-router',\n rootRoute: {\n template: () =>\n [\n 'import { h } from \"vue\"\\n',\n '%%tsrImports%%',\n '\\n\\n',\n '%%tsrExportStart%%{\\n component: RootComponent\\n }%%tsrExportEnd%%\\n\\n',\n 'function RootComponent() { return h(\"div\", {}, [\"Hello \\\\\"%%tsrPath%%\\\\\"!\", h(Outlet)]) };\\n',\n ].join(''),\n imports: {\n tsrImports: () =>\n \"import { Outlet, createRootRoute } from '@tanstack/vue-router';\",\n tsrExportStart: () => 'export const Route = createRootRoute(',\n tsrExportEnd: () => ');',\n },\n },\n route: {\n template: () =>\n [\n 'import { h } from \"vue\"\\n',\n '%%tsrImports%%',\n '\\n\\n',\n '%%tsrExportStart%%{\\n component: RouteComponent\\n }%%tsrExportEnd%%\\n\\n',\n 'function RouteComponent() { return h(\"div\", {}, \"Hello \\\\\"%%tsrPath%%\\\\\"!\") };\\n',\n ].join(''),\n imports: {\n tsrImports: () =>\n \"import { createFileRoute } from '@tanstack/vue-router';\",\n tsrExportStart: (routePath) =>\n `export const Route = createFileRoute(${serializeRoutePath(routePath)})(`,\n tsrExportEnd: () => ');',\n },\n },\n lazyRoute: {\n template: () =>\n [\n 'import { h } from \"vue\"\\n',\n '%%tsrImports%%',\n '\\n\\n',\n '%%tsrExportStart%%{\\n component: RouteComponent\\n }%%tsrExportEnd%%\\n\\n',\n 'function RouteComponent() { return h(\"div\", {}, \"Hello \\\\\"%%tsrPath%%\\\\\"!\") };\\n',\n ].join(''),\n imports: {\n tsrImports: () =>\n \"import { createLazyFileRoute } from '@tanstack/vue-router';\",\n\n tsrExportStart: (routePath) =>\n `export const Route = createLazyFileRoute(${serializeRoutePath(routePath)})(`,\n\n tsrExportEnd: () => ');',\n },\n },\n }\n default:\n throw new Error(`router-generator: Unknown target type: ${target}`)\n }\n}\n"],"mappings":";;AAKA,SAAgB,aACd,QACA,UACA,QACA;AAKA,QAAO,OAJU,SAAS,QACxB,eACC,GAAG,QAAQ,OAAO,QAAuB,GAC3C,EACuB,OAAO;;AAgCjC,SAAS,mBAAmB,WAAmB;AAC7C,QAAO,KAAK,UAAU,UAAU;;AAGlC,SAAgB,kBAAkB,QAAgC;CAChE,MAAM,SAAS,OAAO;AACtB,SAAQ,QAAR;EACE,KAAK,QACH,QAAO;GACL,SAAS;GACT,QAAQ;GACR,WAAW;IACT,gBACE;KACE;KACA;KACA;KACA;KACA;KACD,CAAC,KAAK,GAAG;IACZ,SAAS;KACP,kBACE;KACF,sBAAsB;KACtB,oBAAoB;KACrB;IACF;GACD,OAAO;IACL,gBACE;KACE;KACA;KACA;KACA;KACD,CAAC,KAAK,GAAG;IACZ,SAAS;KACP,kBACE;KACF,iBAAiB,cACf,wCAAwC,mBAAmB,UAAU,CAAC;KACxE,oBAAoB;KACrB;IACF;GACD,WAAW;IACT,gBACE;KACE;KACA;KACA;KACA;KACD,CAAC,KAAK,GAAG;IACZ,SAAS;KACP,kBACE;KACF,iBAAiB,cACf,4CAA4C,mBAAmB,UAAU,CAAC;KAC5E,oBAAoB;KACrB;IACF;GACF;EACH,KAAK,QACH,QAAO;GACL,SAAS;GACT,QAAQ;GACR,WAAW;IACT,gBACE;KACE;KACA;KACA;KACA;KACA;KACD,CAAC,KAAK,GAAG;IACZ,SAAS;KACP,kBACE;KACF,sBAAsB;KACtB,oBAAoB;KACrB;IACF;GACD,OAAO;IACL,gBACE;KACE;KACA;KACA;KACA;KACD,CAAC,KAAK,GAAG;IACZ,SAAS;KACP,kBACE;KACF,iBAAiB,cACf,wCAAwC,mBAAmB,UAAU,CAAC;KACxE,oBAAoB;KACrB;IACF;GACD,WAAW;IACT,gBACE;KACE;KACA;KACA;KACA;KACD,CAAC,KAAK,GAAG;IACZ,SAAS;KACP,kBACE;KAEF,iBAAiB,cACf,4CAA4C,mBAAmB,UAAU,CAAC;KAE5E,oBAAoB;KACrB;IACF;GACF;EACH,KAAK,MACH,QAAO;GACL,SAAS;GACT,QAAQ;GACR,WAAW;IACT,gBACE;KACE;KACA;KACA;KACA;KACA;KACD,CAAC,KAAK,GAAG;IACZ,SAAS;KACP,kBACE;KACF,sBAAsB;KACtB,oBAAoB;KACrB;IACF;GACD,OAAO;IACL,gBACE;KACE;KACA;KACA;KACA;KACA;KACD,CAAC,KAAK,GAAG;IACZ,SAAS;KACP,kBACE;KACF,iBAAiB,cACf,wCAAwC,mBAAmB,UAAU,CAAC;KACxE,oBAAoB;KACrB;IACF;GACD,WAAW;IACT,gBACE;KACE;KACA;KACA;KACA;KACA;KACD,CAAC,KAAK,GAAG;IACZ,SAAS;KACP,kBACE;KAEF,iBAAiB,cACf,4CAA4C,mBAAmB,UAAU,CAAC;KAE5E,oBAAoB;KACrB;IACF;GACF;EACH,QACE,OAAM,IAAI,MAAM,0CAA0C,SAAS"}
@@ -1,4 +1,2 @@
1
- import { types } from 'recast';
2
1
  import { TransformOptions, TransformResult } from './types.js';
3
- export declare function transform({ ctx, source, node, }: TransformOptions): Promise<TransformResult>;
4
- export declare function detectPreferredQuoteStyle(ast: types.ASTNode): "'" | '"';
2
+ export declare function transform({ ctx, source, node, }: TransformOptions): TransformResult;
@@ -1,298 +1,313 @@
1
- import { mergeImportDeclarations } from "../utils.js";
2
- import { ensureStringArgument } from "./utils.js";
1
+ import MagicString from "magic-string";
2
+ import * as t from "@babel/types";
3
3
  import { parseAst } from "@tanstack/router-utils";
4
- import { parse, print, types, visit } from "recast";
5
- import { SourceMapConsumer } from "source-map";
6
4
  //#region src/transform/transform.ts
7
- var b = types.builders;
8
- async function transform({ ctx, source, node }) {
9
- let appliedChanges = false;
5
+ var routeConstructors = ["createFileRoute", "createLazyFileRoute"];
6
+ function transform({ ctx, source, node }) {
10
7
  let ast;
11
8
  try {
12
- ast = parse(source, {
13
- sourceFileName: "output.ts",
14
- parser: { parse(code) {
15
- return parseAst({
16
- code,
17
- tokens: true
18
- });
19
- } }
20
- });
21
- } catch (e) {
22
- console.error("Error parsing code", ctx.routeId, source, e);
9
+ ast = parseAst({ code: source });
10
+ } catch (error) {
23
11
  return {
24
12
  result: "error",
25
- error: e
13
+ error
26
14
  };
27
15
  }
28
- const preferredQuote = detectPreferredQuoteStyle(ast);
29
- let routeExportHandled = false;
30
- function onExportFound(decl) {
31
- if (decl.init?.type === "CallExpression") {
32
- const callExpression = decl.init;
33
- const firstArgument = callExpression.arguments[0];
34
- if (firstArgument) {
35
- if (firstArgument.type === "ObjectExpression") {
36
- const staticProperties = firstArgument.properties.flatMap((p) => {
37
- if (p.type === "ObjectProperty" && p.key.type === "Identifier") return p.key.name;
38
- return [];
39
- });
40
- node.createFileRouteProps = new Set(staticProperties);
41
- }
42
- }
43
- let identifier;
44
- if (callExpression.callee.type === "Identifier") {
45
- identifier = callExpression.callee;
46
- if (ctx.verboseFileRoutes) {
47
- callExpression.callee = b.callExpression(identifier, [b.stringLiteral(ctx.routeId)]);
48
- appliedChanges = true;
49
- }
50
- } else if (callExpression.callee.type === "CallExpression" && callExpression.callee.callee.type === "Identifier") {
51
- identifier = callExpression.callee.callee;
52
- if (!ctx.verboseFileRoutes) {
53
- callExpression.callee = identifier;
54
- appliedChanges = true;
55
- } else appliedChanges = ensureStringArgument(callExpression.callee, ctx.routeId, ctx.preferredQuote);
56
- }
57
- if (identifier === void 0) throw new Error(`expected identifier to be present in ${ctx.routeId} for export "Route"`);
58
- if (identifier.name === "createFileRoute" && ctx.lazy) {
59
- identifier.name = "createLazyFileRoute";
60
- appliedChanges = true;
61
- } else if (identifier.name === "createLazyFileRoute" && !ctx.lazy) {
62
- identifier.name = "createFileRoute";
63
- appliedChanges = true;
64
- }
65
- } else throw new Error(`expected "Route" export to be initialized by a CallExpression`);
66
- routeExportHandled = true;
16
+ const exportedRouteNames = getExportedRouteNames(ast.program.body);
17
+ if (exportedRouteNames.size === 0) return { result: "no-route-export" };
18
+ const { calls: routeCalls, hasUnsupportedRouteId, hasMalformedRouteCall } = findExportedRouteCalls(ast.program.body, exportedRouteNames);
19
+ if (routeCalls.length === 0 && hasMalformedRouteCall) return {
20
+ result: "error",
21
+ error: /* @__PURE__ */ new Error(`expected Route export in ${ctx.routeId} to use createFileRoute('/path')({...}) or createLazyFileRoute('/path')({...})`)
22
+ };
23
+ if (routeCalls.length === 0 && hasUnsupportedRouteId) return {
24
+ result: "error",
25
+ error: /* @__PURE__ */ new Error(`expected route id to be a string literal or plain template literal in ${ctx.routeId}`)
26
+ };
27
+ if (routeCalls.length === 0) return { result: "not-modified" };
28
+ if (routeCalls.length > 1) return {
29
+ result: "error",
30
+ error: /* @__PURE__ */ new Error(`expected exactly one createFileRoute/createLazyFileRoute call in ${ctx.routeId}`)
31
+ };
32
+ const routeCall = routeCalls[0];
33
+ const routeIdQuote = getRouteIdQuote(source, routeCall.routeIdArg);
34
+ const createFileRouteProps = getCreateFileRouteProps(routeCall.optionsArg);
35
+ if (createFileRouteProps) node.createFileRouteProps = createFileRouteProps;
36
+ const expectedCallee = getExpectedRouteConstructor(ctx.lazy);
37
+ const expectedRouteId = `${routeIdQuote}${ctx.routeId}${routeIdQuote}`;
38
+ const currentRouteId = source.slice(routeCall.routeIdArg.start, routeCall.routeIdArg.end);
39
+ const targetModule = `@tanstack/${ctx.target}-router`;
40
+ const imports = parseTargetImports(ast.program.body, source, targetModule);
41
+ const s = new MagicString(source);
42
+ let modified = false;
43
+ if (routeCall.callee.name !== expectedCallee) {
44
+ s.update(routeCall.callee.start, routeCall.callee.end, expectedCallee);
45
+ modified = true;
67
46
  }
68
- const program = ast.program;
69
- for (const n of program.body) {
70
- if (n.type === "ExportNamedDeclaration") {
71
- if (n.declaration?.type === "VariableDeclaration") {
72
- const decl = n.declaration.declarations[0];
73
- if (decl && decl.type === "VariableDeclarator" && decl.id.type === "Identifier") {
74
- if (decl.id.name === "Route") onExportFound(decl);
75
- }
76
- } else if (n.declaration === null && n.specifiers) {
77
- for (const spec of n.specifiers) if (typeof spec.exported.name === "string") {
78
- if (spec.exported.name === "Route") {
79
- const variableName = spec.local?.name || spec.exported.name;
80
- for (const decl of program.body) if (decl.type === "VariableDeclaration" && decl.declarations[0]) {
81
- const variable = decl.declarations[0];
82
- if (variable.type === "VariableDeclarator" && variable.id.type === "Identifier" && variable.id.name === variableName) {
83
- onExportFound(variable);
84
- break;
85
- }
86
- }
87
- }
88
- }
89
- }
90
- }
91
- if (routeExportHandled) break;
47
+ if (currentRouteId !== expectedRouteId) {
48
+ s.update(routeCall.routeIdArg.start, routeCall.routeIdArg.end, expectedRouteId);
49
+ modified = true;
92
50
  }
93
- if (!routeExportHandled) return { result: "no-route-export" };
94
- const imports = {
95
- required: [],
96
- banned: []
51
+ if (updateRouteImports({
52
+ imports,
53
+ source,
54
+ s,
55
+ targetModule,
56
+ required: expectedCallee,
57
+ lineEnding: getLineEnding(source)
58
+ })) modified = true;
59
+ if (!modified) return { result: "not-modified" };
60
+ return {
61
+ result: "modified",
62
+ output: s.toString()
97
63
  };
98
- const targetModule = `@tanstack/${ctx.target}-router`;
99
- if (ctx.verboseFileRoutes === false) imports.banned = [{
100
- source: targetModule,
101
- specifiers: [{ imported: "createLazyFileRoute" }, { imported: "createFileRoute" }]
102
- }];
103
- else if (ctx.lazy) {
104
- imports.required = [{
105
- source: targetModule,
106
- specifiers: [{ imported: "createLazyFileRoute" }]
107
- }];
108
- imports.banned = [{
109
- source: targetModule,
110
- specifiers: [{ imported: "createFileRoute" }]
111
- }];
112
- } else {
113
- imports.required = [{
114
- source: targetModule,
115
- specifiers: [{ imported: "createFileRoute" }]
116
- }];
117
- imports.banned = [{
118
- source: targetModule,
119
- specifiers: [{ imported: "createLazyFileRoute" }]
120
- }];
64
+ }
65
+ function getExportedRouteNames(body) {
66
+ const exportedRouteNames = /* @__PURE__ */ new Set();
67
+ for (const statement of body) {
68
+ if (!t.isExportNamedDeclaration(statement) || statement.source) continue;
69
+ if (t.isVariableDeclaration(statement.declaration)) {
70
+ for (const declarator of statement.declaration.declarations) if (t.isIdentifier(declarator.id) && declarator.id.name === "Route") exportedRouteNames.add("Route");
71
+ }
72
+ for (const specifier of statement.specifiers) {
73
+ if (!t.isExportSpecifier(specifier) || getExportedName(specifier.exported) !== "Route") continue;
74
+ const localName = getLocalBindingName(specifier.local);
75
+ if (localName) exportedRouteNames.add(localName);
76
+ }
121
77
  }
122
- imports.required = mergeImportDeclarations(imports.required);
123
- imports.banned = mergeImportDeclarations(imports.banned);
124
- const importStatementCandidates = [];
125
- const importDeclarationsToRemove = [];
126
- for (const n of program.body) {
127
- const findImport = (opts) => (i) => {
128
- if (i.source === opts.source) {
129
- const importKind = i.importKind || "value";
130
- return (opts.importKind || "value") === importKind;
78
+ return exportedRouteNames;
79
+ }
80
+ function findExportedRouteCalls(body, exportedRouteNames) {
81
+ const calls = [];
82
+ let hasUnsupportedRouteId = false;
83
+ let hasMalformedRouteCall = false;
84
+ for (const statement of body) {
85
+ const declaration = getVariableDeclaration(statement);
86
+ if (!declaration) continue;
87
+ for (const declarator of declaration.declarations) {
88
+ if (!t.isIdentifier(declarator.id) || !exportedRouteNames.has(declarator.id.name)) continue;
89
+ const init = getRouteConstructorInit(declarator.init);
90
+ if (!init) {
91
+ if (isDirectRouteConstructorCall(declarator.init)) hasMalformedRouteCall = true;
92
+ continue;
131
93
  }
132
- return false;
133
- };
134
- if (n.type === "ImportDeclaration" && typeof n.source.value === "string") {
135
- const filterImport = findImport({
136
- source: n.source.value,
137
- importKind: n.importKind
94
+ const routeIdArg = init.innerCall.arguments[0];
95
+ if (isSupportedRouteId(routeIdArg)) calls.push({
96
+ callee: init.callee,
97
+ routeIdArg,
98
+ optionsArg: init.outerCall.arguments[0]
138
99
  });
139
- let requiredImports = imports.required.filter(filterImport)[0];
140
- const bannedImports = imports.banned.filter(filterImport)[0];
141
- if (!requiredImports && !bannedImports) continue;
142
- const importSpecifiersToRemove = [];
143
- if (n.specifiers) {
144
- for (const spec of n.specifiers) {
145
- if (!requiredImports && !bannedImports) break;
146
- if (spec.type === "ImportSpecifier" && typeof spec.imported.name === "string") {
147
- if (requiredImports) {
148
- const requiredImportIndex = requiredImports.specifiers.findIndex((imp) => imp.imported === spec.imported.name);
149
- if (requiredImportIndex !== -1) {
150
- requiredImports.specifiers.splice(requiredImportIndex, 1);
151
- if (requiredImports.specifiers.length === 0) {
152
- imports.required = imports.required.splice(imports.required.indexOf(requiredImports), 1);
153
- requiredImports = void 0;
154
- }
155
- } else importStatementCandidates.push(n);
156
- }
157
- if (bannedImports) {
158
- if (bannedImports.specifiers.findIndex((imp) => imp.imported === spec.imported.name) !== -1) importSpecifiersToRemove.push(spec);
159
- }
160
- }
161
- }
162
- if (importSpecifiersToRemove.length > 0) {
163
- appliedChanges = true;
164
- n.specifiers = n.specifiers.filter((spec) => !importSpecifiersToRemove.includes(spec));
165
- if (n.specifiers.length === 0) importDeclarationsToRemove.push(n);
166
- }
167
- }
100
+ else hasUnsupportedRouteId = true;
168
101
  }
169
102
  }
170
- imports.required.forEach((requiredImport) => {
171
- if (requiredImport.specifiers.length > 0) {
172
- appliedChanges = true;
173
- if (importStatementCandidates.length > 0) {
174
- const importStatement = importStatementCandidates.find((importStatement) => {
175
- if (importStatement.source.value === requiredImport.source) return (importStatement.importKind || "value") === (requiredImport.importKind || "value");
176
- return false;
177
- });
178
- if (importStatement) {
179
- if (importStatement.specifiers === void 0) importStatement.specifiers = [];
180
- const importSpecifiersToAdd = requiredImport.specifiers.map((spec) => b.importSpecifier(b.identifier(spec.imported), b.identifier(spec.imported)));
181
- importStatement.specifiers = [...importStatement.specifiers, ...importSpecifiersToAdd];
182
- return;
183
- }
184
- }
185
- const importStatement = b.importDeclaration(requiredImport.specifiers.map((spec) => b.importSpecifier(b.identifier(spec.imported), spec.local ? b.identifier(spec.local) : null)), b.stringLiteral(requiredImport.source));
186
- program.body.unshift(importStatement);
103
+ return {
104
+ calls,
105
+ hasUnsupportedRouteId,
106
+ hasMalformedRouteCall
107
+ };
108
+ }
109
+ function getVariableDeclaration(statement) {
110
+ const declaration = t.isExportNamedDeclaration(statement) ? statement.declaration : statement;
111
+ return t.isVariableDeclaration(declaration) ? declaration : null;
112
+ }
113
+ function getExportedName(node) {
114
+ return t.isIdentifier(node) ? node.name : node.value;
115
+ }
116
+ function getLocalBindingName(node) {
117
+ return t.isIdentifier(node) ? node.name : null;
118
+ }
119
+ function getRouteConstructorInit(expression) {
120
+ if (!expression || !t.isCallExpression(expression)) return null;
121
+ if (!t.isCallExpression(expression.callee)) return null;
122
+ const innerCall = expression.callee;
123
+ if (!t.isIdentifier(innerCall.callee) || !isRouteConstructor(innerCall.callee)) return null;
124
+ return {
125
+ callee: innerCall.callee,
126
+ outerCall: expression,
127
+ innerCall
128
+ };
129
+ }
130
+ function isDirectRouteConstructorCall(expression) {
131
+ return !!expression && t.isCallExpression(expression) && t.isIdentifier(expression.callee) && isRouteConstructor(expression.callee);
132
+ }
133
+ function isRouteConstructor(callee) {
134
+ return routeConstructors.includes(callee.name);
135
+ }
136
+ function isSupportedRouteId(arg) {
137
+ return !!arg && (t.isStringLiteral(arg) || t.isTemplateLiteral(arg) && arg.expressions.length === 0);
138
+ }
139
+ function getRouteIdQuote(source, arg) {
140
+ const raw = source.slice(arg.start, arg.end);
141
+ if (raw.startsWith("'")) return "'";
142
+ if (raw.startsWith("\"")) return "\"";
143
+ return "`";
144
+ }
145
+ function getCreateFileRouteProps(arg) {
146
+ if (!arg || !t.isObjectExpression(arg)) return;
147
+ const props = /* @__PURE__ */ new Set();
148
+ for (const property of arg.properties) {
149
+ if (!t.isObjectProperty(property) || property.computed) continue;
150
+ if (t.isIdentifier(property.key)) {
151
+ props.add(property.key.name);
152
+ continue;
187
153
  }
154
+ if (t.isStringLiteral(property.key)) props.add(property.key.value);
155
+ }
156
+ return props;
157
+ }
158
+ function parseTargetImports(body, source, targetModule) {
159
+ const imports = [];
160
+ for (const statement of body) {
161
+ if (!t.isImportDeclaration(statement) || statement.importKind === "type" || statement.source.value !== targetModule) continue;
162
+ const rawSource = source.slice(statement.source.start, statement.source.end);
163
+ const importStatement = source.slice(statement.start, statement.end);
164
+ imports.push({
165
+ declaration: statement,
166
+ defaultImport: statement.specifiers.find((specifier) => t.isImportDefaultSpecifier(specifier))?.local.name,
167
+ namespace: statement.specifiers.find((specifier) => t.isImportNamespaceSpecifier(specifier))?.local.name,
168
+ named: statement.specifiers.filter((specifier) => t.isImportSpecifier(specifier)).map((specifier) => ({
169
+ imported: t.isIdentifier(specifier.imported) ? specifier.imported.name : specifier.imported.value,
170
+ local: specifier.local.name,
171
+ importKind: specifier.importKind ?? void 0
172
+ })),
173
+ moduleName: statement.source.value,
174
+ quote: rawSource[0],
175
+ semicolon: importStatement.trimEnd().endsWith(";")
176
+ });
177
+ }
178
+ return imports;
179
+ }
180
+ function updateRouteImports({ imports, source, s, targetModule, required, lineEnding }) {
181
+ const analysis = analyzeRouteImports(imports, required);
182
+ if (analysis.kind === "ok") return false;
183
+ if (analysis.kind === "rename") {
184
+ s.update(analysis.imported.start, analysis.imported.end, analysis.next);
185
+ s.update(analysis.local.start, analysis.local.end, analysis.next);
186
+ return true;
187
+ }
188
+ return normalizeRouteImports({
189
+ imports,
190
+ source,
191
+ s,
192
+ targetModule,
193
+ required,
194
+ lineEnding
188
195
  });
189
- if (importDeclarationsToRemove.length > 0) {
190
- appliedChanges = true;
191
- for (const importDeclaration of importDeclarationsToRemove) if (importDeclaration.specifiers?.length === 0) {
192
- const index = program.body.indexOf(importDeclaration);
193
- if (index !== -1) program.body.splice(index, 1);
196
+ }
197
+ function analyzeRouteImports(imports, required) {
198
+ const opposite = getOtherRouteConstructor(required);
199
+ let requiredCount = 0;
200
+ let oppositeCount = 0;
201
+ let renameCandidate;
202
+ for (const declaration of imports) for (const specifier of declaration.declaration.specifiers) {
203
+ if (!t.isImportSpecifier(specifier)) continue;
204
+ const imported = specifier.imported;
205
+ if (!t.isIdentifier(imported)) return { kind: "normalize" };
206
+ if (!isRouteConstructorName(imported.name)) continue;
207
+ if (specifier.local.name !== imported.name) return { kind: "normalize" };
208
+ if (imported.name === required) {
209
+ requiredCount++;
210
+ continue;
211
+ }
212
+ if (imported.name === opposite) {
213
+ oppositeCount++;
214
+ renameCandidate = {
215
+ imported,
216
+ local: specifier.local,
217
+ next: required
218
+ };
194
219
  }
195
220
  }
196
- if (!appliedChanges) return { result: "not-modified" };
197
- const printResult = print(ast, {
198
- reuseWhitespace: true,
199
- sourceMapName: "output.map"
200
- });
201
- let transformedCode = printResult.code;
202
- if (printResult.map) transformedCode = await fixTransformedOutputText({
203
- originalCode: source,
204
- transformedCode,
205
- sourceMap: printResult.map,
206
- preferredQuote
207
- });
208
- return {
209
- result: "modified",
210
- output: transformedCode
221
+ if (requiredCount === 1 && oppositeCount === 0) return { kind: "ok" };
222
+ if (requiredCount === 0 && oppositeCount === 1 && renameCandidate) return {
223
+ kind: "rename",
224
+ ...renameCandidate
211
225
  };
226
+ return { kind: "normalize" };
212
227
  }
213
- async function fixTransformedOutputText({ originalCode, transformedCode, sourceMap, preferredQuote }) {
214
- const originalLines = originalCode.split("\n");
215
- const transformedLines = transformedCode.split("\n");
216
- const defaultUsesSemicolons = detectSemicolonUsage(originalCode);
217
- const consumer = await new SourceMapConsumer(sourceMap);
218
- return transformedLines.map((line, i) => {
219
- const transformedLineNum = i + 1;
220
- let origLineText = void 0;
221
- for (let col = 0; col < line.length; col++) {
222
- const mapped = consumer.originalPositionFor({
223
- line: transformedLineNum,
224
- column: col
225
- });
226
- if (mapped.line != null && mapped.line > 0) {
227
- origLineText = originalLines[mapped.line - 1];
228
- break;
229
- }
230
- }
231
- if (origLineText !== void 0) {
232
- if (origLineText === line) return origLineText;
233
- return fixLine(line, {
234
- originalLine: origLineText,
235
- useOriginalSemicolon: true,
236
- useOriginalQuotes: true,
237
- fallbackQuote: preferredQuote
238
- });
239
- } else return fixLine(line, {
240
- originalLine: null,
241
- useOriginalSemicolon: false,
242
- useOriginalQuotes: false,
243
- fallbackQuote: preferredQuote,
244
- fallbackSemicolon: defaultUsesSemicolons
228
+ function normalizeRouteImports({ imports, source, s, targetModule, required, lineEnding }) {
229
+ const owner = imports.find((declaration) => hasNamedImport(declaration.named, required)) ?? imports.find((declaration) => !declaration.namespace);
230
+ let modified = false;
231
+ for (const declaration of imports) {
232
+ const named = normalizeNamedImports({
233
+ named: declaration.named,
234
+ required,
235
+ isOwner: declaration === owner
245
236
  });
246
- }).join("\n");
237
+ if (sameNamedImports(declaration.named, named)) continue;
238
+ const replacement = renderImportDeclaration({
239
+ ...declaration,
240
+ named
241
+ });
242
+ if (replacement === null) {
243
+ s.remove(declaration.declaration.start, getRemovalEnd(source, declaration.declaration.end));
244
+ modified = true;
245
+ continue;
246
+ }
247
+ s.update(declaration.declaration.start, declaration.declaration.end, replacement);
248
+ modified = true;
249
+ }
250
+ if (!owner) {
251
+ const quote = imports[0]?.quote ?? "'";
252
+ const semicolon = imports[0]?.semicolon ?? false;
253
+ s.prepend(`import { ${required} } from ${quote}${targetModule}${quote}${semicolon ? ";" : ""}${lineEnding}`);
254
+ modified = true;
255
+ }
256
+ return modified;
247
257
  }
248
- function fixLine(line, { originalLine, useOriginalSemicolon, useOriginalQuotes, fallbackQuote, fallbackSemicolon = true }) {
249
- let result = line;
250
- if (useOriginalQuotes && originalLine) result = fixQuotes(result, originalLine, fallbackQuote);
251
- else if (!useOriginalQuotes && fallbackQuote) result = fixQuotesToPreferred(result, fallbackQuote);
252
- if (useOriginalSemicolon && originalLine) {
253
- const hadSemicolon = originalLine.trimEnd().endsWith(";");
254
- const hasSemicolon = result.trimEnd().endsWith(";");
255
- if (hadSemicolon && !hasSemicolon) result += ";";
256
- if (!hadSemicolon && hasSemicolon) result = result.replace(/;\s*$/, "");
257
- } else if (!useOriginalSemicolon) {
258
- const hasSemicolon = result.trimEnd().endsWith(";");
259
- if (!fallbackSemicolon && hasSemicolon) result = result.replace(/;\s*$/, "");
260
- if (fallbackSemicolon && !hasSemicolon && result.trim()) result += ";";
258
+ function normalizeNamedImports({ named, required, isOwner }) {
259
+ const banned = getOtherRouteConstructor(required);
260
+ const nextNamed = [];
261
+ const seen = /* @__PURE__ */ new Set();
262
+ for (const specifier of named) {
263
+ if (specifier.imported === banned) continue;
264
+ if (specifier.local === required && (specifier.imported !== required || !isOwner)) continue;
265
+ const key = `${specifier.importKind ?? "value"}:${specifier.imported}:${specifier.local}`;
266
+ if (seen.has(key)) continue;
267
+ seen.add(key);
268
+ nextNamed.push(specifier);
261
269
  }
262
- return result;
270
+ if (isOwner && !hasNamedImport(nextNamed, required)) nextNamed.push({
271
+ imported: required,
272
+ local: required
273
+ });
274
+ return nextNamed;
263
275
  }
264
- function fixQuotes(line, originalLine, fallbackQuote) {
265
- let originalQuote = detectQuoteFromLine(originalLine);
266
- if (!originalQuote) originalQuote = fallbackQuote;
267
- return fixQuotesToPreferred(line, originalQuote);
276
+ function getExpectedRouteConstructor(lazy) {
277
+ return lazy ? "createLazyFileRoute" : "createFileRoute";
268
278
  }
269
- function fixQuotesToPreferred(line, quote) {
270
- return line.replace(/(['"`])([^'"`\\]*(?:\\.[^'"`\\]*)*)\1/g, (_, q, content) => {
271
- return `${quote}${content.replaceAll(quote, `\\${quote}`)}${quote}`;
272
- });
279
+ function getOtherRouteConstructor(constructor) {
280
+ return constructor === "createFileRoute" ? "createLazyFileRoute" : "createFileRoute";
273
281
  }
274
- function detectQuoteFromLine(line) {
275
- const match = line.match(/(['"`])(?:\\.|[^\\])*?\1/);
276
- return match ? match[1] : null;
282
+ function hasNamedImport(named, required) {
283
+ return named.some((specifier) => specifier.imported === required && specifier.local === required && specifier.importKind !== "type");
277
284
  }
278
- function detectSemicolonUsage(code) {
279
- const lines = code.split("\n").map((l) => l.trim());
280
- const total = lines.length;
281
- return lines.filter((l) => l.endsWith(";")).length > total / 2;
285
+ function sameNamedImports(left, right) {
286
+ return left.length === right.length && left.every((specifier, index) => specifier.imported === right[index].imported && specifier.local === right[index].local && specifier.importKind === right[index].importKind);
282
287
  }
283
- function detectPreferredQuoteStyle(ast) {
284
- let single = 0;
285
- let double = 0;
286
- visit(ast, { visitStringLiteral(path) {
287
- if (path.parent.node.type !== "JSXAttribute") {
288
- const raw = path.node.extra?.raw;
289
- if (raw?.startsWith("'")) single++;
290
- else if (raw?.startsWith("\"")) double++;
291
- }
292
- return false;
293
- } });
294
- if (single >= double) return "'";
295
- return "\"";
288
+ function isRouteConstructorName(value) {
289
+ return routeConstructors.includes(value);
290
+ }
291
+ function renderImportDeclaration(importDeclaration) {
292
+ const parts = [];
293
+ if (importDeclaration.defaultImport) parts.push(importDeclaration.defaultImport);
294
+ if (importDeclaration.namespace) parts.push(`* as ${importDeclaration.namespace}`);
295
+ if (importDeclaration.named.length > 0) parts.push(`{ ${importDeclaration.named.map((specifier) => `${specifier.importKind === "type" ? "type " : ""}${specifier.imported === specifier.local ? specifier.imported : `${specifier.imported} as ${specifier.local}`}`).join(", ")} }`);
296
+ if (parts.length === 0) return null;
297
+ return `import ${parts.join(", ")} from ${importDeclaration.quote}${importDeclaration.moduleName}${importDeclaration.quote}${importDeclaration.semicolon ? ";" : ""}`;
298
+ }
299
+ function getLineEnding(source) {
300
+ if (source.includes("\r\n")) return "\r\n";
301
+ if (source.includes("\n")) return "\n";
302
+ if (source.includes("\r")) return "\r";
303
+ return "\n";
304
+ }
305
+ function getRemovalEnd(source, end) {
306
+ let pos = end;
307
+ while (pos < source.length && (source[pos] === " " || source[pos] === " ")) pos++;
308
+ if (source[pos] === "\r" && source[pos + 1] === "\n") return pos + 2;
309
+ if (source[pos] === "\n" || source[pos] === "\r") return pos + 1;
310
+ return end;
296
311
  }
297
312
  //#endregion
298
313
  export { transform };