@analogjs/platform 3.0.0-alpha.97 → 3.0.0-alpha.99

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 (87) hide show
  1. package/migrations/migrate-setup-testbed-browser-mode/migrate-setup-testbed-browser-mode.d.ts +7 -0
  2. package/migrations/migrate-setup-testbed-browser-mode/migrate-setup-testbed-browser-mode.js +68 -0
  3. package/migrations/migrate-setup-testbed-browser-mode/migrate-setup-testbed-browser-mode.js.map +1 -0
  4. package/migrations/migrate-to-separated-plugins/migrate-to-separated-plugins.js +1 -6
  5. package/migrations/migrate-to-separated-plugins/migrate-to-separated-plugins.js.map +1 -1
  6. package/migrations/migrate-vitest-builder-aliases/migrate-vitest-builder-aliases.d.ts +6 -0
  7. package/migrations/migrate-vitest-builder-aliases/migrate-vitest-builder-aliases.js +62 -0
  8. package/migrations/migrate-vitest-builder-aliases/migrate-vitest-builder-aliases.js.map +1 -0
  9. package/migrations/migration.json +10 -0
  10. package/migrations/utils/source-edits.d.ts +9 -0
  11. package/migrations/utils/source-edits.js +33 -0
  12. package/migrations/utils/source-edits.js.map +1 -0
  13. package/package.json +5 -5
  14. package/src/lib/nx-plugin/builders.json +1 -2
  15. package/src/lib/nx-plugin/executors.json +1 -7
  16. package/src/lib/nx-plugin/generators.json +0 -10
  17. package/src/lib/nx-plugin/src/generators/app/generator.js +2 -5
  18. package/src/lib/nx-plugin/src/generators/app/generator.js.map +1 -1
  19. package/src/lib/nx-plugin/src/generators/app/versions/minimum-supported-versions.d.ts +1 -4
  20. package/src/lib/nx-plugin/src/generators/app/versions/minimum-supported-versions.js +2 -5
  21. package/src/lib/nx-plugin/src/generators/app/versions/minimum-supported-versions.js.map +1 -1
  22. package/src/lib/nx-plugin/src/generators/app/versions/tailwind-dependencies.js +5 -5
  23. package/src/lib/nx-plugin/src/generators/app/versions/tailwind-dependencies.js.map +1 -1
  24. package/src/lib/nx-plugin/src/generators/app/versions/versions.d.ts +4 -0
  25. package/src/lib/nx-plugin/src/generators/app/versions/versions.js +12 -0
  26. package/src/lib/nx-plugin/src/generators/app/versions/versions.js.map +1 -0
  27. package/src/lib/nx-plugin/src/generators/init/lib/add-analog-dependencies.js +1 -1
  28. package/src/lib/nx-plugin/src/generators/init/lib/add-analog-dependencies.js.map +1 -1
  29. package/src/lib/nx-plugin/src/generators/preset/generator.js +2 -5
  30. package/src/lib/nx-plugin/src/generators/preset/generator.js.map +1 -1
  31. package/src/lib/nx-plugin/src/utils/versions/dependencies.js +8 -8
  32. package/src/lib/nx-plugin/src/utils/versions/dependencies.js.map +1 -1
  33. package/src/lib/nx-plugin/src/utils/versions/dev-dependencies.d.ts +2 -2
  34. package/src/lib/nx-plugin/src/utils/versions/dev-dependencies.js +13 -16
  35. package/src/lib/nx-plugin/src/utils/versions/dev-dependencies.js.map +1 -1
  36. package/src/lib/nx-plugin/src/utils/versions/versions.d.ts +15 -0
  37. package/src/lib/nx-plugin/src/utils/versions/versions.js +34 -0
  38. package/src/lib/nx-plugin/src/utils/versions/versions.js.map +1 -0
  39. package/src/lib/route-file-discovery.js +4 -16
  40. package/src/lib/route-file-discovery.js.map +1 -1
  41. package/src/lib/route-idiom-diagnostics.js +3 -23
  42. package/src/lib/route-idiom-diagnostics.js.map +1 -1
  43. package/src/lib/route-manifest.d.ts +5 -5
  44. package/src/lib/route-manifest.js +8 -8
  45. package/src/lib/route-manifest.js.map +1 -1
  46. package/src/lib/router-plugin.js +2 -15
  47. package/src/lib/router-plugin.js.map +1 -1
  48. package/src/lib/ssr/inject-html-plugin.js +1 -2
  49. package/src/lib/ssr/inject-html-plugin.js.map +1 -1
  50. package/src/lib/nx-plugin/src/executors/vitest/compat.d.ts +0 -3
  51. package/src/lib/nx-plugin/src/executors/vitest/compat.js +0 -8
  52. package/src/lib/nx-plugin/src/executors/vitest/compat.js.map +0 -1
  53. package/src/lib/nx-plugin/src/executors/vitest/schema.d.ts +0 -1
  54. package/src/lib/nx-plugin/src/executors/vitest/schema.json +0 -35
  55. package/src/lib/nx-plugin/src/executors/vitest/vitest.impl.d.ts +0 -2
  56. package/src/lib/nx-plugin/src/executors/vitest/vitest.impl.js +0 -7
  57. package/src/lib/nx-plugin/src/executors/vitest/vitest.impl.js.map +0 -1
  58. package/src/lib/nx-plugin/src/generators/app/lib/add-analog-dependencies.d.ts +0 -2
  59. package/src/lib/nx-plugin/src/generators/app/lib/initialize-analog-workspace.d.ts +0 -3
  60. package/src/lib/nx-plugin/src/generators/app/versions/dependencies.d.ts +0 -5
  61. package/src/lib/nx-plugin/src/generators/app/versions/dev-dependencies.d.ts +0 -4
  62. package/src/lib/nx-plugin/src/generators/app/versions/nx-dependencies.d.ts +0 -4
  63. package/src/lib/nx-plugin/src/generators/app/versions/nx_18_X/versions.d.ts +0 -28
  64. package/src/lib/nx-plugin/src/generators/app/versions/nx_18_X/versions.js +0 -12
  65. package/src/lib/nx-plugin/src/generators/app/versions/nx_18_X/versions.js.map +0 -1
  66. package/src/lib/nx-plugin/src/generators/setup-vitest/compat.d.ts +0 -9
  67. package/src/lib/nx-plugin/src/generators/setup-vitest/compat.js +0 -19
  68. package/src/lib/nx-plugin/src/generators/setup-vitest/compat.js.map +0 -1
  69. package/src/lib/nx-plugin/src/generators/setup-vitest/files/src/test-setup.ts__template__ +0 -22
  70. package/src/lib/nx-plugin/src/generators/setup-vitest/files/vite.config.mts__template__ +0 -23
  71. package/src/lib/nx-plugin/src/generators/setup-vitest/generator.d.ts +0 -4
  72. package/src/lib/nx-plugin/src/generators/setup-vitest/generator.js +0 -38
  73. package/src/lib/nx-plugin/src/generators/setup-vitest/generator.js.map +0 -1
  74. package/src/lib/nx-plugin/src/generators/setup-vitest/lib/add-analog-dependencies.d.ts +0 -2
  75. package/src/lib/nx-plugin/src/generators/setup-vitest/lib/add-analog-dependencies.js +0 -11
  76. package/src/lib/nx-plugin/src/generators/setup-vitest/lib/add-analog-dependencies.js.map +0 -1
  77. package/src/lib/nx-plugin/src/generators/setup-vitest/lib/update-test-target.d.ts +0 -3
  78. package/src/lib/nx-plugin/src/generators/setup-vitest/lib/update-test-target.js +0 -24
  79. package/src/lib/nx-plugin/src/generators/setup-vitest/lib/update-test-target.js.map +0 -1
  80. package/src/lib/nx-plugin/src/generators/setup-vitest/lib/update-tsconfig.d.ts +0 -3
  81. package/src/lib/nx-plugin/src/generators/setup-vitest/lib/update-tsconfig.js +0 -23
  82. package/src/lib/nx-plugin/src/generators/setup-vitest/lib/update-tsconfig.js.map +0 -1
  83. package/src/lib/nx-plugin/src/generators/setup-vitest/schema.d.ts +0 -7
  84. package/src/lib/nx-plugin/src/generators/setup-vitest/schema.json +0 -19
  85. package/src/lib/nx-plugin/src/utils/versions/ng_19_X/versions.d.ts +0 -19
  86. package/src/lib/nx-plugin/src/utils/versions/ng_19_X/versions.js +0 -40
  87. package/src/lib/nx-plugin/src/utils/versions/ng_19_X/versions.js.map +0 -1
@@ -1,15 +1,12 @@
1
1
  require("../../../_virtual/_rolldown/runtime.js");
2
- const require_minimum_supported_versions = require("../app/versions/minimum-supported-versions.js");
3
2
  let _nx_devkit = require("@nx/devkit");
4
3
  let node_path = require("node:path");
5
4
  //#region packages/nx-plugin/src/generators/preset/generator.ts
