@fougere/core 0.8.3-alpha.0 → 0.9.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.
Files changed (279) hide show
  1. package/dist/boot/AppLifecycle.d.ts +8 -0
  2. package/dist/boot/AppLifecycle.d.ts.map +1 -1
  3. package/dist/boot/AppLifecycle.js.map +1 -1
  4. package/dist/boot/Emissions.d.ts +26 -0
  5. package/dist/boot/Emissions.d.ts.map +1 -1
  6. package/dist/boot/Emissions.js +144 -9
  7. package/dist/boot/Emissions.js.map +1 -1
  8. package/dist/boot/auth.d.ts +1 -1
  9. package/dist/boot/auth.d.ts.map +1 -1
  10. package/dist/boot/bootstrap.d.ts.map +1 -1
  11. package/dist/boot/bootstrap.js +401 -598
  12. package/dist/boot/bootstrap.js.map +1 -1
  13. package/dist/boot/card.js +1 -1
  14. package/dist/boot/card.js.map +1 -1
  15. package/dist/boot/hosted.d.ts +1 -1
  16. package/dist/boot/hosted.d.ts.map +1 -1
  17. package/dist/boot/hosted.js +1 -0
  18. package/dist/boot/hosted.js.map +1 -1
  19. package/dist/boot/install.d.ts +42 -0
  20. package/dist/boot/install.d.ts.map +1 -0
  21. package/dist/boot/install.js +327 -0
  22. package/dist/boot/install.js.map +1 -0
  23. package/dist/boot/ownership.d.ts +1 -1
  24. package/dist/boot/ownership.d.ts.map +1 -1
  25. package/dist/boot/ownership.js +14 -1
  26. package/dist/boot/ownership.js.map +1 -1
  27. package/dist/boot/ports.d.ts +12 -3
  28. package/dist/boot/ports.d.ts.map +1 -1
  29. package/dist/boot/ports.js +51 -21
  30. package/dist/boot/ports.js.map +1 -1
  31. package/dist/boot/remote.d.ts.map +1 -1
  32. package/dist/boot/remote.js +3 -3
  33. package/dist/boot/remote.js.map +1 -1
  34. package/dist/boot/seed.d.ts +7 -1
  35. package/dist/boot/seed.d.ts.map +1 -1
  36. package/dist/boot/seed.js +7 -2
  37. package/dist/boot/seed.js.map +1 -1
  38. package/dist/boot/statement-drift.d.ts +1 -1
  39. package/dist/boot/statement-drift.d.ts.map +1 -1
  40. package/dist/boot/together.d.ts +1 -1
  41. package/dist/boot/together.d.ts.map +1 -1
  42. package/dist/boot/together.js +1 -1
  43. package/dist/boot/together.js.map +1 -1
  44. package/dist/boot/types.d.ts +18 -3
  45. package/dist/boot/types.d.ts.map +1 -1
  46. package/dist/builtin/LogLine.d.ts +38 -0
  47. package/dist/builtin/LogLine.d.ts.map +1 -0
  48. package/dist/builtin/LogLine.js +37 -0
  49. package/dist/builtin/LogLine.js.map +1 -0
  50. package/dist/builtin/logger.d.ts +57 -0
  51. package/dist/builtin/logger.d.ts.map +1 -1
  52. package/dist/builtin/logger.js +72 -17
  53. package/dist/builtin/logger.js.map +1 -1
  54. package/dist/config-loader.d.ts +3 -2
  55. package/dist/config-loader.d.ts.map +1 -1
  56. package/dist/config-loader.js.map +1 -1
  57. package/dist/contract.d.ts +3 -7
  58. package/dist/contract.d.ts.map +1 -1
  59. package/dist/contract.js +3 -4
  60. package/dist/contract.js.map +1 -1
  61. package/dist/{scan/conventions.d.ts → conventions.d.ts} +6 -0
  62. package/dist/conventions.d.ts.map +1 -0
  63. package/dist/{scan/conventions.js → conventions.js} +3 -2
  64. package/dist/conventions.js.map +1 -0
  65. package/dist/crypto/encoding.d.ts +0 -1
  66. package/dist/crypto/encoding.d.ts.map +1 -1
  67. package/dist/crypto/encoding.js +0 -7
  68. package/dist/crypto/encoding.js.map +1 -1
  69. package/dist/declare.d.ts +11 -1
  70. package/dist/declare.d.ts.map +1 -1
  71. package/dist/declare.js +10 -1
  72. package/dist/declare.js.map +1 -1
  73. package/dist/descriptor/frond.d.ts +34 -0
  74. package/dist/descriptor/frond.d.ts.map +1 -1
  75. package/dist/descriptor/index.d.ts +15 -0
  76. package/dist/descriptor/index.d.ts.map +1 -0
  77. package/dist/descriptor/index.js +14 -0
  78. package/dist/descriptor/index.js.map +1 -0
  79. package/dist/descriptor/surface.d.ts +8 -0
  80. package/dist/descriptor/surface.d.ts.map +1 -0
  81. package/dist/descriptor/surface.js +16 -0
  82. package/dist/descriptor/surface.js.map +1 -0
  83. package/dist/dispatch/ArgumentResolver.d.ts.map +1 -1
  84. package/dist/dispatch/ArgumentResolver.js +6 -2
  85. package/dist/dispatch/ArgumentResolver.js.map +1 -1
  86. package/dist/dispatch/HandlerFacade.d.ts +2 -0
  87. package/dist/dispatch/HandlerFacade.d.ts.map +1 -1
  88. package/dist/dispatch/HandlerFacade.js +9 -4
  89. package/dist/dispatch/HandlerFacade.js.map +1 -1
  90. package/dist/dispatch/StorageGuard.d.ts.map +1 -1
  91. package/dist/dispatch/StorageGuard.js +9 -23
  92. package/dist/dispatch/StorageGuard.js.map +1 -1
  93. package/dist/dispatch/presenterArguments.d.ts +7 -1
  94. package/dist/dispatch/presenterArguments.d.ts.map +1 -1
  95. package/dist/dispatch/presenterArguments.js +15 -4
  96. package/dist/dispatch/presenterArguments.js.map +1 -1
  97. package/dist/dispatch/validateInput.d.ts.map +1 -1
  98. package/dist/dispatch/validateInput.js +2 -2
  99. package/dist/dispatch/validateInput.js.map +1 -1
  100. package/dist/effective-operation.d.ts +1 -1
  101. package/dist/effective-operation.d.ts.map +1 -1
  102. package/dist/effective-operation.js +13 -19
  103. package/dist/effective-operation.js.map +1 -1
  104. package/dist/frond-config.d.ts +24 -0
  105. package/dist/frond-config.d.ts.map +1 -1
  106. package/dist/frond-config.js.map +1 -1
  107. package/dist/index.d.ts +35 -40
  108. package/dist/index.d.ts.map +1 -1
  109. package/dist/index.js +17 -14
  110. package/dist/index.js.map +1 -1
  111. package/dist/node.d.ts +2 -12
  112. package/dist/node.d.ts.map +1 -1
  113. package/dist/node.js +2 -12
  114. package/dist/node.js.map +1 -1
  115. package/dist/prefab/crud.d.ts +1 -1
  116. package/dist/prefab/crud.d.ts.map +1 -1
  117. package/dist/prefab/mirror.d.ts +10 -11
  118. package/dist/prefab/mirror.d.ts.map +1 -1
  119. package/dist/prefab/mirror.js +1 -27
  120. package/dist/prefab/mirror.js.map +1 -1
  121. package/dist/prefab/repository.d.ts +1 -1
  122. package/dist/prefab/repository.d.ts.map +1 -1
  123. package/dist/{scan/result.d.ts → scan.d.ts} +2 -2
  124. package/dist/scan.d.ts.map +1 -0
  125. package/dist/scan.js +2 -0
  126. package/dist/scan.js.map +1 -0
  127. package/dist/source.d.ts +1 -1
  128. package/dist/source.d.ts.map +1 -1
  129. package/dist/storage/criterion.d.ts.map +1 -0
  130. package/dist/{criterion.js → storage/criterion.js} +2 -2
  131. package/dist/storage/criterion.js.map +1 -0
  132. package/dist/{storage.d.ts → storage/port.d.ts} +6 -3
  133. package/dist/storage/port.d.ts.map +1 -0
  134. package/dist/{storage.js → storage/port.js} +13 -6
  135. package/dist/storage/port.js.map +1 -0
  136. package/dist/{store.d.ts → storage/store.d.ts} +1 -1
  137. package/dist/storage/store.d.ts.map +1 -0
  138. package/dist/{store.js → storage/store.js} +33 -17
  139. package/dist/storage/store.js.map +1 -0
  140. package/dist/verify.js +1 -1
  141. package/dist/verify.js.map +1 -1
  142. package/dist/wire/Invocation.d.ts +1 -3
  143. package/dist/wire/Invocation.d.ts.map +1 -1
  144. package/dist/wire/Invocation.js +1 -5
  145. package/dist/wire/Invocation.js.map +1 -1
  146. package/dist/wire/binding.d.ts +9 -0
  147. package/dist/wire/binding.d.ts.map +1 -1
  148. package/dist/wire/binding.js +11 -6
  149. package/dist/wire/binding.js.map +1 -1
  150. package/dist/wire/emit.d.ts +45 -0
  151. package/dist/wire/emit.d.ts.map +1 -0
  152. package/dist/wire/emit.js +44 -0
  153. package/dist/wire/emit.js.map +1 -0
  154. package/dist/wire/errors.js +2 -2
  155. package/dist/wire/errors.js.map +1 -1
  156. package/dist/wire/loggerMiddleware.d.ts.map +1 -1
  157. package/dist/wire/loggerMiddleware.js +6 -0
  158. package/dist/wire/loggerMiddleware.js.map +1 -1
  159. package/package.json +10 -4
  160. package/src/boot/AppLifecycle.ts +8 -0
  161. package/src/boot/Emissions.ts +177 -9
  162. package/src/boot/auth.ts +1 -1
  163. package/src/boot/bootstrap.ts +456 -672
  164. package/src/boot/card.ts +1 -1
  165. package/src/boot/hosted.ts +4 -2
  166. package/src/boot/install.ts +421 -0
  167. package/src/boot/ownership.ts +17 -2
  168. package/src/boot/ports.ts +71 -27
  169. package/src/boot/remote.ts +3 -3
  170. package/src/boot/seed.ts +18 -3
  171. package/src/boot/statement-drift.ts +1 -1
  172. package/src/boot/together.ts +1 -1
  173. package/src/boot/types.ts +18 -3
  174. package/src/builtin/LogLine.ts +38 -0
  175. package/src/builtin/logger.ts +109 -17
  176. package/src/config-loader.ts +3 -2
  177. package/src/contract.ts +5 -9
  178. package/src/{scan/conventions.ts → conventions.ts} +9 -2
  179. package/src/crypto/encoding.ts +0 -7
  180. package/src/declare.ts +20 -2
  181. package/src/descriptor/frond.ts +31 -0
  182. package/src/descriptor/index.ts +15 -0
  183. package/src/descriptor/surface.ts +23 -0
  184. package/src/dispatch/ArgumentResolver.ts +6 -2
  185. package/src/dispatch/HandlerFacade.ts +11 -4
  186. package/src/dispatch/StorageGuard.ts +8 -21
  187. package/src/dispatch/presenterArguments.ts +21 -9
  188. package/src/dispatch/validateInput.ts +2 -2
  189. package/src/effective-operation.ts +16 -21
  190. package/src/frond-config.ts +20 -0
  191. package/src/index.ts +44 -57
  192. package/src/node.ts +2 -16
  193. package/src/prefab/crud.ts +1 -1
  194. package/src/prefab/mirror.ts +12 -38
  195. package/src/prefab/repository.ts +1 -1
  196. package/src/{scan/result.ts → scan.ts} +1 -1
  197. package/src/source.ts +1 -1
  198. package/src/{criterion.ts → storage/criterion.ts} +2 -2
  199. package/src/{storage.ts → storage/port.ts} +20 -5
  200. package/src/{store.ts → storage/store.ts} +35 -16
  201. package/src/verify.ts +1 -1
  202. package/src/wire/Invocation.ts +2 -7
  203. package/src/wire/binding.ts +17 -6
  204. package/src/wire/call.ts +1 -1
  205. package/src/wire/emit.ts +84 -0
  206. package/src/wire/errors.ts +2 -2
  207. package/src/wire/loggerMiddleware.ts +6 -0
  208. package/dist/boot/boot.d.ts +0 -45
  209. package/dist/boot/boot.d.ts.map +0 -1
  210. package/dist/boot/boot.js +0 -63
  211. package/dist/boot/boot.js.map +0 -1
  212. package/dist/criterion.d.ts.map +0 -1
  213. package/dist/criterion.js.map +0 -1
  214. package/dist/declarations.d.ts +0 -34
  215. package/dist/declarations.d.ts.map +0 -1
  216. package/dist/declarations.js +0 -75
  217. package/dist/declarations.js.map +0 -1
  218. package/dist/emit.d.ts +0 -13
  219. package/dist/emit.d.ts.map +0 -1
  220. package/dist/emit.js +0 -21
  221. package/dist/emit.js.map +0 -1
  222. package/dist/imports.d.ts +0 -16
  223. package/dist/imports.d.ts.map +0 -1
  224. package/dist/imports.js +0 -78
  225. package/dist/imports.js.map +0 -1
  226. package/dist/placement.d.ts +0 -25
  227. package/dist/placement.d.ts.map +0 -1
  228. package/dist/placement.js +0 -69
  229. package/dist/placement.js.map +0 -1
  230. package/dist/scan/adapters.d.ts +0 -3
  231. package/dist/scan/adapters.d.ts.map +0 -1
  232. package/dist/scan/adapters.js +0 -25
  233. package/dist/scan/adapters.js.map +0 -1
  234. package/dist/scan/bundling.d.ts +0 -3
  235. package/dist/scan/bundling.d.ts.map +0 -1
  236. package/dist/scan/bundling.js +0 -15
  237. package/dist/scan/bundling.js.map +0 -1
  238. package/dist/scan/contract.d.ts +0 -27
  239. package/dist/scan/contract.d.ts.map +0 -1
  240. package/dist/scan/contract.js +0 -46
  241. package/dist/scan/contract.js.map +0 -1
  242. package/dist/scan/conventions.d.ts.map +0 -1
  243. package/dist/scan/conventions.js.map +0 -1
  244. package/dist/scan/emit.d.ts +0 -10
  245. package/dist/scan/emit.d.ts.map +0 -1
  246. package/dist/scan/emit.js +0 -144
  247. package/dist/scan/emit.js.map +0 -1
  248. package/dist/scan/handler-parser.d.ts +0 -26
  249. package/dist/scan/handler-parser.d.ts.map +0 -1
  250. package/dist/scan/handler-parser.js +0 -607
  251. package/dist/scan/handler-parser.js.map +0 -1
  252. package/dist/scan/result.d.ts.map +0 -1
  253. package/dist/scan/result.js +0 -2
  254. package/dist/scan/result.js.map +0 -1
  255. package/dist/scan/scanner.d.ts +0 -12
  256. package/dist/scan/scanner.d.ts.map +0 -1
  257. package/dist/scan/scanner.js +0 -573
  258. package/dist/scan/scanner.js.map +0 -1
  259. package/dist/scan/statement.d.ts +0 -4
  260. package/dist/scan/statement.d.ts.map +0 -1
  261. package/dist/scan/statement.js +0 -135
  262. package/dist/scan/statement.js.map +0 -1
  263. package/dist/storage.d.ts.map +0 -1
  264. package/dist/storage.js.map +0 -1
  265. package/dist/store.d.ts.map +0 -1
  266. package/dist/store.js.map +0 -1
  267. package/src/boot/boot.ts +0 -110
  268. package/src/declarations.ts +0 -110
  269. package/src/emit.ts +0 -32
  270. package/src/imports.ts +0 -94
  271. package/src/placement.ts +0 -86
  272. package/src/scan/adapters.ts +0 -32
  273. package/src/scan/bundling.ts +0 -14
  274. package/src/scan/contract.ts +0 -80
  275. package/src/scan/emit.ts +0 -160
  276. package/src/scan/handler-parser.ts +0 -695
  277. package/src/scan/scanner.ts +0 -698
  278. package/src/scan/statement.ts +0 -159
  279. /package/dist/{criterion.d.ts → storage/criterion.d.ts} +0 -0
