orpc-file-based-router 0.1.5 → 0.1.6
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 +33 -22
- package/dist/index.cjs +31 -4
- package/dist/index.d.cts +6 -3
- package/dist/index.d.mts +6 -3
- package/dist/index.d.ts +6 -3
- package/dist/index.mjs +31 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -99,35 +99,34 @@ generateRouter(routesDir, outputFile);
|
|
|
99
99
|
|
|
100
100
|
2. Generated router is ready to use in client:
|
|
101
101
|
|
|
102
|
-
> ⚠️ If you don't want plugin to generate openapi `route({})` suffix, just set parameter `includeRoute` to `false`
|
|
103
|
-
|
|
104
102
|
```typescript
|
|
105
103
|
// router.ts
|
|
106
|
-
|
|
107
|
-
import {
|
|
108
|
-
import {
|
|
109
|
-
import {
|
|
110
|
-
import {
|
|
111
|
-
import {
|
|
112
|
-
import {
|
|
113
|
-
import {
|
|
114
|
-
import {
|
|
104
|
+
|
|
105
|
+
import { me as auth_me__me } from "./routes/auth/me.js"
|
|
106
|
+
import { signin as auth_signin__signin } from "./routes/auth/signin.js"
|
|
107
|
+
import { signup as auth_signup__signup } from "./routes/auth/signup.js"
|
|
108
|
+
import { createPlanet as planets_create__createPlanet } from "./routes/planets/create.js"
|
|
109
|
+
import { indexRoute as planets_index__indexRoute } from "./routes/planets/index.js"
|
|
110
|
+
import { listPlanets as planets_list__listPlanets } from "./routes/planets/list.js"
|
|
111
|
+
import { findPlanet as planets_id_find__findPlanet } from "./routes/planets/{id}/find.js"
|
|
112
|
+
import { updatePlanet as planets_id_update__updatePlanet } from "./routes/planets/{id}/update.js"
|
|
113
|
+
import { sse as sse__sse } from "./routes/sse.js"
|
|
115
114
|
|
|
116
115
|
export const router = {
|
|
117
116
|
auth: {
|
|
118
|
-
me:
|
|
119
|
-
signin:
|
|
120
|
-
signup:
|
|
117
|
+
me: auth_me__me.route({ path: '/auth/me', method: 'GET' }),
|
|
118
|
+
signin: auth_signin__signin.route({ path: '/auth/signin', method: 'POST' }),
|
|
119
|
+
signup: auth_signup__signup.route({ path: '/auth/signup', method: 'POST' })
|
|
121
120
|
},
|
|
122
121
|
planets: {
|
|
123
|
-
create:
|
|
124
|
-
|
|
125
|
-
list:
|
|
126
|
-
find:
|
|
127
|
-
update:
|
|
122
|
+
create: planets_create__createPlanet.route({ path: '/planets/create', method: 'POST' }),
|
|
123
|
+
index: planets_index__indexRoute.route({ path: '/planets', method: 'GET' }),
|
|
124
|
+
list: planets_list__listPlanets.route({ path: '/planets/list', method: 'GET' }),
|
|
125
|
+
find: planets_id_find__findPlanet.route({ path: '/planets/{id}/find', method: 'GET' }),
|
|
126
|
+
update: planets_id_update__updatePlanet.route({ path: '/planets/{id}/update', method: 'PUT' })
|
|
128
127
|
},
|
|
129
|
-
sse:
|
|
130
|
-
}
|
|
128
|
+
sse: sse__sse.route({ path: '/sse', method: 'GET' })
|
|
129
|
+
}
|
|
131
130
|
|
|
132
131
|
|
|
133
132
|
// lib/orpc.ts
|
|
@@ -142,9 +141,21 @@ When using `generateRouter`, you can provide additional options to customize the
|
|
|
142
141
|
| Field | Type | Required | Default Value | Description |
|
|
143
142
|
|-------------------|----------|--------------|-----------------------|------------------------------------------------------------------------------------------------------------------------------|
|
|
144
143
|
| `importExtension` | string | false | `""`(No extension) | File extension to append to import statements in the generated router. Useful when your build setup requires specific extensions. <br>Example: `.js` → `import { me } from "./routes/auth/me.js"` |
|
|
145
|
-
| `
|
|
144
|
+
| `enableOpenAPI` | boolean | false | `true` | When set to true, each route will be wrapped with OpenAPI .route({ path: '...', method: '...' }) call |
|
|
145
|
+
| `additionalMethods` | string[] | false | `[]` | Additional HTTP methods to recognize from export names. |
|
|
146
146
|
|
|
147
147
|
|
|
148
|
+
## Examples
|
|
149
|
+
### HTTP Method Matching
|
|
150
|
+
If you export functions named e.g. `get`, `post`, `put`, `patch`, `delete/del` etc. from a route file, those will get matched their corresponding http method automatically.
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
// ./routes/planets.ts
|
|
154
|
+
|
|
155
|
+
export const get = orpc.handler(async ({ input, context }) => {})
|
|
156
|
+
|
|
157
|
+
export const post = orpc.handler(async ({ input, context }) => {})
|
|
158
|
+
```
|
|
148
159
|
|
|
149
160
|
## 📄 License
|
|
150
161
|
|
package/dist/index.cjs
CHANGED
|
@@ -7,6 +7,25 @@ function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'defau
|
|
|
7
7
|
|
|
8
8
|
const path__default = /*#__PURE__*/_interopDefaultCompat(path);
|
|
9
9
|
|
|
10
|
+
const METHOD_EXPORTS = [
|
|
11
|
+
"GET",
|
|
12
|
+
"POST",
|
|
13
|
+
"PUT",
|
|
14
|
+
"PATCH",
|
|
15
|
+
"DELETE",
|
|
16
|
+
"HEAD"
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
const getMethodKey = (method) => {
|
|
20
|
+
let methodKey = method.toUpperCase();
|
|
21
|
+
if (methodKey === "DEL") return "DELETE";
|
|
22
|
+
return methodKey;
|
|
23
|
+
};
|
|
24
|
+
const isMethodExport = (exportName, extraMethods) => {
|
|
25
|
+
const methods = [...METHOD_EXPORTS, ...extraMethods].map(getMethodKey);
|
|
26
|
+
return methods.includes(getMethodKey(exportName));
|
|
27
|
+
};
|
|
28
|
+
|
|
10
29
|
function walkTree(directory, tree = []) {
|
|
11
30
|
const results = [];
|
|
12
31
|
for (const fileName of node_fs.readdirSync(directory)) {
|
|
@@ -56,20 +75,28 @@ async function generateRouter(routesDir, outputFile, options) {
|
|
|
56
75
|
const exports = await generateRoutes(files);
|
|
57
76
|
const importPaths = exports.map((x) => path.relative(path.dirname(outputFile), routesDir).concat(x.path));
|
|
58
77
|
const content = buildRouter(exports, (r, e) => {
|
|
59
|
-
|
|
60
|
-
|
|
78
|
+
const alias = routePathToAlias(r.path, e);
|
|
79
|
+
if (options?.enableOpenAPI ?? true) {
|
|
80
|
+
const orpcMeta = isORPCProcedure(r.exports[e]) ? r.exports[e]["~orpc"] : void 0;
|
|
81
|
+
const method = isMethodExport(e, options?.additionalMethods || []) ? getMethodKey(e) : orpcMeta?.route?.method || "POST";
|
|
82
|
+
const config = { path: r.path.replace(/\/{0,1}index$/, ""), method };
|
|
83
|
+
return `${alias}.route({ path: '${config.path}', method: '${config.method}' })`;
|
|
61
84
|
}
|
|
62
|
-
return
|
|
85
|
+
return alias;
|
|
63
86
|
});
|
|
64
87
|
let routerContent = `// This file is auto-generated
|
|
65
88
|
|
|
66
89
|
`;
|
|
67
90
|
const extension = options?.importExtension || "";
|
|
68
|
-
routerContent += importPaths.map((x, i) => `import { ${Object.keys(exports[i].exports).join(", ")} } from "./${x}${extension}"`).join("\n");
|
|
91
|
+
routerContent += importPaths.map((x, i) => `import { ${Object.keys(exports[i].exports).map((y) => `${y} as ${routePathToAlias(exports[i].path, y)}`).join(", ")} } from "./${x}${extension}"`).join("\n");
|
|
69
92
|
routerContent += "\n\nexport const router = ";
|
|
70
93
|
routerContent += JSON.stringify(content, null, 2).replace(/"/g, "").replace(/(\s*)([a-zA-Z0-9]+-[a-zA-Z0-9-]+):/g, '$1"$2":');
|
|
71
94
|
node_fs.writeFileSync(path.join(outputFile), routerContent);
|
|
72
95
|
}
|
|
96
|
+
function routePathToAlias(routePath, methodName) {
|
|
97
|
+
const cleanPath = routePath.replace(/\{(\w+)\}/g, "$1").replace(/-/g, "_");
|
|
98
|
+
return cleanPath.split("/").filter(Boolean).join("_") + "__" + methodName;
|
|
99
|
+
}
|
|
73
100
|
function buildRoutePath(parsedFile) {
|
|
74
101
|
const directory = parsedFile.dir === parsedFile.root ? "" : parsedFile.dir;
|
|
75
102
|
const name = `/${parsedFile.name}`;
|
package/dist/index.d.cts
CHANGED
|
@@ -12,11 +12,14 @@ type GeneratorOptions = {
|
|
|
12
12
|
*/
|
|
13
13
|
importExtension?: string;
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
16
|
-
* When set to true, each route will have its openapi path
|
|
15
|
+
* When set to true, each route will be wrapped with OpenAPI .route({ path: '...', method: '...' }) call
|
|
17
16
|
* @default true
|
|
18
17
|
*/
|
|
19
|
-
|
|
18
|
+
enableOpenAPI?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Additional HTTP methods to recognize from export names.
|
|
21
|
+
*/
|
|
22
|
+
additionalMethods?: string[];
|
|
20
23
|
};
|
|
21
24
|
declare function generateRouter(routesDir: string, outputFile: string, options?: GeneratorOptions): Promise<void>;
|
|
22
25
|
type Router = Record<string, any>;
|
package/dist/index.d.mts
CHANGED
|
@@ -12,11 +12,14 @@ type GeneratorOptions = {
|
|
|
12
12
|
*/
|
|
13
13
|
importExtension?: string;
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
16
|
-
* When set to true, each route will have its openapi path
|
|
15
|
+
* When set to true, each route will be wrapped with OpenAPI .route({ path: '...', method: '...' }) call
|
|
17
16
|
* @default true
|
|
18
17
|
*/
|
|
19
|
-
|
|
18
|
+
enableOpenAPI?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Additional HTTP methods to recognize from export names.
|
|
21
|
+
*/
|
|
22
|
+
additionalMethods?: string[];
|
|
20
23
|
};
|
|
21
24
|
declare function generateRouter(routesDir: string, outputFile: string, options?: GeneratorOptions): Promise<void>;
|
|
22
25
|
type Router = Record<string, any>;
|
package/dist/index.d.ts
CHANGED
|
@@ -12,11 +12,14 @@ type GeneratorOptions = {
|
|
|
12
12
|
*/
|
|
13
13
|
importExtension?: string;
|
|
14
14
|
/**
|
|
15
|
-
*
|
|
16
|
-
* When set to true, each route will have its openapi path
|
|
15
|
+
* When set to true, each route will be wrapped with OpenAPI .route({ path: '...', method: '...' }) call
|
|
17
16
|
* @default true
|
|
18
17
|
*/
|
|
19
|
-
|
|
18
|
+
enableOpenAPI?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Additional HTTP methods to recognize from export names.
|
|
21
|
+
*/
|
|
22
|
+
additionalMethods?: string[];
|
|
20
23
|
};
|
|
21
24
|
declare function generateRouter(routesDir: string, outputFile: string, options?: GeneratorOptions): Promise<void>;
|
|
22
25
|
type Router = Record<string, any>;
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,25 @@
|
|
|
1
1
|
import { writeFileSync, readdirSync, statSync } from 'node:fs';
|
|
2
2
|
import path, { relative, dirname, join } from 'node:path';
|
|
3
3
|
|
|
4
|
+
const METHOD_EXPORTS = [
|
|
5
|
+
"GET",
|
|
6
|
+
"POST",
|
|
7
|
+
"PUT",
|
|
8
|
+
"PATCH",
|
|
9
|
+
"DELETE",
|
|
10
|
+
"HEAD"
|
|
11
|
+
];
|
|
12
|
+
|
|
13
|
+
const getMethodKey = (method) => {
|
|
14
|
+
let methodKey = method.toUpperCase();
|
|
15
|
+
if (methodKey === "DEL") return "DELETE";
|
|
16
|
+
return methodKey;
|
|
17
|
+
};
|
|
18
|
+
const isMethodExport = (exportName, extraMethods) => {
|
|
19
|
+
const methods = [...METHOD_EXPORTS, ...extraMethods].map(getMethodKey);
|
|
20
|
+
return methods.includes(getMethodKey(exportName));
|
|
21
|
+
};
|
|
22
|
+
|
|
4
23
|
function walkTree(directory, tree = []) {
|
|
5
24
|
const results = [];
|
|
6
25
|
for (const fileName of readdirSync(directory)) {
|
|
@@ -50,20 +69,28 @@ async function generateRouter(routesDir, outputFile, options) {
|
|
|
50
69
|
const exports = await generateRoutes(files);
|
|
51
70
|
const importPaths = exports.map((x) => relative(dirname(outputFile), routesDir).concat(x.path));
|
|
52
71
|
const content = buildRouter(exports, (r, e) => {
|
|
53
|
-
|
|
54
|
-
|
|
72
|
+
const alias = routePathToAlias(r.path, e);
|
|
73
|
+
if (options?.enableOpenAPI ?? true) {
|
|
74
|
+
const orpcMeta = isORPCProcedure(r.exports[e]) ? r.exports[e]["~orpc"] : void 0;
|
|
75
|
+
const method = isMethodExport(e, options?.additionalMethods || []) ? getMethodKey(e) : orpcMeta?.route?.method || "POST";
|
|
76
|
+
const config = { path: r.path.replace(/\/{0,1}index$/, ""), method };
|
|
77
|
+
return `${alias}.route({ path: '${config.path}', method: '${config.method}' })`;
|
|
55
78
|
}
|
|
56
|
-
return
|
|
79
|
+
return alias;
|
|
57
80
|
});
|
|
58
81
|
let routerContent = `// This file is auto-generated
|
|
59
82
|
|
|
60
83
|
`;
|
|
61
84
|
const extension = options?.importExtension || "";
|
|
62
|
-
routerContent += importPaths.map((x, i) => `import { ${Object.keys(exports[i].exports).join(", ")} } from "./${x}${extension}"`).join("\n");
|
|
85
|
+
routerContent += importPaths.map((x, i) => `import { ${Object.keys(exports[i].exports).map((y) => `${y} as ${routePathToAlias(exports[i].path, y)}`).join(", ")} } from "./${x}${extension}"`).join("\n");
|
|
63
86
|
routerContent += "\n\nexport const router = ";
|
|
64
87
|
routerContent += JSON.stringify(content, null, 2).replace(/"/g, "").replace(/(\s*)([a-zA-Z0-9]+-[a-zA-Z0-9-]+):/g, '$1"$2":');
|
|
65
88
|
writeFileSync(join(outputFile), routerContent);
|
|
66
89
|
}
|
|
90
|
+
function routePathToAlias(routePath, methodName) {
|
|
91
|
+
const cleanPath = routePath.replace(/\{(\w+)\}/g, "$1").replace(/-/g, "_");
|
|
92
|
+
return cleanPath.split("/").filter(Boolean).join("_") + "__" + methodName;
|
|
93
|
+
}
|
|
67
94
|
function buildRoutePath(parsedFile) {
|
|
68
95
|
const directory = parsedFile.dir === parsedFile.root ? "" : parsedFile.dir;
|
|
69
96
|
const name = `/${parsedFile.name}`;
|
package/package.json
CHANGED