@gyoll/builder 0.4.0 → 0.6.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.
@@ -29,19 +29,27 @@ async function scanRoutes(routesDir) {
29
29
  const routes = await walkDirectory(routesDir, routesDir);
30
30
  return routes;
31
31
  }
32
- async function walkDirectory(dir, baseDir, segments = []) {
32
+ async function walkDirectory(dir, baseDir, segments = [], parentLayouts = []) {
33
33
  const entries = await import_promises.default.readdir(dir, { withFileTypes: true });
34
34
  const files = entries.filter((e) => e.isFile());
35
35
  const dirs = entries.filter((e) => e.isDirectory());
36
36
  const routeFiles = collectRouteFiles(files, dir);
37
+ const currentLayouts = [...parentLayouts];
38
+ if (routeFiles.layout) {
39
+ currentLayouts.push(import_path.default.relative(baseDir, routeFiles.layout));
40
+ }
37
41
  const routes = [];
38
42
  if (routeFiles.page) {
43
+ const pathInfo = buildRoutePath(segments);
39
44
  const route = {
40
- path: buildRoutePath(segments),
45
+ path: pathInfo.path,
41
46
  component: import_path.default.relative(baseDir, routeFiles.page)
42
47
  };
43
- if (routeFiles.layout) {
44
- route.layout = import_path.default.relative(baseDir, routeFiles.layout);
48
+ if (pathInfo.catchAllParam) {
49
+ route.catchAllParam = pathInfo.catchAllParam;
50
+ }
51
+ if (currentLayouts.length > 0) {
52
+ route.layouts = [...currentLayouts];
45
53
  }
46
54
  if (routeFiles.error) {
47
55
  route.error = import_path.default.relative(baseDir, routeFiles.error);
@@ -54,10 +62,12 @@ async function walkDirectory(dir, baseDir, segments = []) {
54
62
  for (const subdir of dirs) {
55
63
  const segment = parseSegment(subdir.name);
56
64
  const subdirPath = import_path.default.join(dir, subdir.name);
57
- const childRoutes = await walkDirectory(subdirPath, baseDir, [
58
- ...segments,
59
- segment
60
- ]);
65
+ const childRoutes = await walkDirectory(
66
+ subdirPath,
67
+ baseDir,
68
+ [...segments, segment],
69
+ currentLayouts
70
+ );
61
71
  routes.push(...childRoutes);
62
72
  }
63
73
  return routes;
@@ -98,8 +108,9 @@ function parseSegment(segment) {
98
108
  if (/^\(.+\)$/.test(segment)) {
99
109
  return null;
100
110
  }
101
- if (/^\[\.\.\.(.+)\]$/.test(segment)) {
102
- return "*";
111
+ const catchAllMatch = /^\[\.\.\.(.+)\]$/.exec(segment);
112
+ if (catchAllMatch) {
113
+ return { type: "catchall", param: catchAllMatch[1] };
103
114
  }
104
115
  if (/^\[(.+)\]$/.test(segment)) {
105
116
  const param = segment.slice(1, -1);
@@ -108,11 +119,25 @@ function parseSegment(segment) {
108
119
  return segment;
109
120
  }
110
121
  function buildRoutePath(segments) {
111
- const filtered = segments.filter((s) => s !== null);
112
- if (filtered.length === 0) {
113
- return "/";
122
+ const filtered = [];
123
+ let catchAllParam = null;
124
+ for (const segment of segments) {
125
+ if (segment === null) {
126
+ continue;
127
+ }
128
+ if (typeof segment === "object" && segment.type === "catchall") {
129
+ catchAllParam = segment.param;
130
+ filtered.push("*");
131
+ } else {
132
+ filtered.push(segment);
133
+ }
134
+ }
135
+ const path3 = filtered.length === 0 ? "/" : "/" + filtered.join("/");
136
+ const result = { path: path3 };
137
+ if (catchAllParam) {
138
+ result.catchAllParam = catchAllParam;
114
139
  }
115
- return "/" + filtered.join("/");
140
+ return result;
116
141
  }
117
142
  async function generateManifest(routes, outFile, routesDir) {
118
143
  const outDir = import_path.default.dirname(outFile);
@@ -120,9 +145,12 @@ async function generateManifest(routes, outFile, routesDir) {
120
145
  const adjustedRoutes = JSON.stringify(routes, null, 2).replace(/"component": "(.+?)"/g, (match, p1) => {
121
146
  const importPath = import_path.default.join(relativeRoutesDir, p1).replace(/\\/g, "/");
122
147
  return `"component": () => import("./${importPath}")`;
123
- }).replace(/"layout": "(.+?)"/g, (match, p1) => {
124
- const importPath = import_path.default.join(relativeRoutesDir, p1).replace(/\\/g, "/");
125
- return `"layout": () => import("./${importPath}")`;
148
+ }).replace(/"layouts": \[([\s\S]*?)\]/g, (match, layoutsContent) => {
149
+ const transformed = layoutsContent.replace(/"(.+?)"/g, (m, p1) => {
150
+ const importPath = import_path.default.join(relativeRoutesDir, p1).replace(/\\/g, "/");
151
+ return `() => import("./${importPath}")`;
152
+ });
153
+ return `"layouts": [${transformed}]`;
126
154
  }).replace(/"error": "(.+?)"/g, (match, p1) => {
127
155
  const importPath = import_path.default.join(relativeRoutesDir, p1).replace(/\\/g, "/");
128
156
  return `"error": () => import("./${importPath}")`;
@@ -7,19 +7,27 @@ async function scanRoutes(routesDir) {
7
7
  const routes = await walkDirectory(routesDir, routesDir);
8
8
  return routes;
9
9
  }
10
- async function walkDirectory(dir, baseDir, segments = []) {
10
+ async function walkDirectory(dir, baseDir, segments = [], parentLayouts = []) {
11
11
  const entries = await fs.readdir(dir, { withFileTypes: true });
12
12
  const files = entries.filter((e) => e.isFile());
13
13
  const dirs = entries.filter((e) => e.isDirectory());
14
14
  const routeFiles = collectRouteFiles(files, dir);
15
+ const currentLayouts = [...parentLayouts];
16
+ if (routeFiles.layout) {
17
+ currentLayouts.push(path.relative(baseDir, routeFiles.layout));
18
+ }
15
19
  const routes = [];
16
20
  if (routeFiles.page) {
21
+ const pathInfo = buildRoutePath(segments);
17
22
  const route = {
18
- path: buildRoutePath(segments),
23
+ path: pathInfo.path,
19
24
  component: path.relative(baseDir, routeFiles.page)
20
25
  };
21
- if (routeFiles.layout) {
22
- route.layout = path.relative(baseDir, routeFiles.layout);
26
+ if (pathInfo.catchAllParam) {
27
+ route.catchAllParam = pathInfo.catchAllParam;
28
+ }
29
+ if (currentLayouts.length > 0) {
30
+ route.layouts = [...currentLayouts];
23
31
  }
24
32
  if (routeFiles.error) {
25
33
  route.error = path.relative(baseDir, routeFiles.error);
@@ -32,10 +40,12 @@ async function walkDirectory(dir, baseDir, segments = []) {
32
40
  for (const subdir of dirs) {
33
41
  const segment = parseSegment(subdir.name);
34
42
  const subdirPath = path.join(dir, subdir.name);
35
- const childRoutes = await walkDirectory(subdirPath, baseDir, [
36
- ...segments,
37
- segment
38
- ]);
43
+ const childRoutes = await walkDirectory(
44
+ subdirPath,
45
+ baseDir,
46
+ [...segments, segment],
47
+ currentLayouts
48
+ );
39
49
  routes.push(...childRoutes);
40
50
  }
41
51
  return routes;
@@ -76,8 +86,9 @@ function parseSegment(segment) {
76
86
  if (/^\(.+\)$/.test(segment)) {
77
87
  return null;
78
88
  }
79
- if (/^\[\.\.\.(.+)\]$/.test(segment)) {
80
- return "*";
89
+ const catchAllMatch = /^\[\.\.\.(.+)\]$/.exec(segment);
90
+ if (catchAllMatch) {
91
+ return { type: "catchall", param: catchAllMatch[1] };
81
92
  }
82
93
  if (/^\[(.+)\]$/.test(segment)) {
83
94
  const param = segment.slice(1, -1);
@@ -86,11 +97,25 @@ function parseSegment(segment) {
86
97
  return segment;
87
98
  }
88
99
  function buildRoutePath(segments) {
89
- const filtered = segments.filter((s) => s !== null);
90
- if (filtered.length === 0) {
91
- return "/";
100
+ const filtered = [];
101
+ let catchAllParam = null;
102
+ for (const segment of segments) {
103
+ if (segment === null) {
104
+ continue;
105
+ }
106
+ if (typeof segment === "object" && segment.type === "catchall") {
107
+ catchAllParam = segment.param;
108
+ filtered.push("*");
109
+ } else {
110
+ filtered.push(segment);
111
+ }
112
+ }
113
+ const path3 = filtered.length === 0 ? "/" : "/" + filtered.join("/");
114
+ const result = { path: path3 };
115
+ if (catchAllParam) {
116
+ result.catchAllParam = catchAllParam;
92
117
  }
93
- return "/" + filtered.join("/");
118
+ return result;
94
119
  }
95
120
  async function generateManifest(routes, outFile, routesDir) {
96
121
  const outDir = path.dirname(outFile);
@@ -98,9 +123,12 @@ async function generateManifest(routes, outFile, routesDir) {
98
123
  const adjustedRoutes = JSON.stringify(routes, null, 2).replace(/"component": "(.+?)"/g, (match, p1) => {
99
124
  const importPath = path.join(relativeRoutesDir, p1).replace(/\\/g, "/");
100
125
  return `"component": () => import("./${importPath}")`;
101
- }).replace(/"layout": "(.+?)"/g, (match, p1) => {
102
- const importPath = path.join(relativeRoutesDir, p1).replace(/\\/g, "/");
103
- return `"layout": () => import("./${importPath}")`;
126
+ }).replace(/"layouts": \[([\s\S]*?)\]/g, (match, layoutsContent) => {
127
+ const transformed = layoutsContent.replace(/"(.+?)"/g, (m, p1) => {
128
+ const importPath = path.join(relativeRoutesDir, p1).replace(/\\/g, "/");
129
+ return `() => import("./${importPath}")`;
130
+ });
131
+ return `"layouts": [${transformed}]`;
104
132
  }).replace(/"error": "(.+?)"/g, (match, p1) => {
105
133
  const importPath = path.join(relativeRoutesDir, p1).replace(/\\/g, "/");
106
134
  return `"error": () => import("./${importPath}")`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gyoll/builder",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "type": "module",
5
5
  "description": "CLI tool for generating route manifests from file-system structure",
6
6
  "bin": {