@@ -1,14 +0,0 @@
1
- /** What a Fougere boot loads at RUNTIME, so a bundler must leave it alone. */
2
- export const RUNTIME_PACKAGES: readonly string[] = [
3
- '@fougere/app',
4
- '@fougere/core',
5
- '@fougere/schema',
6
- '@fougere/defaults',
7
- '@fougere/transport-http',
8
- '@fougere/adapter-sql',
9
- '@fougere/adapter-graphql',
10
- '@fougere/auth-better',
11
- 'better-sqlite3',
12
- 'jiti',
13
- 'typescript',
14
- ];
@@ -1,80 +0,0 @@
1
- /** An operation contract, written down — the half two emitters say the same way. */
2
- import { ANONYMOUS_SCHEMA_NAME, Card, type SchemaView } from '@fougere/schema';
3
-
4
- import type { OperationContract } from '../wire/operation.js';
5
-
6
- /** A value that ends up as an import in the module being written. */
7
- export type Live = object;
8
-
9
- /**
10
- * What the writer needs of an emitter's imports, and nothing more.
11
- *
12
- * The two emitters index theirs differently — one by value against a relative path, one
13
- * by file against the package specifier a project already uses — and neither is wrong for
14
- * the module it writes. What they agree on is this: a value already imported has an
15
- * alias, a class can be imported by name, and an entity can be found by its class name.
16
- */
17
- export interface Aliases {
18
- aliasOf(value: Live): string | undefined;
19
- named(value: Live, filePath: string, name: string): string;
20
- /** The entity class this name belongs to — what a `Partial<X>` names as its source. */
21
- classNamed(name: string): Live | undefined;
22
- }
23
-
24
- export const lit = (value: unknown): string => JSON.stringify(value ?? null);
25
-
26
- /** What a schema slot becomes in the generated module. */
27
- export function schemaRef(
28
- schema: SchemaView | undefined,
29
- declaredIn: string,
30
- imports: Aliases,
31
- ): string | undefined {
32
- if (!schema) return undefined;
33
- const known = imports.aliasOf(schema as Live);
34
- if (known) return known;
35
-
36
- const name = (schema as { name?: string }).name;
37
- if (name && name !== ANONYMOUS_SCHEMA_NAME) return imports.named(schema as Live, declaredIn, name);
38
-
39
- const card = Card.fromSchema(schema);
40
- const source = card.origin?.from ?? card.descriptor.title;
41
- const from = source ? imports.classNamed(source) : undefined;
42
- if (from) return `${imports.aliasOf(from)}.partial()`;
43
-
44
- throw new Error(
45
- `A scan cannot be written down: an anonymous schema in ${declaredIn} names no source. `
46
- + 'Only `Partial<X>` is derivable here, and it says which X it came from.',
47
- );
48
- }
49
-
50
- /** One entry of an operations Map, as its module spells it. */
51
- export function contractOf(
52
- op: string,
53
- contract: OperationContract,
54
- declaredIn: string,
55
- imports: Aliases,
56
- ): string {
57
- const parts: string[] = [];
58
- const input = schemaRef(contract.input, declaredIn, imports);
59
- const output = schemaRef(contract.output, declaredIn, imports);
60
- if (input) parts.push(`input: ${input}`);
61
- if (output) parts.push(`output: ${output}`);
62
- if (contract.binding !== undefined) parts.push(`binding: ${lit(contract.binding)}`);
63
- if (contract.description !== undefined) parts.push(`description: ${lit(contract.description)}`);
64
- if (contract.cardinality !== undefined) parts.push(`cardinality: ${lit(contract.cardinality)}`);
65
- if (contract.signature !== undefined) parts.push(`signature: ${lit(contract.signature)}`);
66
-
67
- return `[${lit(op)}, { ${parts.join(', ')} }]`;
68
- }
69
-
70
- /** The operations of one handler, as the Map its reader builds. */
71
- export function operationsOf(
72
- operations: ReadonlyMap<string, OperationContract>,
73
- declaredIn: string,
74
- imports: Aliases,
75
- indent: string,
76
- ): string {
77
- const ops = [...operations].map((entry) => contractOf(entry[0], entry[1], declaredIn, imports));
78
-
79
- return `new Map([\n${indent} ${ops.join(`,\n${indent} `)}\n${indent}])`;
80
- }
package/src/scan/emit.ts DELETED
@@ -1,160 +0,0 @@
1
- /** The scan, written down as a module — what `createApp` is handed where there is no disk. */
2
- import { dirname, relative } from 'node:path';
3
- import { nameOf } from '../descriptor/frond.js';
4
- import type { FrondDescriptor, EntityEntry, HandlerEntry, PresenterEntry, CollectorEntry, ProviderEntry, SeedEntry } from '../descriptor/frond.js';
5
- import type { ScanResult } from './result.js';
6
- import { type Aliases, type Live, lit, operationsOf, schemaRef } from './contract.js';
7
-
8
- export interface EmitOptions {
9
- /** Where the generated module will sit. Imports are written relative to it. */
10
- outFile: string;
11
- /** How `@fougere/core` is reached from there. Default: the package name. */
12
- core?: string;
13
- }
14
-
15
- /** Is a TypeScript compiler going to read this module? Its name is the only thing that says. */
16
- const isTypeScript = (outFile: string): boolean => /\.tsx?$/.test(outFile);
17
-
18
- /** A source file becomes a specifier its reader can follow — and the two readers differ. */
19
- function specifierOf(filePath: string, outFile: string): string {
20
- const path = relative(dirname(outFile), filePath);
21
- const rel = isTypeScript(outFile) ? path.replace(/\.tsx?$/, '.js') : path;
22
- return rel.startsWith('.') ? rel : `./${rel}`;
23
- }
24
-
25
- class Imports implements Aliases {
26
- private readonly byValue = new Map<Live, string>();
27
- private readonly lines: string[] = [];
28
- /** Entity classes by their class name — what a `Partial<X>` names as its source. */
29
- readonly byClassName = new Map<string, Live>();
30
-
31
- constructor(private readonly outFile: string) {}
32
-
33
- /** Register `value` as the default export of `filePath`, and answer its alias. */
34
- default(value: Live, filePath: string): string {
35
- const known = this.byValue.get(value);
36
- if (known) return known;
37
- const alias = `_${this.lines.length}`;
38
- this.lines.push(`import ${alias} from '${specifierOf(filePath, this.outFile)}';`);
39
- this.byValue.set(value, alias);
40
- return alias;
41
- }
42
-
43
- /** Register `value` as a NAMED export of `filePath` — its class name is the export. */
44
- named(value: Live, filePath: string, name: string): string {
45
- const known = this.byValue.get(value);
46
- if (known) return known;
47
- const alias = `_${this.lines.length}`;
48
- this.lines.push(`import { ${name} as ${alias} } from '${specifierOf(filePath, this.outFile)}';`);
49
- this.byValue.set(value, alias);
50
- return alias;
51
- }
52
-
53
- has(value: Live): boolean { return this.byValue.has(value); }
54
- aliasOf(value: Live): string | undefined { return this.byValue.get(value); }
55
- classNamed(name: string): Live | undefined { return this.byClassName.get(name); }
56
- render(): string { return this.lines.join('\n'); }
57
- }
58
-
59
- function entityOf(e: EntityEntry, imports: Imports): string {
60
- return `{ name: ${lit(e.name)}, entityClass: ${imports.aliasOf(e.entityClass as Live)}, `
61
- + `filePath: ${lit(e.filePath)}, exposed: ${lit(e.exposed)} }`;
62
- }
63
-
64
- function handlerOf(h: HandlerEntry, imports: Imports): string {
65
- const ops = operationsOf(h.operations, h.filePath, imports, ' ');
66
- const override = schemaRef(h.outputOverride, h.filePath, imports);
67
- return `{ name: ${lit(h.name)}, address: ${lit(h.address)}, ctor: ${imports.aliasOf(h.ctor as Live)}, `
68
- + `deps: ${lit(h.deps)}, filePath: ${lit(h.filePath)}, exposed: ${lit(h.exposed)}, `
69
- + (h.surface ? `surface: ${lit(h.surface)}, ` : '')
70
- + (override ? `outputOverride: ${override}, ` : '')
71
- + `operations: ${ops} }`;
72
- }
73
-
74
- function presenterOf(p: PresenterEntry, imports: Imports): string {
75
- // `views` is not written: it is read back off the constructor (`__views`), so emitting
76
- // it would be a second copy of a statement the imported class already carries.
77
- return `{ entityName: ${lit(p.entityName)}, ctor: ${imports.aliasOf(p.ctor as Live)}, `
78
- + `fields: ${lit(p.fields)}, fieldMeta: ${lit(p.fieldMeta)}, deps: ${lit(p.deps)}, `
79
- + `filePath: ${lit(p.filePath)} }`;
80
- }
81
-
82
- function collectorOf(c: CollectorEntry, imports: Imports): string {
83
- return `{ typeName: ${lit(c.typeName)}, ctor: ${imports.aliasOf(c.ctor as Live)}, `
84
- + `deps: ${lit(c.deps)}, filePath: ${lit(c.filePath)} }`;
85
- }
86
-
87
- function providerOf(p: ProviderEntry, imports: Imports): string {
88
- return `{ name: ${lit(nameOf(p))}, ctor: ${imports.aliasOf(p.ctor as Live)}, `
89
- + `deps: ${lit(p.deps)}, filePath: ${lit(p.filePath)} }`;
90
- }
91
-
92
- function seedOf(s: SeedEntry, imports: Imports): string {
93
- const data = typeof s.data === 'function' ? imports.aliasOf(s.data as Live) : lit(s.data);
94
- return `{ entityName: ${lit(s.entityName)}, data: ${data}, filePath: ${lit(s.filePath)} }`;
95
- }
96
-
97
- function frondOf(f: FrondDescriptor, imports: Imports): string {
98
- const list = (label: string, items: string[]) =>
99
- ` ${label}: [${items.length ? `\n ${items.join(',\n ')},\n ` : ''}],`;
100
- return [
101
- ' {',
102
- ` name: ${lit(f.name)},`,
103
- ` source: ${lit(f.source)},`,
104
- list('providers', f.providers.map((p) => providerOf(p, imports))),
105
- list('entities', f.entities.map((e) => entityOf(e, imports))),
106
- list('handlers', f.handlers.map((h) => handlerOf(h, imports))),
107
- list('presenters', f.presenters.map((p) => presenterOf(p, imports))),
108
- list('collectors', f.collectors.map((c) => collectorOf(c, imports))),
109
- list('seeds', f.seeds.map((s) => seedOf(s, imports))),
110
- f.surfaces ? ` surfaces: ${lit(f.surfaces)},` : '',
111
- f.reads ? ` reads: ${lit(f.reads)},` : '',
112
- ' }',
113
- ].filter(Boolean).join('\n');
114
- }
115
-
116
- /** Write a scan down. */
117
- export function emitScan(result: ScanResult, options: EmitOptions): string {
118
- const imports = new Imports(options.outFile);
119
- const core = options.core ?? '@fougere/core';
120
-
121
- // Every class the descriptor names by a file comes first: a schema slot holding one of
122
- // them then finds it in the table instead of being imported a second time.
123
- for (const f of result.fronds) {
124
- for (const e of f.entities) {
125
- imports.default(e.entityClass as Live, e.filePath);
126
- const name = (e.entityClass as { name?: string }).name;
127
- if (name) imports.byClassName.set(name, e.entityClass as Live);
128
- }
129
- for (const p of f.providers) imports.default(p.ctor as Live, p.filePath);
130
- for (const h of f.handlers) imports.default(h.ctor as Live, h.filePath);
131
- for (const p of f.presenters) imports.default(p.ctor as Live, p.filePath);
132
- for (const c of f.collectors) imports.default(c.ctor as Live, c.filePath);
133
- for (const s of f.seeds) if (typeof s.data === 'function') imports.default(s.data as Live, s.filePath);
134
- }
135
-
136
- const fronds = result.fronds.map((f) => frondOf(f, imports)).join(',\n');
137
- // `cause` is dropped: it is an Error, and the build that produced this already reported
138
- // it. What a boot logs is the message, and that travels.
139
- const diagnostics = result.diagnostics.map(({ cause: _cause, ...rest }) => lit(rest));
140
-
141
- // The annotation is a convenience for a file a human's tsc will read; it is never what
142
- // makes the value correct. A bundler parses a `.mjs` as JavaScript and `import type`
143
- // stops it dead — measured, Nitro's rollup refused the Nuxt template at that line.
144
- const typed = isTypeScript(options.outFile);
145
-
146
- return `// Generated by \`fougere build\` — the scan, written down. Do not edit.
147
- //
148
- // \`createApp\` reads this instead of a disk. Everything here was decided by the scan that
149
- // produced it; nothing is resolved a second time.
150
- import { Fronds } from '${core}';
151
- ${typed ? `import type { ScanResult } from '${core}';\n` : ''}${imports.render()}
152
-
153
- export const scan${typed ? ': ScanResult' : ''} = {
154
- fronds: Fronds.hosting([
155
- ${fronds}
156
- ]),
157
- diagnostics: [${diagnostics.join(', ')}],
158
- };
159
- `;
160
- }