orpc-file-based-router 0.0.1 → 0.0.2

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.
package/README.md CHANGED
@@ -16,12 +16,11 @@ yarn add orpc-file-based-router
16
16
  // generator.ts
17
17
  import { generateRouter } from 'orpc-file-based-router'
18
18
 
19
- const routesDir = './routes'
20
- const outputFile = './router.ts'
19
+ const routesDir = new URL('./routes', import.meta.url).pathname
20
+ const outputFile = new URL('./router.ts', import.meta.url).pathname
21
+ const router = await generateRouter(routesDir, outputFile)
21
22
 
22
- generateRouter(routesDir, outputFile)
23
- .then(() => console.log('Router generated successfully'))
24
- .catch(console.error)
23
+ const handler = new RPCHandler(router)
25
24
  ```
26
25
 
27
26
  ### File Structure Example
package/dist/index.cjs CHANGED
@@ -32,37 +32,38 @@ async function generateRouter(routesDir, outputFile) {
32
32
  routesDir
33
33
  );
34
34
  const exports = await generateRoutes(files);
35
- const importPaths = exports.map((x) => path.relative(path.dirname(outputFile), routesDir).concat(x.routePath));
36
- const router = buildRouter(exports.map((x) => {
37
- return {
38
- exports: Object.keys(x.exports),
39
- routePath: x.routePath
40
- };
41
- }));
35
+ const importPaths = exports.map((x) => path.relative(path.dirname(outputFile), routesDir).concat(x.path));
36
+ const content = buildRouter(exports, (r, e) => {
37
+ return `${e}.route({ path: '${r.path}' })`;
38
+ });
42
39
  let routerContent = `// This file is auto-generated
43
40
 
44
41
  `;
45
42
  routerContent += importPaths.map((x, i) => `import { ${Object.keys(exports[i].exports).join(", ")} } from "./${x}"`).join("\n");
46
43
  routerContent += "\n\nexport const router = ";
47
- routerContent += JSON.stringify(router, null, 2).replace(/"/g, "");
44
+ routerContent += JSON.stringify(content, null, 2).replace(/"/g, "");
48
45
  node_fs.writeFileSync(path.join(outputFile), routerContent);
46
+ const router = buildRouter(exports, (r, e) => {
47
+ return r.exports[e].route({ path: `${r.path}` });
48
+ });
49
+ return router;
49
50
  }
50
51
  function buildRoutePath(parsedFile) {
51
52
  const directory = parsedFile.dir === parsedFile.root ? "" : parsedFile.dir;
52
53
  const name = parsedFile.name.startsWith("index") ? parsedFile.name.replace("index", "") : `/${parsedFile.name}`;
53
54
  return directory + name;
54
55
  }
55
- function buildRouter(inputs) {
56
+ function buildRouter(routes, mapper) {
56
57
  const router = {};
57
- for (const input of inputs) {
58
- const segments = input.routePath.replace(/\{\w+\}/g, "").replace(/\/\//g, "/").split("/").filter(Boolean);
58
+ for (const route of routes) {
59
+ const segments = route.path.replace(/\{\w+\}/g, "").replace(/\/\//g, "/").split("/").filter(Boolean);
59
60
  let current = router;
60
61
  for (let i = 0; i < segments.length; i++) {
61
62
  const segment = segments[i];
62
63
  if (i === segments.length - 1) {
63
64
  current[segment] = current[segment] || {};
64
- for (const exp of input.exports) {
65
- current[segment][exp] = `${exp}.route({ path: '${input.routePath}' })`;
65
+ for (const exp in route.exports) {
66
+ current[segment][exp] = mapper(route, exp);
66
67
  }
67
68
  } else {
68
69
  current[segment] = current[segment] || {};
@@ -75,7 +76,7 @@ function buildRouter(inputs) {
75
76
  function simplifyRouter(router) {
76
77
  const simplifiedRouter = {};
77
78
  for (const key in router) {
78
- if (typeof router[key] === "string") {
79
+ if (typeof router[key] === "string" || isORPCProcedure(router, key)) {
79
80
  simplifiedRouter[key] = router[key];
80
81
  } else if (typeof router[key] === "object" && isSingleLeaf(router[key])) {
81
82
  const childKey = Object.keys(router[key])[0];
@@ -86,9 +87,12 @@ function simplifyRouter(router) {
86
87
  }
87
88
  return simplifiedRouter;
88
89
  }
90
+ function isORPCProcedure(obj, key) {
91
+ return "~orpc" in obj[key];
92
+ }
89
93
  function isSingleLeaf(obj) {
90
94
  const keys = Object.keys(obj);
91
- return keys.length === 1 && typeof obj[keys[0]] === "string";
95
+ return keys.length === 1;
92
96
  }
93
97
  const isCjs = () => typeof module !== "undefined" && !!module?.exports;
94
98
  const IS_ESM = !isCjs();
@@ -101,7 +105,7 @@ async function generateRoutes(files) {
101
105
  const exports = await import(MODULE_IMPORT_PREFIX + path__default.join(file.path, file.name));
102
106
  routes.push({
103
107
  exports,
104
- routePath
108
+ path: routePath
105
109
  });
106
110
  }
107
111
  return routes;
package/dist/index.d.cts CHANGED
@@ -1,3 +1,4 @@
1
- declare function generateRouter(routesDir: string, outputFile: string): Promise<void>;
1
+ declare function generateRouter(routesDir: string, outputFile: string): Promise<Router>;
2
+ type Router = Record<string, any>;
2
3
 
3
4
  export { generateRouter };
package/dist/index.d.mts CHANGED
@@ -1,3 +1,4 @@
1
- declare function generateRouter(routesDir: string, outputFile: string): Promise<void>;
1
+ declare function generateRouter(routesDir: string, outputFile: string): Promise<Router>;
2
+ type Router = Record<string, any>;
2
3
 
3
4
  export { generateRouter };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
- declare function generateRouter(routesDir: string, outputFile: string): Promise<void>;
1
+ declare function generateRouter(routesDir: string, outputFile: string): Promise<Router>;
2
+ type Router = Record<string, any>;
2
3
 
3
4
  export { generateRouter };
package/dist/index.mjs CHANGED
@@ -26,37 +26,38 @@ async function generateRouter(routesDir, outputFile) {
26
26
  routesDir
27
27
  );
28
28
  const exports = await generateRoutes(files);
29
- const importPaths = exports.map((x) => relative(dirname(outputFile), routesDir).concat(x.routePath));
30
- const router = buildRouter(exports.map((x) => {
31
- return {
32
- exports: Object.keys(x.exports),
33
- routePath: x.routePath
34
- };
35
- }));
29
+ const importPaths = exports.map((x) => relative(dirname(outputFile), routesDir).concat(x.path));
30
+ const content = buildRouter(exports, (r, e) => {
31
+ return `${e}.route({ path: '${r.path}' })`;
32
+ });
36
33
  let routerContent = `// This file is auto-generated
