@fougere/compiler 0.9.3-alpha.0 → 0.11.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/dist/boot.d.ts.map +1 -1
- package/dist/boot.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/scan/Aliases.d.ts +16 -0
- package/dist/scan/Aliases.d.ts.map +1 -0
- package/dist/scan/Aliases.js +2 -0
- package/dist/scan/Aliases.js.map +1 -0
- package/dist/scan/FacadeOptions.d.ts +5 -0
- package/dist/scan/FacadeOptions.d.ts.map +1 -0
- package/dist/scan/FacadeOptions.js +2 -0
- package/dist/scan/FacadeOptions.js.map +1 -0
- package/dist/scan/{contract.d.ts → Live.d.ts} +2 -16
- package/dist/scan/Live.d.ts.map +1 -0
- package/dist/scan/{contract.js → Live.js} +5 -1
- package/dist/scan/Live.js.map +1 -0
- package/dist/scan/Served.d.ts +47 -0
- package/dist/scan/Served.d.ts.map +1 -0
- package/dist/scan/Served.js +111 -0
- package/dist/scan/Served.js.map +1 -0
- package/dist/scan/emit.d.ts.map +1 -1
- package/dist/scan/emit.js +1 -1
- package/dist/scan/emit.js.map +1 -1
- package/dist/scan/handler-parser.d.ts +8 -0
- package/dist/scan/handler-parser.d.ts.map +1 -1
- package/dist/scan/handler-parser.js +24 -6
- package/dist/scan/handler-parser.js.map +1 -1
- package/dist/scan/names.d.ts +7 -0
- package/dist/scan/names.d.ts.map +1 -0
- package/dist/scan/names.js +93 -0
- package/dist/scan/names.js.map +1 -0
- package/dist/scan/refusals.d.ts +33 -0
- package/dist/scan/refusals.d.ts.map +1 -0
- package/dist/scan/refusals.js +118 -0
- package/dist/scan/refusals.js.map +1 -0
- package/dist/scan/scanner.d.ts.map +1 -1
- package/dist/scan/scanner.js +38 -3
- package/dist/scan/scanner.js.map +1 -1
- package/dist/scan/statement.d.ts.map +1 -1
- package/dist/scan/statement.js +1 -1
- package/dist/scan/statement.js.map +1 -1
- package/package.json +6 -6
- package/src/boot.ts +1 -1
- package/src/index.ts +3 -0
- package/src/scan/Aliases.ts +16 -0
- package/src/scan/FacadeOptions.ts +4 -0
- package/src/scan/{contract.ts → Live.ts} +4 -16
- package/src/scan/Served.ts +135 -0
- package/src/scan/emit.ts +2 -1
- package/src/scan/handler-parser.ts +34 -7
- package/src/scan/names.ts +101 -0
- package/src/scan/refusals.ts +167 -0
- package/src/scan/scanner.ts +49 -7
- package/src/scan/statement.ts +2 -1
- package/dist/scan/contract.d.ts.map +0 -1
- package/dist/scan/contract.js.map +0 -1
package/src/scan/scanner.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { DEFAULT_CONVENTIONS, frondDirsOf, frondPackage, providerDirsOf, resolveConventions, togetherKeyOf, type Conventions, type ConventionsInput, type
|
|
2
|
-
import { Fronds, awaitKeyOf, cardinalityOf, computeBindingPlan, emitKeyOf, getPresenterFields, outputOf, ownedBy, repositoryKeyOf, storageKeyOf, targetOf, type CollectorEntry, type EntityEntry, type FrondDescriptor, type HandlerEntry, type MiddlewareEntry, type OperationContract, type OperationsMap, type PresenterEntry, type ProviderEntry, type SeedEntry, type TypeRef, viewsOf } from '@fougere/core/descriptor';
|
|
1
|
+
import { DEFAULT_CONVENTIONS, frondDirsOf, frondPackage, providerDirsOf, resolveConventions, togetherKeyOf, type Conventions, type ConventionsInput, type Diagnostic, type ScanResult } from '@fougere/core';
|
|
2
|
+
import { Fronds, awaitKeyOf, cardinalityOf, computeBindingPlan, emitKeyOf, getPresenterFields, outputOf, ownedBy, repositoryKeyOf, storageKeyOf, targetOf, type CollectorEntry, type EntityEntry, type FrondDescriptor, type HandlerEntry, type MiddlewareEntry, type OperationContract, type OperationsMap, type PresenterEntry, type ProviderEntry, type SeedEntry, type TypeRef, viewsOf, type ExtensionEntry } from '@fougere/core/descriptor';
|
|
3
3
|
import { getModuleLoader, loadFrondConfig } from '@fougere/core/node';
|
|
4
|
-
import type { FrondConfig } from '@fougere/core';
|
|
4
|
+
import type { FrondConfig, ErrorCode } from '@fougere/core';
|
|
5
5
|
import { readdir, readFile } from 'node:fs/promises';
|
|
6
6
|
import { existsSync, type Dirent } from 'node:fs';
|
|
7
7
|
import { join, dirname, basename, resolve as resolvePath } from 'node:path';
|
|
@@ -10,6 +10,7 @@ import { ANONYMOUS_SCHEMA_NAME, type SchemaView } from '@fougere/schema';
|
|
|
10
10
|
|
|
11
11
|
import {
|
|
12
12
|
parseAllHandlerMethods,
|
|
13
|
+
parseRefusals,
|
|
13
14
|
parsePresenterMethods,
|
|
14
15
|
parseConstructorParams,
|
|
15
16
|
resetTypePrograms,
|
|
@@ -21,9 +22,9 @@ import { lowerFirst } from '@fougere/schema';
|
|
|
21
22
|
// FS
|
|
22
23
|
|
|
23
24
|
/** What this scan run could not do. */
|
|
24
|
-
let diagnostics:
|
|
25
|
+
let diagnostics: Diagnostic[] = [];
|
|
25
26
|
|
|
26
|
-
function record(d:
|
|
27
|
+
function record(d: Diagnostic): void {
|
|
27
28
|
diagnostics.push(d);
|
|
28
29
|
}
|
|
29
30
|
|
|
@@ -125,7 +126,7 @@ function toAddress(className: string): string {
|
|
|
125
126
|
function depKeyOf(type: TypeRef): string {
|
|
126
127
|
// `Facade<PostHandler>` — the second port, read exactly like the first. The type names
|
|
127
128
|
// what arrives: not the handler (its methods take positional arguments and it is never
|
|
128
|
-
// injected), but the
|
|
129
|
+
// injected), but the facade built in front of it. Same key whether that facade is the local
|
|
129
130
|
// façade or a doublure, which is what makes the topology invisible from a signature.
|
|
130
131
|
const facadeOf = type.name === 'Facade' ? type.generics?.[0]?.name : undefined;
|
|
131
132
|
if (facadeOf) return lowerFirst(facadeOf);
|
|
@@ -211,6 +212,28 @@ async function toProvider(filePath: string): Promise<ProviderEntry> {
|
|
|
211
212
|
return { name, ctor, deps, filePath };
|
|
212
213
|
}
|
|
213
214
|
|
|
215
|
+
/**
|
|
216
|
+
* An extension is recognized by its FORM: a module stating `up` or `down`.
|
|
217
|
+
*
|
|
218
|
+
* Not a class, unlike every other convention directory — nothing resolves it from a container
|
|
219
|
+
* and nothing asks for it by type. It is handed to the ascent as a value, which is what
|
|
220
|
+
* `CreateAppOptions.extensions` already takes, so a file here and a line there declare the
|
|
221
|
+
* same thing.
|
|
222
|
+
*/
|
|
223
|
+
async function toExtensionEntry(filePath: string): Promise<ExtensionEntry | null> {
|
|
224
|
+
const exported = await loadDefault(filePath);
|
|
225
|
+
if (typeof exported !== 'object' || exported === null) return null;
|
|
226
|
+
|
|
227
|
+
const stated = exported as { name?: unknown; up?: unknown; down?: unknown };
|
|
228
|
+
if (typeof stated.up !== 'function' && typeof stated.down !== 'function') return null;
|
|
229
|
+
|
|
230
|
+
return {
|
|
231
|
+
name: typeof stated.name === 'string' ? stated.name : basename(filePath).replace(/\.[^.]+$/, ''),
|
|
232
|
+
extension: exported as ExtensionEntry['extension'],
|
|
233
|
+
filePath,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
|
|
214
237
|
async function toEntityEntry(filePath: string): Promise<EntityEntry | null> {
|
|
215
238
|
const exported = await loadDefault(filePath);
|
|
216
239
|
if (!isEntityClass(exported)) return null;
|
|
@@ -285,6 +308,16 @@ async function inferOperations(
|
|
|
285
308
|
return map;
|
|
286
309
|
}
|
|
287
310
|
|
|
311
|
+
// What every op of this handler can refuse, walked from each `throw` up to whoever reaches
|
|
312
|
+
// it. Read from the SAME program the signatures came from, so a dependency resolves through
|
|
313
|
+
// the checker rather than by name — and a guard living in a helper beside the handler is
|
|
314
|
+
// found, where reading the method's own body would have missed it.
|
|
315
|
+
const refusals = await parseRefusals(
|
|
316
|
+
filePath,
|
|
317
|
+
(name) => name.startsWith(`${handlerName}.`),
|
|
318
|
+
projectRoot,
|
|
319
|
+
).catch(() => new Map<string, ErrorCode[]>());
|
|
320
|
+
|
|
288
321
|
/**
|
|
289
322
|
* A base class the parse could not open — an installed package, typically, whose source is not
|
|
290
323
|
* in the workspace.
|
|
@@ -304,9 +337,11 @@ async function inferOperations(
|
|
|
304
337
|
// The contract is what carries the description; `signature` is the raw material it
|
|
305
338
|
// was read from. Leaving it only on the signature meant every consumer had to know
|
|
306
339
|
// to look one level down, and only the façade did.
|
|
340
|
+
const refused = refusals.get(`${handlerName}.${method.name}`);
|
|
307
341
|
const meta: OperationContract = {
|
|
308
342
|
signature: method,
|
|
309
343
|
...(method.description && { description: method.description }),
|
|
344
|
+
...(refused?.length ? { errors: refused } : {}),
|
|
310
345
|
};
|
|
311
346
|
|
|
312
347
|
// A convention may omit a declaration only when it has one answer. Only values the
|
|
@@ -387,7 +422,7 @@ async function toHandlerEntry(
|
|
|
387
422
|
|
|
388
423
|
// Read output override from Crud(Entity, Output) — static __output property
|
|
389
424
|
// A handler-wide view, when it is not simply the entity — the two are compared by
|
|
390
|
-
// identity, which is why both slots are read through the same
|
|
425
|
+
// identity, which is why both slots are read through the same facade.
|
|
391
426
|
const subject = targetOf(ctor);
|
|
392
427
|
const declared = outputOf(ctor);
|
|
393
428
|
const outputOverride = declared && subject && declared !== subject
|
|
@@ -525,9 +560,15 @@ async function scanFrond(frondPath: string, name: string, source: FrondDescripto
|
|
|
525
560
|
return entries.filter((entry): entry is T => entry !== null);
|
|
526
561
|
};
|
|
527
562
|
|
|
563
|
+
// vocabulary/ FIRST, and for its effect: a file here calls `Generators.register` or its
|
|
564
|
+
// neighbours at module level, and an entity below may write the name it just added. Nothing
|
|
565
|
+
// is kept — the registry holds what the module put in it.
|
|
566
|
+
for (const filePath of await files(join(frondPath, conventions.dirs.vocabulary))) await loadModule(filePath);
|
|
567
|
+
|
|
528
568
|
// services/ and repositories/ — two spellings, one provider list.
|
|
529
569
|
const providers = (await Promise.all(providerDirsOf(conventions).map((dir) => collect(dir, toProvider)))).flat();
|
|
530
570
|
const entities = await collect(entitiesDir, toEntityEntry);
|
|
571
|
+
const extensions = await collect(conventions.dirs.extensions, toExtensionEntry);
|
|
531
572
|
const collectors = await collect(collectorsDir, toCollectorEntry);
|
|
532
573
|
const collectorTypeNames = new Set(collectors.map((collector) => collector.typeName));
|
|
533
574
|
const frondConfig = await loadFrondConfig(frondPath);
|
|
@@ -599,6 +640,7 @@ async function scanFrond(frondPath: string, name: string, source: FrondDescripto
|
|
|
599
640
|
collectors,
|
|
600
641
|
seeds,
|
|
601
642
|
middlewares,
|
|
643
|
+
...(extensions.length > 0 ? { extensions } : {}),
|
|
602
644
|
...(frondConfig?.pipes ? { pipes: frondConfig.pipes } : {}),
|
|
603
645
|
surfaces: frondConfig?.surfaces,
|
|
604
646
|
reads: frondConfig?.reads,
|
package/src/scan/statement.ts
CHANGED
|
@@ -3,7 +3,8 @@ import { type ScanResult } from '@fougere/core';
|
|
|
3
3
|
import { nameOf, type FrondDescriptor } from '@fougere/core/descriptor';
|
|
4
4
|
import { relative } from 'node:path';
|
|
5
5
|
|
|
6
|
-
import { type Aliases
|
|
6
|
+
import { type Aliases } from './Aliases.js';
|
|
7
|
+
import { operationsOf, type Live } from './Live.js';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* A file becomes the specifier the PROJECT already uses for it: `@fronds/blog/…`, the import scope
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../src/scan/contract.ts"],"names":[],"mappings":"AAAA,oFAAoF;AACpF,OAAO,EAAE,KAAK,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAA+B,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE/E,qEAAqE;AACrE,MAAM,MAAM,IAAI,GAAG,MAAM,CAAC;AAE1B;;;;;;;GAOG;AACH,MAAM,WAAW,OAAO;IACtB,OAAO,CAAC,KAAK,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,CAAC;IACzC,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3D,uFAAuF;IACvF,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CAC5C;AAED,eAAO,MAAM,GAAG,UAAW,OAAO,KAAG,MAAuC,CAAC;AAE7E,0DAA0D;AAC1D,wBAAgB,SAAS,CACvB,MAAM,EAAE,UAAU,GAAG,SAAS,EAC9B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,OAAO,GACf,MAAM,GAAG,SAAS,CAiBpB;AAED,+DAA+D;AAC/D,wBAAgB,UAAU,CACxB,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,iBAAiB,EAC3B,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,OAAO,GACf,MAAM,CAYR;AAED,mEAAmE;AACnE,wBAAgB,YAAY,CAC1B,UAAU,EAAE,WAAW,CAAC,MAAM,EAAE,iBAAiB,CAAC,EAClD,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,MAAM,GACb,MAAM,CAIR"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../../src/scan/contract.ts"],"names":[],"mappings":"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"}
|