@potentiajs/core 0.1.0-preview.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.
- package/CHANGELOG.md +45 -0
- package/LICENSE +21 -0
- package/README.md +441 -0
- package/bin/potentia.js +14 -0
- package/examples/file-routing-basic/README.md +156 -0
- package/examples/file-routing-basic/app.js +16 -0
- package/examples/file-routing-basic/generate.js +21 -0
- package/examples/file-routing-basic/routes/health.js +3 -0
- package/examples/file-routing-basic/routes/index.js +3 -0
- package/examples/file-routing-basic/routes/users/[id].js +6 -0
- package/examples/file-routing-basic/routes/users/_routes.js +15 -0
- package/examples/form-rendering-basic/README.md +43 -0
- package/examples/form-rendering-basic/index.js +120 -0
- package/examples/full-flow-basic/README.md +141 -0
- package/examples/full-flow-basic/app.js +16 -0
- package/examples/full-flow-basic/form.js +205 -0
- package/examples/full-flow-basic/generate.js +21 -0
- package/examples/full-flow-basic/routes/index.js +5 -0
- package/examples/full-flow-basic/routes/users/[id].js +5 -0
- package/examples/full-flow-basic/routes/users/_routes.js +8 -0
- package/examples/full-flow-basic/routes/users/index.js +5 -0
- package/examples/full-flow-basic/routes/users/new.js +5 -0
- package/package.json +90 -0
- package/src/cli.js +407 -0
- package/src/dev/file-routing/diagnostics.js +24 -0
- package/src/dev/file-routing/generator.js +126 -0
- package/src/dev/file-routing/index.js +5 -0
- package/src/dev/file-routing/path-mapping.js +125 -0
- package/src/dev/file-routing/scanner.js +154 -0
- package/src/dev/file-routing/writer.js +100 -0
- package/src/file-routing.d.ts +36 -0
- package/src/file-routing.js +1 -0
- package/src/forms.d.ts +9 -0
- package/src/forms.js +334 -0
- package/src/index.d.ts +185 -0
- package/src/index.js +15 -0
- package/src/index.mjs +25 -0
- package/src/kernel/action-projection.js +35 -0
- package/src/kernel/action.js +172 -0
- package/src/kernel/app.js +144 -0
- package/src/kernel/context.js +37 -0
- package/src/kernel/contract-projection.js +129 -0
- package/src/kernel/contract.js +135 -0
- package/src/kernel/diagnostics.js +147 -0
- package/src/kernel/effect.js +119 -0
- package/src/kernel/error.js +93 -0
- package/src/kernel/form-projection.js +251 -0
- package/src/kernel/form-state.js +173 -0
- package/src/kernel/plugin.js +46 -0
- package/src/kernel/response.js +187 -0
- package/src/kernel/result.js +45 -0
- package/src/kernel/route-collection.js +148 -0
- package/src/kernel/route-id.js +11 -0
- package/src/kernel/route-manifest.js +129 -0
- package/src/kernel/route-projection.js +139 -0
- package/src/kernel/route.js +156 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
|
|
3
|
+
export const FILE_ROUTE_DIAGNOSTIC_CODES = Object.freeze({
|
|
4
|
+
COLLISION: 'POTENTIA_FILE_ROUTE_COLLISION',
|
|
5
|
+
UNSUPPORTED_CATCH_ALL: 'POTENTIA_FILE_ROUTE_UNSUPPORTED_CATCH_ALL',
|
|
6
|
+
UNSUPPORTED_OPTIONAL_PARAM: 'POTENTIA_FILE_ROUTE_UNSUPPORTED_OPTIONAL_PARAM',
|
|
7
|
+
UNSUPPORTED_GROUP: 'POTENTIA_FILE_ROUTE_UNSUPPORTED_GROUP',
|
|
8
|
+
INVALID_PARAM: 'POTENTIA_FILE_ROUTE_INVALID_PARAM',
|
|
9
|
+
MISSING_ROOT: 'POTENTIA_FILE_ROUTE_MISSING_ROOT'
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export function mapRouteFile(filePath, rootDir) {
|
|
13
|
+
const normalizedFile = normalizePath(filePath);
|
|
14
|
+
const normalizedRoot = normalizePath(rootDir);
|
|
15
|
+
const relativePath = normalizeRelative(path.posix.relative(normalizedRoot, normalizedFile));
|
|
16
|
+
const parts = relativePath.split('/').filter(Boolean);
|
|
17
|
+
const fileName = parts.at(-1) || '';
|
|
18
|
+
|
|
19
|
+
if (!relativePath || relativePath.startsWith('..')) {
|
|
20
|
+
return invalid(normalizedFile, relativePath, FILE_ROUTE_DIAGNOSTIC_CODES.MISSING_ROOT, 'Route file is outside the route root');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const privateFolder = parts.slice(0, -1).find((part) => part.startsWith('_'));
|
|
24
|
+
if (privateFolder) return ignored(normalizedFile, relativePath, 'private-folder');
|
|
25
|
+
|
|
26
|
+
if (!fileName.endsWith('.js')) return ignored(normalizedFile, relativePath, 'unsupported-extension');
|
|
27
|
+
if (fileName.startsWith('_')) return ignored(normalizedFile, relativePath, 'private-file');
|
|
28
|
+
|
|
29
|
+
const routeSegments = [];
|
|
30
|
+
for (const part of parts) {
|
|
31
|
+
const segment = part === fileName ? stripExtension(part) : part;
|
|
32
|
+
if (segment === 'index' && part === fileName) continue;
|
|
33
|
+
const mapped = mapSegment(segment, normalizedFile, relativePath);
|
|
34
|
+
if (!mapped.ok) return mapped;
|
|
35
|
+
routeSegments.push(mapped.segment);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const routePath = routeSegments.length === 0 ? '/' : `/${routeSegments.join('/')}`;
|
|
39
|
+
return {
|
|
40
|
+
ok: true,
|
|
41
|
+
filePath: normalizedFile,
|
|
42
|
+
relativePath: relativePath,
|
|
43
|
+
routePath: routePath,
|
|
44
|
+
kind: 'route',
|
|
45
|
+
ignored: false,
|
|
46
|
+
reason: null,
|
|
47
|
+
error: null,
|
|
48
|
+
segments: routeSegments
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function normalizePath(value) {
|
|
53
|
+
return String(value || '').replaceAll('\\\\', '/').replace(/\/+/g, '/').replace(/\/$/, '') || '/';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function normalizeRelative(value) {
|
|
57
|
+
return String(value || '').replaceAll('\\\\', '/').replace(/\/+/g, '/');
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function stripExtension(fileName) {
|
|
61
|
+
return fileName.slice(0, -'.js'.length);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function mapSegment(segment, filePath, relativePath) {
|
|
65
|
+
if (!segment) return invalid(filePath, relativePath, FILE_ROUTE_DIAGNOSTIC_CODES.INVALID_PARAM, 'Empty route segment is not supported');
|
|
66
|
+
|
|
67
|
+
if (segment.startsWith('(') && segment.endsWith(')')) {
|
|
68
|
+
return invalid(filePath, relativePath, FILE_ROUTE_DIAGNOSTIC_CODES.UNSUPPORTED_GROUP, 'Route groups are deferred');
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (segment.startsWith('[[') && segment.endsWith(']]')) {
|
|
72
|
+
return invalid(filePath, relativePath, FILE_ROUTE_DIAGNOSTIC_CODES.UNSUPPORTED_OPTIONAL_PARAM, 'Optional route params are deferred');
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (segment.startsWith('[...') && segment.endsWith(']')) {
|
|
76
|
+
return invalid(filePath, relativePath, FILE_ROUTE_DIAGNOSTIC_CODES.UNSUPPORTED_CATCH_ALL, 'Catch-all route params are deferred');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (segment.startsWith('[') && segment.endsWith(']')) {
|
|
80
|
+
const name = segment.slice(1, -1);
|
|
81
|
+
if (!/^[A-Za-z0-9_-]+$/.test(name)) {
|
|
82
|
+
return invalid(filePath, relativePath, FILE_ROUTE_DIAGNOSTIC_CODES.INVALID_PARAM, 'Dynamic route param name is invalid');
|
|
83
|
+
}
|
|
84
|
+
return { ok: true, segment: `:${name}` };
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (segment.includes('[') || segment.includes(']')) {
|
|
88
|
+
return invalid(filePath, relativePath, FILE_ROUTE_DIAGNOSTIC_CODES.INVALID_PARAM, 'Dynamic route param syntax is invalid');
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return { ok: true, segment: segment };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function ignored(filePath, relativePath, reason) {
|
|
95
|
+
return {
|
|
96
|
+
ok: true,
|
|
97
|
+
filePath: filePath,
|
|
98
|
+
relativePath: relativePath,
|
|
99
|
+
routePath: null,
|
|
100
|
+
kind: 'ignored',
|
|
101
|
+
ignored: true,
|
|
102
|
+
reason: reason,
|
|
103
|
+
error: null,
|
|
104
|
+
segments: []
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function invalid(filePath, relativePath, code, message) {
|
|
109
|
+
return {
|
|
110
|
+
ok: false,
|
|
111
|
+
filePath: filePath,
|
|
112
|
+
relativePath: relativePath,
|
|
113
|
+
routePath: null,
|
|
114
|
+
kind: 'invalid',
|
|
115
|
+
ignored: false,
|
|
116
|
+
reason: null,
|
|
117
|
+
error: {
|
|
118
|
+
code: code,
|
|
119
|
+
message: message,
|
|
120
|
+
filePath: filePath,
|
|
121
|
+
relativePath: relativePath
|
|
122
|
+
},
|
|
123
|
+
segments: []
|
|
124
|
+
};
|
|
125
|
+
}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
import { routeCollisionDiagnostics } from './diagnostics.js';
|
|
5
|
+
import { FILE_ROUTE_DIAGNOSTIC_CODES, mapRouteFile, normalizePath } from './path-mapping.js';
|
|
6
|
+
|
|
7
|
+
export function scanRouteTree(rootDir) {
|
|
8
|
+
const normalizedRoot = normalizePath(rootDir);
|
|
9
|
+
|
|
10
|
+
if (!fs.existsSync(normalizedRoot) || !fs.statSync(normalizedRoot).isDirectory()) {
|
|
11
|
+
return emptyScan(normalizedRoot, [{
|
|
12
|
+
code: FILE_ROUTE_DIAGNOSTIC_CODES.MISSING_ROOT,
|
|
13
|
+
message: 'Route root directory was not found',
|
|
14
|
+
rootDir: normalizedRoot
|
|
15
|
+
}]);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const files = listFiles(normalizedRoot);
|
|
19
|
+
const routes = [];
|
|
20
|
+
const scopes = [];
|
|
21
|
+
const ignored = [];
|
|
22
|
+
const errors = [];
|
|
23
|
+
|
|
24
|
+
for (const filePath of files) {
|
|
25
|
+
const relativePath = normalizeRelative(path.posix.relative(normalizedRoot, filePath));
|
|
26
|
+
const fileName = path.posix.basename(filePath);
|
|
27
|
+
|
|
28
|
+
if (isPrivateFolder(relativePath)) {
|
|
29
|
+
ignored.push(ignoredEntry(filePath, normalizedRoot, 'private-folder'));
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (fileName === '_routes.js') {
|
|
34
|
+
scopes.push(scopeEntry(filePath, normalizedRoot));
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const mapped = mapRouteFile(filePath, normalizedRoot);
|
|
39
|
+
if (!mapped.ok) {
|
|
40
|
+
errors.push(mapped.error);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (mapped.ignored) {
|
|
45
|
+
ignored.push({ ...mapped, importPath: toImportPath(relativePath) });
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
routes.push({
|
|
50
|
+
filePath: mapped.filePath,
|
|
51
|
+
importPath: toImportPath(mapped.relativePath),
|
|
52
|
+
routePath: mapped.routePath,
|
|
53
|
+
segments: mapped.segments,
|
|
54
|
+
kind: 'route'
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const sortedRoutes = sortByPath(routes);
|
|
59
|
+
const allErrors = sortErrors(errors.concat(routeCollisionDiagnostics(sortedRoutes)));
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
ok: allErrors.length === 0,
|
|
63
|
+
rootDir: normalizedRoot,
|
|
64
|
+
routes: sortedRoutes,
|
|
65
|
+
scopes: sortByPath(scopes),
|
|
66
|
+
ignored: sortByFile(ignored),
|
|
67
|
+
errors: allErrors
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function emptyScan(rootDir, errors = []) {
|
|
72
|
+
return {
|
|
73
|
+
ok: errors.length === 0,
|
|
74
|
+
rootDir: rootDir,
|
|
75
|
+
routes: [],
|
|
76
|
+
scopes: [],
|
|
77
|
+
ignored: [],
|
|
78
|
+
errors: errors
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function listFiles(dir) {
|
|
83
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
84
|
+
const files = [];
|
|
85
|
+
|
|
86
|
+
for (const entry of entries) {
|
|
87
|
+
const entryPath = normalizePath(path.posix.join(dir, entry.name));
|
|
88
|
+
if (entry.isDirectory()) {
|
|
89
|
+
files.push(...listFiles(entryPath));
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (entry.isFile()) files.push(entryPath);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return files;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function scopeEntry(filePath, rootDir) {
|
|
99
|
+
const normalizedFile = normalizePath(filePath);
|
|
100
|
+
const relativePath = normalizeRelative(path.posix.relative(rootDir, normalizedFile));
|
|
101
|
+
const directoryRelative = normalizeRelative(path.posix.dirname(relativePath));
|
|
102
|
+
const segments = directoryRelative === '.' ? [] : directoryRelative.split('/').filter(Boolean);
|
|
103
|
+
const routePath = segments.length === 0 ? '/' : `/${segments.join('/')}`;
|
|
104
|
+
|
|
105
|
+
return {
|
|
106
|
+
filePath: normalizedFile,
|
|
107
|
+
importPath: toImportPath(relativePath),
|
|
108
|
+
routePath: routePath,
|
|
109
|
+
directoryPath: normalizePath(path.posix.dirname(normalizedFile)),
|
|
110
|
+
segments: segments,
|
|
111
|
+
kind: 'scope'
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function ignoredEntry(filePath, rootDir, reason) {
|
|
116
|
+
const normalizedFile = normalizePath(filePath);
|
|
117
|
+
const relativePath = normalizeRelative(path.posix.relative(rootDir, normalizedFile));
|
|
118
|
+
return {
|
|
119
|
+
ok: true,
|
|
120
|
+
filePath: normalizedFile,
|
|
121
|
+
relativePath: relativePath,
|
|
122
|
+
importPath: toImportPath(relativePath),
|
|
123
|
+
routePath: null,
|
|
124
|
+
kind: 'ignored',
|
|
125
|
+
ignored: true,
|
|
126
|
+
reason: reason,
|
|
127
|
+
error: null,
|
|
128
|
+
segments: []
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function isPrivateFolder(relativePath) {
|
|
133
|
+
return relativePath.split('/').filter(Boolean).slice(0, -1).some((part) => part.startsWith('_'));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function toImportPath(relativePath) {
|
|
137
|
+
return `./${normalizeRelative(relativePath)}`;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function normalizeRelative(value) {
|
|
141
|
+
return String(value || '').replaceAll('\\\\', '/').replace(/\/+/g, '/');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function sortByPath(values) {
|
|
145
|
+
return values.slice().sort((a, b) => a.routePath.localeCompare(b.routePath) || a.filePath.localeCompare(b.filePath));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function sortByFile(values) {
|
|
149
|
+
return values.slice().sort((a, b) => a.filePath.localeCompare(b.filePath));
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function sortErrors(values) {
|
|
153
|
+
return values.slice().sort((a, b) => String(a.filePath || '').localeCompare(String(b.filePath || '')) || String(a.code).localeCompare(String(b.code)));
|
|
154
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { mkdir, rename, rm, writeFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
import { generateRouteModule } from './generator.js';
|
|
5
|
+
import { normalizePath } from './path-mapping.js';
|
|
6
|
+
import { scanRouteTree } from './scanner.js';
|
|
7
|
+
|
|
8
|
+
export async function generateFileRoutes(options = {}) {
|
|
9
|
+
const prepared = generateFileRouteSource(options);
|
|
10
|
+
if (!prepared.ok) return prepared;
|
|
11
|
+
|
|
12
|
+
const outputFile = prepared.outputFile;
|
|
13
|
+
|
|
14
|
+
const tempFile = `${outputFile}.tmp-${process.pid}-${Date.now()}`;
|
|
15
|
+
|
|
16
|
+
try {
|
|
17
|
+
await mkdir(path.posix.dirname(outputFile), { recursive: true });
|
|
18
|
+
await writeFile(tempFile, prepared.source);
|
|
19
|
+
await rename(tempFile, outputFile);
|
|
20
|
+
} catch (error) {
|
|
21
|
+
await rm(tempFile, { force: true }).catch(() => {});
|
|
22
|
+
return failureResult(prepared.rootDir, outputFile, [{
|
|
23
|
+
code: 'POTENTIA_FILE_ROUTE_WRITE_FAILED',
|
|
24
|
+
message: 'Failed to write generated route module',
|
|
25
|
+
outputFile: outputFile,
|
|
26
|
+
cause: error instanceof Error ? error.message : String(error)
|
|
27
|
+
}], prepared.routes, prepared.scopes);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
ok: true,
|
|
32
|
+
rootDir: prepared.rootDir,
|
|
33
|
+
outputFile: prepared.outputFile,
|
|
34
|
+
written: true,
|
|
35
|
+
source: prepared.source,
|
|
36
|
+
routes: prepared.routes,
|
|
37
|
+
scopes: prepared.scopes,
|
|
38
|
+
diagnostics: [],
|
|
39
|
+
errors: []
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function generateFileRouteSource(options = {}) {
|
|
44
|
+
const rootDir = resolveOptionPath(options.rootDir, options.cwd);
|
|
45
|
+
const outputFile = resolveOptionPath(options.outputFile, options.cwd);
|
|
46
|
+
|
|
47
|
+
if (!rootDir || !outputFile) {
|
|
48
|
+
return failureResult(rootDir, outputFile, [{
|
|
49
|
+
code: 'POTENTIA_FILE_ROUTE_INVALID_OPTIONS',
|
|
50
|
+
message: 'rootDir and outputFile are required'
|
|
51
|
+
}]);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const scan = scanRouteTree(rootDir);
|
|
55
|
+
if (!scan.ok || scan.errors.length > 0) {
|
|
56
|
+
return failureResult(rootDir, outputFile, scan.errors, scan.routes.length, scan.scopes.length);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const generated = generateRouteModule(scan, {
|
|
60
|
+
outputPath: outputFile,
|
|
61
|
+
packageName: options.packageName
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
if (!generated.ok || generated.errors.length > 0) {
|
|
65
|
+
return failureResult(rootDir, outputFile, generated.errors, scan.routes.length, scan.scopes.length);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
ok: true,
|
|
70
|
+
rootDir: rootDir,
|
|
71
|
+
outputFile: outputFile,
|
|
72
|
+
written: false,
|
|
73
|
+
source: generated.source,
|
|
74
|
+
routes: scan.routes.length,
|
|
75
|
+
scopes: scan.scopes.length,
|
|
76
|
+
diagnostics: [],
|
|
77
|
+
errors: []
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function failureResult(rootDir, outputFile, errors, routes = 0, scopes = 0) {
|
|
82
|
+
return {
|
|
83
|
+
ok: false,
|
|
84
|
+
rootDir: rootDir || null,
|
|
85
|
+
outputFile: outputFile || null,
|
|
86
|
+
written: false,
|
|
87
|
+
source: '',
|
|
88
|
+
routes: routes,
|
|
89
|
+
scopes: scopes,
|
|
90
|
+
diagnostics: errors,
|
|
91
|
+
errors: errors
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function resolveOptionPath(value, cwd = process.cwd()) {
|
|
96
|
+
if (!value) return null;
|
|
97
|
+
const asString = String(value);
|
|
98
|
+
if (path.posix.isAbsolute(asString)) return normalizePath(asString);
|
|
99
|
+
return normalizePath(path.posix.resolve(cwd, asString));
|
|
100
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Experimental TypeScript declarations for @potentiajs/core/file-routing.
|
|
2
|
+
// File routing is a dev/build-time projection API. It does not perform runtime request-time filesystem scanning.
|
|
3
|
+
|
|
4
|
+
export interface FileRouteDiagnostic {
|
|
5
|
+
code: string;
|
|
6
|
+
message: string;
|
|
7
|
+
filePath?: string;
|
|
8
|
+
relativePath?: string;
|
|
9
|
+
routePath?: string;
|
|
10
|
+
files?: string[];
|
|
11
|
+
rootDir?: string;
|
|
12
|
+
outputFile?: string;
|
|
13
|
+
cause?: string;
|
|
14
|
+
[key: string]: unknown;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface GenerateFileRoutesOptions {
|
|
18
|
+
rootDir: string;
|
|
19
|
+
outputFile: string;
|
|
20
|
+
packageName?: string;
|
|
21
|
+
cwd?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface GenerateFileRoutesResult {
|
|
25
|
+
ok: boolean;
|
|
26
|
+
rootDir: string | null;
|
|
27
|
+
outputFile: string | null;
|
|
28
|
+
written: boolean;
|
|
29
|
+
source: string;
|
|
30
|
+
routes: number;
|
|
31
|
+
scopes: number;
|
|
32
|
+
diagnostics: FileRouteDiagnostic[];
|
|
33
|
+
errors: FileRouteDiagnostic[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function generateFileRoutes(options: GenerateFileRoutesOptions): Promise<GenerateFileRoutesResult>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { generateFileRoutes } from './dev/file-routing/writer.js';
|
package/src/forms.d.ts
ADDED