@tanstack/router-generator 1.58.12 → 1.64.0

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.
@@ -7,13 +7,13 @@ const indexRouteSchema = zod.z.object({
7
7
  });
8
8
  const layoutRouteSchema = zod.z.object({
9
9
  type: zod.z.literal("layout"),
10
- id: zod.z.string(),
10
+ id: zod.z.string().optional(),
11
11
  file: zod.z.string(),
12
12
  children: zod.z.array(zod.z.lazy(() => virtualRouteNodeSchema)).optional()
13
13
  });
14
14
  const routeSchema = zod.z.object({
15
15
  type: zod.z.literal("route"),
16
- file: zod.z.string(),
16
+ file: zod.z.string().optional(),
17
17
  path: zod.z.string(),
18
18
  children: zod.z.array(zod.z.lazy(() => virtualRouteNodeSchema)).optional()
19
19
  });
@@ -1 +1 @@
1
- {"version":3,"file":"config.cjs","sources":["../../../../src/filesystem/virtual/config.ts"],"sourcesContent":["import { z } from 'zod'\nimport type {\n LayoutRoute,\n PhysicalSubtree,\n Route,\n VirtualRootRoute,\n} from '@tanstack/virtual-file-routes'\n\nconst indexRouteSchema = z.object({\n type: z.literal('index'),\n file: z.string(),\n})\n\nconst layoutRouteSchema: z.ZodType<LayoutRoute> = z.object({\n type: z.literal('layout'),\n id: z.string(),\n file: z.string(),\n children: z.array(z.lazy(() => virtualRouteNodeSchema)).optional(),\n})\n\nconst routeSchema: z.ZodType<Route> = z.object({\n type: z.literal('route'),\n file: z.string(),\n path: z.string(),\n children: z.array(z.lazy(() => virtualRouteNodeSchema)).optional(),\n})\n\nconst physicalSubTreeSchema: z.ZodType<PhysicalSubtree> = z.object({\n type: z.literal('physical'),\n directory: z.string(),\n pathPrefix: z.string(),\n})\n\nconst virtualRouteNodeSchema = z.union([\n indexRouteSchema,\n layoutRouteSchema,\n routeSchema,\n physicalSubTreeSchema,\n])\n\nexport const virtualRootRouteSchema: z.ZodType<VirtualRootRoute> = z.object({\n type: z.literal('root'),\n file: z.string(),\n children: z.array(virtualRouteNodeSchema).optional(),\n})\n"],"names":["z"],"mappings":";;;AAQA,MAAM,mBAAmBA,MAAE,OAAO;AAAA,EAChC,MAAMA,IAAAA,EAAE,QAAQ,OAAO;AAAA,EACvB,MAAMA,MAAE,OAAO;AACjB,CAAC;AAED,MAAM,oBAA4CA,MAAE,OAAO;AAAA,EACzD,MAAMA,IAAAA,EAAE,QAAQ,QAAQ;AAAA,EACxB,IAAIA,MAAE,OAAO;AAAA,EACb,MAAMA,MAAE,OAAO;AAAA,EACf,UAAUA,IAAAA,EAAE,MAAMA,IAAA,EAAE,KAAK,MAAM,sBAAsB,CAAC,EAAE,SAAS;AACnE,CAAC;AAED,MAAM,cAAgCA,MAAE,OAAO;AAAA,EAC7C,MAAMA,IAAAA,EAAE,QAAQ,OAAO;AAAA,EACvB,MAAMA,MAAE,OAAO;AAAA,EACf,MAAMA,MAAE,OAAO;AAAA,EACf,UAAUA,IAAAA,EAAE,MAAMA,IAAA,EAAE,KAAK,MAAM,sBAAsB,CAAC,EAAE,SAAS;AACnE,CAAC;AAED,MAAM,wBAAoDA,MAAE,OAAO;AAAA,EACjE,MAAMA,IAAAA,EAAE,QAAQ,UAAU;AAAA,EAC1B,WAAWA,MAAE,OAAO;AAAA,EACpB,YAAYA,MAAE,OAAO;AACvB,CAAC;AAED,MAAM,yBAAyBA,MAAE,MAAM;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEY,MAAA,yBAAsDA,MAAE,OAAO;AAAA,EAC1E,MAAMA,IAAAA,EAAE,QAAQ,MAAM;AAAA,EACtB,MAAMA,MAAE,OAAO;AAAA,EACf,UAAUA,IAAAA,EAAE,MAAM,sBAAsB,EAAE,SAAS;AACrD,CAAC;;"}
1
+ {"version":3,"file":"config.cjs","sources":["../../../../src/filesystem/virtual/config.ts"],"sourcesContent":["import { z } from 'zod'\nimport type {\n LayoutRoute,\n PhysicalSubtree,\n Route,\n VirtualRootRoute,\n} from '@tanstack/virtual-file-routes'\n\nconst indexRouteSchema = z.object({\n type: z.literal('index'),\n file: z.string(),\n})\n\nconst layoutRouteSchema: z.ZodType<LayoutRoute> = z.object({\n type: z.literal('layout'),\n id: z.string().optional(),\n file: z.string(),\n children: z.array(z.lazy(() => virtualRouteNodeSchema)).optional(),\n})\n\nconst routeSchema: z.ZodType<Route> = z.object({\n type: z.literal('route'),\n file: z.string().optional(),\n path: z.string(),\n children: z.array(z.lazy(() => virtualRouteNodeSchema)).optional(),\n})\n\nconst physicalSubTreeSchema: z.ZodType<PhysicalSubtree> = z.object({\n type: z.literal('physical'),\n directory: z.string(),\n pathPrefix: z.string(),\n})\n\nconst virtualRouteNodeSchema = z.union([\n indexRouteSchema,\n layoutRouteSchema,\n routeSchema,\n physicalSubTreeSchema,\n])\n\nexport const virtualRootRouteSchema: z.ZodType<VirtualRootRoute> = z.object({\n type: z.literal('root'),\n file: z.string(),\n children: z.array(virtualRouteNodeSchema).optional(),\n})\n"],"names":["z"],"mappings":";;;AAQA,MAAM,mBAAmBA,MAAE,OAAO;AAAA,EAChC,MAAMA,IAAAA,EAAE,QAAQ,OAAO;AAAA,EACvB,MAAMA,MAAE,OAAO;AACjB,CAAC;AAED,MAAM,oBAA4CA,MAAE,OAAO;AAAA,EACzD,MAAMA,IAAAA,EAAE,QAAQ,QAAQ;AAAA,EACxB,IAAIA,IAAA,EAAE,OAAO,EAAE,SAAS;AAAA,EACxB,MAAMA,MAAE,OAAO;AAAA,EACf,UAAUA,IAAAA,EAAE,MAAMA,IAAA,EAAE,KAAK,MAAM,sBAAsB,CAAC,EAAE,SAAS;AACnE,CAAC;AAED,MAAM,cAAgCA,MAAE,OAAO;AAAA,EAC7C,MAAMA,IAAAA,EAAE,QAAQ,OAAO;AAAA,EACvB,MAAMA,IAAA,EAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,MAAMA,MAAE,OAAO;AAAA,EACf,UAAUA,IAAAA,EAAE,MAAMA,IAAA,EAAE,KAAK,MAAM,sBAAsB,CAAC,EAAE,SAAS;AACnE,CAAC;AAED,MAAM,wBAAoDA,MAAE,OAAO;AAAA,EACjE,MAAMA,IAAAA,EAAE,QAAQ,UAAU;AAAA,EAC1B,WAAWA,MAAE,OAAO;AAAA,EACpB,YAAYA,MAAE,OAAO;AACvB,CAAC;AAED,MAAM,yBAAyBA,MAAE,MAAM;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEY,MAAA,yBAAsDA,MAAE,OAAO;AAAA,EAC1E,MAAMA,IAAAA,EAAE,QAAQ,MAAM;AAAA,EACtB,MAAMA,MAAE,OAAO;AAAA,EACf,UAAUA,IAAAA,EAAE,MAAM,sBAAsB,EAAE,SAAS;AACrD,CAAC;;"}
@@ -61,13 +61,17 @@ async function getRouteNodesRecursive(tsrConfig, fullDir, nodes, parent) {
61
61
  });
62
62
  return routeNodes;
63
63
  }
64
- const filePath = node.file;
65
- const variableName = utils.routePathToVariable(utils.removeExt(filePath));
66
- const fullPath = path.join(fullDir, filePath);
64
+ function getFile(file) {
65
+ const filePath = file.split("/").join(path.sep);
66
+ const variableName = utils.routePathToVariable(utils.removeExt(filePath));
67
+ const fullPath = path.join(fullDir, filePath);
68
+ return { filePath, variableName, fullPath };
69
+ }
67
70
  const parentRoutePath = utils.removeTrailingSlash((parent == null ? void 0 : parent.routePath) ?? "/");
68
71
  const isLayout = node.type === "layout";
