@fougere/core 0.1.0-alpha.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/LICENSE +21 -0
- package/README.md +21 -0
- package/dist/binding.d.ts +63 -0
- package/dist/binding.d.ts.map +1 -0
- package/dist/binding.js +107 -0
- package/dist/binding.js.map +1 -0
- package/dist/boot.d.ts +38 -0
- package/dist/boot.d.ts.map +1 -0
- package/dist/boot.js +53 -0
- package/dist/boot.js.map +1 -0
- package/dist/bootstrap.d.ts +4 -0
- package/dist/bootstrap.d.ts.map +1 -0
- package/dist/bootstrap.js +825 -0
- package/dist/bootstrap.js.map +1 -0
- package/dist/builtins/config.d.ts +4 -0
- package/dist/builtins/config.d.ts.map +1 -0
- package/dist/builtins/config.js +6 -0
- package/dist/builtins/config.js.map +1 -0
- package/dist/builtins/logger.d.ts +28 -0
- package/dist/builtins/logger.d.ts.map +1 -0
- package/dist/builtins/logger.js +76 -0
- package/dist/builtins/logger.js.map +1 -0
- package/dist/call.d.ts +172 -0
- package/dist/call.d.ts.map +1 -0
- package/dist/call.js +209 -0
- package/dist/call.js.map +1 -0
- package/dist/collector.d.ts +28 -0
- package/dist/collector.d.ts.map +1 -0
- package/dist/collector.js +32 -0
- package/dist/collector.js.map +1 -0
- package/dist/config-loader.d.ts +59 -0
- package/dist/config-loader.d.ts.map +1 -0
- package/dist/config-loader.js +97 -0
- package/dist/config-loader.js.map +1 -0
- package/dist/contract.d.ts +43 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/contract.js +29 -0
- package/dist/contract.js.map +1 -0
- package/dist/crud.d.ts +61 -0
- package/dist/crud.d.ts.map +1 -0
- package/dist/crud.js +85 -0
- package/dist/crud.js.map +1 -0
- package/dist/define.d.ts +8 -0
- package/dist/define.d.ts.map +1 -0
- package/dist/define.js +9 -0
- package/dist/define.js.map +1 -0
- package/dist/egress.d.ts +78 -0
- package/dist/egress.d.ts.map +1 -0
- package/dist/egress.js +185 -0
- package/dist/egress.js.map +1 -0
- package/dist/emit.d.ts +51 -0
- package/dist/emit.d.ts.map +1 -0
- package/dist/emit.js +57 -0
- package/dist/emit.js.map +1 -0
- package/dist/errors.d.ts +22 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +74 -0
- package/dist/errors.js.map +1 -0
- package/dist/frond-config.d.ts +80 -0
- package/dist/frond-config.d.ts.map +1 -0
- package/dist/frond-config.js +32 -0
- package/dist/frond-config.js.map +1 -0
- package/dist/graph.d.ts +33 -0
- package/dist/graph.d.ts.map +1 -0
- package/dist/graph.js +142 -0
- package/dist/graph.js.map +1 -0
- package/dist/handler-parser.d.ts +82 -0
- package/dist/handler-parser.d.ts.map +1 -0
- package/dist/handler-parser.js +505 -0
- package/dist/handler-parser.js.map +1 -0
- package/dist/imports.d.ts +22 -0
- package/dist/imports.d.ts.map +1 -0
- package/dist/imports.js +80 -0
- package/dist/imports.js.map +1 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +37 -0
- package/dist/index.js.map +1 -0
- package/dist/invocation.d.ts +20 -0
- package/dist/invocation.d.ts.map +1 -0
- package/dist/invocation.js +15 -0
- package/dist/invocation.js.map +1 -0
- package/dist/middleware/error-handler.d.ts +15 -0
- package/dist/middleware/error-handler.d.ts.map +1 -0
- package/dist/middleware/error-handler.js +29 -0
- package/dist/middleware/error-handler.js.map +1 -0
- package/dist/middleware/logger.d.ts +14 -0
- package/dist/middleware/logger.d.ts.map +1 -0
- package/dist/middleware/logger.js +25 -0
- package/dist/middleware/logger.js.map +1 -0
- package/dist/middleware.d.ts +75 -0
- package/dist/middleware.d.ts.map +1 -0
- package/dist/middleware.js +89 -0
- package/dist/middleware.js.map +1 -0
- package/dist/operation.d.ts +87 -0
- package/dist/operation.d.ts.map +1 -0
- package/dist/operation.js +95 -0
- package/dist/operation.js.map +1 -0
- package/dist/orm.d.ts +96 -0
- package/dist/orm.d.ts.map +1 -0
- package/dist/orm.js +33 -0
- package/dist/orm.js.map +1 -0
- package/dist/presenter.d.ts +63 -0
- package/dist/presenter.d.ts.map +1 -0
- package/dist/presenter.js +72 -0
- package/dist/presenter.js.map +1 -0
- package/dist/remote.d.ts +48 -0
- package/dist/remote.d.ts.map +1 -0
- package/dist/remote.js +135 -0
- package/dist/remote.js.map +1 -0
- package/dist/repository.d.ts +55 -0
- package/dist/repository.d.ts.map +1 -0
- package/dist/repository.js +26 -0
- package/dist/repository.js.map +1 -0
- package/dist/scan-cache.d.ts +10 -0
- package/dist/scan-cache.d.ts.map +1 -0
- package/dist/scan-cache.js +92 -0
- package/dist/scan-cache.js.map +1 -0
- package/dist/scanner.d.ts +34 -0
- package/dist/scanner.d.ts.map +1 -0
- package/dist/scanner.js +595 -0
- package/dist/scanner.js.map +1 -0
- package/dist/seed.d.ts +28 -0
- package/dist/seed.d.ts.map +1 -0
- package/dist/seed.js +110 -0
- package/dist/seed.js.map +1 -0
- package/dist/types.d.ts +387 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/verify.d.ts +57 -0
- package/dist/verify.d.ts.map +1 -0
- package/dist/verify.js +147 -0
- package/dist/verify.js.map +1 -0
- package/package.json +47 -0
package/dist/scanner.js
ADDED
|
@@ -0,0 +1,595 @@
|
|
|
1
|
+
import { readdir, readFile } from 'node:fs/promises';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { join, dirname, basename, resolve as resolvePath } from 'node:path';
|
|
4
|
+
import { pathToFileURL } from 'node:url';
|
|
5
|
+
import { ANONYMOUS_SCHEMA_NAME } from '@fougere/schema';
|
|
6
|
+
import { cardinalityOf } from './operation.js';
|
|
7
|
+
import { parseAllHandlerMethods, parsePresenterMethods, parseConstructorParams } from './handler-parser.js';
|
|
8
|
+
import { hashFile, getCached, setCached, flushCache, setCacheRoot } from './scan-cache.js';
|
|
9
|
+
import { loadFrondConfig } from './frond-config.js';
|
|
10
|
+
import { emitKeyOf } from './emit.js';
|
|
11
|
+
import { getPresenterTarget, getPresenterFields, getPresenterViews } from './presenter.js';
|
|
12
|
+
import { getRepositoryTarget } from './repository.js';
|
|
13
|
+
import { ormKeyOf } from './orm.js';
|
|
14
|
+
import { getCollectorTarget } from './collector.js';
|
|
15
|
+
const defaultLoader = async (filePath) => await import(pathToFileURL(filePath).href);
|
|
16
|
+
let activeLoader = defaultLoader;
|
|
17
|
+
/** Override the module loader used by the scanner (e.g. for jiti/tsx support). */
|
|
18
|
+
export function setModuleLoader(loader) {
|
|
19
|
+
activeLoader = loader;
|
|
20
|
+
}
|
|
21
|
+
/** Used by config-loader to load fougere.config.ts via the same TS-aware loader. */
|
|
22
|
+
export function getModuleLoader() {
|
|
23
|
+
return activeLoader;
|
|
24
|
+
}
|
|
25
|
+
// FS
|
|
26
|
+
/**
|
|
27
|
+
* What this scan run could not do. Reset by {@link scanProject}, which owns a run.
|
|
28
|
+
*
|
|
29
|
+
* Module-scoped like the loader and the cache root above: the scanner already has
|
|
30
|
+
* a notion of "the current run", and threading a collector through twenty call
|
|
31
|
+
* sites would state the same thing more loudly and less clearly.
|
|
32
|
+
*/
|
|
33
|
+
let diagnostics = [];
|
|
34
|
+
function record(d) {
|
|
35
|
+
diagnostics.push(d);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* An absent convention directory is the ordinary case — a frond without
|
|
39
|
+
* `presenters/` is not a defect. Anything else (permissions, an I/O error, a path
|
|
40
|
+
* that is not a directory) means the scan did not look, and answering `[]` says
|
|
41
|
+
* it did. One `catch` used to conflate the two.
|
|
42
|
+
*/
|
|
43
|
+
async function readEntries(path) {
|
|
44
|
+
try {
|
|
45
|
+
return await readdir(path, { withFileTypes: true });
|
|
46
|
+
}
|
|
47
|
+
catch (cause) {
|
|
48
|
+
if (cause?.code === 'ENOENT')
|
|
49
|
+
return [];
|
|
50
|
+
record({
|
|
51
|
+
severity: 'blocking',
|
|
52
|
+
code: 'directory-unreadable',
|
|
53
|
+
filePath: path,
|
|
54
|
+
// The path is NOT repeated here: `filePath` carries it, and a renderer that
|
|
55
|
+
// prints both wraps an absolute path twice into an unreadable box.
|
|
56
|
+
message: 'Could not read this directory — anything it declares is missing from '
|
|
57
|
+
+ 'the app, and nothing downstream can tell that from an empty directory.',
|
|
58
|
+
cause,
|
|
59
|
+
});
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async function dirs(path) {
|
|
64
|
+
const entries = await readEntries(path);
|
|
65
|
+
return entries.filter((e) => e.isDirectory()).map((e) => e.name);
|
|
66
|
+
}
|
|
67
|
+
async function files(path) {
|
|
68
|
+
const entries = await readEntries(path);
|
|
69
|
+
return entries
|
|
70
|
+
.filter((e) => e.isFile() && (e.name.endsWith('.ts') || e.name.endsWith('.js')))
|
|
71
|
+
.map((e) => join(path, e.name));
|
|
72
|
+
}
|
|
73
|
+
// Module
|
|
74
|
+
async function loadModule(filePath) {
|
|
75
|
+
return await activeLoader(filePath);
|
|
76
|
+
}
|
|
77
|
+
async function loadDefault(filePath) {
|
|
78
|
+
const mod = await loadModule(filePath);
|
|
79
|
+
return mod.default;
|
|
80
|
+
}
|
|
81
|
+
async function loadClass(filePath) {
|
|
82
|
+
const ctor = await loadDefault(filePath);
|
|
83
|
+
if (typeof ctor !== 'function' || !ctor.prototype)
|
|
84
|
+
throw new Error(`${filePath}: default export is not a class`);
|
|
85
|
+
return ctor;
|
|
86
|
+
}
|
|
87
|
+
function isEntityClass(value) {
|
|
88
|
+
return typeof value === 'function' && 'getFields' in value;
|
|
89
|
+
}
|
|
90
|
+
// Workspace
|
|
91
|
+
/** Walk up from project root to find the monorepo root (pnpm-workspace.yaml + packages/). */
|
|
92
|
+
function findWorkspaceRoot(from) {
|
|
93
|
+
let dir = resolvePath(from);
|
|
94
|
+
while (dir !== dirname(dir)) {
|
|
95
|
+
if (existsSync(join(dir, 'pnpm-workspace.yaml')) && existsSync(join(dir, 'packages')))
|
|
96
|
+
return dir;
|
|
97
|
+
dir = dirname(dir);
|
|
98
|
+
}
|
|
99
|
+
return resolvePath(from); // fallback: use project root itself
|
|
100
|
+
}
|
|
101
|
+
// Convention
|
|
102
|
+
/** Directories whose classes register as providers — two spellings, one behaviour. */
|
|
103
|
+
const PROVIDER_DIRS = ['services', 'repositories'];
|
|
104
|
+
/**
|
|
105
|
+
* The frond vocabulary — every directory {@link scanFrond} reads. A frond directory says
|
|
106
|
+
* nothing else, which is why this list is what a reader needs to bound one: the Nuxt
|
|
107
|
+
* module watches these for the root frond (watching the root itself would match every
|
|
108
|
+
* write), and a flat app's tsconfig lists them instead of `["."]`, which would swallow
|
|
109
|
+
* `app/` and `nuxt.config.ts`.
|
|
110
|
+
*/
|
|
111
|
+
export const FROND_DIRS = [
|
|
112
|
+
'entities', 'handlers', 'presenters', 'collectors', 'seeds', ...PROVIDER_DIRS,
|
|
113
|
+
];
|
|
114
|
+
export { toRegistrationName } from './contract.js';
|
|
115
|
+
import { toRegistrationName } from './contract.js';
|
|
116
|
+
/**
|
|
117
|
+
* Strip the 'Handler' suffix → the name the handler answers to. 'PostHandler' → 'post'.
|
|
118
|
+
*
|
|
119
|
+
* Nothing here checks that an entity carries the result, and nothing should: a handler
|
|
120
|
+
* about no stored row is ordinary. The old name of this function — `toEntityName` — is
|
|
121
|
+
* what let "one façade per entity" be repeated until it read as a rule.
|
|
122
|
+
*/
|
|
123
|
+
function toAddress(className) {
|
|
124
|
+
const base = className.endsWith('Handler') ? className.slice(0, -7) : className;
|
|
125
|
+
return base[0].toLowerCase() + base.slice(1);
|
|
126
|
+
}
|
|
127
|
+
// Scan
|
|
128
|
+
/**
|
|
129
|
+
* The container key a constructor parameter asks for — derived from its TYPE, not from
|
|
130
|
+
* how the type was spelled.
|
|
131
|
+
*
|
|
132
|
+
* `deps` used to be `p.type.name`, so the key WAS the alias's name: `type ListOrm =
|
|
133
|
+
* EntityOrm<List>` resolved only because someone had spelled it exactly like the
|
|
134
|
+
* registration key (`ListOrm`), while `type ListRepo = EntityOrm<List>` — the same type —
|
|
135
|
+
* typechecked and died at boot on `'ListRepo' is not registered`. And `EntityOrm<List>`
|
|
136
|
+
* written out in full asked for `'EntityOrm'`, which nothing registers.
|
|
137
|
+
*
|
|
138
|
+
* `EntityOrm<X>` names X's storage, so that is the key. The generic argument was already
|
|
139
|
+
* parsed (`ParsedType.generics`) and thrown away. Anything else keeps its own name: a
|
|
140
|
+
* plain service IS designated by its class name.
|
|
141
|
+
*/
|
|
142
|
+
function depKeyOf(type) {
|
|
143
|
+
// `Facade<PostHandler>` — the second port, read exactly like the first. The type names
|
|
144
|
+
// what arrives: not the handler (its methods take positional arguments and it is never
|
|
145
|
+
// injected), but the door built in front of it. Same key whether that door is the local
|
|
146
|
+
// façade or a doublure, which is what makes the topology invisible from a signature.
|
|
147
|
+
const facadeOf = type.name === 'Facade' ? type.generics?.[0]?.name : undefined;
|
|
148
|
+
if (facadeOf)
|
|
149
|
+
return toRegistrationName(facadeOf);
|
|
150
|
+
// `Emit<PostPublished>` — the third port, and the only one that names a SUBJECT rather
|
|
151
|
+
// than an interlocutor. Read like the other two: the type names what arrives, here a
|
|
152
|
+
// function that announces. Who receives it is not in the signature and never will be.
|
|
153
|
+
const factOf = type.name === 'Emit' ? type.generics?.[0]?.name : undefined;
|
|
154
|
+
if (factOf)
|
|
155
|
+
return emitKeyOf(factOf);
|
|
156
|
+
const target = type.name === 'EntityOrm' ? type.generics?.[0]?.name : undefined;
|
|
157
|
+
if (!target)
|
|
158
|
+
return type.name;
|
|
159
|
+
return ormKeyOf(target);
|
|
160
|
+
}
|
|
161
|
+
/** Cached parseConstructorParams — skips TS loading when cache is warm. */
|
|
162
|
+
async function cachedCtorParams(filePath) {
|
|
163
|
+
const hash = hashFile(filePath);
|
|
164
|
+
const key = filePath + ':ctor';
|
|
165
|
+
const cached = getCached(key, hash);
|
|
166
|
+
if (cached)
|
|
167
|
+
return cached;
|
|
168
|
+
const params = await parseConstructorParams(filePath);
|
|
169
|
+
setCached(key, hash, params);
|
|
170
|
+
return params;
|
|
171
|
+
}
|
|
172
|
+
/** Cached parsePresenterMethods — skips TS loading when cache is warm. */
|
|
173
|
+
async function cachedPresenterMethods(filePath) {
|
|
174
|
+
const hash = hashFile(filePath);
|
|
175
|
+
const key = filePath + ':presenter';
|
|
176
|
+
const cached = getCached(key, hash);
|
|
177
|
+
if (cached)
|
|
178
|
+
return cached;
|
|
179
|
+
const methods = await parsePresenterMethods(filePath);
|
|
180
|
+
setCached(key, hash, methods);
|
|
181
|
+
return methods;
|
|
182
|
+
}
|
|
183
|
+
async function toProvider(filePath) {
|
|
184
|
+
const ctor = await loadClass(filePath);
|
|
185
|
+
const params = await cachedCtorParams(filePath);
|
|
186
|
+
const deps = params.map((p) => depKeyOf(p.type));
|
|
187
|
+
// A repository inherits its constructor from `Repository(Entity)`, so the file
|
|
188
|
+
// declares none and the scan reads no parameter. The mixin knows which entity it
|
|
189
|
+
// was built for and says so at runtime — same escape as `Crud.__ops`, and the same
|
|
190
|
+
// reason: what a prefab fabricates, only the prefab can describe.
|
|
191
|
+
const target = getRepositoryTarget(ctor);
|
|
192
|
+
if (target && deps.length === 0) {
|
|
193
|
+
deps.push(`${toRegistrationName(target.name).replace(/^./, (c) => c.toUpperCase())}Orm`);
|
|
194
|
+
}
|
|
195
|
+
return { name: toRegistrationName(ctor.name), ctor, deps, filePath };
|
|
196
|
+
}
|
|
197
|
+
async function toEntityEntry(filePath) {
|
|
198
|
+
const exported = await loadDefault(filePath);
|
|
199
|
+
if (!isEntityClass(exported))
|
|
200
|
+
return null;
|
|
201
|
+
const runtimeName = exported.name;
|
|
202
|
+
// A derivation returned directly (`export default User.extend(...)`) carries the
|
|
203
|
+
// factory's own name, which the schema package stamps and exports. The file is then
|
|
204
|
+
// the declaration site and therefore the only name the author actually supplied;
|
|
205
|
+
// named classes keep winning.
|
|
206
|
+
const declaredName = runtimeName && runtimeName !== ANONYMOUS_SCHEMA_NAME
|
|
207
|
+
? runtimeName
|
|
208
|
+
: basename(filePath).replace(/\.[^.]+$/, '');
|
|
209
|
+
const name = toRegistrationName(declaredName);
|
|
210
|
+
return { name, entityClass: exported, filePath };
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Resolve a ParsedType to a runtime schema if available in module exports.
|
|
214
|
+
* Handles arrays, generics (uses base name), and simple references.
|
|
215
|
+
*/
|
|
216
|
+
function resolveSchema(type, moduleExports) {
|
|
217
|
+
// For arrays, resolve the element type
|
|
218
|
+
const name = type.array ? type.name : type.name;
|
|
219
|
+
// For generics like Pagination<Post>, also check inner types
|
|
220
|
+
if (type.generics) {
|
|
221
|
+
for (const g of type.generics) {
|
|
222
|
+
const resolved = moduleExports[g.name];
|
|
223
|
+
if (resolved && typeof resolved === 'function' && 'getFields' in resolved) {
|
|
224
|
+
// `Partial<X>` in a signature IS the patch declaration (Crud.update) —
|
|
225
|
+
// project it onto the schema view instead of dropping the wrapper, so
|
|
226
|
+
// the facade validates in patch mode (absent field → untouched).
|
|
227
|
+
if (type.name === 'Partial' && 'partial' in resolved && typeof resolved.partial === 'function') {
|
|
228
|
+
return resolved.partial();
|
|
229
|
+
}
|
|
230
|
+
return resolved;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
const resolved = moduleExports[name];
|
|
235
|
+
if (resolved && typeof resolved === 'function' && 'getFields' in resolved) {
|
|
236
|
+
return resolved;
|
|
237
|
+
}
|
|
238
|
+
return undefined;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Parse ALL method signatures for unified binding.
|
|
242
|
+
*
|
|
243
|
+
* Resolves schemas for all params (not just the first) and stores
|
|
244
|
+
* full signatures for the binding algorithm.
|
|
245
|
+
*/
|
|
246
|
+
async function inferOperations(filePath, moduleExports, projectRoot) {
|
|
247
|
+
const map = new Map();
|
|
248
|
+
let parsed;
|
|
249
|
+
try {
|
|
250
|
+
const hash = hashFile(filePath);
|
|
251
|
+
const cacheKey = filePath + ':all' + (projectRoot ? ':inherited' : '');
|
|
252
|
+
const cached = getCached(cacheKey, hash);
|
|
253
|
+
if (cached) {
|
|
254
|
+
parsed = cached;
|
|
255
|
+
}
|
|
256
|
+
else {
|
|
257
|
+
parsed = await parseAllHandlerMethods(filePath, projectRoot);
|
|
258
|
+
setCached(cacheKey, hash, parsed);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
catch (cause) {
|
|
262
|
+
// The handler still gets a façade — its methods exist at runtime — but with no
|
|
263
|
+
// contract: no binding plan, no input schema, no doc sentence. It used to
|
|
264
|
+
// return the empty map, so the app served a stranger's idea of the handler and
|
|
265
|
+
// said nothing. The operations are gone; the sentence saying so is not.
|
|
266
|
+
record({
|
|
267
|
+
severity: 'blocking',
|
|
268
|
+
code: 'handler-parse-failed',
|
|
269
|
+
filePath,
|
|
270
|
+
message: 'Could not parse this handler — its operations carry no contract, so the '
|
|
271
|
+
+ 'façade serves them unbound. Not the same as a handler with no operation.',
|
|
272
|
+
cause,
|
|
273
|
+
});
|
|
274
|
+
return map;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* A base class the parse could not open — an installed package, typically, whose
|
|
278
|
+
* source is not in the workspace. Its operations are missing from this façade, and
|
|
279
|
+
* the scan cannot tell whether there were any.
|
|
280
|
+
*
|
|
281
|
+
* A warning, not a refusal: an installed base class with no operation is perfectly
|
|
282
|
+
* ordinary, and the boot has no way to decide between the two. So it names the
|
|
283
|
+
* clause and stops there. Stating the contract in `frond.config.ts` is the answer
|
|
284
|
+
* — the third producer, which creates an op neither other producer found — and it
|
|
285
|
+
* silences this by making the op exist.
|
|
286
|
+
*/
|
|
287
|
+
for (const base of parsed.unresolvedHeritage) {
|
|
288
|
+
record({
|
|
289
|
+
severity: 'warning',
|
|
290
|
+
code: 'heritage-unresolved',
|
|
291
|
+
filePath,
|
|
292
|
+
message: `Could not resolve 'extends ${base}' — any operation it declares is absent `
|
|
293
|
+
+ `from this façade, and the scan cannot tell that from a base class with none. `
|
|
294
|
+
+ `State the contract in frond.config.ts to put it back.`,
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
for (const method of parsed.methods) {
|
|
298
|
+
// The contract is what carries the description; `signature` is the raw material it
|
|
299
|
+
// was read from. Leaving it only on the signature meant every consumer had to know
|
|
300
|
+
// to look one level down, and only the façade did.
|
|
301
|
+
const meta = {
|
|
302
|
+
signature: method,
|
|
303
|
+
...(method.description && { description: method.description }),
|
|
304
|
+
};
|
|
305
|
+
// Resolve schemas for all params
|
|
306
|
+
for (const param of method.params) {
|
|
307
|
+
const schema = resolveSchema(param.type, moduleExports);
|
|
308
|
+
if (schema && !meta.input)
|
|
309
|
+
meta.input = schema;
|
|
310
|
+
}
|
|
311
|
+
if (method.returnType) {
|
|
312
|
+
meta.output = resolveSchema(method.returnType, moduleExports);
|
|
313
|
+
// `output` is the shape of one row; this says how many rows come back.
|
|
314
|
+
meta.cardinality = cardinalityOf(method.returnType);
|
|
315
|
+
}
|
|
316
|
+
map.set(method.name, meta);
|
|
317
|
+
}
|
|
318
|
+
return map;
|
|
319
|
+
}
|
|
320
|
+
async function toHandlerEntry(filePath, entityByClassName, projectRoot, surface) {
|
|
321
|
+
const mod = await loadModule(filePath);
|
|
322
|
+
const ctor = mod.default;
|
|
323
|
+
if (typeof ctor !== 'function' || !ctor.prototype)
|
|
324
|
+
throw new Error(`${filePath}: default export is not a class`);
|
|
325
|
+
// Augment module exports with known entity classes so resolveSchema
|
|
326
|
+
// can find them when T is substituted (e.g. T → Post after parsing Crud(Post))
|
|
327
|
+
const augmented = { ...mod };
|
|
328
|
+
for (const [className, entityClass] of entityByClassName) {
|
|
329
|
+
if (!(className in augmented))
|
|
330
|
+
augmented[className] = entityClass;
|
|
331
|
+
}
|
|
332
|
+
const address = toAddress(ctor.name);
|
|
333
|
+
const operations = await inferOperations(filePath, augmented, projectRoot);
|
|
334
|
+
const ctorParams = await cachedCtorParams(filePath);
|
|
335
|
+
const deps = ctorParams.map((p) => depKeyOf(p.type));
|
|
336
|
+
// Read output override from Crud(Entity, Output) — static __output property
|
|
337
|
+
const __entity = ctor.__entity;
|
|
338
|
+
const __output = ctor.__output;
|
|
339
|
+
const outputOverride = __output && __entity && __output !== __entity ? __output : undefined;
|
|
340
|
+
return {
|
|
341
|
+
name: toRegistrationName(ctor.name),
|
|
342
|
+
address,
|
|
343
|
+
ctor: ctor,
|
|
344
|
+
operations,
|
|
345
|
+
deps,
|
|
346
|
+
filePath,
|
|
347
|
+
outputOverride,
|
|
348
|
+
surface,
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
/** Strip '.seed' suffix → entity name. 'Author.seed.ts' → 'author'. */
|
|
352
|
+
function toSeedEntityName(fileName) {
|
|
353
|
+
const base = fileName.replace(/\.seed\.(ts|js)$/, '').replace(/\.(ts|js)$/, '');
|
|
354
|
+
return base[0].toLowerCase() + base.slice(1);
|
|
355
|
+
}
|
|
356
|
+
async function toSeedEntry(filePath) {
|
|
357
|
+
const data = await loadDefault(filePath);
|
|
358
|
+
if (Array.isArray(data) || typeof data === 'function') {
|
|
359
|
+
const fileName = filePath.split('/').pop();
|
|
360
|
+
return { entityName: toSeedEntityName(fileName), data: data, filePath };
|
|
361
|
+
}
|
|
362
|
+
return null;
|
|
363
|
+
}
|
|
364
|
+
async function toPresenterEntry(filePath) {
|
|
365
|
+
const ctor = await loadClass(filePath);
|
|
366
|
+
const target = getPresenterTarget(ctor);
|
|
367
|
+
if (!target)
|
|
368
|
+
return null;
|
|
369
|
+
const entityName = toRegistrationName(target.name);
|
|
370
|
+
const fields = getPresenterFields(ctor);
|
|
371
|
+
const presenterParams = await cachedCtorParams(filePath);
|
|
372
|
+
const deps = presenterParams.map((p) => depKeyOf(p.type));
|
|
373
|
+
// Parse method return types from source
|
|
374
|
+
let fieldMeta = [];
|
|
375
|
+
try {
|
|
376
|
+
const parsed = await cachedPresenterMethods(filePath);
|
|
377
|
+
fieldMeta = parsed.map((m) => ({
|
|
378
|
+
name: m.name,
|
|
379
|
+
returnType: m.returnType?.name,
|
|
380
|
+
// One array level IS the page — the method answers one value per row. What is left
|
|
381
|
+
// over is the field's own arity: `string[]` a scalar per row, `string[][]` a list.
|
|
382
|
+
list: (m.returnType?.arrayDepth ?? 0) > 1,
|
|
383
|
+
nullable: m.returnType?.nullable,
|
|
384
|
+
// Everything after the rows is bound like a handler's argument.
|
|
385
|
+
params: m.params.slice(1),
|
|
386
|
+
}));
|
|
387
|
+
}
|
|
388
|
+
catch { /* parse failure — fall back to untyped */ }
|
|
389
|
+
// Declared at runtime on the class, so it survives a scan that resolved nothing.
|
|
390
|
+
return { entityName, ctor, fields, fieldMeta, views: getPresenterViews(ctor), deps, filePath };
|
|
391
|
+
}
|
|
392
|
+
async function toCollectorEntry(filePath) {
|
|
393
|
+
const ctor = await loadClass(filePath);
|
|
394
|
+
const target = getCollectorTarget(ctor);
|
|
395
|
+
if (!target)
|
|
396
|
+
return null;
|
|
397
|
+
const entityName = toRegistrationName(target.name);
|
|
398
|
+
const collectorParams = await cachedCtorParams(filePath);
|
|
399
|
+
const deps = collectorParams.map((p) => depKeyOf(p.type));
|
|
400
|
+
return { entityName, ctor, deps, filePath };
|
|
401
|
+
}
|
|
402
|
+
async function scanFrond(frondPath, name, source, projectRoot) {
|
|
403
|
+
const providers = [];
|
|
404
|
+
const entities = [];
|
|
405
|
+
const handlers = [];
|
|
406
|
+
const presenters = [];
|
|
407
|
+
const collectors = [];
|
|
408
|
+
const seeds = [];
|
|
409
|
+
// Scan services/ and repositories/ — both land in the same provider list.
|
|
410
|
+
for (const dir of PROVIDER_DIRS) {
|
|
411
|
+
const paths = await files(join(frondPath, dir));
|
|
412
|
+
providers.push(...await Promise.all(paths.map((f) => toProvider(f))));
|
|
413
|
+
}
|
|
414
|
+
// Scan entities/
|
|
415
|
+
const entityPaths = await files(join(frondPath, 'entities'));
|
|
416
|
+
const entityEntries = await Promise.all(entityPaths.map((f) => toEntityEntry(f)));
|
|
417
|
+
entities.push(...entityEntries.filter((e) => e !== null));
|
|
418
|
+
// Build entity class map for schema resolution in handlers (T → entity class)
|
|
419
|
+
const entityByClassName = new Map(entities.map((e) => [e.entityClass.name, e.entityClass]));
|
|
420
|
+
// Scan handlers/ (root = default surface, subdirectories = named surfaces)
|
|
421
|
+
const handlerPaths = await files(join(frondPath, 'handlers'));
|
|
422
|
+
handlers.push(...await Promise.all(handlerPaths.map((f) => toHandlerEntry(f, entityByClassName, projectRoot))));
|
|
423
|
+
const surfaceDirs = await dirs(join(frondPath, 'handlers'));
|
|
424
|
+
for (const surfaceName of surfaceDirs) {
|
|
425
|
+
const surfacePaths = await files(join(frondPath, 'handlers', surfaceName));
|
|
426
|
+
handlers.push(...await Promise.all(surfacePaths.map((f) => toHandlerEntry(f, entityByClassName, projectRoot, surfaceName))));
|
|
427
|
+
}
|
|
428
|
+
// Scan presenters/
|
|
429
|
+
const presenterPaths = await files(join(frondPath, 'presenters'));
|
|
430
|
+
const presenterEntries = await Promise.all(presenterPaths.map((f) => toPresenterEntry(f)));
|
|
431
|
+
presenters.push(...presenterEntries.filter((p) => p !== null));
|
|
432
|
+
// Scan collectors/
|
|
433
|
+
const collectorPaths = await files(join(frondPath, 'collectors'));
|
|
434
|
+
const collectorEntries = await Promise.all(collectorPaths.map((f) => toCollectorEntry(f)));
|
|
435
|
+
collectors.push(...collectorEntries.filter((c) => c !== null));
|
|
436
|
+
// Scan seeds/
|
|
437
|
+
const seedPaths = await files(join(frondPath, 'seeds'));
|
|
438
|
+
const seedEntries = await Promise.all(seedPaths.map((f) => toSeedEntry(f)));
|
|
439
|
+
seeds.push(...seedEntries.filter((s) => s !== null));
|
|
440
|
+
// Mark exposed entries: frond.config.ts takes precedence, then @expose decorator
|
|
441
|
+
const frondConfig = await loadFrondConfig(frondPath);
|
|
442
|
+
if (frondConfig?.expose) {
|
|
443
|
+
const exposeSet = new Set(frondConfig.expose);
|
|
444
|
+
for (const e of entities) {
|
|
445
|
+
e.exposed = exposeSet.has(e.entityClass.name);
|
|
446
|
+
}
|
|
447
|
+
for (const h of handlers) {
|
|
448
|
+
h.exposed = exposeSet.has(h.ctor.name);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
else {
|
|
452
|
+
// Fallback: check @expose decorator, default to true (expose everything unless explicitly hidden)
|
|
453
|
+
for (const e of entities) {
|
|
454
|
+
e.exposed = e.entityClass.__exposed !== false;
|
|
455
|
+
}
|
|
456
|
+
for (const h of handlers) {
|
|
457
|
+
h.exposed = h.ctor.__exposed !== false;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
// Flatten per-op config overrides: the only thing that needs flattening is the handler
|
|
461
|
+
// CLASS, which becomes its name (that is the DI key). Everything else — the surface keys
|
|
462
|
+
// AND the contract keys (`input`, `binding`) — travels verbatim, so a slot added to
|
|
463
|
+
// OperationOverride reaches its reader without a stop here. Enumerating keys by hand is
|
|
464
|
+
// what used to silently drop whatever was added last (the same invariant `cloneField`
|
|
465
|
+
// holds one layer down).
|
|
466
|
+
const operationsOverrides = frondConfig?.operations
|
|
467
|
+
? Object.fromEntries(Object.entries(frondConfig.operations).map(([opName, { handler, ...rest }]) => [
|
|
468
|
+
opName,
|
|
469
|
+
{ ...rest, handlerName: handler?.name },
|
|
470
|
+
]))
|
|
471
|
+
: undefined;
|
|
472
|
+
return {
|
|
473
|
+
name,
|
|
474
|
+
source,
|
|
475
|
+
providers,
|
|
476
|
+
entities,
|
|
477
|
+
handlers,
|
|
478
|
+
presenters,
|
|
479
|
+
collectors,
|
|
480
|
+
seeds,
|
|
481
|
+
surfaces: frondConfig?.surfaces,
|
|
482
|
+
operationsOverrides,
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* The frond's name — the directory, unless its `package.json` renames it. One rule for a
|
|
487
|
+
* frond under `fronds/` and for the root frond alike, so the root needs no second spelling.
|
|
488
|
+
*
|
|
489
|
+
* Carrying the convention is what makes a frond; the key never marked anything and
|
|
490
|
+
* nothing read it. It earns its keep as the one thing the directory cannot say: that
|
|
491
|
+
* `fronds/blog-v2/` serves the frond still called `blog` — so a rename on disk does not
|
|
492
|
+
* rename the entity keys, the `@frond/*` import or a `remotes:` entry.
|
|
493
|
+
*/
|
|
494
|
+
async function frondNameOf(frondPath, dirName) {
|
|
495
|
+
try {
|
|
496
|
+
const pkg = JSON.parse(await readFile(join(frondPath, 'package.json'), 'utf8'));
|
|
497
|
+
const declared = pkg.fougere?.frond;
|
|
498
|
+
return typeof declared === 'string' && declared.length > 0 ? declared : dirName;
|
|
499
|
+
}
|
|
500
|
+
catch {
|
|
501
|
+
return dirName;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* A frond is a directory carrying the convention, and the project root is one such
|
|
506
|
+
* directory — so a single-domain app writes `entities/` next to `app/` and never names
|
|
507
|
+
* anything. `fronds/` is not the definition, it is where the OTHERS live: the root frond
|
|
508
|
+
* stays put when a second domain appears, which is what makes flattening free instead of
|
|
509
|
+
* a deferred move.
|
|
510
|
+
*
|
|
511
|
+
* `entities/` is the test, not "any convention directory". `services/` and `repositories/`
|
|
512
|
+
* are ordinary top-level names in projects that never heard of Fougere, and a domain
|
|
513
|
+
* without a single entity is not a domain.
|
|
514
|
+
*/
|
|
515
|
+
async function rootFrondOf(root, workspaceRoot) {
|
|
516
|
+
if ((await files(join(root, 'entities'))).length === 0)
|
|
517
|
+
return null;
|
|
518
|
+
const name = await frondNameOf(root, basename(resolvePath(root)));
|
|
519
|
+
return scanFrond(root, name, { path: root, package: `@frond/${name}` }, workspaceRoot);
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* `@frond/<name>` → the directory it names, for every frond of a project.
|
|
523
|
+
*
|
|
524
|
+
* The framework states this convention — `FrondSource.package` has always spelled it, and
|
|
525
|
+
* `fougere sync` writes it into a consumer's tsconfig — and until now its own reader could
|
|
526
|
+
* not resolve it. The Nuxt module registered a Vite alias, so a `.vue` page could import
|
|
527
|
+
* `@frond/blog/entities/Post`, while the SCAN loaded sources through a bare jiti: a frond
|
|
528
|
+
* naming its neighbour got `Cannot find module '@frond/user/entities/User.js'`. So the one
|
|
529
|
+
* form that survives a split was the one form that did not run.
|
|
530
|
+
*
|
|
531
|
+
* Hand it to the module loader — `createJiti(url, { alias: await frondAliases(root) })` —
|
|
532
|
+
* and the named form resolves everywhere the framework reads. A directory listing and a
|
|
533
|
+
* `package.json` read, no parsing: it is deliberately callable BEFORE the loader exists,
|
|
534
|
+
* which is what makes the chicken-and-egg go away.
|
|
535
|
+
*/
|
|
536
|
+
export async function frondAliases(root) {
|
|
537
|
+
const frondsDir = join(root, 'fronds');
|
|
538
|
+
const aliases = {};
|
|
539
|
+
// The root itself is a frond when it carries `entities/` — same rule as the scan.
|
|
540
|
+
if ((await files(join(root, 'entities'))).length > 0) {
|
|
541
|
+
aliases[`@frond/${await frondNameOf(root, basename(resolvePath(root)))}`] = resolvePath(root);
|
|
542
|
+
}
|
|
543
|
+
for (const dir of await dirs(frondsDir)) {
|
|
544
|
+
const path = join(frondsDir, dir);
|
|
545
|
+
aliases[`@frond/${await frondNameOf(path, dir)}`] = resolvePath(path);
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* A SYNCED frond answers to the same name.
|
|
549
|
+
*
|
|
550
|
+
* `fougere sync` writes `.fougere/remotes/<name>/` and registers it in `remotes.json`,
|
|
551
|
+
* which the Nuxt module already reads to alias `@frond/<name>`. Doing it here too is
|
|
552
|
+
* what makes the convention mean ONE thing: a consumer writes `@frond/blog/entities/Post`
|
|
553
|
+
* and never learns whether that frond is on this disk or was fetched from a card.
|
|
554
|
+
*
|
|
555
|
+
* A local frond wins a name collision — its source is the truth, a synced copy is a
|
|
556
|
+
* mirror of somebody else's.
|
|
557
|
+
*/
|
|
558
|
+
try {
|
|
559
|
+
const registry = JSON.parse(await readFile(join(root, '.fougere', 'remotes.json'), 'utf8'));
|
|
560
|
+
for (const [name, entry] of Object.entries(registry)) {
|
|
561
|
+
if (typeof entry?.path !== 'string' || aliases[`@frond/${name}`])
|
|
562
|
+
continue;
|
|
563
|
+
aliases[`@frond/${name}`] = resolvePath(entry.path);
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
catch {
|
|
567
|
+
// No registry, or an unreadable one: nothing was synced here. Not this function's
|
|
568
|
+
// complaint — `sync` owns that file and reports on it.
|
|
569
|
+
}
|
|
570
|
+
return aliases;
|
|
571
|
+
}
|
|
572
|
+
export async function scanProject(root, filter) {
|
|
573
|
+
setCacheRoot(root);
|
|
574
|
+
// A run owns its findings: two scans in one process (a test suite, a watcher)
|
|
575
|
+
// must not inherit each other's.
|
|
576
|
+
diagnostics = [];
|
|
577
|
+
const frondsDir = join(root, 'fronds');
|
|
578
|
+
const dirNames = await dirs(frondsDir);
|
|
579
|
+
// Resolve workspace root (parent of packages/) for package import resolution
|
|
580
|
+
// For monorepo: root is the project dir (e.g. demos/nuxt-blog), workspace root is the repo root
|
|
581
|
+
const workspaceRoot = findWorkspaceRoot(root);
|
|
582
|
+
const [rootFrond, under] = await Promise.all([
|
|
583
|
+
rootFrondOf(root, workspaceRoot),
|
|
584
|
+
Promise.all(dirNames.map(async (dir) => {
|
|
585
|
+
const name = await frondNameOf(join(frondsDir, dir), dir);
|
|
586
|
+
return scanFrond(join(frondsDir, dir), name, { path: join(frondsDir, dir), package: `@frond/${name}` }, workspaceRoot);
|
|
587
|
+
})),
|
|
588
|
+
]);
|
|
589
|
+
// The app's own domain first, then the ones it took in.
|
|
590
|
+
const all = rootFrond ? [rootFrond, ...under] : under;
|
|
591
|
+
const fronds = filter ? all.filter((f) => filter.includes(f.name)) : all;
|
|
592
|
+
flushCache();
|
|
593
|
+
return { fronds, diagnostics };
|
|
594
|
+
}
|
|
595
|
+
//# sourceMappingURL=scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scanner.js","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"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"}
|
package/dist/seed.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { App, FrondDescriptor, SeedEntry } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Seeds in dependency order — a `ref()` target is planted before its referrer.
|
|
4
|
+
*
|
|
5
|
+
* The order is a fact about the entity graph, not about the surface running the seeds,
|
|
6
|
+
* so it is stated once here. The Nuxt module read it off a pairwise comparator (which
|
|
7
|
+
* `Array.sort` cannot make transitive: `a` before `b` and `b` before `c` never implies
|
|
8
|
+
* `a` before `c`), and `boot()` had no order at all — the same fact, told twice and
|
|
9
|
+
* wrong both times. A list seeded before its owner failed on the foreign key, and the
|
|
10
|
+
* driver's error named neither the entity nor the file.
|
|
11
|
+
*
|
|
12
|
+
* Kahn, like `orderTables` in `@fougere/schema-sql` — the same shape one level up: there
|
|
13
|
+
* the nodes are tables and the edges FK columns, here they are seeds and the edges the
|
|
14
|
+
* `one` relations of the entities they target. A cycle cannot be satisfied by ordering,
|
|
15
|
+
* so its remaining seeds keep their scan order and land last: the driver refuses what is
|
|
16
|
+
* genuinely impossible, and everything acyclic around it still gets planted.
|
|
17
|
+
*/
|
|
18
|
+
export declare function orderSeeds(fronds: FrondDescriptor[]): SeedEntry[];
|
|
19
|
+
/**
|
|
20
|
+
* Plant a set of seeds, in the order given. Reports what it did, one line per entity.
|
|
21
|
+
*
|
|
22
|
+
* The one seeding loop. `boot()` had one and the Nuxt module generated a second into its
|
|
23
|
+
* Nitro plugin, which had drifted: no ORM fallback, so an entity with no façade was
|
|
24
|
+
* skipped there and planted here. Two answers to "how does a row get in at boot" is one
|
|
25
|
+
* too many, and the second was the one running in the browser.
|
|
26
|
+
*/
|
|
27
|
+
export declare function runSeeds(app: App, seeds: SeedEntry[], report?: (message: string) => void): Promise<void>;
|
|
28
|
+
//# sourceMappingURL=seed.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seed.d.ts","sourceRoot":"","sources":["../src/seed.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,eAAe,EAAE,SAAS,EAAe,MAAM,YAAY,CAAC;AAE/E;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,SAAS,EAAE,CAyCjE;AAQD;;;;;;;GAOG;AACH,wBAAsB,QAAQ,CAC5B,GAAG,EAAE,GAAG,EACR,KAAK,EAAE,SAAS,EAAE,EAClB,MAAM,GAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAe,GAC3C,OAAO,CAAC,IAAI,CAAC,CA+Bf"}
|