37
34
 
38
35
  `;
39
36
  routerContent += importPaths.map((x, i) => `import { ${Object.keys(exports[i].exports).join(", ")} } from "./${x}"`).join("\n");
40
37
  routerContent += "\n\nexport const router = ";
41
- routerContent += JSON.stringify(router, null, 2).replace(/"/g, "");
38
+ routerContent += JSON.stringify(content, null, 2).replace(/"/g, "");
42
39
  writeFileSync(join(outputFile), routerContent);
40
+ const router = buildRouter(exports, (r, e) => {
41
+ return r.exports[e].route({ path: `${r.path}` });
42
+ });
43
+ return router;
43
44
  }
44
45
  function buildRoutePath(parsedFile) {
45
46
  const directory = parsedFile.dir === parsedFile.root ? "" : parsedFile.dir;
46
47
  const name = parsedFile.name.startsWith("index") ? parsedFile.name.replace("index", "") : `/${parsedFile.name}`;
47
48
  return directory + name;
48
49
  }
49
- function buildRouter(inputs) {
50
+ function buildRouter(routes, mapper) {
50
51
  const router = {};
51
- for (const input of inputs) {
52
- const segments = input.routePath.replace(/\{\w+\}/g, "").replace(/\/\//g, "/").split("/").filter(Boolean);
52
+ for (const route of routes) {
53
+ const segments = route.path.replace(/\{\w+\}/g, "").replace(/\/\//g, "/").split("/").filter(Boolean);
53
54
  let current = router;
54
55
  for (let i = 0; i < segments.length; i++) {
55
56
  const segment = segments[i];
56
57
  if (i === segments.length - 1) {
57
58
  current[segment] = current[segment] || {};
58
- for (const exp of input.exports) {
59
- current[segment][exp] = `${exp}.route({ path: '${input.routePath}' })`;
59
+ for (const exp in route.exports) {
60
+ current[segment][exp] = mapper(route, exp);
60
61
  }
61
62
  } else {
62
63
  current[segment] = current[segment] || {};
@@ -69,7 +70,7 @@ function buildRouter(inputs) {
69
70
  function simplifyRouter(router) {
70
71
  const simplifiedRouter = {};
71
72
  for (const key in router) {
72
- if (typeof router[key] === "string") {
73
+ if (typeof router[key] === "string" || isORPCProcedure(router, key)) {
73
74
  simplifiedRouter[key] = router[key];
74
75
  } else if (typeof router[key] === "object" && isSingleLeaf(router[key])) {
75
76
  const childKey = Object.keys(router[key])[0];
@@ -80,9 +81,12 @@ function simplifyRouter(router) {
80
81
  }
81
82
  return simplifiedRouter;
82
83
  }
84
+ function isORPCProcedure(obj, key) {
85
+ return "~orpc" in obj[key];
86
+ }
83
87
  function isSingleLeaf(obj) {
84
88
  const keys = Object.keys(obj);
85
- return keys.length === 1 && typeof obj[keys[0]] === "string";
89
+ return keys.length === 1;
86
90
  }
87
91
  const isCjs = () => typeof module !== "undefined" && !!module?.exports;
88
92
  const IS_ESM = !isCjs();
@@ -95,7 +99,7 @@ async function generateRoutes(files) {
95
99
  const exports = await import(MODULE_IMPORT_PREFIX + path.join(file.path, file.name));
96
100
  routes.push({
97
101
  exports,
98
- routePath
102
+ path: routePath
99
103
  });
100
104
  }
101
105
  return routes;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "orpc-file-based-router",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "File-based router plugin for oRPC - automatically generate oRPC router from your file structure",
5
5
  "author": "zeeeeby",
6
6
  "license": "MIT",