6
5
  async function generator_default(tree, options) {
7
6
  (0, _nx_devkit.ensurePackage)("@nx/angular", _nx_devkit.NX_VERSION);
8
7
  (0, _nx_devkit.ensurePackage)("@nx/vite", _nx_devkit.NX_VERSION);
9
- if (options.linter === "oxlint") {
10
- if (require_minimum_supported_versions.belowMinimumSupportedOxlintNxVersion(_nx_devkit.NX_VERSION)) throw new Error(`Nx v${require_minimum_supported_versions.MINIMUM_SUPPORTED_OXLINT_NX_VERSION} or newer is required to use the oxlint linter`);
11
- (0, _nx_devkit.ensurePackage)("@nx/oxlint", _nx_devkit.NX_VERSION);
12
- } else if (options.linter !== "none") (0, _nx_devkit.ensurePackage)("@nx/eslint", _nx_devkit.NX_VERSION);
8
+ if (options.linter === "oxlint") (0, _nx_devkit.ensurePackage)("@nx/oxlint", _nx_devkit.NX_VERSION);
9
+ else if (options.linter !== "none") (0, _nx_devkit.ensurePackage)("@nx/eslint", _nx_devkit.NX_VERSION);
13
10
  (0, _nx_devkit.ensurePackage)("@angular-devkit/core", "latest");
14
11
  (0, _nx_devkit.ensurePackage)("rxjs", "latest");
15
12
  const generatorModule = await Promise.resolve().then(() => require("../app/generator.js"));
@@ -1 +1 @@
1
- {"version":3,"file":"generator.js","names":[],"sources":["../../../../../../../../nx-plugin/src/generators/preset/generator.ts"],"sourcesContent":["import {\n ensurePackage,\n generateFiles,\n NX_VERSION,\n Tree,\n updateJson,\n} from '@nx/devkit';\nimport { join } from 'node:path';\nimport {\n belowMinimumSupportedOxlintNxVersion,\n MINIMUM_SUPPORTED_OXLINT_NX_VERSION,\n} from '../app/versions/minimum-supported-versions';\nimport { PresetGeneratorSchema } from './schema';\n\nexport default async function (\n tree: Tree,\n options: PresetGeneratorSchema,\n): Promise<() => void> {\n ensurePackage('@nx/angular', NX_VERSION);\n ensurePackage('@nx/vite', NX_VERSION);\n if (options.linter === 'oxlint') {\n if (belowMinimumSupportedOxlintNxVersion(NX_VERSION)) {\n throw new Error(\n `Nx v${MINIMUM_SUPPORTED_OXLINT_NX_VERSION} or newer is required to use the oxlint linter`,\n );\n }\n ensurePackage('@nx/oxlint', NX_VERSION);\n } else if (options.linter !== 'none') {\n ensurePackage('@nx/eslint', NX_VERSION);\n }\n ensurePackage('@angular-devkit/core', 'latest');\n ensurePackage('rxjs', 'latest');\n\n const generatorModule = await import('../app/generator');\n const appGenerator =\n 'default' in generatorModule ? generatorModule.default : generatorModule;\n\n const installTask = await appGenerator(tree, {\n ...options,\n skipAgentContext: true,\n });\n\n // Seed agent context at the workspace root so AI coding assistants pick up\n // Analog conventions (see node_modules/@analogjs/platform/AGENTS.md).\n generateFiles(\n tree,\n join(__dirname, '..', 'app', 'files', 'agents'),\n '.',\n options,\n );\n\n if (tree.exists('/tsconfig.base.json')) {\n updateJson<{\n compilerOptions?: {\n baseUrl?: string;\n };\n }>(tree, '/tsconfig.base.json', (json) => {\n delete json.compilerOptions?.baseUrl;\n return json;\n });\n }\n\n return installTask;\n}\n"],"mappings":";;;;;AAcA,eAAA,kBACE,MACA,SACqB;AACrB,EAAA,GAAA,WAAA,eAAc,eAAe,WAAA,WAAW;AACxC,EAAA,GAAA,WAAA,eAAc,YAAY,WAAA,WAAW;AACrC,KAAI,QAAQ,WAAW,UAAU;AAC/B,MAAI,mCAAA,qCAAqC,WAAA,WAAW,CAClD,OAAM,IAAI,MACR,OAAO,mCAAA,oCAAoC,gDAC5C;AAEH,GAAA,GAAA,WAAA,eAAc,cAAc,WAAA,WAAW;YAC9B,QAAQ,WAAW,OAC5B,EAAA,GAAA,WAAA,eAAc,cAAc,WAAA,WAAW;AAEzC,EAAA,GAAA,WAAA,eAAc,wBAAwB,SAAS;AAC/C,EAAA,GAAA,WAAA,eAAc,QAAQ,SAAS;CAE/B,MAAM,kBAAkB,MAAA,QAAA,SAAA,CAAA,WAAA,QAAM,sBAAA,CAAA;CAI9B,MAAM,cAAc,OAFlB,aAAa,kBAAkB,gBAAgB,UAAU,iBAEpB,MAAM;EAC3C,GAAG;EACH,kBAAkB;EACnB,CAAC;AAIF,EAAA,GAAA,WAAA,eACE,OAAA,GAAA,UAAA,MACK,WAAW,MAAM,OAAO,SAAS,SAAS,EAC/C,KACA,QACD;AAED,KAAI,KAAK,OAAO,sBAAsB,CACpC,EAAA,GAAA,WAAA,YAIG,MAAM,wBAAwB,SAAS;AACxC,SAAO,KAAK,iBAAiB;AAC7B,SAAO;GACP;AAGJ,QAAO"}
1
+ {"version":3,"file":"generator.js","names":[],"sources":["../../../../../../../../nx-plugin/src/generators/preset/generator.ts"],"sourcesContent":["import {\n ensurePackage,\n generateFiles,\n NX_VERSION,\n Tree,\n updateJson,\n} from '@nx/devkit';\nimport { join } from 'node:path';\nimport { PresetGeneratorSchema } from './schema';\n\nexport default async function (\n tree: Tree,\n options: PresetGeneratorSchema,\n): Promise<() => void> {\n ensurePackage('@nx/angular', NX_VERSION);\n ensurePackage('@nx/vite', NX_VERSION);\n if (options.linter === 'oxlint') {\n ensurePackage('@nx/oxlint', NX_VERSION);\n } else if (options.linter !== 'none') {\n ensurePackage('@nx/eslint', NX_VERSION);\n }\n ensurePackage('@angular-devkit/core', 'latest');\n ensurePackage('rxjs', 'latest');\n\n const generatorModule = await import('../app/generator');\n const appGenerator =\n 'default' in generatorModule ? generatorModule.default : generatorModule;\n\n const installTask = await appGenerator(tree, {\n ...options,\n skipAgentContext: true,\n });\n\n // Seed agent context at the workspace root so AI coding assistants pick up\n // Analog conventions (see node_modules/@analogjs/platform/AGENTS.md).\n generateFiles(\n tree,\n join(__dirname, '..', 'app', 'files', 'agents'),\n '.',\n options,\n );\n\n if (tree.exists('/tsconfig.base.json')) {\n updateJson<{\n compilerOptions?: {\n baseUrl?: string;\n };\n }>(tree, '/tsconfig.base.json', (json) => {\n delete json.compilerOptions?.baseUrl;\n return json;\n });\n }\n\n return installTask;\n}\n"],"mappings":";;;;AAUA,eAAA,kBACE,MACA,SACqB;AACrB,EAAA,GAAA,WAAA,eAAc,eAAe,WAAA,WAAW;AACxC,EAAA,GAAA,WAAA,eAAc,YAAY,WAAA,WAAW;AACrC,KAAI,QAAQ,WAAW,SACrB,EAAA,GAAA,WAAA,eAAc,cAAc,WAAA,WAAW;UAC9B,QAAQ,WAAW,OAC5B,EAAA,GAAA,WAAA,eAAc,cAAc,WAAA,WAAW;AAEzC,EAAA,GAAA,WAAA,eAAc,wBAAwB,SAAS;AAC/C,EAAA,GAAA,WAAA,eAAc,QAAQ,SAAS;CAE/B,MAAM,kBAAkB,MAAA,QAAA,SAAA,CAAA,WAAA,QAAM,sBAAA,CAAA;CAI9B,MAAM,cAAc,OAFlB,aAAa,kBAAkB,gBAAgB,UAAU,iBAEpB,MAAM;EAC3C,GAAG;EACH,kBAAkB;EACnB,CAAC;AAIF,EAAA,GAAA,WAAA,eACE,OAAA,GAAA,UAAA,MACK,WAAW,MAAM,OAAO,SAAS,SAAS,EAC/C,KACA,QACD;AAED,KAAI,KAAK,OAAO,sBAAsB,CACpC,EAAA,GAAA,WAAA,YAIG,MAAM,wBAAwB,SAAS;AACxC,SAAO,KAAK,iBAAiB;AAC7B,SAAO;GACP;AAGJ,QAAO"}
@@ -1,5 +1,5 @@
1
1
  require("../../../_virtual/_rolldown/runtime.js");
2
- const require_versions = require("./ng_19_X/versions.js");
2
+ const require_versions = require("./versions.js");
3
3
  let _nx_devkit = require("@nx/devkit");
4
4
  let semver = require("semver");
5
5
  //#region packages/nx-plugin/src/utils/versions/dependencies.ts
@@ -9,13 +9,13 @@ var getAnalogDependencies = (ngVersion) => {
9
9
  var getDependencies = (escapedAngularVersion) => {
10
10
  if ((0, semver.lt)(escapedAngularVersion, "20.0.0")) throw new Error(_nx_devkit.stripIndents`Angular v20.0.0 or newer is required.`);
11
11
  return {
12
- "@analogjs/content": require_versions.V19_X_ANALOG_JS_CONTENT,
13
- "@analogjs/router": require_versions.V19_X_ANALOG_JS_ROUTER,
14
- marked: require_versions.V19_X_MARKED,
15
- "marked-gfm-heading-id": require_versions.V19_X_MARKED_GFM_HEADING_ID,
16
- "marked-highlight": require_versions.V19_X_MARKED_HIGHLIGHT,
17
- "marked-mangle": require_versions.V19_X_MARKED_MANGLE,
18
- prismjs: require_versions.V19_X_PRISMJS
12
+ "@analogjs/content": require_versions.ANALOG_JS_CONTENT,
13
+ "@analogjs/router": require_versions.ANALOG_JS_ROUTER,
14
+ marked: require_versions.MARKED,
15
+ "marked-gfm-heading-id": require_versions.MARKED_GFM_HEADING_ID,
16
+ "marked-highlight": require_versions.MARKED_HIGHLIGHT,
17
+ "marked-mangle": require_versions.MARKED_MANGLE,
18
+ prismjs: require_versions.PRISMJS
19
19
  };
20
20
  };
21
21
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"dependencies.js","names":[],"sources":["../../../../../../../../nx-plugin/src/utils/versions/dependencies.ts"],"sourcesContent":["import { lt } from 'semver';\nimport { stripIndents } from '@nx/devkit';\nimport {\n V19_X_ANALOG_JS_CONTENT,\n V19_X_ANALOG_JS_ROUTER,\n V19_X_MARKED,\n V19_X_MARKED_GFM_HEADING_ID,\n V19_X_MARKED_HIGHLIGHT,\n V19_X_MARKED_MANGLE,\n V19_X_PRISMJS,\n} from './ng_19_X/versions';\n\nconst dependencyKeys = [\n '@analogjs/content',\n '@analogjs/router',\n 'marked',\n 'marked-gfm-heading-id',\n 'marked-highlight',\n 'prismjs',\n] as const;\nexport type AnalogDependency = (typeof dependencyKeys)[number];\n\nexport const getAnalogDependencies = (\n ngVersion: string,\n): Record<AnalogDependency, string> => {\n const escapedNgVersion = ngVersion.replace(/[~^]/, '');\n\n const dependencies = getDependencies(escapedNgVersion);\n\n return { ...dependencies };\n};\n\nconst getDependencies = (escapedAngularVersion: string) => {\n // fail out for versions <20.0.0\n if (lt(escapedAngularVersion, '20.0.0')) {\n throw new Error(stripIndents`Angular v20.0.0 or newer is required.`);\n }\n\n // return latest deps for versions >=20.0.0\n return {\n '@analogjs/content': V19_X_ANALOG_JS_CONTENT,\n '@analogjs/router': V19_X_ANALOG_JS_ROUTER,\n marked: V19_X_MARKED,\n 'marked-gfm-heading-id': V19_X_MARKED_GFM_HEADING_ID,\n 'marked-highlight': V19_X_MARKED_HIGHLIGHT,\n 'marked-mangle': V19_X_MARKED_MANGLE,\n prismjs: V19_X_PRISMJS,\n };\n};\n"],"mappings":";;;;;AAsBA,IAAa,yBACX,cACqC;AAKrC,QAAO,EAAE,GAFY,gBAFI,UAAU,QAAQ,QAAQ,GAAG,CAEA,EAE5B;;AAG5B,IAAM,mBAAmB,0BAAkC;AAEzD,MAAA,GAAA,OAAA,IAAO,uBAAuB,SAAS,CACrC,OAAM,IAAI,MAAM,WAAA,YAAY,wCAAwC;AAItE,QAAO;EACL,qBAAqB,iBAAA;EACrB,oBAAoB,iBAAA;EACpB,QAAQ,iBAAA;EACR,yBAAyB,iBAAA;EACzB,oBAAoB,iBAAA;EACpB,iBAAiB,iBAAA;EACjB,SAAS,iBAAA;EACV"}
1
+ {"version":3,"file":"dependencies.js","names":[],"sources":["../../../../../../../../nx-plugin/src/utils/versions/dependencies.ts"],"sourcesContent":["import { lt } from 'semver';\nimport { stripIndents } from '@nx/devkit';\nimport {\n ANALOG_JS_CONTENT,\n ANALOG_JS_ROUTER,\n MARKED,\n MARKED_GFM_HEADING_ID,\n MARKED_HIGHLIGHT,\n MARKED_MANGLE,\n PRISMJS,\n} from './versions';\n\nconst dependencyKeys = [\n '@analogjs/content',\n '@analogjs/router',\n 'marked',\n 'marked-gfm-heading-id',\n 'marked-highlight',\n 'prismjs',\n] as const;\nexport type AnalogDependency = (typeof dependencyKeys)[number];\n\nexport const getAnalogDependencies = (\n ngVersion: string,\n): Record<AnalogDependency, string> => {\n const escapedNgVersion = ngVersion.replace(/[~^]/, '');\n\n const dependencies = getDependencies(escapedNgVersion);\n\n return { ...dependencies };\n};\n\nconst getDependencies = (escapedAngularVersion: string) => {\n // fail out for versions <20.0.0\n if (lt(escapedAngularVersion, '20.0.0')) {\n throw new Error(stripIndents`Angular v20.0.0 or newer is required.`);\n }\n\n // return latest deps for versions >=20.0.0\n return {\n '@analogjs/content': ANALOG_JS_CONTENT,\n '@analogjs/router': ANALOG_JS_ROUTER,\n marked: MARKED,\n 'marked-gfm-heading-id': MARKED_GFM_HEADING_ID,\n 'marked-highlight': MARKED_HIGHLIGHT,\n 'marked-mangle': MARKED_MANGLE,\n prismjs: PRISMJS,\n };\n};\n"],"mappings":";;;;;AAsBA,IAAa,yBACX,cACqC;AAKrC,QAAO,EAAE,GAFY,gBAFI,UAAU,QAAQ,QAAQ,GAAG,CAEA,EAE5B;;AAG5B,IAAM,mBAAmB,0BAAkC;AAEzD,MAAA,GAAA,OAAA,IAAO,uBAAuB,SAAS,CACrC,OAAM,IAAI,MAAM,WAAA,YAAY,wCAAwC;AAItE,QAAO;EACL,qBAAqB,iBAAA;EACrB,oBAAoB,iBAAA;EACpB,QAAQ,iBAAA;EACR,yBAAyB,iBAAA;EACzB,oBAAoB,iBAAA;EACpB,iBAAiB,iBAAA;EACjB,SAAS,iBAAA;EACV"}
@@ -1,4 +1,4 @@
1
- declare const devDependencyKeys: readonly ["@analogjs/platform", "@analogjs/vite-plugin-angular", "jsdom", "vite-tsconfig-paths", "vitest", "vite", "@vitest/coverage-v8", "@vitest/ui"];
1
+ declare const devDependencyKeys: readonly ["@analogjs/platform", "@analogjs/vite-plugin-angular", "@analogjs/vitest-angular", "@nx/vite", "jsdom", "vite-tsconfig-paths", "vitest", "vite", "@vitest/coverage-v8", "@vitest/ui"];
2
2
  export type AnalogDevDependency = (typeof devDependencyKeys)[number];
3
- export declare const getAnalogDevDependencies: (ngVersion: string, nxVersion?: string) => Record<AnalogDevDependency, string>;
3
+ export declare const getAnalogDevDependencies: (ngVersion: string) => Record<AnalogDevDependency, string>;
4
4
  export {};
@@ -1,24 +1,21 @@
1
1
  require("../../../_virtual/_rolldown/runtime.js");
2
- const require_versions = require("./ng_19_X/versions.js");
2
+ const require_versions = require("./versions.js");
3
3
  let _nx_devkit = require("@nx/devkit");
4
4
  let semver = require("semver");
5
5
  //#region packages/nx-plugin/src/utils/versions/dev-dependencies.ts
6
- var getAnalogDevDependencies = (ngVersion, nxVersion) => {
7
- return { ...getDevDependencies(ngVersion.replace(/[~^]/, ""), nxVersion ? nxVersion.replace(/[~^]/, "") : null) };
8
- };
9
- var getDevDependencies = (escapedAngularVersion, escapedNxVersion) => {
10
- if ((0, semver.lt)(escapedAngularVersion, "20.0.0")) throw new Error(_nx_devkit.stripIndents`Angular v20.0.0 or newer is required.`);
6
+ var getAnalogDevDependencies = (ngVersion) => {
7
+ if ((0, semver.lt)(ngVersion.replace(/[~^]/, ""), "20.0.0")) throw new Error(_nx_devkit.stripIndents`Angular v20.0.0 or newer is required.`);
11
8
  return {
12
- "@analogjs/platform": require_versions.V19_X_ANALOG_JS_PLATFORM,
13
- "@analogjs/vite-plugin-angular": require_versions.V19_X_ANALOG_JS_VITE_PLUGIN_ANGULAR,
14
- "@analogjs/vitest-angular": require_versions.V19_X_ANALOG_JS_VITEST_ANGULAR,
15
- "@nx/vite": escapedNxVersion && !(0, semver.lt)(escapedNxVersion, "23.0.0") ? require_versions.NX_X_LATEST_NX : require_versions.V19_X_NX_VITE,
16
- jsdom: require_versions.V19_X_JSDOM,
17
- "vite-tsconfig-paths": require_versions.V19_X_VITE_TSCONFIG_PATHS,
18
- vite: escapedNxVersion && (0, semver.lt)(escapedNxVersion, "20.5.0") ? require_versions.V19_X_VITE : require_versions.NX_X_LATEST_VITE,
19
- vitest: (0, semver.lt)(escapedAngularVersion, "21.0.0") || escapedNxVersion && (0, semver.lt)(escapedNxVersion, "22.3.0") ? require_versions.V19_X_VITEST : require_versions.NX_X_LATEST_VITEST,
20
- "@vitest/coverage-v8": (0, semver.lt)(escapedAngularVersion, "21.0.0") || escapedNxVersion && (0, semver.lt)(escapedNxVersion, "22.3.0") ? require_versions.V19_X_VITEST : require_versions.NX_X_LATEST_VITEST,
21
- "@vitest/ui": (0, semver.lt)(escapedAngularVersion, "21.0.0") || escapedNxVersion && (0, semver.lt)(escapedNxVersion, "22.3.0") ? require_versions.V19_X_VITEST : require_versions.NX_X_LATEST_VITEST
9
+ "@analogjs/platform": require_versions.ANALOG_JS_PLATFORM,
10
+ "@analogjs/vite-plugin-angular": require_versions.ANALOG_JS_VITE_PLUGIN_ANGULAR,
11
+ "@analogjs/vitest-angular": require_versions.ANALOG_JS_VITEST_ANGULAR,
12
+ "@nx/vite": require_versions.NX,
13
+ jsdom: require_versions.JSDOM,
14
+ "vite-tsconfig-paths": require_versions.VITE_TSCONFIG_PATHS,
15
+ vite: require_versions.VITE,
16
+ vitest: require_versions.VITEST,
17
+ "@vitest/coverage-v8": require_versions.VITEST,
18
+ "@vitest/ui": require_versions.VITEST
22
19
  };
23
20
  };
24
21
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"dev-dependencies.js","names":[],"sources":["../../../../../../../../nx-plugin/src/utils/versions/dev-dependencies.ts"],"sourcesContent":["import { lt } from 'semver';\nimport { stripIndents } from '@nx/devkit';\nimport {\n V19_X_ANALOG_JS_PLATFORM,\n V19_X_ANALOG_JS_VITE_PLUGIN_ANGULAR,\n V19_X_ANALOG_JS_VITEST_ANGULAR,\n V19_X_NX_VITE,\n V19_X_JSDOM,\n V19_X_VITE_TSCONFIG_PATHS,\n V19_X_VITEST,\n V19_X_VITE,\n NX_X_LATEST_VITE,\n NX_X_LATEST_VITEST,\n NX_X_LATEST_NX,\n} from './ng_19_X/versions';\n\nconst devDependencyKeys = [\n '@analogjs/platform',\n '@analogjs/vite-plugin-angular',\n 'jsdom',\n 'vite-tsconfig-paths',\n 'vitest',\n 'vite',\n '@vitest/coverage-v8',\n '@vitest/ui',\n] as const;\nexport type AnalogDevDependency = (typeof devDependencyKeys)[number];\n\nexport const getAnalogDevDependencies = (\n ngVersion: string,\n nxVersion?: string,\n): Record<AnalogDevDependency, string> => {\n const escapedNgVersion = ngVersion.replace(/[~^]/, '');\n const escapedNxVersion = nxVersion ? nxVersion.replace(/[~^]/, '') : null;\n\n const devDependencies = getDevDependencies(\n escapedNgVersion,\n escapedNxVersion,\n );\n\n return { ...devDependencies };\n};\n\nconst getDevDependencies = (\n escapedAngularVersion: string,\n escapedNxVersion: string | null,\n) => {\n // fail out for versions <20.0.0\n if (lt(escapedAngularVersion, '20.0.0')) {\n throw new Error(stripIndents`Angular v20.0.0 or newer is required.`);\n }\n\n // return latest deps for versions >=20.0.0\n return {\n '@analogjs/platform': V19_X_ANALOG_JS_PLATFORM,\n '@analogjs/vite-plugin-angular': V19_X_ANALOG_JS_VITE_PLUGIN_ANGULAR,\n '@analogjs/vitest-angular': V19_X_ANALOG_JS_VITEST_ANGULAR,\n '@nx/vite':\n escapedNxVersion && !lt(escapedNxVersion, '23.0.0')\n ? NX_X_LATEST_NX\n : V19_X_NX_VITE,\n jsdom: V19_X_JSDOM,\n 'vite-tsconfig-paths': V19_X_VITE_TSCONFIG_PATHS,\n vite:\n escapedNxVersion && lt(escapedNxVersion, '20.5.0')\n ? V19_X_VITE\n : NX_X_LATEST_VITE,\n vitest:\n lt(escapedAngularVersion, '21.0.0') ||\n (escapedNxVersion && lt(escapedNxVersion, '22.3.0'))\n ? V19_X_VITEST\n : NX_X_LATEST_VITEST,\n '@vitest/coverage-v8':\n lt(escapedAngularVersion, '21.0.0') ||\n (escapedNxVersion && lt(escapedNxVersion, '22.3.0'))\n ? V19_X_VITEST\n : NX_X_LATEST_VITEST,\n '@vitest/ui':\n lt(escapedAngularVersion, '21.0.0') ||\n (escapedNxVersion && lt(escapedNxVersion, '22.3.0'))\n ? V19_X_VITEST\n : NX_X_LATEST_VITEST,\n };\n};\n"],"mappings":";;;;;AA4BA,IAAa,4BACX,WACA,cACwC;AASxC,QAAO,EAAE,GALe,mBAHC,UAAU,QAAQ,QAAQ,GAAG,EAC7B,YAAY,UAAU,QAAQ,QAAQ,GAAG,GAAG,KAKpE,EAE4B;;AAG/B,IAAM,sBACJ,uBACA,qBACG;AAEH,MAAA,GAAA,OAAA,IAAO,uBAAuB,SAAS,CACrC,OAAM,IAAI,MAAM,WAAA,YAAY,wCAAwC;AAItE,QAAO;EACL,sBAAsB,iBAAA;EACtB,iCAAiC,iBAAA;EACjC,4BAA4B,iBAAA;EAC5B,YACE,oBAAoB,EAAA,GAAA,OAAA,IAAI,kBAAkB,SAAS,GAC/C,iBAAA,iBACA,iBAAA;EACN,OAAO,iBAAA;EACP,uBAAuB,iBAAA;EACvB,MACE,qBAAA,GAAA,OAAA,IAAuB,kBAAkB,SAAS,GAC9C,iBAAA,aACA,iBAAA;EACN,SAAA,GAAA,OAAA,IACK,uBAAuB,SAAS,IAClC,qBAAA,GAAA,OAAA,IAAuB,kBAAkB,SAAS,GAC/C,iBAAA,eACA,iBAAA;EACN,wBAAA,GAAA,OAAA,IACK,uBAAuB,SAAS,IAClC,qBAAA,GAAA,OAAA,IAAuB,kBAAkB,SAAS,GAC/C,iBAAA,eACA,iBAAA;EACN,eAAA,GAAA,OAAA,IACK,uBAAuB,SAAS,IAClC,qBAAA,GAAA,OAAA,IAAuB,kBAAkB,SAAS,GAC/C,iBAAA,eACA,iBAAA;EACP"}
1
+ {"version":3,"file":"dev-dependencies.js","names":[],"sources":["../../../../../../../../nx-plugin/src/utils/versions/dev-dependencies.ts"],"sourcesContent":["import { lt } from 'semver';\nimport { stripIndents } from '@nx/devkit';\nimport {\n ANALOG_JS_PLATFORM,\n ANALOG_JS_VITE_PLUGIN_ANGULAR,\n ANALOG_JS_VITEST_ANGULAR,\n JSDOM,\n VITE_TSCONFIG_PATHS,\n VITE,\n VITEST,\n NX,\n} from './versions';\n\nconst devDependencyKeys = [\n '@analogjs/platform',\n '@analogjs/vite-plugin-angular',\n '@analogjs/vitest-angular',\n '@nx/vite',\n 'jsdom',\n 'vite-tsconfig-paths',\n 'vitest',\n 'vite',\n '@vitest/coverage-v8',\n '@vitest/ui',\n] as const;\nexport type AnalogDevDependency = (typeof devDependencyKeys)[number];\n\nexport const getAnalogDevDependencies = (\n ngVersion: string,\n): Record<AnalogDevDependency, string> => {\n const escapedNgVersion = ngVersion.replace(/[~^]/, '');\n\n // fail out for versions <20.0.0\n if (lt(escapedNgVersion, '20.0.0')) {\n throw new Error(stripIndents`Angular v20.0.0 or newer is required.`);\n }\n\n return {\n '@analogjs/platform': ANALOG_JS_PLATFORM,\n '@analogjs/vite-plugin-angular': ANALOG_JS_VITE_PLUGIN_ANGULAR,\n '@analogjs/vitest-angular': ANALOG_JS_VITEST_ANGULAR,\n '@nx/vite': NX,\n jsdom: JSDOM,\n 'vite-tsconfig-paths': VITE_TSCONFIG_PATHS,\n vite: VITE,\n vitest: VITEST,\n '@vitest/coverage-v8': VITEST,\n '@vitest/ui': VITEST,\n };\n};\n"],"mappings":";;;;;AA2BA,IAAa,4BACX,cACwC;AAIxC,MAAA,GAAA,OAAA,IAHyB,UAAU,QAAQ,QAAQ,GAAG,EAG7B,SAAS,CAChC,OAAM,IAAI,MAAM,WAAA,YAAY,wCAAwC;AAGtE,QAAO;EACL,sBAAsB,iBAAA;EACtB,iCAAiC,iBAAA;EACjC,4BAA4B,iBAAA;EAC5B,YAAY,iBAAA;EACZ,OAAO,iBAAA;EACP,uBAAuB,iBAAA;EACvB,MAAM,iBAAA;EACN,QAAQ,iBAAA;EACR,uBAAuB,iBAAA;EACvB,cAAc,iBAAA;EACf"}
@@ -0,0 +1,15 @@
1
+ export declare const ANALOG_JS_ROUTER = "^3.0.0-alpha.99";
2
+ export declare const ANALOG_JS_CONTENT = "^3.0.0-alpha.99";
3
+ export declare const MARKED = "^18.0.0";
4
+ export declare const MARKED_GFM_HEADING_ID = "^4.1.1";
5
+ export declare const MARKED_HIGHLIGHT = "^2.2.1";
6
+ export declare const MARKED_MANGLE = "^1.1.10";
7
+ export declare const PRISMJS = "^1.29.0";
8
+ export declare const ANALOG_JS_PLATFORM = "^3.0.0-alpha.99";
9
+ export declare const ANALOG_JS_VITE_PLUGIN_ANGULAR = "^3.0.0-alpha.99";
10
+ export declare const ANALOG_JS_VITEST_ANGULAR = "^3.0.0-alpha.99";
11
+ export declare const JSDOM = "^22.0.0";
12
+ export declare const VITE_TSCONFIG_PATHS = "^4.2.0";
13
+ export declare const VITE = "^8.0.0";
14
+ export declare const VITEST = "^5.0.0";
15
+ export declare const NX = "^23.2.0";
@@ -0,0 +1,34 @@
1
+ //#region packages/nx-plugin/src/utils/versions/versions.ts
2
+ var ANALOG_JS_ROUTER = "^3.0.0-alpha.99";
3
+ var ANALOG_JS_CONTENT = "^3.0.0-alpha.99";
4
+ var MARKED = "^18.0.0";
5
+ var MARKED_GFM_HEADING_ID = "^4.1.1";
6
+ var MARKED_HIGHLIGHT = "^2.2.1";
7
+ var MARKED_MANGLE = "^1.1.10";
8
+ var PRISMJS = "^1.29.0";
9
+ var ANALOG_JS_PLATFORM = "^3.0.0-alpha.99";
10
+ var ANALOG_JS_VITE_PLUGIN_ANGULAR = "^3.0.0-alpha.99";
11
+ var ANALOG_JS_VITEST_ANGULAR = "^3.0.0-alpha.99";
12
+ var JSDOM = "^22.0.0";
13
+ var VITE_TSCONFIG_PATHS = "^4.2.0";
14
+ var VITE = "^8.0.0";
15
+ var VITEST = "^5.0.0";
16
+ var NX = "^23.2.0";
17
+ //#endregion
18
+ exports.ANALOG_JS_CONTENT = ANALOG_JS_CONTENT;
19
+ exports.ANALOG_JS_PLATFORM = ANALOG_JS_PLATFORM;
20
+ exports.ANALOG_JS_ROUTER = ANALOG_JS_ROUTER;
21
+ exports.ANALOG_JS_VITEST_ANGULAR = ANALOG_JS_VITEST_ANGULAR;
22
+ exports.ANALOG_JS_VITE_PLUGIN_ANGULAR = ANALOG_JS_VITE_PLUGIN_ANGULAR;
23
+ exports.JSDOM = JSDOM;
24
+ exports.MARKED = MARKED;
25
+ exports.MARKED_GFM_HEADING_ID = MARKED_GFM_HEADING_ID;
26
+ exports.MARKED_HIGHLIGHT = MARKED_HIGHLIGHT;
27
+ exports.MARKED_MANGLE = MARKED_MANGLE;
28
+ exports.NX = NX;
29
+ exports.PRISMJS = PRISMJS;
30
+ exports.VITE = VITE;
31
+ exports.VITEST = VITEST;
32
+ exports.VITE_TSCONFIG_PATHS = VITE_TSCONFIG_PATHS;
33
+
34
+ //# sourceMappingURL=versions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"versions.js","names":[],"sources":["../../../../../../../../nx-plugin/src/utils/versions/versions.ts"],"sourcesContent":["// dependencies\nexport const ANALOG_JS_ROUTER = '^3.0.0-alpha.99';\nexport const ANALOG_JS_CONTENT = '^3.0.0-alpha.99';\nexport const MARKED = '^18.0.0';\nexport const MARKED_GFM_HEADING_ID = '^4.1.1';\nexport const MARKED_HIGHLIGHT = '^2.2.1';\nexport const MARKED_MANGLE = '^1.1.10';\nexport const PRISMJS = '^1.29.0';\n\n// devDependencies\nexport const ANALOG_JS_PLATFORM = '^3.0.0-alpha.99';\nexport const ANALOG_JS_VITE_PLUGIN_ANGULAR = '^3.0.0-alpha.99';\nexport const ANALOG_JS_VITEST_ANGULAR = '^3.0.0-alpha.99';\nexport const JSDOM = '^22.0.0';\nexport const VITE_TSCONFIG_PATHS = '^4.2.0';\nexport const VITE = '^8.0.0';\nexport const VITEST = '^5.0.0';\nexport const NX = '^23.2.0';\n"],"mappings":";AACA,IAAa,mBAAmB;AAChC,IAAa,oBAAoB;AACjC,IAAa,SAAS;AACtB,IAAa,wBAAwB;AACrC,IAAa,mBAAmB;AAChC,IAAa,gBAAgB;AAC7B,IAAa,UAAU;AAGvB,IAAa,qBAAqB;AAClC,IAAa,gCAAgC;AAC7C,IAAa,2BAA2B;AACxC,IAAa,QAAQ;AACrB,IAAa,sBAAsB;AACnC,IAAa,OAAO;AACpB,IAAa,SAAS;AACtB,IAAa,KAAK"}
@@ -21,12 +21,8 @@ function createRouteFileDiscovery(options) {
21
21
  return path === dir || path.startsWith(`${dir}/`);
22
22
  }
23
23
  function getAppLocalFileKind(path) {
24
- if (path.endsWith(".md") && [
25
- "src/app/routes",
26
- "src/app/pages",
27
- "src/content"
28
- ].some((dir) => isWithinDir(path, `${root}/${dir}`))) return "content";
29
- if (path.endsWith(".ts") && ["app/routes", "src/app/routes"].some((dir) => isWithinDir(path, `${root}/${dir}`)) || path.endsWith(".page.ts") && isWithinDir(path, `${root}/src/app/pages`)) return "route";
24
+ if (path.endsWith(".md") && ["src/app/pages", "src/content"].some((dir) => isWithinDir(path, `${root}/${dir}`))) return "content";
25
+ if (path.endsWith(".page.ts") && isWithinDir(path, `${root}/src/app/pages`)) return "route";
30
26
  return null;
31
27
  }
32
28
  function getDiscoveredFileKind(path) {
@@ -39,11 +35,7 @@ function createRouteFileDiscovery(options) {
39
35
  return null;
40
36
  }
41
37
  function scanRouteFiles() {
42
- const appLocalGlobs = [
43
- `${root}/app/routes/**/*.ts`,
44
- `${root}/src/app/routes/**/*.ts`,
45
- `${root}/src/app/pages/**/*.page.ts`
46
- ];
38
+ const appLocalGlobs = [`${root}/src/app/pages/**/*.page.ts`];
47
39
  const additionalGlobs = additionalPagesDirs.map((dir) => `${joinDir(dir)}/**/*.page.ts`);
48
40
  const appLocal = globSync(appLocalGlobs, {
49
41
  dot: true,
@@ -57,11 +49,7 @@ function createRouteFileDiscovery(options) {
57
49
  return [...appLocal, ...additional];
58
50
  }
59
51
  function scanContentFiles() {
60
- const appLocalGlobs = [
61
- `${root}/src/app/routes/**/*.md`,
62
- `${root}/src/app/pages/**/*.md`,
63
- `${root}/src/content/**/*.md`
64
- ];
52
+ const appLocalGlobs = [`${root}/src/app/pages/**/*.md`, `${root}/src/content/**/*.md`];
65
53
  const additionalGlobs = additionalContentDirs.map((dir) => `${joinDir(dir)}/**/*.md`);
66
54
  const appLocal = globSync(appLocalGlobs, {
67
55
  dot: true,
@@ -1 +1 @@
1
- {"version":3,"file":"route-file-discovery.js","names":[],"sources":["../../../src/lib/route-file-discovery.ts"],"sourcesContent":["import { normalizePath } from 'vite';\nimport { resolve } from 'node:path';\nimport { globSync } from 'tinyglobby';\n\nexport interface RouteFileDiscoveryOptions {\n root: string;\n workspaceRoot: string;\n additionalPagesDirs: string[];\n additionalContentDirs: string[];\n}\n\nexport type RouteFileKind = 'route' | 'content' | 'server';\n\nexport interface RouteFileDiscovery {\n getRouteFiles(): string[];\n getContentFiles(): string[];\n /** `server` marks page `.server.ts` files, which affect `load` types only. */\n getDiscoveredFileKind(path: string): RouteFileKind | null;\n updateDiscoveredFile(path: string, event: 'add' | 'change' | 'unlink'): void;\n /**\n * Returns true if the normalized filename was discovered from an app-local\n * glob (under the configured root) rather than from an additional directory.\n *\n * Used by collision priority to prefer app-local routes over shared/external\n * routes based on actual configured roots instead of hard-coded path\n * substrings.\n */\n isAppLocal(normalizedFilename: string): boolean;\n reset(): void;\n}\n\nexport function createRouteFileDiscovery(\n options: RouteFileDiscoveryOptions,\n): RouteFileDiscovery {\n const { root, workspaceRoot, additionalPagesDirs, additionalContentDirs } =\n options;\n\n let routeFilesCache = new Set<string>();\n let contentFilesCache = new Set<string>();\n let appLocalFilesCache = new Set<string>();\n let initialized = false;\n const joinDir = (dir: string) =>\n isWithinDir(dir, workspaceRoot)\n ? normalizePath(dir)\n : dir.startsWith('/')\n ? normalizePath(`${workspaceRoot}${dir}`)\n : normalizePath(resolve(workspaceRoot, dir));\n const additionalPagesRoots = additionalPagesDirs.map(joinDir);\n const additionalContentRoots = additionalContentDirs.map(joinDir);\n\n function normalizePath_(absolutePath: string): string {\n const normalized = normalizePath(absolutePath);\n if (isWithinDir(normalized, root)) {\n return normalized.slice(root.length);\n }\n if (isWithinDir(normalized, workspaceRoot)) {\n return normalized.slice(workspaceRoot.length);\n }\n return normalized;\n }\n\n function isWithinDir(path: string, dir: string): boolean {\n return path === dir || path.startsWith(`${dir}/`);\n }\n\n function getAppLocalFileKind(path: string): 'route' | 'content' | null {\n if (\n path.endsWith('.md') &&\n ['src/app/routes', 'src/app/pages', 'src/content'].some((dir) =>\n isWithinDir(path, `${root}/${dir}`),\n )\n )\n return 'content';\n if (\n (path.endsWith('.ts') &&\n ['app/routes', 'src/app/routes'].some((dir) =>\n isWithinDir(path, `${root}/${dir}`),\n )) ||\n (path.endsWith('.page.ts') && isWithinDir(path, `${root}/src/app/pages`))\n )\n return 'route';\n return null;\n }\n\n function getDiscoveredFileKind(path: string): RouteFileKind | null {\n const normalized = normalizePath(path);\n const localKind = getAppLocalFileKind(normalized);\n if (localKind) return localKind;\n if (\n normalized.endsWith('.md') &&\n additionalContentRoots.some((dir) => isWithinDir(normalized, dir))\n ) {\n return 'content';\n }\n if (\n normalized.endsWith('.page.ts') &&\n additionalPagesRoots.some((dir) => isWithinDir(normalized, dir))\n ) {\n return 'route';\n }\n if (\n normalized.endsWith('.server.ts') &&\n [`${root}/src/app/pages`, ...additionalPagesRoots].some((dir) =>\n isWithinDir(normalized, dir),\n )\n ) {\n return 'server';\n }\n return null;\n }\n\n function scanRouteFiles(): string[] {\n const appLocalGlobs = [\n `${root}/app/routes/**/*.ts`,\n `${root}/src/app/routes/**/*.ts`,\n `${root}/src/app/pages/**/*.page.ts`,\n ];\n const additionalGlobs = additionalPagesDirs.map(\n (dir) => `${joinDir(dir)}/**/*.page.ts`,\n );\n\n const appLocal = globSync(appLocalGlobs, {\n dot: true,\n absolute: true,\n }).map(normalizePath_);\n\n const additional = globSync(additionalGlobs, {\n dot: true,\n absolute: true,\n }).map(normalizePath_);\n\n for (const f of appLocal) {\n appLocalFilesCache.add(f);\n }\n\n return [...appLocal, ...additional];\n }\n\n function scanContentFiles(): string[] {\n const appLocalGlobs = [\n `${root}/src/app/routes/**/*.md`,\n `${root}/src/app/pages/**/*.md`,\n `${root}/src/content/**/*.md`,\n ];\n const additionalGlobs = additionalContentDirs.map(\n (dir) => `${joinDir(dir)}/**/*.md`,\n );\n\n const appLocal = globSync(appLocalGlobs, {\n dot: true,\n absolute: true,\n }).map(normalizePath_);\n\n const additional = globSync(additionalGlobs, {\n dot: true,\n absolute: true,\n }).map(normalizePath_);\n\n for (const f of appLocal) {\n appLocalFilesCache.add(f);\n }\n\n return [...appLocal, ...additional];\n }\n\n function isAppLocalByPath(absolutePath: string): boolean {\n const normalized = normalizePath(absolutePath);\n return getAppLocalFileKind(normalized) !== null;\n }\n\n function ensureInitialized(): void {\n if (initialized) {\n return;\n }\n\n routeFilesCache = new Set(scanRouteFiles());\n contentFilesCache = new Set(scanContentFiles());\n initialized = true;\n }\n\n return {\n getRouteFiles(): string[] {\n ensureInitialized();\n return [...routeFilesCache].sort();\n },\n\n getContentFiles(): string[] {\n ensureInitialized();\n return [...contentFilesCache].sort();\n },\n\n getDiscoveredFileKind(path: string): RouteFileKind | null {\n return getDiscoveredFileKind(path);\n },\n\n updateDiscoveredFile(\n path: string,\n event: 'add' | 'change' | 'unlink',\n ): void {\n ensureInitialized();\n const kind = getDiscoveredFileKind(path);\n if (!kind || kind === 'server') {\n return;\n }\n\n const normalizedPath = normalizePath_(path);\n const targetCache =\n kind === 'content' ? contentFilesCache : routeFilesCache;\n\n if (event === 'unlink') {\n targetCache.delete(normalizedPath);\n appLocalFilesCache.delete(normalizedPath);\n return;\n }\n\n targetCache.add(normalizedPath);\n if (isAppLocalByPath(path)) {\n appLocalFilesCache.add(normalizedPath);\n }\n },\n\n isAppLocal(normalizedFilename: string): boolean {\n ensureInitialized();\n return appLocalFilesCache.has(normalizedFilename);\n },\n\n reset(): void {\n initialized = false;\n appLocalFilesCache = new Set<string>();\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"route-file-discovery.js","names":[],"sources":["../../../src/lib/route-file-discovery.ts"],"sourcesContent":["import { normalizePath } from 'vite';\nimport { resolve } from 'node:path';\nimport { globSync } from 'tinyglobby';\n\nexport interface RouteFileDiscoveryOptions {\n root: string;\n workspaceRoot: string;\n additionalPagesDirs: string[];\n additionalContentDirs: string[];\n}\n\nexport type RouteFileKind = 'route' | 'content' | 'server';\n\nexport interface RouteFileDiscovery {\n getRouteFiles(): string[];\n getContentFiles(): string[];\n /** `server` marks page `.server.ts` files, which affect `load` types only. */\n getDiscoveredFileKind(path: string): RouteFileKind | null;\n updateDiscoveredFile(path: string, event: 'add' | 'change' | 'unlink'): void;\n /**\n * Returns true if the normalized filename was discovered from an app-local\n * glob (under the configured root) rather than from an additional directory.\n *\n * Used by collision priority to prefer app-local routes over shared/external\n * routes based on actual configured roots instead of hard-coded path\n * substrings.\n */\n isAppLocal(normalizedFilename: string): boolean;\n reset(): void;\n}\n\nexport function createRouteFileDiscovery(\n options: RouteFileDiscoveryOptions,\n): RouteFileDiscovery {\n const { root, workspaceRoot, additionalPagesDirs, additionalContentDirs } =\n options;\n\n let routeFilesCache = new Set<string>();\n let contentFilesCache = new Set<string>();\n let appLocalFilesCache = new Set<string>();\n let initialized = false;\n const joinDir = (dir: string) =>\n isWithinDir(dir, workspaceRoot)\n ? normalizePath(dir)\n : dir.startsWith('/')\n ? normalizePath(`${workspaceRoot}${dir}`)\n : normalizePath(resolve(workspaceRoot, dir));\n const additionalPagesRoots = additionalPagesDirs.map(joinDir);\n const additionalContentRoots = additionalContentDirs.map(joinDir);\n\n function normalizePath_(absolutePath: string): string {\n const normalized = normalizePath(absolutePath);\n if (isWithinDir(normalized, root)) {\n return normalized.slice(root.length);\n }\n if (isWithinDir(normalized, workspaceRoot)) {\n return normalized.slice(workspaceRoot.length);\n }\n return normalized;\n }\n\n function isWithinDir(path: string, dir: string): boolean {\n return path === dir || path.startsWith(`${dir}/`);\n }\n\n function getAppLocalFileKind(path: string): 'route' | 'content' | null {\n if (\n path.endsWith('.md') &&\n ['src/app/pages', 'src/content'].some((dir) =>\n isWithinDir(path, `${root}/${dir}`),\n )\n )\n return 'content';\n if (path.endsWith('.page.ts') && isWithinDir(path, `${root}/src/app/pages`))\n return 'route';\n return null;\n }\n\n function getDiscoveredFileKind(path: string): RouteFileKind | null {\n const normalized = normalizePath(path);\n const localKind = getAppLocalFileKind(normalized);\n if (localKind) return localKind;\n if (\n normalized.endsWith('.md') &&\n additionalContentRoots.some((dir) => isWithinDir(normalized, dir))\n ) {\n return 'content';\n }\n if (\n normalized.endsWith('.page.ts') &&\n additionalPagesRoots.some((dir) => isWithinDir(normalized, dir))\n ) {\n return 'route';\n }\n if (\n normalized.endsWith('.server.ts') &&\n [`${root}/src/app/pages`, ...additionalPagesRoots].some((dir) =>\n isWithinDir(normalized, dir),\n )\n ) {\n return 'server';\n }\n return null;\n }\n\n function scanRouteFiles(): string[] {\n const appLocalGlobs = [`${root}/src/app/pages/**/*.page.ts`];\n const additionalGlobs = additionalPagesDirs.map(\n (dir) => `${joinDir(dir)}/**/*.page.ts`,\n );\n\n const appLocal = globSync(appLocalGlobs, {\n dot: true,\n absolute: true,\n }).map(normalizePath_);\n\n const additional = globSync(additionalGlobs, {\n dot: true,\n absolute: true,\n }).map(normalizePath_);\n\n for (const f of appLocal) {\n appLocalFilesCache.add(f);\n }\n\n return [...appLocal, ...additional];\n }\n\n function scanContentFiles(): string[] {\n const appLocalGlobs = [\n `${root}/src/app/pages/**/*.md`,\n `${root}/src/content/**/*.md`,\n ];\n const additionalGlobs = additionalContentDirs.map(\n (dir) => `${joinDir(dir)}/**/*.md`,\n );\n\n const appLocal = globSync(appLocalGlobs, {\n dot: true,\n absolute: true,\n }).map(normalizePath_);\n\n const additional = globSync(additionalGlobs, {\n dot: true,\n absolute: true,\n }).map(normalizePath_);\n\n for (const f of appLocal) {\n appLocalFilesCache.add(f);\n }\n\n return [...appLocal, ...additional];\n }\n\n function isAppLocalByPath(absolutePath: string): boolean {\n const normalized = normalizePath(absolutePath);\n return getAppLocalFileKind(normalized) !== null;\n }\n\n function ensureInitialized(): void {\n if (initialized) {\n return;\n }\n\n routeFilesCache = new Set(scanRouteFiles());\n contentFilesCache = new Set(scanContentFiles());\n initialized = true;\n }\n\n return {\n getRouteFiles(): string[] {\n ensureInitialized();\n return [...routeFilesCache].sort();\n },\n\n getContentFiles(): string[] {\n ensureInitialized();\n return [...contentFilesCache].sort();\n },\n\n getDiscoveredFileKind(path: string): RouteFileKind | null {\n return getDiscoveredFileKind(path);\n },\n\n updateDiscoveredFile(\n path: string,\n event: 'add' | 'change' | 'unlink',\n ): void {\n ensureInitialized();\n const kind = getDiscoveredFileKind(path);\n if (!kind || kind === 'server') {\n return;\n }\n\n const normalizedPath = normalizePath_(path);\n const targetCache =\n kind === 'content' ? contentFilesCache : routeFilesCache;\n\n if (event === 'unlink') {\n targetCache.delete(normalizedPath);\n appLocalFilesCache.delete(normalizedPath);\n return;\n }\n\n targetCache.add(normalizedPath);\n if (isAppLocalByPath(path)) {\n appLocalFilesCache.add(normalizedPath);\n }\n },\n\n isAppLocal(normalizedFilename: string): boolean {\n ensureInitialized();\n return appLocalFilesCache.has(normalizedFilename);\n },\n\n reset(): void {\n initialized = false;\n appLocalFilesCache = new Set<string>();\n },\n };\n}\n"],"mappings":"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"}
@@ -17,7 +17,6 @@ function analyzeAnalogRouteFile(options) {
17
17
  const program = parseResult.program;
18
18
  const exportedBindings = collectExportedBindings(program);
19
19
  const routeMetaBindingName = exportedBindings.routeMeta;
20
- const routeJsonLdBindingName = exportedBindings.routeJsonLd;
21
20
  const diagnostics = [...parseDiagnostics];
22
21
  const routeMetaInfo = routeMetaBindingName ? getRouteMetaInfo(program, routeMetaBindingName) : null;
23
22
  if (!exportedBindings.hasDefaultExport && !routeMetaInfo?.hasRedirect) diagnostics.push({
@@ -38,12 +37,6 @@ function analyzeAnalogRouteFile(options) {
38
37
  message: "`routeMeta.redirectTo` should use an absolute path.",
39
38
  details: "Nested redirects are documented to use absolute targets such as `/cities/new-york`."
40
39
  });
41
- if (routeJsonLdBindingName) diagnostics.push({
42
- code: "legacy-route-jsonld-export",
43
- severity: "warning",
44
- message: "Prefer `routeMeta.jsonLd` over the legacy top-level `routeJsonLd` export.",
45
- details: "Keeping JSON-LD inside `routeMeta` makes the route module easier to read and matches the current docs."
46
- });
47
40
  if (isLikelyLayoutRoute(filename, routeFiles) && !ROUTER_OUTLET_RE.test(code)) diagnostics.push({
48
41
  code: "layout-without-router-outlet",
49
42
  severity: "warning",
@@ -79,8 +72,8 @@ function isLikelyLayoutRoute(filename, routeFiles) {
79
72
  return routeFiles.some((routeFile) => routeFile !== filename && routeFile.startsWith(`${routeStem}/`));
80
73
  }
81
74
  function getRouteMetaInfo(program, bindingName) {
82
- const routeMetaNode = unwrapRouteMetaObject(getExportedBindingInitializer(program, bindingName));
83
- if (!routeMetaNode) return null;
75
+ const routeMetaNode = getExportedBindingInitializer(program, bindingName);
76
+ if (routeMetaNode?.type !== "ObjectExpression") return null;
84
77
  let redirectTo;
85
78
  for (const property of routeMetaNode.properties ?? []) {
86
79
  if (property?.type !== "Property") continue;
@@ -92,15 +85,6 @@ function getRouteMetaInfo(program, bindingName) {
92
85
  redirectTo
93
86
  };
94
87
  }
95
- function unwrapRouteMetaObject(initializer) {
96
- if (!initializer) return null;
97
- if (initializer.type === "ObjectExpression") return initializer;
98
- if (initializer.type === "CallExpression" && initializer.callee?.type === "Identifier" && initializer.callee.name === "defineRouteMeta") {
99
- const firstArgument = initializer.arguments?.[0];
100
- return firstArgument?.type === "ObjectExpression" ? firstArgument : null;
101
- }
102
- return null;
103
- }
104
88
  function getExportedBindingInitializer(program, bindingName) {
105
89
  for (const statement of program.body ?? []) {
106
90
  if (statement?.type === "VariableDeclaration") {
@@ -120,7 +104,6 @@ function getVariableInitializer(declaration, bindingName) {
120
104
  function collectExportedBindings(program) {
121
105
  let hasDefaultExport = false;
122
106
  let routeMeta;
123
- let routeJsonLd;
124
107
  for (const statement of program.body ?? []) {
125
108
  if (statement?.type === "ExportDefaultDeclaration") {
126
109
  hasDefaultExport = true;
@@ -131,19 +114,16 @@ function collectExportedBindings(program) {
131
114
  if (declaration?.type === "VariableDeclaration") for (const declarator of declaration.declarations ?? []) {
132
115
  if (declarator.id?.type !== "Identifier") continue;
133
116
  if (declarator.id.name === "routeMeta") routeMeta = "routeMeta";
134
- if (declarator.id.name === "routeJsonLd") routeJsonLd = "routeJsonLd";
135
117
  }
136
118
  for (const specifier of statement.specifiers ?? []) {
137
119
  if (specifier?.type !== "ExportSpecifier" || specifier.local?.type !== "Identifier") continue;
138
120
  if (specifier.exported?.type !== "Identifier") continue;
139
121
  if (specifier.exported.name === "routeMeta") routeMeta = specifier.local.name;
140
- if (specifier.exported.name === "routeJsonLd") routeJsonLd = specifier.local.name;
141
122
  }
142
123
  }
143
124
  return {
144
125
  hasDefaultExport,
145
- routeMeta,
146
- routeJsonLd
126
+ routeMeta
147
127
  };
148
128
  }
149
129
  function getPropertyName(node) {
@@ -1 +1 @@
1
- {"version":3,"file":"route-idiom-diagnostics.js","names":[],"sources":["../../../src/lib/route-idiom-diagnostics.ts"],"sourcesContent":["import { parseSync, type OxcError, type Severity } from 'oxc-parser';\nimport { relative } from 'node:path';\nimport { normalizePath } from 'vite';\n\nexport interface AnalogRouteIdiomDiagnostic {\n code: string;\n severity: 'error' | 'warning';\n message: string;\n details?: string;\n}\n\nexport interface AnalyzeAnalogRouteFileOptions {\n filename: string;\n code: string;\n routeFiles?: string[];\n}\n\nconst PAGE_FILE_RE = /\\.page\\.ts$/;\nconst ROUTER_OUTLET_RE = /\\bRouterOutlet\\b|<router-outlet(?:\\s|>)/;\n\nexport function analyzeAnalogRouteFile(\n options: AnalyzeAnalogRouteFileOptions,\n): AnalogRouteIdiomDiagnostic[] {\n const { filename, code, routeFiles = [] } = options;\n const parseResult = parseSync(filename, code, {\n lang: 'ts',\n sourceType: 'module',\n range: true,\n showSemanticErrors: true,\n });\n\n const parseDiagnostics = parseResult.errors.map((error) =>\n toParseDiagnostic(error),\n );\n\n if (parseDiagnostics.some((diagnostic) => diagnostic.severity === 'error')) {\n return parseDiagnostics;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const program: any = parseResult.program;\n const exportedBindings = collectExportedBindings(program);\n const routeMetaBindingName = exportedBindings.routeMeta;\n const routeJsonLdBindingName = exportedBindings.routeJsonLd;\n const diagnostics = [...parseDiagnostics];\n\n const routeMetaInfo = routeMetaBindingName\n ? getRouteMetaInfo(program, routeMetaBindingName)\n : null;\n\n if (!exportedBindings.hasDefaultExport && !routeMetaInfo?.hasRedirect) {\n diagnostics.push({\n code: 'missing-default-export',\n severity: 'warning',\n message:\n 'Route files should default-export the page component, unless they are redirect-only routes.',\n details:\n 'Add `export default class ...` or define `routeMeta.redirectTo` for a redirect route.',\n });\n }\n\n if (exportedBindings.hasDefaultExport && routeMetaInfo?.hasRedirect) {\n diagnostics.push({\n code: 'redirect-with-component',\n severity: 'warning',\n message: 'Redirect routes should not also export a page component.',\n details:\n 'Analog ignores the default export when `routeMeta.redirectTo` is present. Remove the component export or remove the redirect.',\n });\n }\n\n if (\n routeMetaInfo?.hasRedirect &&\n routeMetaInfo.redirectTo &&\n !routeMetaInfo.redirectTo.startsWith('/')\n ) {\n diagnostics.push({\n code: 'relative-redirect',\n severity: 'warning',\n message: '`routeMeta.redirectTo` should use an absolute path.',\n details:\n 'Nested redirects are documented to use absolute targets such as `/cities/new-york`.',\n });\n }\n\n if (routeJsonLdBindingName) {\n diagnostics.push({\n code: 'legacy-route-jsonld-export',\n severity: 'warning',\n message:\n 'Prefer `routeMeta.jsonLd` over the legacy top-level `routeJsonLd` export.',\n details:\n 'Keeping JSON-LD inside `routeMeta` makes the route module easier to read and matches the current docs.',\n });\n }\n\n if (\n isLikelyLayoutRoute(filename, routeFiles) &&\n !ROUTER_OUTLET_RE.test(code)\n ) {\n diagnostics.push({\n code: 'layout-without-router-outlet',\n severity: 'warning',\n message:\n 'This route file looks like a layout shell, but it does not reference `RouterOutlet` or `<router-outlet>`.',\n details:\n 'Parent layout pages usually import `RouterOutlet` and render an outlet so child routes have somewhere to mount.',\n });\n }\n\n return diagnostics;\n}\n\nexport function formatAnalogRouteIdiomDiagnostic(\n diagnostic: AnalogRouteIdiomDiagnostic,\n filename: string,\n workspaceRoot: string,\n): string {\n const displayName = toDisplayPath(filename, workspaceRoot);\n const header = `[Analog] ${displayName} (${diagnostic.code})`;\n const severity = diagnostic.severity.toUpperCase();\n\n if (diagnostic.details) {\n return `${header}\\n${severity}: ${diagnostic.message}\\n${diagnostic.details}`;\n }\n\n return `${header}\\n${severity}: ${diagnostic.message}`;\n}\n\nfunction toDisplayPath(filename: string, workspaceRoot: string): string {\n const normalizedFilename = normalizePath(filename);\n const normalizedRoot = normalizePath(workspaceRoot);\n const relativePath = normalizePath(\n relative(normalizedRoot, normalizedFilename),\n );\n\n if (relativePath && !relativePath.startsWith('..')) {\n return `/${relativePath}`;\n }\n\n return normalizedFilename;\n}\n\nfunction toParseDiagnostic(error: OxcError): AnalogRouteIdiomDiagnostic {\n return {\n code: 'oxc-parse',\n severity: error.severity === severityError ? 'error' : 'warning',\n message: error.message,\n details: error.codeframe ?? error.helpMessage ?? undefined,\n };\n}\n\nconst severityError: Severity = 'Error';\n\nfunction isLikelyLayoutRoute(filename: string, routeFiles: string[]): boolean {\n if (!PAGE_FILE_RE.test(filename)) {\n return false;\n }\n\n const routeStem = filename.replace(PAGE_FILE_RE, '');\n return routeFiles.some(\n (routeFile) =>\n routeFile !== filename && routeFile.startsWith(`${routeStem}/`),\n );\n}\n\nfunction getRouteMetaInfo(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n program: any,\n bindingName: string,\n): {\n hasRedirect: boolean;\n redirectTo?: string;\n} | null {\n const initializer = getExportedBindingInitializer(program, bindingName);\n const routeMetaNode = unwrapRouteMetaObject(initializer);\n\n if (!routeMetaNode) {\n return null;\n }\n\n let redirectTo: string | undefined;\n\n for (const property of routeMetaNode.properties ?? []) {\n if (property?.type !== 'Property') {\n continue;\n }\n\n const keyName = getPropertyName(property.key);\n if (keyName !== 'redirectTo') {\n continue;\n }\n\n redirectTo = getStringValue(property.value);\n }\n\n return {\n hasRedirect: typeof redirectTo === 'string' && redirectTo.length > 0,\n redirectTo,\n };\n}\n\nfunction unwrapRouteMetaObject(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n initializer: any,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): any | null {\n if (!initializer) {\n return null;\n }\n\n if (initializer.type === 'ObjectExpression') {\n return initializer;\n }\n\n if (\n initializer.type === 'CallExpression' &&\n initializer.callee?.type === 'Identifier' &&\n initializer.callee.name === 'defineRouteMeta'\n ) {\n const firstArgument = initializer.arguments?.[0];\n return firstArgument?.type === 'ObjectExpression' ? firstArgument : null;\n }\n\n return null;\n}\n\nfunction getExportedBindingInitializer(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n program: any,\n bindingName: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): any | undefined {\n for (const statement of program.body ?? []) {\n if (statement?.type === 'VariableDeclaration') {\n const initializer = getVariableInitializer(statement, bindingName);\n if (initializer) {\n return initializer;\n }\n continue;\n }\n\n if (\n statement?.type === 'ExportNamedDeclaration' &&\n statement.declaration?.type === 'VariableDeclaration'\n ) {\n const initializer = getVariableInitializer(\n statement.declaration,\n bindingName,\n );\n if (initializer) {\n return initializer;\n }\n }\n }\n\n return undefined;\n}\n\nfunction getVariableInitializer(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n declaration: any,\n bindingName: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): any | undefined {\n for (const declarator of declaration.declarations ?? []) {\n if (\n declarator.id?.type === 'Identifier' &&\n declarator.id.name === bindingName\n ) {\n return declarator.init;\n }\n }\n\n return undefined;\n}\n\nfunction collectExportedBindings(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n program: any,\n): {\n hasDefaultExport: boolean;\n routeMeta?: string;\n routeJsonLd?: string;\n} {\n let hasDefaultExport = false;\n let routeMeta: string | undefined;\n let routeJsonLd: string | undefined;\n\n for (const statement of program.body ?? []) {\n if (statement?.type === 'ExportDefaultDeclaration') {\n hasDefaultExport = true;\n continue;\n }\n\n if (statement?.type !== 'ExportNamedDeclaration') {\n continue;\n }\n\n const declaration = statement.declaration;\n if (declaration?.type === 'VariableDeclaration') {\n for (const declarator of declaration.declarations ?? []) {\n if (declarator.id?.type !== 'Identifier') {\n continue;\n }\n\n if (declarator.id.name === 'routeMeta') {\n routeMeta = 'routeMeta';\n }\n\n if (declarator.id.name === 'routeJsonLd') {\n routeJsonLd = 'routeJsonLd';\n }\n }\n }\n\n for (const specifier of statement.specifiers ?? []) {\n if (\n specifier?.type !== 'ExportSpecifier' ||\n specifier.local?.type !== 'Identifier'\n ) {\n continue;\n }\n\n if (specifier.exported?.type !== 'Identifier') {\n continue;\n }\n\n if (specifier.exported.name === 'routeMeta') {\n routeMeta = specifier.local.name;\n }\n\n if (specifier.exported.name === 'routeJsonLd') {\n routeJsonLd = specifier.local.name;\n }\n }\n }\n\n return {\n hasDefaultExport,\n routeMeta,\n routeJsonLd,\n };\n}\n\nfunction getPropertyName(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n node: any,\n): string | undefined {\n if (node?.type === 'Identifier') {\n return node.name;\n }\n\n if (\n (node?.type === 'Literal' || node?.type === 'StringLiteral') &&\n typeof node.value === 'string'\n ) {\n return node.value;\n }\n\n return undefined;\n}\n\nfunction getStringValue(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n node: any,\n): string | undefined {\n if (\n (node?.type === 'Literal' || node?.type === 'StringLiteral') &&\n typeof node.value === 'string'\n ) {\n return node.value;\n }\n\n if (\n node?.type === 'TemplateLiteral' &&\n node.expressions?.length === 0 &&\n node.quasis?.length === 1\n ) {\n return node.quasis[0].value.cooked ?? node.quasis[0].value.raw;\n }\n\n return undefined;\n}\n"],"mappings":";;;;AAiBA,IAAM,eAAe;AACrB,IAAM,mBAAmB;AAEzB,SAAgB,uBACd,SAC8B;CAC9B,MAAM,EAAE,UAAU,MAAM,aAAa,EAAE,KAAK;CAC5C,MAAM,cAAc,UAAU,UAAU,MAAM;EAC5C,MAAM;EACN,YAAY;EACZ,OAAO;EACP,oBAAoB;EACrB,CAAC;CAEF,MAAM,mBAAmB,YAAY,OAAO,KAAK,UAC/C,kBAAkB,MAAM,CACzB;AAED,KAAI,iBAAiB,MAAM,eAAe,WAAW,aAAa,QAAQ,CACxE,QAAO;CAIT,MAAM,UAAe,YAAY;CACjC,MAAM,mBAAmB,wBAAwB,QAAQ;CACzD,MAAM,uBAAuB,iBAAiB;CAC9C,MAAM,yBAAyB,iBAAiB;CAChD,MAAM,cAAc,CAAC,GAAG,iBAAiB;CAEzC,MAAM,gBAAgB,uBAClB,iBAAiB,SAAS,qBAAqB,GAC/C;AAEJ,KAAI,CAAC,iBAAiB,oBAAoB,CAAC,eAAe,YACxD,aAAY,KAAK;EACf,MAAM;EACN,UAAU;EACV,SACE;EACF,SACE;EACH,CAAC;AAGJ,KAAI,iBAAiB,oBAAoB,eAAe,YACtD,aAAY,KAAK;EACf,MAAM;EACN,UAAU;EACV,SAAS;EACT,SACE;EACH,CAAC;AAGJ,KACE,eAAe,eACf,cAAc,cACd,CAAC,cAAc,WAAW,WAAW,IAAI,CAEzC,aAAY,KAAK;EACf,MAAM;EACN,UAAU;EACV,SAAS;EACT,SACE;EACH,CAAC;AAGJ,KAAI,uBACF,aAAY,KAAK;EACf,MAAM;EACN,UAAU;EACV,SACE;EACF,SACE;EACH,CAAC;AAGJ,KACE,oBAAoB,UAAU,WAAW,IACzC,CAAC,iBAAiB,KAAK,KAAK,CAE5B,aAAY,KAAK;EACf,MAAM;EACN,UAAU;EACV,SACE;EACF,SACE;EACH,CAAC;AAGJ,QAAO;;AAGT,SAAgB,iCACd,YACA,UACA,eACQ;CAER,MAAM,SAAS,YADK,cAAc,UAAU,cAAc,CACnB,IAAI,WAAW,KAAK;CAC3D,MAAM,WAAW,WAAW,SAAS,aAAa;AAElD,KAAI,WAAW,QACb,QAAO,GAAG,OAAO,IAAI,SAAS,IAAI,WAAW,QAAQ,IAAI,WAAW;AAGtE,QAAO,GAAG,OAAO,IAAI,SAAS,IAAI,WAAW;;AAG/C,SAAS,cAAc,UAAkB,eAA+B;CACtE,MAAM,qBAAqB,cAAc,SAAS;CAElD,MAAM,eAAe,cACnB,SAFqB,cAAc,cAAc,EAExB,mBAAmB,CAC7C;AAED,KAAI,gBAAgB,CAAC,aAAa,WAAW,KAAK,CAChD,QAAO,IAAI;AAGb,QAAO;;AAGT,SAAS,kBAAkB,OAA6C;AACtE,QAAO;EACL,MAAM;EACN,UAAU,MAAM,aAAa,gBAAgB,UAAU;EACvD,SAAS,MAAM;EACf,SAAS,MAAM,aAAa,MAAM,eAAe,KAAA;EAClD;;AAGH,IAAM,gBAA0B;AAEhC,SAAS,oBAAoB,UAAkB,YAA+B;AAC5E,KAAI,CAAC,aAAa,KAAK,SAAS,CAC9B,QAAO;CAGT,MAAM,YAAY,SAAS,QAAQ,cAAc,GAAG;AACpD,QAAO,WAAW,MACf,cACC,cAAc,YAAY,UAAU,WAAW,GAAG,UAAU,GAAG,CAClE;;AAGH,SAAS,iBAEP,SACA,aAIO;CAEP,MAAM,gBAAgB,sBADF,8BAA8B,SAAS,YAAY,CACf;AAExD,KAAI,CAAC,cACH,QAAO;CAGT,IAAI;AAEJ,MAAK,MAAM,YAAY,cAAc,cAAc,EAAE,EAAE;AACrD,MAAI,UAAU,SAAS,WACrB;AAIF,MADgB,gBAAgB,SAAS,IAAI,KAC7B,aACd;AAGF,eAAa,eAAe,SAAS,MAAM;;AAG7C,QAAO;EACL,aAAa,OAAO,eAAe,YAAY,WAAW,SAAS;EACnE;EACD;;AAGH,SAAS,sBAEP,aAEY;AACZ,KAAI,CAAC,YACH,QAAO;AAGT,KAAI,YAAY,SAAS,mBACvB,QAAO;AAGT,KACE,YAAY,SAAS,oBACrB,YAAY,QAAQ,SAAS,gBAC7B,YAAY,OAAO,SAAS,mBAC5B;EACA,MAAM,gBAAgB,YAAY,YAAY;AAC9C,SAAO,eAAe,SAAS,qBAAqB,gBAAgB;;AAGtE,QAAO;;AAGT,SAAS,8BAEP,SACA,aAEiB;AACjB,MAAK,MAAM,aAAa,QAAQ,QAAQ,EAAE,EAAE;AAC1C,MAAI,WAAW,SAAS,uBAAuB;GAC7C,MAAM,cAAc,uBAAuB,WAAW,YAAY;AAClE,OAAI,YACF,QAAO;AAET;;AAGF,MACE,WAAW,SAAS,4BACpB,UAAU,aAAa,SAAS,uBAChC;GACA,MAAM,cAAc,uBAClB,UAAU,aACV,YACD;AACD,OAAI,YACF,QAAO;;;;AAQf,SAAS,uBAEP,aACA,aAEiB;AACjB,MAAK,MAAM,cAAc,YAAY,gBAAgB,EAAE,CACrD,KACE,WAAW,IAAI,SAAS,gBACxB,WAAW,GAAG,SAAS,YAEvB,QAAO,WAAW;;AAOxB,SAAS,wBAEP,SAKA;CACA,IAAI,mBAAmB;CACvB,IAAI;CACJ,IAAI;AAEJ,MAAK,MAAM,aAAa,QAAQ,QAAQ,EAAE,EAAE;AAC1C,MAAI,WAAW,SAAS,4BAA4B;AAClD,sBAAmB;AACnB;;AAGF,MAAI,WAAW,SAAS,yBACtB;EAGF,MAAM,cAAc,UAAU;AAC9B,MAAI,aAAa,SAAS,sBACxB,MAAK,MAAM,cAAc,YAAY,gBAAgB,EAAE,EAAE;AACvD,OAAI,WAAW,IAAI,SAAS,aAC1B;AAGF,OAAI,WAAW,GAAG,SAAS,YACzB,aAAY;AAGd,OAAI,WAAW,GAAG,SAAS,cACzB,eAAc;;AAKpB,OAAK,MAAM,aAAa,UAAU,cAAc,EAAE,EAAE;AAClD,OACE,WAAW,SAAS,qBACpB,UAAU,OAAO,SAAS,aAE1B;AAGF,OAAI,UAAU,UAAU,SAAS,aAC/B;AAGF,OAAI,UAAU,SAAS,SAAS,YAC9B,aAAY,UAAU,MAAM;AAG9B,OAAI,UAAU,SAAS,SAAS,cAC9B,eAAc,UAAU,MAAM;;;AAKpC,QAAO;EACL;EACA;EACA;EACD;;AAGH,SAAS,gBAEP,MACoB;AACpB,KAAI,MAAM,SAAS,aACjB,QAAO,KAAK;AAGd,MACG,MAAM,SAAS,aAAa,MAAM,SAAS,oBAC5C,OAAO,KAAK,UAAU,SAEtB,QAAO,KAAK;;AAMhB,SAAS,eAEP,MACoB;AACpB,MACG,MAAM,SAAS,aAAa,MAAM,SAAS,oBAC5C,OAAO,KAAK,UAAU,SAEtB,QAAO,KAAK;AAGd,KACE,MAAM,SAAS,qBACf,KAAK,aAAa,WAAW,KAC7B,KAAK,QAAQ,WAAW,EAExB,QAAO,KAAK,OAAO,GAAG,MAAM,UAAU,KAAK,OAAO,GAAG,MAAM"}
1
+ {"version":3,"file":"route-idiom-diagnostics.js","names":[],"sources":["../../../src/lib/route-idiom-diagnostics.ts"],"sourcesContent":["import { parseSync, type OxcError, type Severity } from 'oxc-parser';\nimport { relative } from 'node:path';\nimport { normalizePath } from 'vite';\n\nexport interface AnalogRouteIdiomDiagnostic {\n code: string;\n severity: 'error' | 'warning';\n message: string;\n details?: string;\n}\n\nexport interface AnalyzeAnalogRouteFileOptions {\n filename: string;\n code: string;\n routeFiles?: string[];\n}\n\nconst PAGE_FILE_RE = /\\.page\\.ts$/;\nconst ROUTER_OUTLET_RE = /\\bRouterOutlet\\b|<router-outlet(?:\\s|>)/;\n\nexport function analyzeAnalogRouteFile(\n options: AnalyzeAnalogRouteFileOptions,\n): AnalogRouteIdiomDiagnostic[] {\n const { filename, code, routeFiles = [] } = options;\n const parseResult = parseSync(filename, code, {\n lang: 'ts',\n sourceType: 'module',\n range: true,\n showSemanticErrors: true,\n });\n\n const parseDiagnostics = parseResult.errors.map((error) =>\n toParseDiagnostic(error),\n );\n\n if (parseDiagnostics.some((diagnostic) => diagnostic.severity === 'error')) {\n return parseDiagnostics;\n }\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const program: any = parseResult.program;\n const exportedBindings = collectExportedBindings(program);\n const routeMetaBindingName = exportedBindings.routeMeta;\n const diagnostics = [...parseDiagnostics];\n\n const routeMetaInfo = routeMetaBindingName\n ? getRouteMetaInfo(program, routeMetaBindingName)\n : null;\n\n if (!exportedBindings.hasDefaultExport && !routeMetaInfo?.hasRedirect) {\n diagnostics.push({\n code: 'missing-default-export',\n severity: 'warning',\n message:\n 'Route files should default-export the page component, unless they are redirect-only routes.',\n details:\n 'Add `export default class ...` or define `routeMeta.redirectTo` for a redirect route.',\n });\n }\n\n if (exportedBindings.hasDefaultExport && routeMetaInfo?.hasRedirect) {\n diagnostics.push({\n code: 'redirect-with-component',\n severity: 'warning',\n message: 'Redirect routes should not also export a page component.',\n details:\n 'Analog ignores the default export when `routeMeta.redirectTo` is present. Remove the component export or remove the redirect.',\n });\n }\n\n if (\n routeMetaInfo?.hasRedirect &&\n routeMetaInfo.redirectTo &&\n !routeMetaInfo.redirectTo.startsWith('/')\n ) {\n diagnostics.push({\n code: 'relative-redirect',\n severity: 'warning',\n message: '`routeMeta.redirectTo` should use an absolute path.',\n details:\n 'Nested redirects are documented to use absolute targets such as `/cities/new-york`.',\n });\n }\n\n if (\n isLikelyLayoutRoute(filename, routeFiles) &&\n !ROUTER_OUTLET_RE.test(code)\n ) {\n diagnostics.push({\n code: 'layout-without-router-outlet',\n severity: 'warning',\n message:\n 'This route file looks like a layout shell, but it does not reference `RouterOutlet` or `<router-outlet>`.',\n details:\n 'Parent layout pages usually import `RouterOutlet` and render an outlet so child routes have somewhere to mount.',\n });\n }\n\n return diagnostics;\n}\n\nexport function formatAnalogRouteIdiomDiagnostic(\n diagnostic: AnalogRouteIdiomDiagnostic,\n filename: string,\n workspaceRoot: string,\n): string {\n const displayName = toDisplayPath(filename, workspaceRoot);\n const header = `[Analog] ${displayName} (${diagnostic.code})`;\n const severity = diagnostic.severity.toUpperCase();\n\n if (diagnostic.details) {\n return `${header}\\n${severity}: ${diagnostic.message}\\n${diagnostic.details}`;\n }\n\n return `${header}\\n${severity}: ${diagnostic.message}`;\n}\n\nfunction toDisplayPath(filename: string, workspaceRoot: string): string {\n const normalizedFilename = normalizePath(filename);\n const normalizedRoot = normalizePath(workspaceRoot);\n const relativePath = normalizePath(\n relative(normalizedRoot, normalizedFilename),\n );\n\n if (relativePath && !relativePath.startsWith('..')) {\n return `/${relativePath}`;\n }\n\n return normalizedFilename;\n}\n\nfunction toParseDiagnostic(error: OxcError): AnalogRouteIdiomDiagnostic {\n return {\n code: 'oxc-parse',\n severity: error.severity === severityError ? 'error' : 'warning',\n message: error.message,\n details: error.codeframe ?? error.helpMessage ?? undefined,\n };\n}\n\nconst severityError: Severity = 'Error';\n\nfunction isLikelyLayoutRoute(filename: string, routeFiles: string[]): boolean {\n if (!PAGE_FILE_RE.test(filename)) {\n return false;\n }\n\n const routeStem = filename.replace(PAGE_FILE_RE, '');\n return routeFiles.some(\n (routeFile) =>\n routeFile !== filename && routeFile.startsWith(`${routeStem}/`),\n );\n}\n\nfunction getRouteMetaInfo(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n program: any,\n bindingName: string,\n): {\n hasRedirect: boolean;\n redirectTo?: string;\n} | null {\n const routeMetaNode = getExportedBindingInitializer(program, bindingName);\n\n if (routeMetaNode?.type !== 'ObjectExpression') {\n return null;\n }\n\n let redirectTo: string | undefined;\n\n for (const property of routeMetaNode.properties ?? []) {\n if (property?.type !== 'Property') {\n continue;\n }\n\n const keyName = getPropertyName(property.key);\n if (keyName !== 'redirectTo') {\n continue;\n }\n\n redirectTo = getStringValue(property.value);\n }\n\n return {\n hasRedirect: typeof redirectTo === 'string' && redirectTo.length > 0,\n redirectTo,\n };\n}\n\nfunction getExportedBindingInitializer(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n program: any,\n bindingName: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): any | undefined {\n for (const statement of program.body ?? []) {\n if (statement?.type === 'VariableDeclaration') {\n const initializer = getVariableInitializer(statement, bindingName);\n if (initializer) {\n return initializer;\n }\n continue;\n }\n\n if (\n statement?.type === 'ExportNamedDeclaration' &&\n statement.declaration?.type === 'VariableDeclaration'\n ) {\n const initializer = getVariableInitializer(\n statement.declaration,\n bindingName,\n );\n if (initializer) {\n return initializer;\n }\n }\n }\n\n return undefined;\n}\n\nfunction getVariableInitializer(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n declaration: any,\n bindingName: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): any | undefined {\n for (const declarator of declaration.declarations ?? []) {\n if (\n declarator.id?.type === 'Identifier' &&\n declarator.id.name === bindingName\n ) {\n return declarator.init;\n }\n }\n\n return undefined;\n}\n\nfunction collectExportedBindings(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n program: any,\n): {\n hasDefaultExport: boolean;\n routeMeta?: string;\n} {\n let hasDefaultExport = false;\n let routeMeta: string | undefined;\n\n for (const statement of program.body ?? []) {\n if (statement?.type === 'ExportDefaultDeclaration') {\n hasDefaultExport = true;\n continue;\n }\n\n if (statement?.type !== 'ExportNamedDeclaration') {\n continue;\n }\n\n const declaration = statement.declaration;\n if (declaration?.type === 'VariableDeclaration') {\n for (const declarator of declaration.declarations ?? []) {\n if (declarator.id?.type !== 'Identifier') {\n continue;\n }\n\n if (declarator.id.name === 'routeMeta') {\n routeMeta = 'routeMeta';\n }\n }\n }\n\n for (const specifier of statement.specifiers ?? []) {\n if (\n specifier?.type !== 'ExportSpecifier' ||\n specifier.local?.type !== 'Identifier'\n ) {\n continue;\n }\n\n if (specifier.exported?.type !== 'Identifier') {\n continue;\n }\n\n if (specifier.exported.name === 'routeMeta') {\n routeMeta = specifier.local.name;\n }\n }\n }\n\n return {\n hasDefaultExport,\n routeMeta,\n };\n}\n\nfunction getPropertyName(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n node: any,\n): string | undefined {\n if (node?.type === 'Identifier') {\n return node.name;\n }\n\n if (\n (node?.type === 'Literal' || node?.type === 'StringLiteral') &&\n typeof node.value === 'string'\n ) {\n return node.value;\n }\n\n return undefined;\n}\n\nfunction getStringValue(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n node: any,\n): string | undefined {\n if (\n (node?.type === 'Literal' || node?.type === 'StringLiteral') &&\n typeof node.value === 'string'\n ) {\n return node.value;\n }\n\n if (\n node?.type === 'TemplateLiteral' &&\n node.expressions?.length === 0 &&\n node.quasis?.length === 1\n ) {\n return node.quasis[0].value.cooked ?? node.quasis[0].value.raw;\n }\n\n return undefined;\n}\n"],"mappings":"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"}
@@ -63,16 +63,16 @@ export interface RouteManifest {
63
63
  * up to and including the first /routes/, /pages/, or /content/ segment.
64
64
  * Handles app-local paths (`/src/app/pages/`) AND additional dirs
65
65
  * (`/libs/shared/feature/src/content/`) uniformly.
66
- * 2. `[\\/](?:app[\\/](?:routes|pages)|src[\\/]content)[\\/]` — non-anchored
67
- * fallback for legacy paths where the directory marker appears mid-string.
66
+ * 2. `[\\/](?:app[\\/]pages|src[\\/]content)[\\/]` — non-anchored
67
+ * fallback for paths where the directory marker appears mid-string.
68
68
  * 3. `\.page\.(js|ts)$` — strips page file extensions.
69
69
  * 4. `\.(ts|md)$` — strips remaining file extensions.
70
70
  *
71
71
  * Examples:
72
- * - '/app/routes/index.ts' -> '/'
73
- * - '/app/routes/about.ts' -> '/about'
72
+ * - '/src/app/pages/index.page.ts' -> '/'
73
+ * - '/src/app/pages/about.page.ts' -> '/about'
74
74
  * - '/src/app/pages/users/[id].page.ts' -> '/users/[id]'
75
- * - '/app/routes/blog.[slug].ts' -> '/blog/[slug]'
75
+ * - '/src/app/pages/blog.[slug].page.ts' -> '/blog/[slug]'
76
76
  * - '/src/app/pages/(auth)/login.page.ts' -> '/login'
77
77
  * - '/src/app/pages/docs/[...slug].page.ts' -> '/docs/[...slug]'
78
78
  * - '/src/app/pages/shop/[[...category]].page.ts' -> '/shop/[[...category]]'
@@ -11,23 +11,23 @@
11
11
  * up to and including the first /routes/, /pages/, or /content/ segment.
12
12
  * Handles app-local paths (`/src/app/pages/`) AND additional dirs
13
13
  * (`/libs/shared/feature/src/content/`) uniformly.
14
- * 2. `[\\/](?:app[\\/](?:routes|pages)|src[\\/]content)[\\/]` — non-anchored
15
- * fallback for legacy paths where the directory marker appears mid-string.
14
+ * 2. `[\\/](?:app[\\/]pages|src[\\/]content)[\\/]` — non-anchored
15
+ * fallback for paths where the directory marker appears mid-string.
16
16
  * 3. `\.page\.(js|ts)$` — strips page file extensions.
17
17
  * 4. `\.(ts|md)$` — strips remaining file extensions.
18
18
  *
19
19
  * Examples:
20
- * - '/app/routes/index.ts' -> '/'
21
- * - '/app/routes/about.ts' -> '/about'
20
+ * - '/src/app/pages/index.page.ts' -> '/'
21
+ * - '/src/app/pages/about.page.ts' -> '/about'
22
22
  * - '/src/app/pages/users/[id].page.ts' -> '/users/[id]'
23
- * - '/app/routes/blog.[slug].ts' -> '/blog/[slug]'
23
+ * - '/src/app/pages/blog.[slug].page.ts' -> '/blog/[slug]'
24
24
  * - '/src/app/pages/(auth)/login.page.ts' -> '/login'
25
25
  * - '/src/app/pages/docs/[...slug].page.ts' -> '/docs/[...slug]'
26
26
  * - '/src/app/pages/shop/[[...category]].page.ts' -> '/shop/[[...category]]'
27
27
  * - '/libs/shared/feature/src/content/test.md' -> '/test'
28
28
  */
29
29
  function filenameToRoutePath(filename) {
30
- let path = filename.replace(/^(?:[a-zA-Z]:[\\/])?(.*?)[\\/](?:routes|pages|content)[\\/]|(?:[\\/](?:app[\\/](?:routes|pages)|src[\\/]content)[\\/])|(\.page\.(js|ts)$)|(\.(ts|md)$)/g, "");
30
+ let path = filename.replace(/^(?:[a-zA-Z]:[\\/])?(.*?)[\\/](?:routes|pages|content)[\\/]|(?:[\\/](?:app[\\/]pages|src[\\/]content)[\\/])|(\.page\.(js|ts)$)|(\.(ts|md)$)/g, "");
31
31
  const brackets = [];
32
32
  path = path.replace(/\[\[?\.{0,3}[^\]]*\]?\]/g, (match) => {
33
33
  brackets.push(match);
@@ -48,7 +48,7 @@ function filenameToRoutePath(filename) {
48
48
  * changes to the regex must be kept in sync between both functions.
49
49
  */
50
50
  function filenameToRouteId(filename) {
51
- let path = filename.replace(/^(?:[a-zA-Z]:[\\/])?(.*?)[\\/](?:routes|pages|content)[\\/]|(?:[\\/](?:app[\\/](?:routes|pages)|src[\\/]content)[\\/])|(\.page\.(js|ts)$)|(\.(ts|md)$)/g, "");
51
+ let path = filename.replace(/^(?:[a-zA-Z]:[\\/])?(.*?)[\\/](?:routes|pages|content)[\\/]|(?:[\\/](?:app[\\/]pages|src[\\/]content)[\\/])|(\.page\.(js|ts)$)|(\.(ts|md)$)/g, "");
52
52
  const brackets = [];
53
53
  path = path.replace(/\(.*?\)|\[\[?\.{0,3}[^\]]*\]?\]/g, (match) => {
54
54
  brackets.push(match);
@@ -213,7 +213,7 @@ function getRouteWeight(path) {
213
213
  return 0;
214
214
  }
215
215
  function getCollisionPriority(filename) {
216
- if (filename.includes("/src/app/pages/") || filename.includes("/src/app/routes/") || filename.includes("/app/pages/") || filename.includes("/app/routes/") || filename.includes("/src/content/")) return 0;
216
+ if (filename.includes("/src/app/pages/") || filename.includes("/app/pages/") || filename.includes("/src/content/")) return 0;
217
217
  return 1;
218
218
  }
219
219
  /**