69
72
  switch (node.type) {
70
73
  case "index": {
74
+ const { filePath, variableName, fullPath } = getFile(node.file);
71
75
  const routePath = `${parentRoutePath}/`;
72
76
  return {
73
77
  filePath,
@@ -77,19 +81,50 @@ async function getRouteNodesRecursive(tsrConfig, fullDir, nodes, parent) {
77
81
  isLayout
78
82
  };
79
83
  }
80
- case "route":
84
+ case "route": {
85
+ const lastSegment = node.path;
86
+ let routeNode;
87
+ const routePath = `${parentRoutePath}/${utils.removeLeadingSlash(lastSegment)}`;
88
+ if (node.file) {
89
+ const { filePath, variableName, fullPath } = getFile(node.file);
90
+ routeNode = {
91
+ filePath,
92
+ fullPath,
93
+ variableName,
94
+ routePath,
95
+ isLayout
96
+ };
97
+ } else {
98
+ routeNode = {
99
+ filePath: "",
100
+ fullPath: "",
101
+ variableName: "",
102
+ routePath,
103
+ isLayout,
104
+ isVirtual: true
105
+ };
106
+ }
107
+ if (node.children !== void 0) {
108
+ const children2 = await getRouteNodesRecursive(
109
+ tsrConfig,
110
+ fullDir,
111
+ node.children,
112
+ routeNode
113
+ );
114
+ routeNode.children = children2;
115
+ }
116
+ return routeNode;
117
+ }
81
118
  case "layout": {
82
- let lastSegment;
83
- if (node.type === "layout") {
84
- if (node.id !== void 0) {
85
- node.id = ensureLeadingUnderScore(node.id);
86
- } else {
87
- node.id = "_layout";
88
- }
89
- lastSegment = node.id;
119
+ const { filePath, variableName, fullPath } = getFile(node.file);
120
+ if (node.id !== void 0) {
121
+ node.id = ensureLeadingUnderScore(node.id);
90
122
  } else {
91
- lastSegment = node.path;
123
+ const baseName = path.basename(filePath);
124
+ const fileNameWithoutExt = path.parse(baseName).name;
125
+ node.id = ensureLeadingUnderScore(fileNameWithoutExt);
92
126
  }
127
+ const lastSegment = node.id;
93
128
  const routePath = `${parentRoutePath}/${utils.removeLeadingSlash(lastSegment)}`;
94
129
  const routeNode = {
95
130
  fullPath,
@@ -1 +1 @@
1
- {"version":3,"file":"getRouteNodes.cjs","sources":["../../../../src/filesystem/virtual/getRouteNodes.ts"],"sourcesContent":["import { join, resolve } from 'node:path'\nimport {\n removeExt,\n removeLeadingSlash,\n removeTrailingSlash,\n routePathToVariable,\n} from '../../utils'\nimport { getRouteNodes as getRouteNodesPhysical } from '../physical/getRouteNodes'\nimport type { VirtualRouteNode } from '@tanstack/virtual-file-routes'\nimport type { GetRouteNodesResult, RouteNode } from '../../types'\nimport type { Config } from '../../config'\n\nfunction ensureLeadingUnderScore(id: string) {\n if (id.startsWith('_')) {\n return id\n }\n return `_${id}`\n}\n\nfunction flattenTree(node: RouteNode): Array<RouteNode> {\n const result = [node]\n\n if (node.children) {\n for (const child of node.children) {\n result.push(...flattenTree(child))\n }\n }\n delete node.children\n\n return result\n}\n\nexport async function getRouteNodes(\n tsrConfig: Config,\n): Promise<GetRouteNodesResult> {\n const fullDir = resolve(tsrConfig.routesDirectory)\n if (tsrConfig.virtualRouteConfig === undefined) {\n throw new Error(`virtualRouteConfig is undefined`)\n }\n const children = await getRouteNodesRecursive(\n tsrConfig,\n fullDir,\n tsrConfig.virtualRouteConfig.children,\n )\n const allNodes = flattenTree({\n children,\n filePath: tsrConfig.virtualRouteConfig.file,\n fullPath: join(fullDir, tsrConfig.virtualRouteConfig.file),\n variableName: 'rootRoute',\n routePath: '/',\n isRoot: true,\n })\n\n const rootRouteNode = allNodes[0]\n const routeNodes = allNodes.slice(1)\n\n return { rootRouteNode, routeNodes }\n}\n\nexport async function getRouteNodesRecursive(\n tsrConfig: Config,\n fullDir: string,\n nodes?: Array<VirtualRouteNode>,\n parent?: RouteNode,\n): Promise<Array<RouteNode>> {\n if (nodes === undefined) {\n return []\n }\n const children = await Promise.all(\n nodes.map(async (node) => {\n if (node.type === 'physical') {\n const { routeNodes } = await getRouteNodesPhysical({\n ...tsrConfig,\n routesDirectory: resolve(fullDir, node.directory),\n })\n routeNodes.forEach((subtreeNode) => {\n subtreeNode.variableName = routePathToVariable(\n `${node.pathPrefix}/${removeExt(subtreeNode.filePath)}`,\n )\n subtreeNode.routePath = `${parent?.routePath ?? ''}${node.pathPrefix}${subtreeNode.routePath}`\n subtreeNode.filePath = `${node.directory}/${subtreeNode.filePath}`\n })\n return routeNodes\n }\n\n const filePath = node.file\n const variableName = routePathToVariable(removeExt(filePath))\n const fullPath = join(fullDir, filePath)\n const parentRoutePath = removeTrailingSlash(parent?.routePath ?? '/')\n const isLayout = node.type === 'layout'\n switch (node.type) {\n case 'index': {\n const routePath = `${parentRoutePath}/`\n return {\n filePath,\n fullPath,\n variableName,\n routePath,\n isLayout,\n } satisfies RouteNode\n }\n\n case 'route':\n case 'layout': {\n let lastSegment: string\n if (node.type === 'layout') {\n if (node.id !== undefined) {\n node.id = ensureLeadingUnderScore(node.id)\n } else {\n node.id = '_layout'\n }\n lastSegment = node.id\n } else {\n lastSegment = node.path\n }\n const routePath = `${parentRoutePath}/${removeLeadingSlash(lastSegment)}`\n\n const routeNode: RouteNode = {\n fullPath,\n isLayout,\n filePath,\n variableName,\n routePath,\n }\n\n if (node.children !== undefined) {\n const children = await getRouteNodesRecursive(\n tsrConfig,\n fullDir,\n node.children,\n routeNode,\n )\n routeNode.children = children\n }\n return routeNode\n }\n }\n }),\n )\n return children.flat()\n}\n"],"names":["resolve","join","getRouteNodesPhysical","routePathToVariable","removeExt","removeTrailingSlash","removeLeadingSlash","children"],"mappings":"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"}
1
+ {"version":3,"file":"getRouteNodes.cjs","sources":["../../../../src/filesystem/virtual/getRouteNodes.ts"],"sourcesContent":["import path, { join, resolve } from 'node:path'\nimport {\n removeExt,\n removeLeadingSlash,\n removeTrailingSlash,\n routePathToVariable,\n} from '../../utils'\nimport { getRouteNodes as getRouteNodesPhysical } from '../physical/getRouteNodes'\nimport type { Route, VirtualRouteNode } from '@tanstack/virtual-file-routes'\nimport type { GetRouteNodesResult, RouteNode } from '../../types'\nimport type { Config } from '../../config'\n\nfunction ensureLeadingUnderScore(id: string) {\n if (id.startsWith('_')) {\n return id\n }\n return `_${id}`\n}\n\nfunction flattenTree(node: RouteNode): Array<RouteNode> {\n const result = [node]\n\n if (node.children) {\n for (const child of node.children) {\n result.push(...flattenTree(child))\n }\n }\n delete node.children\n\n return result\n}\n\nexport async function getRouteNodes(\n tsrConfig: Config,\n): Promise<GetRouteNodesResult> {\n const fullDir = resolve(tsrConfig.routesDirectory)\n if (tsrConfig.virtualRouteConfig === undefined) {\n throw new Error(`virtualRouteConfig is undefined`)\n }\n const children = await getRouteNodesRecursive(\n tsrConfig,\n fullDir,\n tsrConfig.virtualRouteConfig.children,\n )\n const allNodes = flattenTree({\n children,\n filePath: tsrConfig.virtualRouteConfig.file,\n fullPath: join(fullDir, tsrConfig.virtualRouteConfig.file),\n variableName: 'rootRoute',\n routePath: '/',\n isRoot: true,\n })\n\n const rootRouteNode = allNodes[0]\n const routeNodes = allNodes.slice(1)\n\n return { rootRouteNode, routeNodes }\n}\n\nexport async function getRouteNodesRecursive(\n tsrConfig: Config,\n fullDir: string,\n nodes?: Array<VirtualRouteNode>,\n parent?: RouteNode,\n): Promise<Array<RouteNode>> {\n if (nodes === undefined) {\n return []\n }\n const children = await Promise.all(\n nodes.map(async (node) => {\n if (node.type === 'physical') {\n const { routeNodes } = await getRouteNodesPhysical({\n ...tsrConfig,\n routesDirectory: resolve(fullDir, node.directory),\n })\n routeNodes.forEach((subtreeNode) => {\n subtreeNode.variableName = routePathToVariable(\n `${node.pathPrefix}/${removeExt(subtreeNode.filePath)}`,\n )\n subtreeNode.routePath = `${parent?.routePath ?? ''}${node.pathPrefix}${subtreeNode.routePath}`\n subtreeNode.filePath = `${node.directory}/${subtreeNode.filePath}`\n })\n return routeNodes\n }\n\n function getFile(file: string) {\n const filePath = file.split('/').join(path.sep)\n const variableName = routePathToVariable(removeExt(filePath))\n const fullPath = join(fullDir, filePath)\n return { filePath, variableName, fullPath }\n }\n const parentRoutePath = removeTrailingSlash(parent?.routePath ?? '/')\n const isLayout = node.type === 'layout'\n switch (node.type) {\n case 'index': {\n const { filePath, variableName, fullPath } = getFile(node.file)\n const routePath = `${parentRoutePath}/`\n return {\n filePath,\n fullPath,\n variableName,\n routePath,\n isLayout,\n } satisfies RouteNode\n }\n\n case 'route': {\n const lastSegment = node.path\n let routeNode: RouteNode\n\n const routePath = `${parentRoutePath}/${removeLeadingSlash(lastSegment)}`\n if (node.file) {\n const { filePath, variableName, fullPath } = getFile(node.file)\n routeNode = {\n filePath,\n fullPath,\n variableName,\n routePath,\n isLayout,\n }\n } else {\n routeNode = {\n filePath: '',\n fullPath: '',\n variableName: '',\n routePath,\n isLayout,\n isVirtual: true,\n }\n }\n\n if (node.children !== undefined) {\n const children = await getRouteNodesRecursive(\n tsrConfig,\n fullDir,\n node.children,\n routeNode,\n )\n routeNode.children = children\n }\n return routeNode\n }\n case 'layout': {\n const { filePath, variableName, fullPath } = getFile(node.file)\n\n if (node.id !== undefined) {\n node.id = ensureLeadingUnderScore(node.id)\n } else {\n const baseName = path.basename(filePath)\n const fileNameWithoutExt = path.parse(baseName).name\n node.id = ensureLeadingUnderScore(fileNameWithoutExt)\n }\n const lastSegment = node.id\n const routePath = `${parentRoutePath}/${removeLeadingSlash(lastSegment)}`\n\n const routeNode: RouteNode = {\n fullPath,\n isLayout,\n filePath,\n variableName,\n routePath,\n }\n\n if (node.children !== undefined) {\n const children = await getRouteNodesRecursive(\n tsrConfig,\n fullDir,\n node.children,\n routeNode,\n )\n routeNode.children = children\n }\n return routeNode\n }\n }\n }),\n )\n return children.flat()\n}\n"],"names":["resolve","join","getRouteNodesPhysical","routePathToVariable","removeExt","removeTrailingSlash","removeLeadingSlash","children"],"mappings":"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"}
@@ -46,21 +46,35 @@ function trimPathLeft(path) {
46
46
  return path === "/" ? path : path.replace(/^\/{1,}/, "");
47
47
  }
48
48
  function logging(config) {
49
+ function stripEmojis(str) {
50
+ return str.replace(
51
+ /[\p{Emoji_Presentation}\p{Extended_Pictographic}]/gu,
52
+ ""
53
+ );
54
+ }
55
+ function formatLogArgs(args) {
56
+ if (process.env.CI) {
57
+ return args.map(
58
+ (arg) => typeof arg === "string" ? stripEmojis(arg) : arg
59
+ );
60
+ }
61
+ return args;
62
+ }
49
63
  return {
50
64
  log: (...args) => {
51
- if (!config.disabled) console["log"](...args);
65
+ if (!config.disabled) console.log(...formatLogArgs(args));
52
66
  },
53
67
  debug: (...args) => {
54
- if (!config.disabled) console.debug(...args);
68
+ if (!config.disabled) console.debug(...formatLogArgs(args));
55
69
  },
56
70
  info: (...args) => {
57
- if (!config.disabled) console.info(...args);
71
+ if (!config.disabled) console.info(...formatLogArgs(args));
58
72
  },
59
73
  warn: (...args) => {
60
- if (!config.disabled) console.warn(...args);
74
+ if (!config.disabled) console.warn(...formatLogArgs(args));
61
75
  },
62
76
  error: (...args) => {
63
- if (!config.disabled) console.error(...args);
77
+ if (!config.disabled) console.error(...formatLogArgs(args));
64
78
  }
65
79
  };
66
80
  }
@@ -1 +1 @@
1
- {"version":3,"file":"utils.cjs","sources":["../../src/utils.ts"],"sourcesContent":["import * as fs from 'node:fs'\nimport * as prettier from 'prettier'\n\nexport function multiSortBy<T>(\n arr: Array<T>,\n accessors: Array<(item: T) => any> = [(d) => d],\n): Array<T> {\n return arr\n .map((d, i) => [d, i] as const)\n .sort(([a, ai], [b, bi]) => {\n for (const accessor of accessors) {\n const ao = accessor(a)\n const bo = accessor(b)\n\n if (typeof ao === 'undefined') {\n if (typeof bo === 'undefined') {\n continue\n }\n return 1\n }\n\n if (ao === bo) {\n continue\n }\n\n return ao > bo ? 1 : -1\n }\n\n return ai - bi\n })\n .map(([d]) => d)\n}\n\nexport function cleanPath(path: string) {\n // remove double slashes\n return path.replace(/\\/{2,}/g, '/')\n}\n\nexport function trimPathLeft(path: string) {\n return path === '/' ? path : path.replace(/^\\/{1,}/, '')\n}\n\nexport function logging(config: { disabled: boolean }) {\n return {\n log: (...args: Array<any>) => {\n if (!config.disabled) console['log'](...args)\n },\n debug: (...args: Array<any>) => {\n if (!config.disabled) console.debug(...args)\n },\n info: (...args: Array<any>) => {\n if (!config.disabled) console.info(...args)\n },\n warn: (...args: Array<any>) => {\n if (!config.disabled) console.warn(...args)\n },\n error: (...args: Array<any>) => {\n if (!config.disabled) console.error(...args)\n },\n }\n}\n\nexport function removeLeadingSlash(path: string): string {\n return path.replace(/^\\//, '')\n}\n\nexport function removeTrailingSlash(s: string) {\n return s.replace(/\\/$/, '')\n}\n\nexport function determineInitialRoutePath(routePath: string) {\n return cleanPath(`/${routePath.split('.').join('/')}`) || ''\n}\n\nexport function replaceBackslash(s: string) {\n return s.replaceAll(/\\\\/gi, '/')\n}\n\nexport function routePathToVariable(routePath: string): string {\n return (\n removeUnderscores(routePath)\n ?.replace(/\\/\\$\\//g, '/splat/')\n .replace(/\\$$/g, 'splat')\n .replace(/\\$/g, '')\n .split(/[/-]/g)\n .map((d, i) => (i > 0 ? capitalize(d) : d))\n .join('')\n .replace(/([^a-zA-Z0-9]|[.])/gm, '')\n .replace(/^(\\d)/g, 'R$1') ?? ''\n )\n}\n\nexport function removeUnderscores(s?: string) {\n return s?.replaceAll(/(^_|_$)/gi, '').replaceAll(/(\\/_|_\\/)/gi, '/')\n}\n\nexport function capitalize(s: string) {\n if (typeof s !== 'string') return ''\n return s.charAt(0).toUpperCase() + s.slice(1)\n}\n\nexport function removeExt(d: string, keepExtension: boolean = false) {\n return keepExtension ? d : d.substring(0, d.lastIndexOf('.')) || d\n}\n\n/**\n * This function writes to a file if the content is different.\n *\n * @param filepath The path to the file\n * @param prettierOptions Prettier options\n * @param content Original content\n * @param incomingContent New content\n * @param callbacks Callbacks to run before and after writing\n * @returns Whether the file was written\n */\nexport async function writeIfDifferent(\n filepath: string,\n prettierOptions: prettier.Options,\n content: string,\n incomingContent: string,\n callbacks?: { beforeWrite?: () => void; afterWrite?: () => void },\n): Promise<boolean> {\n const [formattedContent, updatedContent] = await Promise.all([\n prettier.format(content, prettierOptions),\n prettier.format(incomingContent, prettierOptions),\n ])\n\n if (formattedContent !== updatedContent) {\n callbacks?.beforeWrite?.()\n fs.writeFileSync(filepath, updatedContent)\n callbacks?.afterWrite?.()\n return true\n }\n\n return false\n}\n"],"names":["prettier","fs"],"mappings":"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"}
1
+ {"version":3,"file":"utils.cjs","sources":["../../src/utils.ts"],"sourcesContent":["import * as fs from 'node:fs'\nimport * as prettier from 'prettier'\n\nexport function multiSortBy<T>(\n arr: Array<T>,\n accessors: Array<(item: T) => any> = [(d) => d],\n): Array<T> {\n return arr\n .map((d, i) => [d, i] as const)\n .sort(([a, ai], [b, bi]) => {\n for (const accessor of accessors) {\n const ao = accessor(a)\n const bo = accessor(b)\n\n if (typeof ao === 'undefined') {\n if (typeof bo === 'undefined') {\n continue\n }\n return 1\n }\n\n if (ao === bo) {\n continue\n }\n\n return ao > bo ? 1 : -1\n }\n\n return ai - bi\n })\n .map(([d]) => d)\n}\n\nexport function cleanPath(path: string) {\n // remove double slashes\n return path.replace(/\\/{2,}/g, '/')\n}\n\nexport function trimPathLeft(path: string) {\n return path === '/' ? path : path.replace(/^\\/{1,}/, '')\n}\n\nexport function logging(config: { disabled: boolean }) {\n function stripEmojis(str: string) {\n return str.replace(\n /[\\p{Emoji_Presentation}\\p{Extended_Pictographic}]/gu,\n '',\n )\n }\n\n function formatLogArgs(args: Array<any>): Array<any> {\n if (process.env.CI) {\n return args.map((arg) =>\n typeof arg === 'string' ? stripEmojis(arg) : arg,\n )\n }\n return args\n }\n\n return {\n log: (...args: Array<any>) => {\n if (!config.disabled) console.log(...formatLogArgs(args))\n },\n debug: (...args: Array<any>) => {\n if (!config.disabled) console.debug(...formatLogArgs(args))\n },\n info: (...args: Array<any>) => {\n if (!config.disabled) console.info(...formatLogArgs(args))\n },\n warn: (...args: Array<any>) => {\n if (!config.disabled) console.warn(...formatLogArgs(args))\n },\n error: (...args: Array<any>) => {\n if (!config.disabled) console.error(...formatLogArgs(args))\n },\n }\n}\n\nexport function removeLeadingSlash(path: string): string {\n return path.replace(/^\\//, '')\n}\n\nexport function removeTrailingSlash(s: string) {\n return s.replace(/\\/$/, '')\n}\n\nexport function determineInitialRoutePath(routePath: string) {\n return cleanPath(`/${routePath.split('.').join('/')}`) || ''\n}\n\nexport function replaceBackslash(s: string) {\n return s.replaceAll(/\\\\/gi, '/')\n}\n\nexport function routePathToVariable(routePath: string): string {\n return (\n removeUnderscores(routePath)\n ?.replace(/\\/\\$\\//g, '/splat/')\n .replace(/\\$$/g, 'splat')\n .replace(/\\$/g, '')\n .split(/[/-]/g)\n .map((d, i) => (i > 0 ? capitalize(d) : d))\n .join('')\n .replace(/([^a-zA-Z0-9]|[.])/gm, '')\n .replace(/^(\\d)/g, 'R$1') ?? ''\n )\n}\n\nexport function removeUnderscores(s?: string) {\n return s?.replaceAll(/(^_|_$)/gi, '').replaceAll(/(\\/_|_\\/)/gi, '/')\n}\n\nexport function capitalize(s: string) {\n if (typeof s !== 'string') return ''\n return s.charAt(0).toUpperCase() + s.slice(1)\n}\n\nexport function removeExt(d: string, keepExtension: boolean = false) {\n return keepExtension ? d : d.substring(0, d.lastIndexOf('.')) || d\n}\n\n/**\n * This function writes to a file if the content is different.\n *\n * @param filepath The path to the file\n * @param prettierOptions Prettier options\n * @param content Original content\n * @param incomingContent New content\n * @param callbacks Callbacks to run before and after writing\n * @returns Whether the file was written\n */\nexport async function writeIfDifferent(\n filepath: string,\n prettierOptions: prettier.Options,\n content: string,\n incomingContent: string,\n callbacks?: { beforeWrite?: () => void; afterWrite?: () => void },\n): Promise<boolean> {\n const [formattedContent, updatedContent] = await Promise.all([\n prettier.format(content, prettierOptions),\n prettier.format(incomingContent, prettierOptions),\n ])\n\n if (formattedContent !== updatedContent) {\n callbacks?.beforeWrite?.()\n fs.writeFileSync(filepath, updatedContent)\n callbacks?.afterWrite?.()\n return true\n }\n\n return false\n}\n"],"names":["prettier","fs"],"mappings":"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"}
@@ -5,13 +5,13 @@ const indexRouteSchema = z.object({
5
5
  });
6
6
  const layoutRouteSchema = z.object({
7
7
  type: z.literal("layout"),
8
- id: z.string(),
8
+ id: z.string().optional(),
9
9
  file: z.string(),
10
10
  children: z.array(z.lazy(() => virtualRouteNodeSchema)).optional()
11
11
  });
12
12
  const routeSchema = z.object({
13
13
  type: z.literal("route"),
14
- file: z.string(),
14
+ file: z.string().optional(),
15
15
  path: z.string(),
16
16
  children: z.array(z.lazy(() => virtualRouteNodeSchema)).optional()
17
17
  });
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sources":["../../../../src/filesystem/virtual/config.ts"],"sourcesContent":["import { z } from 'zod'\nimport type {\n LayoutRoute,\n PhysicalSubtree,\n Route,\n VirtualRootRoute,\n} from '@tanstack/virtual-file-routes'\n\nconst indexRouteSchema = z.object({\n type: z.literal('index'),\n file: z.string(),\n})\n\nconst layoutRouteSchema: z.ZodType<LayoutRoute> = z.object({\n type: z.literal('layout'),\n id: z.string(),\n file: z.string(),\n children: z.array(z.lazy(() => virtualRouteNodeSchema)).optional(),\n})\n\nconst routeSchema: z.ZodType<Route> = z.object({\n type: z.literal('route'),\n file: z.string(),\n path: z.string(),\n children: z.array(z.lazy(() => virtualRouteNodeSchema)).optional(),\n})\n\nconst physicalSubTreeSchema: z.ZodType<PhysicalSubtree> = z.object({\n type: z.literal('physical'),\n directory: z.string(),\n pathPrefix: z.string(),\n})\n\nconst virtualRouteNodeSchema = z.union([\n indexRouteSchema,\n layoutRouteSchema,\n routeSchema,\n physicalSubTreeSchema,\n])\n\nexport const virtualRootRouteSchema: z.ZodType<VirtualRootRoute> = z.object({\n type: z.literal('root'),\n file: z.string(),\n children: z.array(virtualRouteNodeSchema).optional(),\n})\n"],"names":[],"mappings":";AAQA,MAAM,mBAAmB,EAAE,OAAO;AAAA,EAChC,MAAM,EAAE,QAAQ,OAAO;AAAA,EACvB,MAAM,EAAE,OAAO;AACjB,CAAC;AAED,MAAM,oBAA4C,EAAE,OAAO;AAAA,EACzD,MAAM,EAAE,QAAQ,QAAQ;AAAA,EACxB,IAAI,EAAE,OAAO;AAAA,EACb,MAAM,EAAE,OAAO;AAAA,EACf,UAAU,EAAE,MAAM,EAAE,KAAK,MAAM,sBAAsB,CAAC,EAAE,SAAS;AACnE,CAAC;AAED,MAAM,cAAgC,EAAE,OAAO;AAAA,EAC7C,MAAM,EAAE,QAAQ,OAAO;AAAA,EACvB,MAAM,EAAE,OAAO;AAAA,EACf,MAAM,EAAE,OAAO;AAAA,EACf,UAAU,EAAE,MAAM,EAAE,KAAK,MAAM,sBAAsB,CAAC,EAAE,SAAS;AACnE,CAAC;AAED,MAAM,wBAAoD,EAAE,OAAO;AAAA,EACjE,MAAM,EAAE,QAAQ,UAAU;AAAA,EAC1B,WAAW,EAAE,OAAO;AAAA,EACpB,YAAY,EAAE,OAAO;AACvB,CAAC;AAED,MAAM,yBAAyB,EAAE,MAAM;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEY,MAAA,yBAAsD,EAAE,OAAO;AAAA,EAC1E,MAAM,EAAE,QAAQ,MAAM;AAAA,EACtB,MAAM,EAAE,OAAO;AAAA,EACf,UAAU,EAAE,MAAM,sBAAsB,EAAE,SAAS;AACrD,CAAC;"}
1
+ {"version":3,"file":"config.js","sources":["../../../../src/filesystem/virtual/config.ts"],"sourcesContent":["import { z } from 'zod'\nimport type {\n LayoutRoute,\n PhysicalSubtree,\n Route,\n VirtualRootRoute,\n} from '@tanstack/virtual-file-routes'\n\nconst indexRouteSchema = z.object({\n type: z.literal('index'),\n file: z.string(),\n})\n\nconst layoutRouteSchema: z.ZodType<LayoutRoute> = z.object({\n type: z.literal('layout'),\n id: z.string().optional(),\n file: z.string(),\n children: z.array(z.lazy(() => virtualRouteNodeSchema)).optional(),\n})\n\nconst routeSchema: z.ZodType<Route> = z.object({\n type: z.literal('route'),\n file: z.string().optional(),\n path: z.string(),\n children: z.array(z.lazy(() => virtualRouteNodeSchema)).optional(),\n})\n\nconst physicalSubTreeSchema: z.ZodType<PhysicalSubtree> = z.object({\n type: z.literal('physical'),\n directory: z.string(),\n pathPrefix: z.string(),\n})\n\nconst virtualRouteNodeSchema = z.union([\n indexRouteSchema,\n layoutRouteSchema,\n routeSchema,\n physicalSubTreeSchema,\n])\n\nexport const virtualRootRouteSchema: z.ZodType<VirtualRootRoute> = z.object({\n type: z.literal('root'),\n file: z.string(),\n children: z.array(virtualRouteNodeSchema).optional(),\n})\n"],"names":[],"mappings":";AAQA,MAAM,mBAAmB,EAAE,OAAO;AAAA,EAChC,MAAM,EAAE,QAAQ,OAAO;AAAA,EACvB,MAAM,EAAE,OAAO;AACjB,CAAC;AAED,MAAM,oBAA4C,EAAE,OAAO;AAAA,EACzD,MAAM,EAAE,QAAQ,QAAQ;AAAA,EACxB,IAAI,EAAE,OAAO,EAAE,SAAS;AAAA,EACxB,MAAM,EAAE,OAAO;AAAA,EACf,UAAU,EAAE,MAAM,EAAE,KAAK,MAAM,sBAAsB,CAAC,EAAE,SAAS;AACnE,CAAC;AAED,MAAM,cAAgC,EAAE,OAAO;AAAA,EAC7C,MAAM,EAAE,QAAQ,OAAO;AAAA,EACvB,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,EAC1B,MAAM,EAAE,OAAO;AAAA,EACf,UAAU,EAAE,MAAM,EAAE,KAAK,MAAM,sBAAsB,CAAC,EAAE,SAAS;AACnE,CAAC;AAED,MAAM,wBAAoD,EAAE,OAAO;AAAA,EACjE,MAAM,EAAE,QAAQ,UAAU;AAAA,EAC1B,WAAW,EAAE,OAAO;AAAA,EACpB,YAAY,EAAE,OAAO;AACvB,CAAC;AAED,MAAM,yBAAyB,EAAE,MAAM;AAAA,EACrC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAEY,MAAA,yBAAsD,EAAE,OAAO;AAAA,EAC1E,MAAM,EAAE,QAAQ,MAAM;AAAA,EACtB,MAAM,EAAE,OAAO;AAAA,EACf,UAAU,EAAE,MAAM,sBAAsB,EAAE,SAAS;AACrD,CAAC;"}
@@ -1,4 +1,4 @@
1
- import { resolve, join } from "node:path";
1
+ import path, { resolve, join } from "node:path";
2
2
  import { routePathToVariable, removeExt, removeTrailingSlash, removeLeadingSlash } from "../../utils.js";
3
3
  import { getRouteNodes as getRouteNodes$1 } from "../physical/getRouteNodes.js";
4
4
  function ensureLeadingUnderScore(id) {
@@ -59,13 +59,17 @@ async function getRouteNodesRecursive(tsrConfig, fullDir, nodes, parent) {
59
59
  });
60
60
  return routeNodes;
61
61
  }
62
- const filePath = node.file;
63
- const variableName = routePathToVariable(removeExt(filePath));
64
- const fullPath = join(fullDir, filePath);
62
+ function getFile(file) {
63
+ const filePath = file.split("/").join(path.sep);
64
+ const variableName = routePathToVariable(removeExt(filePath));
65
+ const fullPath = join(fullDir, filePath);
66
+ return { filePath, variableName, fullPath };
67
+ }
65
68
  const parentRoutePath = removeTrailingSlash((parent == null ? void 0 : parent.routePath) ?? "/");
66
69
  const isLayout = node.type === "layout";
67
70
  switch (node.type) {
68
71
  case "index": {
72
+ const { filePath, variableName, fullPath } = getFile(node.file);
69
73
  const routePath = `${parentRoutePath}/`;
70
74
  return {
71
75
  filePath,
@@ -75,19 +79,50 @@ async function getRouteNodesRecursive(tsrConfig, fullDir, nodes, parent) {
75
79
  isLayout
76
80
  };
77
81
  }
78
- case "route":
82
+ case "route": {
83
+ const lastSegment = node.path;
84
+ let routeNode;
85
+ const routePath = `${parentRoutePath}/${removeLeadingSlash(lastSegment)}`;
86
+ if (node.file) {
87
+ const { filePath, variableName, fullPath } = getFile(node.file);
88
+ routeNode = {
89
+ filePath,
90
+ fullPath,
91
+ variableName,
92
+ routePath,
93
+ isLayout
94
+ };
95
+ } else {
96
+ routeNode = {
97
+ filePath: "",
98
+ fullPath: "",
99
+ variableName: "",
100
+ routePath,
101
+ isLayout,
102
+ isVirtual: true
103
+ };
104
+ }
105
+ if (node.children !== void 0) {
106
+ const children2 = await getRouteNodesRecursive(
107
+ tsrConfig,
108
+ fullDir,
109
+ node.children,
110
+ routeNode
111
+ );
112
+ routeNode.children = children2;
113
+ }
114
+ return routeNode;
115
+ }
79
116
  case "layout": {
80
- let lastSegment;
81
- if (node.type === "layout") {
82
- if (node.id !== void 0) {
83
- node.id = ensureLeadingUnderScore(node.id);
84
- } else {
85
- node.id = "_layout";
86
- }
87
- lastSegment = node.id;
117
+ const { filePath, variableName, fullPath } = getFile(node.file);
118
+ if (node.id !== void 0) {
119
+ node.id = ensureLeadingUnderScore(node.id);
88
120
  } else {
89
- lastSegment = node.path;
121
+ const baseName = path.basename(filePath);
122
+ const fileNameWithoutExt = path.parse(baseName).name;
123
+ node.id = ensureLeadingUnderScore(fileNameWithoutExt);
90
124
  }
125
+ const lastSegment = node.id;
91
126
  const routePath = `${parentRoutePath}/${removeLeadingSlash(lastSegment)}`;
92
127
  const routeNode = {
93
128
  fullPath,
@@ -1 +1 @@
1
- {"version":3,"file":"getRouteNodes.js","sources":["../../../../src/filesystem/virtual/getRouteNodes.ts"],"sourcesContent":["import { join, resolve } from 'node:path'\nimport {\n removeExt,\n removeLeadingSlash,\n removeTrailingSlash,\n routePathToVariable,\n} from '../../utils'\nimport { getRouteNodes as getRouteNodesPhysical } from '../physical/getRouteNodes'\nimport type { VirtualRouteNode } from '@tanstack/virtual-file-routes'\nimport type { GetRouteNodesResult, RouteNode } from '../../types'\nimport type { Config } from '../../config'\n\nfunction ensureLeadingUnderScore(id: string) {\n if (id.startsWith('_')) {\n return id\n }\n return `_${id}`\n}\n\nfunction flattenTree(node: RouteNode): Array<RouteNode> {\n const result = [node]\n\n if (node.children) {\n for (const child of node.children) {\n result.push(...flattenTree(child))\n }\n }\n delete node.children\n\n return result\n}\n\nexport async function getRouteNodes(\n tsrConfig: Config,\n): Promise<GetRouteNodesResult> {\n const fullDir = resolve(tsrConfig.routesDirectory)\n if (tsrConfig.virtualRouteConfig === undefined) {\n throw new Error(`virtualRouteConfig is undefined`)\n }\n const children = await getRouteNodesRecursive(\n tsrConfig,\n fullDir,\n tsrConfig.virtualRouteConfig.children,\n )\n const allNodes = flattenTree({\n children,\n filePath: tsrConfig.virtualRouteConfig.file,\n fullPath: join(fullDir, tsrConfig.virtualRouteConfig.file),\n variableName: 'rootRoute',\n routePath: '/',\n isRoot: true,\n })\n\n const rootRouteNode = allNodes[0]\n const routeNodes = allNodes.slice(1)\n\n return { rootRouteNode, routeNodes }\n}\n\nexport async function getRouteNodesRecursive(\n tsrConfig: Config,\n fullDir: string,\n nodes?: Array<VirtualRouteNode>,\n parent?: RouteNode,\n): Promise<Array<RouteNode>> {\n if (nodes === undefined) {\n return []\n }\n const children = await Promise.all(\n nodes.map(async (node) => {\n if (node.type === 'physical') {\n const { routeNodes } = await getRouteNodesPhysical({\n ...tsrConfig,\n routesDirectory: resolve(fullDir, node.directory),\n })\n routeNodes.forEach((subtreeNode) => {\n subtreeNode.variableName = routePathToVariable(\n `${node.pathPrefix}/${removeExt(subtreeNode.filePath)}`,\n )\n subtreeNode.routePath = `${parent?.routePath ?? ''}${node.pathPrefix}${subtreeNode.routePath}`\n subtreeNode.filePath = `${node.directory}/${subtreeNode.filePath}`\n })\n return routeNodes\n }\n\n const filePath = node.file\n const variableName = routePathToVariable(removeExt(filePath))\n const fullPath = join(fullDir, filePath)\n const parentRoutePath = removeTrailingSlash(parent?.routePath ?? '/')\n const isLayout = node.type === 'layout'\n switch (node.type) {\n case 'index': {\n const routePath = `${parentRoutePath}/`\n return {\n filePath,\n fullPath,\n variableName,\n routePath,\n isLayout,\n } satisfies RouteNode\n }\n\n case 'route':\n case 'layout': {\n let lastSegment: string\n if (node.type === 'layout') {\n if (node.id !== undefined) {\n node.id = ensureLeadingUnderScore(node.id)\n } else {\n node.id = '_layout'\n }\n lastSegment = node.id\n } else {\n lastSegment = node.path\n }\n const routePath = `${parentRoutePath}/${removeLeadingSlash(lastSegment)}`\n\n const routeNode: RouteNode = {\n fullPath,\n isLayout,\n filePath,\n variableName,\n routePath,\n }\n\n if (node.children !== undefined) {\n const children = await getRouteNodesRecursive(\n tsrConfig,\n fullDir,\n node.children,\n routeNode,\n )\n routeNode.children = children\n }\n return routeNode\n }\n }\n }),\n )\n return children.flat()\n}\n"],"names":["getRouteNodesPhysical","children"],"mappings":"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"}
1
+ {"version":3,"file":"getRouteNodes.js","sources":["../../../../src/filesystem/virtual/getRouteNodes.ts"],"sourcesContent":["import path, { join, resolve } from 'node:path'\nimport {\n removeExt,\n removeLeadingSlash,\n removeTrailingSlash,\n routePathToVariable,\n} from '../../utils'\nimport { getRouteNodes as getRouteNodesPhysical } from '../physical/getRouteNodes'\nimport type { Route, VirtualRouteNode } from '@tanstack/virtual-file-routes'\nimport type { GetRouteNodesResult, RouteNode } from '../../types'\nimport type { Config } from '../../config'\n\nfunction ensureLeadingUnderScore(id: string) {\n if (id.startsWith('_')) {\n return id\n }\n return `_${id}`\n}\n\nfunction flattenTree(node: RouteNode): Array<RouteNode> {\n const result = [node]\n\n if (node.children) {\n for (const child of node.children) {\n result.push(...flattenTree(child))\n }\n }\n delete node.children\n\n return result\n}\n\nexport async function getRouteNodes(\n tsrConfig: Config,\n): Promise<GetRouteNodesResult> {\n const fullDir = resolve(tsrConfig.routesDirectory)\n if (tsrConfig.virtualRouteConfig === undefined) {\n throw new Error(`virtualRouteConfig is undefined`)\n }\n const children = await getRouteNodesRecursive(\n tsrConfig,\n fullDir,\n tsrConfig.virtualRouteConfig.children,\n )\n const allNodes = flattenTree({\n children,\n filePath: tsrConfig.virtualRouteConfig.file,\n fullPath: join(fullDir, tsrConfig.virtualRouteConfig.file),\n variableName: 'rootRoute',\n routePath: '/',\n isRoot: true,\n })\n\n const rootRouteNode = allNodes[0]\n const routeNodes = allNodes.slice(1)\n\n return { rootRouteNode, routeNodes }\n}\n\nexport async function getRouteNodesRecursive(\n tsrConfig: Config,\n fullDir: string,\n nodes?: Array<VirtualRouteNode>,\n parent?: RouteNode,\n): Promise<Array<RouteNode>> {\n if (nodes === undefined) {\n return []\n }\n const children = await Promise.all(\n nodes.map(async (node) => {\n if (node.type === 'physical') {\n const { routeNodes } = await getRouteNodesPhysical({\n ...tsrConfig,\n routesDirectory: resolve(fullDir, node.directory),\n })\n routeNodes.forEach((subtreeNode) => {\n subtreeNode.variableName = routePathToVariable(\n `${node.pathPrefix}/${removeExt(subtreeNode.filePath)}`,\n )\n subtreeNode.routePath = `${parent?.routePath ?? ''}${node.pathPrefix}${subtreeNode.routePath}`\n subtreeNode.filePath = `${node.directory}/${subtreeNode.filePath}`\n })\n return routeNodes\n }\n\n function getFile(file: string) {\n const filePath = file.split('/').join(path.sep)\n const variableName = routePathToVariable(removeExt(filePath))\n const fullPath = join(fullDir, filePath)\n return { filePath, variableName, fullPath }\n }\n const parentRoutePath = removeTrailingSlash(parent?.routePath ?? '/')\n const isLayout = node.type === 'layout'\n switch (node.type) {\n case 'index': {\n const { filePath, variableName, fullPath } = getFile(node.file)\n const routePath = `${parentRoutePath}/`\n return {\n filePath,\n fullPath,\n variableName,\n routePath,\n isLayout,\n } satisfies RouteNode\n }\n\n case 'route': {\n const lastSegment = node.path\n let routeNode: RouteNode\n\n const routePath = `${parentRoutePath}/${removeLeadingSlash(lastSegment)}`\n if (node.file) {\n const { filePath, variableName, fullPath } = getFile(node.file)\n routeNode = {\n filePath,\n fullPath,\n variableName,\n routePath,\n isLayout,\n }\n } else {\n routeNode = {\n filePath: '',\n fullPath: '',\n variableName: '',\n routePath,\n isLayout,\n isVirtual: true,\n }\n }\n\n if (node.children !== undefined) {\n const children = await getRouteNodesRecursive(\n tsrConfig,\n fullDir,\n node.children,\n routeNode,\n )\n routeNode.children = children\n }\n return routeNode\n }\n case 'layout': {\n const { filePath, variableName, fullPath } = getFile(node.file)\n\n if (node.id !== undefined) {\n node.id = ensureLeadingUnderScore(node.id)\n } else {\n const baseName = path.basename(filePath)\n const fileNameWithoutExt = path.parse(baseName).name\n node.id = ensureLeadingUnderScore(fileNameWithoutExt)\n }\n const lastSegment = node.id\n const routePath = `${parentRoutePath}/${removeLeadingSlash(lastSegment)}`\n\n const routeNode: RouteNode = {\n fullPath,\n isLayout,\n filePath,\n variableName,\n routePath,\n }\n\n if (node.children !== undefined) {\n const children = await getRouteNodesRecursive(\n tsrConfig,\n fullDir,\n node.children,\n routeNode,\n )\n routeNode.children = children\n }\n return routeNode\n }\n }\n }),\n )\n return children.flat()\n}\n"],"names":["getRouteNodesPhysical","children"],"mappings":"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"}
package/dist/esm/utils.js CHANGED
@@ -26,21 +26,35 @@ function trimPathLeft(path) {
26
26
  return path === "/" ? path : path.replace(/^\/{1,}/, "");
27
27
  }
28
28
  function logging(config) {
29
+ function stripEmojis(str) {
30
+ return str.replace(
31
+ /[\p{Emoji_Presentation}\p{Extended_Pictographic}]/gu,
32
+ ""
33
+ );
34
+ }
35
+ function formatLogArgs(args) {
36
+ if (process.env.CI) {
37
+ return args.map(
38
+ (arg) => typeof arg === "string" ? stripEmojis(arg) : arg
39
+ );
40
+ }
41
+ return args;
42
+ }
29
43
  return {
30
44
  log: (...args) => {
31
- if (!config.disabled) console["log"](...args);
45
+ if (!config.disabled) console.log(...formatLogArgs(args));
32
46
  },
33
47
  debug: (...args) => {
34
- if (!config.disabled) console.debug(...args);
48
+ if (!config.disabled) console.debug(...formatLogArgs(args));
35
49
  },
36
50
  info: (...args) => {
37
- if (!config.disabled) console.info(...args);
51
+ if (!config.disabled) console.info(...formatLogArgs(args));
38
52
  },
39
53
  warn: (...args) => {
40
- if (!config.disabled) console.warn(...args);
54
+ if (!config.disabled) console.warn(...formatLogArgs(args));
41
55
  },
42
56
  error: (...args) => {
43
- if (!config.disabled) console.error(...args);
57
+ if (!config.disabled) console.error(...formatLogArgs(args));
44
58
  }
45
59
  };
46
60
  }
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sources":["../../src/utils.ts"],"sourcesContent":["import * as fs from 'node:fs'\nimport * as prettier from 'prettier'\n\nexport function multiSortBy<T>(\n arr: Array<T>,\n accessors: Array<(item: T) => any> = [(d) => d],\n): Array<T> {\n return arr\n .map((d, i) => [d, i] as const)\n .sort(([a, ai], [b, bi]) => {\n for (const accessor of accessors) {\n const ao = accessor(a)\n const bo = accessor(b)\n\n if (typeof ao === 'undefined') {\n if (typeof bo === 'undefined') {\n continue\n }\n return 1\n }\n\n if (ao === bo) {\n continue\n }\n\n return ao > bo ? 1 : -1\n }\n\n return ai - bi\n })\n .map(([d]) => d)\n}\n\nexport function cleanPath(path: string) {\n // remove double slashes\n return path.replace(/\\/{2,}/g, '/')\n}\n\nexport function trimPathLeft(path: string) {\n return path === '/' ? path : path.replace(/^\\/{1,}/, '')\n}\n\nexport function logging(config: { disabled: boolean }) {\n return {\n log: (...args: Array<any>) => {\n if (!config.disabled) console['log'](...args)\n },\n debug: (...args: Array<any>) => {\n if (!config.disabled) console.debug(...args)\n },\n info: (...args: Array<any>) => {\n if (!config.disabled) console.info(...args)\n },\n warn: (...args: Array<any>) => {\n if (!config.disabled) console.warn(...args)\n },\n error: (...args: Array<any>) => {\n if (!config.disabled) console.error(...args)\n },\n }\n}\n\nexport function removeLeadingSlash(path: string): string {\n return path.replace(/^\\//, '')\n}\n\nexport function removeTrailingSlash(s: string) {\n return s.replace(/\\/$/, '')\n}\n\nexport function determineInitialRoutePath(routePath: string) {\n return cleanPath(`/${routePath.split('.').join('/')}`) || ''\n}\n\nexport function replaceBackslash(s: string) {\n return s.replaceAll(/\\\\/gi, '/')\n}\n\nexport function routePathToVariable(routePath: string): string {\n return (\n removeUnderscores(routePath)\n ?.replace(/\\/\\$\\//g, '/splat/')\n .replace(/\\$$/g, 'splat')\n .replace(/\\$/g, '')\n .split(/[/-]/g)\n .map((d, i) => (i > 0 ? capitalize(d) : d))\n .join('')\n .replace(/([^a-zA-Z0-9]|[.])/gm, '')\n .replace(/^(\\d)/g, 'R$1') ?? ''\n )\n}\n\nexport function removeUnderscores(s?: string) {\n return s?.replaceAll(/(^_|_$)/gi, '').replaceAll(/(\\/_|_\\/)/gi, '/')\n}\n\nexport function capitalize(s: string) {\n if (typeof s !== 'string') return ''\n return s.charAt(0).toUpperCase() + s.slice(1)\n}\n\nexport function removeExt(d: string, keepExtension: boolean = false) {\n return keepExtension ? d : d.substring(0, d.lastIndexOf('.')) || d\n}\n\n/**\n * This function writes to a file if the content is different.\n *\n * @param filepath The path to the file\n * @param prettierOptions Prettier options\n * @param content Original content\n * @param incomingContent New content\n * @param callbacks Callbacks to run before and after writing\n * @returns Whether the file was written\n */\nexport async function writeIfDifferent(\n filepath: string,\n prettierOptions: prettier.Options,\n content: string,\n incomingContent: string,\n callbacks?: { beforeWrite?: () => void; afterWrite?: () => void },\n): Promise<boolean> {\n const [formattedContent, updatedContent] = await Promise.all([\n prettier.format(content, prettierOptions),\n prettier.format(incomingContent, prettierOptions),\n ])\n\n if (formattedContent !== updatedContent) {\n callbacks?.beforeWrite?.()\n fs.writeFileSync(filepath, updatedContent)\n callbacks?.afterWrite?.()\n return true\n }\n\n return false\n}\n"],"names":[],"mappings":";;AAGO,SAAS,YACd,KACA,YAAqC,CAAC,CAAC,MAAM,CAAC,GACpC;AACV,SAAO,IACJ,IAAI,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAU,EAC7B,KAAK,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,MAAM;AAC1B,eAAW,YAAY,WAAW;AAC1B,YAAA,KAAK,SAAS,CAAC;AACf,YAAA,KAAK,SAAS,CAAC;AAEjB,UAAA,OAAO,OAAO,aAAa;AACzB,YAAA,OAAO,OAAO,aAAa;AAC7B;AAAA,QACF;AACO,eAAA;AAAA,MACT;AAEA,UAAI,OAAO,IAAI;AACb;AAAA,MACF;AAEO,aAAA,KAAK,KAAK,IAAI;AAAA,IACvB;AAEA,WAAO,KAAK;AAAA,EACb,CAAA,EACA,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;AACnB;AAEO,SAAS,UAAU,MAAc;AAE/B,SAAA,KAAK,QAAQ,WAAW,GAAG;AACpC;AAEO,SAAS,aAAa,MAAc;AACzC,SAAO,SAAS,MAAM,OAAO,KAAK,QAAQ,WAAW,EAAE;AACzD;AAEO,SAAS,QAAQ,QAA+B;AAC9C,SAAA;AAAA,IACL,KAAK,IAAI,SAAqB;AAC5B,UAAI,CAAC,OAAO,kBAAkB,KAAK,EAAE,GAAG,IAAI;AAAA,IAC9C;AAAA,IACA,OAAO,IAAI,SAAqB;AAC9B,UAAI,CAAC,OAAO,SAAkB,SAAA,MAAM,GAAG,IAAI;AAAA,IAC7C;AAAA,IACA,MAAM,IAAI,SAAqB;AAC7B,UAAI,CAAC,OAAO,SAAkB,SAAA,KAAK,GAAG,IAAI;AAAA,IAC5C;AAAA,IACA,MAAM,IAAI,SAAqB;AAC7B,UAAI,CAAC,OAAO,SAAkB,SAAA,KAAK,GAAG,IAAI;AAAA,IAC5C;AAAA,IACA,OAAO,IAAI,SAAqB;AAC9B,UAAI,CAAC,OAAO,SAAkB,SAAA,MAAM,GAAG,IAAI;AAAA,IAC7C;AAAA,EAAA;AAEJ;AAEO,SAAS,mBAAmB,MAAsB;AAChD,SAAA,KAAK,QAAQ,OAAO,EAAE;AAC/B;AAEO,SAAS,oBAAoB,GAAW;AACtC,SAAA,EAAE,QAAQ,OAAO,EAAE;AAC5B;AAEO,SAAS,0BAA0B,WAAmB;AACpD,SAAA,UAAU,IAAI,UAAU,MAAM,GAAG,EAAE,KAAK,GAAG,CAAC,EAAE,KAAK;AAC5D;AAEO,SAAS,iBAAiB,GAAW;AACnC,SAAA,EAAE,WAAW,QAAQ,GAAG;AACjC;AAEO,SAAS,oBAAoB,WAA2B;;AAC7D,WACE,uBAAkB,SAAS,MAA3B,mBACI,QAAQ,WAAW,WACpB,QAAQ,QAAQ,SAChB,QAAQ,OAAO,IACf,MAAM,SACN,IAAI,CAAC,GAAG,MAAO,IAAI,IAAI,WAAW,CAAC,IAAI,GACvC,KAAK,IACL,QAAQ,wBAAwB,IAChC,QAAQ,UAAU,WAAU;AAEnC;AAEO,SAAS,kBAAkB,GAAY;AAC5C,SAAO,uBAAG,WAAW,aAAa,IAAI,WAAW,eAAe;AAClE;AAEO,SAAS,WAAW,GAAW;AAChC,MAAA,OAAO,MAAM,SAAiB,QAAA;AAC3B,SAAA,EAAE,OAAO,CAAC,EAAE,gBAAgB,EAAE,MAAM,CAAC;AAC9C;AAEgB,SAAA,UAAU,GAAW,gBAAyB,OAAO;AAC5D,SAAA,gBAAgB,IAAI,EAAE,UAAU,GAAG,EAAE,YAAY,GAAG,CAAC,KAAK;AACnE;AAYA,eAAsB,iBACpB,UACA,iBACA,SACA,iBACA,WACkB;;AAClB,QAAM,CAAC,kBAAkB,cAAc,IAAI,MAAM,QAAQ,IAAI;AAAA,IAC3D,SAAS,OAAO,SAAS,eAAe;AAAA,IACxC,SAAS,OAAO,iBAAiB,eAAe;AAAA,EAAA,CACjD;AAED,MAAI,qBAAqB,gBAAgB;AACvC,iDAAW,gBAAX;AACG,OAAA,cAAc,UAAU,cAAc;AACzC,iDAAW,eAAX;AACO,WAAA;AAAA,EACT;AAEO,SAAA;AACT;"}
1
+ {"version":3,"file":"utils.js","sources":["../../src/utils.ts"],"sourcesContent":["import * as fs from 'node:fs'\nimport * as prettier from 'prettier'\n\nexport function multiSortBy<T>(\n arr: Array<T>,\n accessors: Array<(item: T) => any> = [(d) => d],\n): Array<T> {\n return arr\n .map((d, i) => [d, i] as const)\n .sort(([a, ai], [b, bi]) => {\n for (const accessor of accessors) {\n const ao = accessor(a)\n const bo = accessor(b)\n\n if (typeof ao === 'undefined') {\n if (typeof bo === 'undefined') {\n continue\n }\n return 1\n }\n\n if (ao === bo) {\n continue\n }\n\n return ao > bo ? 1 : -1\n }\n\n return ai - bi\n })\n .map(([d]) => d)\n}\n\nexport function cleanPath(path: string) {\n // remove double slashes\n return path.replace(/\\/{2,}/g, '/')\n}\n\nexport function trimPathLeft(path: string) {\n return path === '/' ? path : path.replace(/^\\/{1,}/, '')\n}\n\nexport function logging(config: { disabled: boolean }) {\n function stripEmojis(str: string) {\n return str.replace(\n /[\\p{Emoji_Presentation}\\p{Extended_Pictographic}]/gu,\n '',\n )\n }\n\n function formatLogArgs(args: Array<any>): Array<any> {\n if (process.env.CI) {\n return args.map((arg) =>\n typeof arg === 'string' ? stripEmojis(arg) : arg,\n )\n }\n return args\n }\n\n return {\n log: (...args: Array<any>) => {\n if (!config.disabled) console.log(...formatLogArgs(args))\n },\n debug: (...args: Array<any>) => {\n if (!config.disabled) console.debug(...formatLogArgs(args))\n },\n info: (...args: Array<any>) => {\n if (!config.disabled) console.info(...formatLogArgs(args))\n },\n warn: (...args: Array<any>) => {\n if (!config.disabled) console.warn(...formatLogArgs(args))\n },\n error: (...args: Array<any>) => {\n if (!config.disabled) console.error(...formatLogArgs(args))\n },\n }\n}\n\nexport function removeLeadingSlash(path: string): string {\n return path.replace(/^\\//, '')\n}\n\nexport function removeTrailingSlash(s: string) {\n return s.replace(/\\/$/, '')\n}\n\nexport function determineInitialRoutePath(routePath: string) {\n return cleanPath(`/${routePath.split('.').join('/')}`) || ''\n}\n\nexport function replaceBackslash(s: string) {\n return s.replaceAll(/\\\\/gi, '/')\n}\n\nexport function routePathToVariable(routePath: string): string {\n return (\n removeUnderscores(routePath)\n ?.replace(/\\/\\$\\//g, '/splat/')\n .replace(/\\$$/g, 'splat')\n .replace(/\\$/g, '')\n .split(/[/-]/g)\n .map((d, i) => (i > 0 ? capitalize(d) : d))\n .join('')\n .replace(/([^a-zA-Z0-9]|[.])/gm, '')\n .replace(/^(\\d)/g, 'R$1') ?? ''\n )\n}\n\nexport function removeUnderscores(s?: string) {\n return s?.replaceAll(/(^_|_$)/gi, '').replaceAll(/(\\/_|_\\/)/gi, '/')\n}\n\nexport function capitalize(s: string) {\n if (typeof s !== 'string') return ''\n return s.charAt(0).toUpperCase() + s.slice(1)\n}\n\nexport function removeExt(d: string, keepExtension: boolean = false) {\n return keepExtension ? d : d.substring(0, d.lastIndexOf('.')) || d\n}\n\n/**\n * This function writes to a file if the content is different.\n *\n * @param filepath The path to the file\n * @param prettierOptions Prettier options\n * @param content Original content\n * @param incomingContent New content\n * @param callbacks Callbacks to run before and after writing\n * @returns Whether the file was written\n */\nexport async function writeIfDifferent(\n filepath: string,\n prettierOptions: prettier.Options,\n content: string,\n incomingContent: string,\n callbacks?: { beforeWrite?: () => void; afterWrite?: () => void },\n): Promise<boolean> {\n const [formattedContent, updatedContent] = await Promise.all([\n prettier.format(content, prettierOptions),\n prettier.format(incomingContent, prettierOptions),\n ])\n\n if (formattedContent !== updatedContent) {\n callbacks?.beforeWrite?.()\n fs.writeFileSync(filepath, updatedContent)\n callbacks?.afterWrite?.()\n return true\n }\n\n return false\n}\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack/router-generator",
3
- "version": "1.58.12",
3
+ "version": "1.64.0",
4
4
  "description": "Modern and scalable routing for React applications",
5
5
  "author": "Tanner Linsley",
6
6
  "license": "MIT",
@@ -52,7 +52,7 @@
52
52
  "tsx": "^4.19.1",
53
53
  "prettier": "^3.3.3",
54
54
  "zod": "^3.23.8",
55
- "@tanstack/virtual-file-routes": "^1.56.0"
55
+ "@tanstack/virtual-file-routes": "^1.64.0"
56
56
  },
57
57
  "scripts": {}
58
58
  }
@@ -13,14 +13,14 @@ const indexRouteSchema = z.object({
13
13
 
14
14
  const layoutRouteSchema: z.ZodType<LayoutRoute> = z.object({
15
15
  type: z.literal('layout'),
16
- id: z.string(),
16
+ id: z.string().optional(),
17
17
  file: z.string(),
18
18
  children: z.array(z.lazy(() => virtualRouteNodeSchema)).optional(),
19
19
  })
20
20
 
21
21
  const routeSchema: z.ZodType<Route> = z.object({
22
22
  type: z.literal('route'),
23
- file: z.string(),
23
+ file: z.string().optional(),
24
24
  path: z.string(),
25
25
  children: z.array(z.lazy(() => virtualRouteNodeSchema)).optional(),
26
26
  })
@@ -1,4 +1,4 @@
1
- import { join, resolve } from 'node:path'
1
+ import path, { join, resolve } from 'node:path'
2
2
  import {
3
3
  removeExt,
4
4
  removeLeadingSlash,
@@ -6,7 +6,7 @@ import {
6
6
  routePathToVariable,
7
7
  } from '../../utils'
8
8
  import { getRouteNodes as getRouteNodesPhysical } from '../physical/getRouteNodes'
9
- import type { VirtualRouteNode } from '@tanstack/virtual-file-routes'
9
+ import type { Route, VirtualRouteNode } from '@tanstack/virtual-file-routes'
10
10
  import type { GetRouteNodesResult, RouteNode } from '../../types'
11
11
  import type { Config } from '../../config'
12
12
 
@@ -83,13 +83,17 @@ export async function getRouteNodesRecursive(
83
83
  return routeNodes
84
84
  }
85
85
 
86
- const filePath = node.file
87
- const variableName = routePathToVariable(removeExt(filePath))
88
- const fullPath = join(fullDir, filePath)
86
+ function getFile(file: string) {
87
+ const filePath = file.split('/').join(path.sep)
88
+ const variableName = routePathToVariable(removeExt(filePath))
89
+ const fullPath = join(fullDir, filePath)
90
+ return { filePath, variableName, fullPath }
91
+ }
89
92
  const parentRoutePath = removeTrailingSlash(parent?.routePath ?? '/')
90
93
  const isLayout = node.type === 'layout'
91
94
  switch (node.type) {
92
95
  case 'index': {
96
+ const { filePath, variableName, fullPath } = getFile(node.file)
93
97
  const routePath = `${parentRoutePath}/`
94
98
  return {
95
99
  filePath,
@@ -100,19 +104,53 @@ export async function getRouteNodesRecursive(
100
104
  } satisfies RouteNode
101
105
  }
102
106
 
103
- case 'route':
104
- case 'layout': {
105
- let lastSegment: string
106
- if (node.type === 'layout') {
107
- if (node.id !== undefined) {
108
- node.id = ensureLeadingUnderScore(node.id)
109
- } else {
110
- node.id = '_layout'
107
+ case 'route': {
108
+ const lastSegment = node.path
109
+ let routeNode: RouteNode
110
+
111
+ const routePath = `${parentRoutePath}/${removeLeadingSlash(lastSegment)}`
112
+ if (node.file) {
113
+ const { filePath, variableName, fullPath } = getFile(node.file)
114
+ routeNode = {
115
+ filePath,
116
+ fullPath,
117
+ variableName,
118
+ routePath,
119
+ isLayout,
120
+ }
121
+ } else {
122
+ routeNode = {
123
+ filePath: '',
124
+ fullPath: '',
125
+ variableName: '',
126
+ routePath,
127
+ isLayout,
128
+ isVirtual: true,
111
129
  }
112
- lastSegment = node.id
130
+ }
131
+
132
+ if (node.children !== undefined) {
133
+ const children = await getRouteNodesRecursive(
134
+ tsrConfig,
135
+ fullDir,
136
+ node.children,
137
+ routeNode,
138
+ )
139
+ routeNode.children = children
140
+ }
141
+ return routeNode
142
+ }
143
+ case 'layout': {
144
+ const { filePath, variableName, fullPath } = getFile(node.file)
145
+
146
+ if (node.id !== undefined) {
147
+ node.id = ensureLeadingUnderScore(node.id)
113
148
  } else {
114
- lastSegment = node.path
149
+ const baseName = path.basename(filePath)
150
+ const fileNameWithoutExt = path.parse(baseName).name
151
+ node.id = ensureLeadingUnderScore(fileNameWithoutExt)
115
152
  }
153
+ const lastSegment = node.id
116
154
  const routePath = `${parentRoutePath}/${removeLeadingSlash(lastSegment)}`
117
155
 
118
156
  const routeNode: RouteNode = {
package/src/utils.ts CHANGED
@@ -41,21 +41,37 @@ export function trimPathLeft(path: string) {
41
41
  }
42
42
 
43
43
  export function logging(config: { disabled: boolean }) {
44
+ function stripEmojis(str: string) {
45
+ return str.replace(
46
+ /[\p{Emoji_Presentation}\p{Extended_Pictographic}]/gu,
47
+ '',
48
+ )
49
+ }
50
+
51
+ function formatLogArgs(args: Array<any>): Array<any> {
52
+ if (process.env.CI) {
53
+ return args.map((arg) =>
54
+ typeof arg === 'string' ? stripEmojis(arg) : arg,
55
+ )
56
+ }
57
+ return args
58
+ }
59
+
44
60
  return {
45
61
  log: (...args: Array<any>) => {
46
- if (!config.disabled) console['log'](...args)
62
+ if (!config.disabled) console.log(...formatLogArgs(args))
47
63
  },
48
64
  debug: (...args: Array<any>) => {
49
- if (!config.disabled) console.debug(...args)
65
+ if (!config.disabled) console.debug(...formatLogArgs(args))
50
66
  },
51
67
  info: (...args: Array<any>) => {
52
- if (!config.disabled) console.info(...args)
68
+ if (!config.disabled) console.info(...formatLogArgs(args))
53
69
  },
54
70
  warn: (...args: Array<any>) => {
55
- if (!config.disabled) console.warn(...args)
71
+ if (!config.disabled) console.warn(...formatLogArgs(args))
56
72
  },
57
73
  error: (...args: Array<any>) => {
58
- if (!config.disabled) console.error(...args)
74
+ if (!config.disabled) console.error(...formatLogArgs(args))
59
75
  },
60
76
  }
61
77
  }