@metaobjectsdev/cli 1.0.13 → 1.1.1-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -22
- package/dist/bin/meta.js +14 -2
- package/dist/bin/meta.js.map +1 -1
- package/dist/src/commands/docs.d.ts +1 -14
- package/dist/src/commands/docs.d.ts.map +1 -1
- package/dist/src/commands/docs.js +11 -835
- package/dist/src/commands/docs.js.map +1 -1
- package/dist/src/commands/eject.d.ts +24 -1
- package/dist/src/commands/eject.d.ts.map +1 -1
- package/dist/src/commands/eject.js +240 -69
- package/dist/src/commands/eject.js.map +1 -1
- package/dist/src/commands/gen.d.ts +7 -0
- package/dist/src/commands/gen.d.ts.map +1 -1
- package/dist/src/commands/gen.js +91 -21
- package/dist/src/commands/gen.js.map +1 -1
- package/dist/src/commands/generator.js +2 -2
- package/dist/src/commands/generator.js.map +1 -1
- package/dist/src/commands/init.d.ts +7 -0
- package/dist/src/commands/init.d.ts.map +1 -1
- package/dist/src/commands/init.js +71 -36
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/migrate.d.ts +1 -1
- package/dist/src/commands/migrate.d.ts.map +1 -1
- package/dist/src/commands/migrate.js +224 -125
- package/dist/src/commands/migrate.js.map +1 -1
- package/dist/src/commands/types.d.ts.map +1 -1
- package/dist/src/commands/types.js +16 -2
- package/dist/src/commands/types.js.map +1 -1
- package/dist/src/commands/upgrade.d.ts.map +1 -1
- package/dist/src/commands/upgrade.js +4 -1
- package/dist/src/commands/upgrade.js.map +1 -1
- package/dist/src/commands/verify.d.ts.map +1 -1
- package/dist/src/commands/verify.js +189 -125
- package/dist/src/commands/verify.js.map +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +59 -72
- package/dist/src/index.js.map +1 -1
- package/dist/src/lib/agent-context-staleness.d.ts +8 -1
- package/dist/src/lib/agent-context-staleness.d.ts.map +1 -1
- package/dist/src/lib/agent-context-staleness.js +20 -5
- package/dist/src/lib/agent-context-staleness.js.map +1 -1
- package/dist/src/lib/agent-schema.d.ts +9 -0
- package/dist/src/lib/agent-schema.d.ts.map +1 -0
- package/dist/src/lib/agent-schema.js +61 -0
- package/dist/src/lib/agent-schema.js.map +1 -0
- package/dist/src/lib/allow.d.ts +6 -0
- package/dist/src/lib/allow.d.ts.map +1 -1
- package/dist/src/lib/allow.js +49 -5
- package/dist/src/lib/allow.js.map +1 -1
- package/dist/src/lib/anti-patterns.d.ts.map +1 -1
- package/dist/src/lib/anti-patterns.js +4 -2
- package/dist/src/lib/anti-patterns.js.map +1 -1
- package/dist/src/lib/args.d.ts +51 -10
- package/dist/src/lib/args.d.ts.map +1 -1
- package/dist/src/lib/args.js +44 -18
- package/dist/src/lib/args.js.map +1 -1
- package/dist/src/lib/catalog-listing.d.ts +21 -1
- package/dist/src/lib/catalog-listing.d.ts.map +1 -1
- package/dist/src/lib/catalog-listing.js +85 -16
- package/dist/src/lib/catalog-listing.js.map +1 -1
- package/dist/src/lib/catalog.d.ts +30 -0
- package/dist/src/lib/catalog.d.ts.map +1 -1
- package/dist/src/lib/catalog.js +40 -5
- package/dist/src/lib/catalog.js.map +1 -1
- package/dist/src/lib/codegen-drift.d.ts +31 -2
- package/dist/src/lib/codegen-drift.d.ts.map +1 -1
- package/dist/src/lib/codegen-drift.js +109 -4
- package/dist/src/lib/codegen-drift.js.map +1 -1
- package/dist/src/lib/collection-load-options.d.ts +1 -1
- package/dist/src/lib/collection-load-options.d.ts.map +1 -1
- package/dist/src/lib/collection-load-options.js +1 -0
- package/dist/src/lib/collection-load-options.js.map +1 -1
- package/dist/src/lib/config.d.ts +4 -2
- package/dist/src/lib/config.d.ts.map +1 -1
- package/dist/src/lib/config.js +4 -2
- package/dist/src/lib/config.js.map +1 -1
- package/dist/src/lib/decimal-precision-advisory.d.ts +10 -0
- package/dist/src/lib/decimal-precision-advisory.d.ts.map +1 -0
- package/dist/src/lib/decimal-precision-advisory.js +34 -0
- package/dist/src/lib/decimal-precision-advisory.js.map +1 -0
- package/dist/src/lib/deprecation-lint.d.ts.map +1 -1
- package/dist/src/lib/deprecation-lint.js +17 -26
- package/dist/src/lib/deprecation-lint.js.map +1 -1
- package/dist/src/lib/docs-removed.d.ts +13 -0
- package/dist/src/lib/docs-removed.d.ts.map +1 -0
- package/dist/src/lib/docs-removed.js +31 -0
- package/dist/src/lib/docs-removed.js.map +1 -0
- package/dist/src/lib/docs-site-eject.d.ts +13 -0
- package/dist/src/lib/docs-site-eject.d.ts.map +1 -0
- package/dist/src/lib/docs-site-eject.js +40 -0
- package/dist/src/lib/docs-site-eject.js.map +1 -0
- package/dist/src/lib/field-lint.d.ts +25 -0
- package/dist/src/lib/field-lint.d.ts.map +1 -0
- package/dist/src/lib/field-lint.js +102 -0
- package/dist/src/lib/field-lint.js.map +1 -0
- package/dist/src/lib/fk-index-advisory.d.ts +1 -2
- package/dist/src/lib/fk-index-advisory.d.ts.map +1 -1
- package/dist/src/lib/fk-index-advisory.js +4 -3
- package/dist/src/lib/fk-index-advisory.js.map +1 -1
- package/dist/src/lib/format.d.ts +7 -0
- package/dist/src/lib/format.d.ts.map +1 -1
- package/dist/src/lib/format.js +13 -0
- package/dist/src/lib/format.js.map +1 -1
- package/dist/src/lib/gen-migrate-advice.d.ts +3 -1
- package/dist/src/lib/gen-migrate-advice.d.ts.map +1 -1
- package/dist/src/lib/gen-migrate-advice.js +3 -4
- package/dist/src/lib/gen-migrate-advice.js.map +1 -1
- package/dist/src/lib/install-set.d.ts +10 -1
- package/dist/src/lib/install-set.d.ts.map +1 -1
- package/dist/src/lib/install-set.js +20 -2
- package/dist/src/lib/install-set.js.map +1 -1
- package/dist/src/lib/load-metaobjects-config.d.ts +13 -11
- package/dist/src/lib/load-metaobjects-config.d.ts.map +1 -1
- package/dist/src/lib/load-metaobjects-config.js +53 -75
- package/dist/src/lib/load-metaobjects-config.js.map +1 -1
- package/dist/src/lib/manifest-ignored-check.d.ts +4 -1
- package/dist/src/lib/manifest-ignored-check.d.ts.map +1 -1
- package/dist/src/lib/manifest-ignored-check.js +9 -4
- package/dist/src/lib/manifest-ignored-check.js.map +1 -1
- package/dist/src/lib/output.d.ts +15 -0
- package/dist/src/lib/output.d.ts.map +1 -1
- package/dist/src/lib/output.js +9 -1
- package/dist/src/lib/output.js.map +1 -1
- package/dist/src/lib/payload-field-tree.d.ts +4 -5
- package/dist/src/lib/payload-field-tree.d.ts.map +1 -1
- package/dist/src/lib/payload-field-tree.js +16 -31
- package/dist/src/lib/payload-field-tree.js.map +1 -1
- package/dist/src/lib/requirement-check.d.ts +7 -0
- package/dist/src/lib/requirement-check.d.ts.map +1 -1
- package/dist/src/lib/requirement-check.js +14 -7
- package/dist/src/lib/requirement-check.js.map +1 -1
- package/dist/src/lib/strict-args.d.ts +28 -0
- package/dist/src/lib/strict-args.d.ts.map +1 -0
- package/dist/src/lib/strict-args.js +49 -0
- package/dist/src/lib/strict-args.js.map +1 -0
- package/dist/src/lib/template-eject.d.ts +108 -0
- package/dist/src/lib/template-eject.d.ts.map +1 -0
- package/dist/src/lib/template-eject.js +438 -0
- package/dist/src/lib/template-eject.js.map +1 -0
- package/dist/src/lib/version.d.ts +9 -0
- package/dist/src/lib/version.d.ts.map +1 -1
- package/dist/src/lib/version.js +15 -0
- package/dist/src/lib/version.js.map +1 -1
- package/package.json +10 -10
- package/src/commands/docs.ts +11 -952
- package/src/commands/eject.ts +318 -73
- package/src/commands/gen.ts +94 -22
- package/src/commands/generator.ts +2 -2
- package/src/commands/init.ts +80 -38
- package/src/commands/migrate.ts +248 -117
- package/src/commands/types.ts +18 -2
- package/src/commands/upgrade.ts +5 -1
- package/src/commands/verify.ts +229 -136
- package/src/index.ts +59 -72
- package/src/lib/agent-context-staleness.ts +20 -5
- package/src/lib/agent-schema.ts +74 -0
- package/src/lib/allow.ts +57 -6
- package/src/lib/anti-patterns.ts +4 -2
- package/src/lib/args.ts +83 -28
- package/src/lib/catalog-listing.ts +105 -25
- package/src/lib/catalog.ts +51 -6
- package/src/lib/codegen-drift.ts +138 -3
- package/src/lib/collection-load-options.ts +2 -1
- package/src/lib/config.ts +5 -3
- package/src/lib/decimal-precision-advisory.ts +50 -0
- package/src/lib/deprecation-lint.ts +16 -24
- package/src/lib/docs-removed.ts +41 -0
- package/src/lib/docs-site-eject.ts +48 -0
- package/src/lib/field-lint.ts +122 -0
- package/src/lib/fk-index-advisory.ts +4 -4
- package/src/lib/format.ts +12 -0
- package/src/lib/gen-migrate-advice.ts +6 -4
- package/src/lib/install-set.ts +20 -1
- package/src/lib/load-metaobjects-config.ts +57 -78
- package/src/lib/manifest-ignored-check.ts +14 -10
- package/src/lib/output.ts +18 -1
- package/src/lib/payload-field-tree.ts +18 -35
- package/src/lib/requirement-check.ts +21 -6
- package/src/lib/strict-args.ts +52 -0
- package/src/lib/template-eject.ts +526 -0
- package/src/lib/version.ts +18 -0
- package/dist/src/lib/docs-drift.d.ts +0 -42
- package/dist/src/lib/docs-drift.d.ts.map +0 -1
- package/dist/src/lib/docs-drift.js +0 -264
- package/dist/src/lib/docs-drift.js.map +0 -1
- package/src/lib/docs-drift.ts +0 -312
package/src/lib/args.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { parseCommandArgs } from "./strict-args.js";
|
|
2
2
|
import type { DeclaredRename } from "@metaobjectsdev/migrate-ts";
|
|
3
3
|
import { parseAdvisoryLimit } from "./advisory.js";
|
|
4
4
|
|
|
@@ -36,7 +36,7 @@ export const INIT_OPTIONS = {
|
|
|
36
36
|
} as const;
|
|
37
37
|
|
|
38
38
|
export function parseInitArgs(argv: string[]): InitFlags {
|
|
39
|
-
const { values } =
|
|
39
|
+
const { values } = parseCommandArgs("init", {
|
|
40
40
|
args: argv,
|
|
41
41
|
options: INIT_OPTIONS,
|
|
42
42
|
strict: true,
|
|
@@ -79,7 +79,7 @@ export const AGENT_DOCS_OPTIONS = {
|
|
|
79
79
|
} as const;
|
|
80
80
|
|
|
81
81
|
export function parseAgentDocsArgs(argv: string[]): AgentDocsFlags {
|
|
82
|
-
const { values } =
|
|
82
|
+
const { values } = parseCommandArgs("agent-docs", {
|
|
83
83
|
args: argv,
|
|
84
84
|
options: AGENT_DOCS_OPTIONS,
|
|
85
85
|
strict: true,
|
|
@@ -122,6 +122,12 @@ export interface GenFlags {
|
|
|
122
122
|
* a structured payload, which carries every finding.
|
|
123
123
|
*/
|
|
124
124
|
limit: number;
|
|
125
|
+
/**
|
|
126
|
+
* `--generators <names>`: narrow the run to these declared generators, by stable name
|
|
127
|
+
* (ADR-0034 Amendment 9). Undefined runs everything the config declares. A name the
|
|
128
|
+
* config does not declare is refused; a narrowing never adds a generator.
|
|
129
|
+
*/
|
|
130
|
+
generators?: string[];
|
|
125
131
|
}
|
|
126
132
|
|
|
127
133
|
/** The flag table `parseGenArgs` parses. Exported so the help text can be gated against it. */
|
|
@@ -132,10 +138,11 @@ export const GEN_OPTIONS = {
|
|
|
132
138
|
"probe": { type: "boolean", default: false },
|
|
133
139
|
"no-antipatterns": { type: "boolean", default: false },
|
|
134
140
|
"limit": { type: "string" },
|
|
141
|
+
"generators": { type: "string" },
|
|
135
142
|
} as const;
|
|
136
143
|
|
|
137
144
|
export function parseGenArgs(argv: string[]): GenFlags {
|
|
138
|
-
const { values, positionals } =
|
|
145
|
+
const { values, positionals } = parseCommandArgs("gen", {
|
|
139
146
|
args: argv,
|
|
140
147
|
options: GEN_OPTIONS,
|
|
141
148
|
strict: true,
|
|
@@ -162,9 +169,19 @@ export function parseGenArgs(argv: string[]): GenFlags {
|
|
|
162
169
|
// Throws on a bad value; the command layer reports it and exits 2, exactly as
|
|
163
170
|
// it does for --baseline above.
|
|
164
171
|
limit: parseAdvisoryLimit(values.limit as string | undefined),
|
|
172
|
+
...(values.generators !== undefined && { generators: parseGeneratorNames(values.generators as string) }),
|
|
165
173
|
};
|
|
166
174
|
}
|
|
167
175
|
|
|
176
|
+
/** `docs,api-docs` → `["docs", "api-docs"]`; an empty list is refused, since it would run nothing. */
|
|
177
|
+
function parseGeneratorNames(raw: string): string[] {
|
|
178
|
+
const names = raw.split(",").map((n) => n.trim()).filter((n) => n !== "");
|
|
179
|
+
if (names.length === 0) {
|
|
180
|
+
throw new Error("--generators needs at least one generator name, e.g. --generators docs,api-docs");
|
|
181
|
+
}
|
|
182
|
+
return names;
|
|
183
|
+
}
|
|
184
|
+
|
|
168
185
|
// ---------------------------------------------------------------------------
|
|
169
186
|
// export flags
|
|
170
187
|
// ---------------------------------------------------------------------------
|
|
@@ -179,7 +196,7 @@ export const EXPORT_OPTIONS = {
|
|
|
179
196
|
} as const;
|
|
180
197
|
|
|
181
198
|
export function parseExportArgs(argv: string[]): ExportFlags {
|
|
182
|
-
const { values } =
|
|
199
|
+
const { values } = parseCommandArgs("export", {
|
|
183
200
|
args: argv,
|
|
184
201
|
options: EXPORT_OPTIONS,
|
|
185
202
|
strict: true,
|
|
@@ -207,7 +224,7 @@ export const FMT_OPTIONS = {
|
|
|
207
224
|
} as const;
|
|
208
225
|
|
|
209
226
|
export function parseFmtArgs(argv: string[]): FmtFlags {
|
|
210
|
-
const { values, positionals } =
|
|
227
|
+
const { values, positionals } = parseCommandArgs("fmt", {
|
|
211
228
|
args: argv,
|
|
212
229
|
options: FMT_OPTIONS,
|
|
213
230
|
strict: true,
|
|
@@ -251,6 +268,20 @@ function assertSchemaDialect(dialect: string | undefined): void {
|
|
|
251
268
|
export const MIGRATE_FORMATS = ["default", "flyway"] as const;
|
|
252
269
|
export type MigrateFormat = (typeof MIGRATE_FORMATS)[number];
|
|
253
270
|
|
|
271
|
+
/**
|
|
272
|
+
* A `--migration-format` value, validated. One parser for `meta migrate` and `meta verify`,
|
|
273
|
+
* so the two accept the same formats and refuse a bad one with the same message.
|
|
274
|
+
*
|
|
275
|
+
* The flag is --migration-format, not --format: `--format` is already a GLOBAL cli flag
|
|
276
|
+
* selecting output rendering (toon|json|text), consumed in index.ts.
|
|
277
|
+
*/
|
|
278
|
+
function parseMigrationFormat(raw: string | undefined): MigrateFormat | undefined {
|
|
279
|
+
if (raw !== undefined && !MIGRATE_FORMATS.includes(raw as MigrateFormat)) {
|
|
280
|
+
throw new Error(`invalid --migration-format '${raw}'; expected: ${MIGRATE_FORMATS.join(", ")}`);
|
|
281
|
+
}
|
|
282
|
+
return raw as MigrateFormat | undefined;
|
|
283
|
+
}
|
|
284
|
+
|
|
254
285
|
// Exported (not just module-local) so allow-tokens-pinned.test.ts can pin it
|
|
255
286
|
// against sdk's AllowTokenEnum (config.json's static migrate.allow validator)
|
|
256
287
|
// — the two lists drifted silently before that test existed: sdk's enum was
|
|
@@ -308,6 +339,12 @@ export interface VerifyFlags {
|
|
|
308
339
|
allow: AllowToken[];
|
|
309
340
|
/** Skip the schema-drift gate even when --db is present. */
|
|
310
341
|
skipSchema: boolean;
|
|
342
|
+
/**
|
|
343
|
+
* The migration file layout the project uses, spelled as `meta migrate` spells it and
|
|
344
|
+
* resolved with the same precedence (flag > `.metaobjects/config.json` > default). Under
|
|
345
|
+
* `flyway` the schema-drift gate leaves Flyway's own history table out of the comparison.
|
|
346
|
+
*/
|
|
347
|
+
migrationFormat: MigrateFormat | undefined;
|
|
311
348
|
/**
|
|
312
349
|
* #225 — D1 binding name from wrangler.toml, spelled/documented the same way
|
|
313
350
|
* `meta migrate --d1 <binding>` does. Gated on `--dialect d1` (D1 has no URL
|
|
@@ -334,16 +371,9 @@ export interface VerifyFlags {
|
|
|
334
371
|
*/
|
|
335
372
|
forbidHandEdits: boolean;
|
|
336
373
|
/**
|
|
337
|
-
*
|
|
338
|
-
*
|
|
339
|
-
*
|
|
340
|
-
* A SEPARATE subverb rather than part of `--codegen`, because they check different
|
|
341
|
-
* trees under different ownership rules: `--codegen` regenerates `outDir`/`targets` and
|
|
342
|
-
* must respect the hand edits `meta gen` preserves, while the docs tree has no merge,
|
|
343
|
-
* no manifest, and lives in a directory the adopter chose (`./docs/generated` by
|
|
344
|
-
* default) that may hold hand-written files it does not own. Folding them together
|
|
345
|
-
* would have to pick one of those rules
|
|
346
|
-
* for both.
|
|
374
|
+
* `--docs`, removed in 1.1.0 (ADR-0034 Amendment 9): `--codegen` checks documentation with
|
|
375
|
+
* everything else the generator list declares. Still parsed, so the command can say where
|
|
376
|
+
* it went (exit 2) rather than "unknown flag".
|
|
347
377
|
*/
|
|
348
378
|
docs: boolean;
|
|
349
379
|
/**
|
|
@@ -381,6 +411,21 @@ export interface VerifyFlags {
|
|
|
381
411
|
* the half that CAN fail a build switched on. Same shape as --no-antipatterns.
|
|
382
412
|
*/
|
|
383
413
|
noRequirementLint: boolean;
|
|
414
|
+
/**
|
|
415
|
+
* The requirement gate's strict switch (ADR-0057): report a live functional
|
|
416
|
+
* requirement that nothing implements (`WARN_REQUIREMENT_NOTHING_IMPLEMENTS`) at
|
|
417
|
+
* severity `error`, so it fails the build. The code is unchanged and no other
|
|
418
|
+
* diagnostic moves. Off by default because a ledger authored ahead of its links is
|
|
419
|
+
* the normal incremental state.
|
|
420
|
+
*
|
|
421
|
+
* Named for what it requires, not `--strict`: `--lax` below is a different axis
|
|
422
|
+
* (ADR-0023 attribute strictness), and a `--strict` beside it would read as that
|
|
423
|
+
* flag's opposite rather than as a requirement-gate setting — the same reason
|
|
424
|
+
* `--replay-snapshot` above is a subverb and not a `--strict` modifier. It is not
|
|
425
|
+
* an explicit subverb either: the requirement gate runs on every `verify`, so this
|
|
426
|
+
* flag modifies a gate that is already selected.
|
|
427
|
+
*/
|
|
428
|
+
requireImplementers: boolean;
|
|
384
429
|
/**
|
|
385
430
|
* Suppress the advisory overlay AUTHORING lint (FR-023 §11.1 item 4) — the
|
|
386
431
|
* finding that an unflagged cross-file redeclaration works today only
|
|
@@ -405,6 +450,13 @@ export interface VerifyFlags {
|
|
|
405
450
|
* and can never fail the build.
|
|
406
451
|
*/
|
|
407
452
|
noDeprecationLint: boolean;
|
|
453
|
+
/**
|
|
454
|
+
* Suppress the advisory FIELD authoring lint — a reference identity whose
|
|
455
|
+
* `@fields` names a field the object lacks, and a field name declared twice in
|
|
456
|
+
* one children list. Advisory only, like its siblings: it has no gate half and
|
|
457
|
+
* can never fail the build.
|
|
458
|
+
*/
|
|
459
|
+
noFieldLint: boolean;
|
|
408
460
|
/**
|
|
409
461
|
* ADR-0023 strict-attr load opt-OUT (#96). `verify` is strict-by-default — an
|
|
410
462
|
* undeclared/typo'd own `@attr` fails verify (ERR_UNKNOWN_ATTR). `--lax`
|
|
@@ -436,18 +488,23 @@ export const VERIFY_OPTIONS = {
|
|
|
436
488
|
dialect: { type: "string" },
|
|
437
489
|
allow: { type: "string", multiple: true },
|
|
438
490
|
"skip-schema": { type: "boolean", default: false },
|
|
491
|
+
"migration-format": { type: "string" },
|
|
439
492
|
templates: { type: "boolean", default: false },
|
|
440
493
|
codegen: { type: "boolean", default: false },
|
|
441
494
|
"forbid-hand-edits": { type: "boolean", default: false },
|
|
495
|
+
// Removed in 1.1.0 (ADR-0034 Amendment 9). Still parsed, so `meta verify --docs` prints
|
|
496
|
+
// where the check went instead of an unknown-flag error.
|
|
442
497
|
docs: { type: "boolean", default: false },
|
|
443
498
|
deps: { type: "boolean", default: false },
|
|
444
499
|
replay: { type: "boolean", default: false },
|
|
445
500
|
"replay-snapshot": { type: "boolean", default: false },
|
|
446
501
|
"no-antipatterns": { type: "boolean", default: false },
|
|
447
502
|
"no-requirement-lint": { type: "boolean", default: false },
|
|
503
|
+
"require-implementers": { type: "boolean", default: false },
|
|
448
504
|
"no-overlay-lint": { type: "boolean", default: false },
|
|
449
505
|
"no-name-lint": { type: "boolean", default: false },
|
|
450
506
|
"no-deprecation-lint": { type: "boolean", default: false },
|
|
507
|
+
"no-field-lint": { type: "boolean", default: false },
|
|
451
508
|
lax: { type: "boolean", default: false },
|
|
452
509
|
"d1": { type: "string" },
|
|
453
510
|
"remote": { type: "boolean", default: false },
|
|
@@ -482,7 +539,7 @@ function parseAllowTokens(raw: string | string[] | undefined): AllowToken[] {
|
|
|
482
539
|
}
|
|
483
540
|
|
|
484
541
|
export function parseVerifyArgs(argv: string[]): VerifyFlags {
|
|
485
|
-
const { values } =
|
|
542
|
+
const { values } = parseCommandArgs("verify", {
|
|
486
543
|
args: argv,
|
|
487
544
|
options: VERIFY_OPTIONS,
|
|
488
545
|
strict: true,
|
|
@@ -521,6 +578,7 @@ export function parseVerifyArgs(argv: string[]): VerifyFlags {
|
|
|
521
578
|
dialect: dialect as Dialect | undefined,
|
|
522
579
|
allow: allowTokens as AllowToken[],
|
|
523
580
|
skipSchema: !!values["skip-schema"],
|
|
581
|
+
migrationFormat: parseMigrationFormat(values["migration-format"] as string | undefined),
|
|
524
582
|
templates,
|
|
525
583
|
codegen,
|
|
526
584
|
forbidHandEdits,
|
|
@@ -531,9 +589,11 @@ export function parseVerifyArgs(argv: string[]): VerifyFlags {
|
|
|
531
589
|
anyExplicit,
|
|
532
590
|
noAntipatterns: !!values["no-antipatterns"],
|
|
533
591
|
noRequirementLint: !!values["no-requirement-lint"],
|
|
592
|
+
requireImplementers: !!values["require-implementers"],
|
|
534
593
|
noOverlayLint: !!values["no-overlay-lint"],
|
|
535
594
|
noNameLint: !!values["no-name-lint"],
|
|
536
595
|
noDeprecationLint: !!values["no-deprecation-lint"],
|
|
596
|
+
noFieldLint: !!values["no-field-lint"],
|
|
537
597
|
lax: !!values.lax,
|
|
538
598
|
d1: values.d1 as string | undefined,
|
|
539
599
|
remote: !!values.remote,
|
|
@@ -561,7 +621,7 @@ export const PROMPT_SNAPSHOT_OPTIONS = {
|
|
|
561
621
|
} as const;
|
|
562
622
|
|
|
563
623
|
export function parsePromptSnapshotArgs(argv: string[]): PromptSnapshotFlags {
|
|
564
|
-
const { values } =
|
|
624
|
+
const { values } = parseCommandArgs("prompt-snapshot", {
|
|
565
625
|
args: argv,
|
|
566
626
|
options: PROMPT_SNAPSHOT_OPTIONS,
|
|
567
627
|
strict: true,
|
|
@@ -632,7 +692,7 @@ export const MIGRATE_OPTIONS = {
|
|
|
632
692
|
} as const;
|
|
633
693
|
|
|
634
694
|
export function parseMigrateArgs(argv: string[]): MigrateFlags {
|
|
635
|
-
const { values, positionals } =
|
|
695
|
+
const { values, positionals } = parseCommandArgs("migrate", {
|
|
636
696
|
args: argv,
|
|
637
697
|
options: MIGRATE_OPTIONS,
|
|
638
698
|
strict: true,
|
|
@@ -652,12 +712,7 @@ export function parseMigrateArgs(argv: string[]): MigrateFlags {
|
|
|
652
712
|
const dialect = values.dialect as string | undefined;
|
|
653
713
|
assertSchemaDialect(dialect);
|
|
654
714
|
|
|
655
|
-
|
|
656
|
-
// GLOBAL cli flag selecting output rendering (toon|json|text), consumed in index.ts.
|
|
657
|
-
const format = values["migration-format"] as string | undefined;
|
|
658
|
-
if (format !== undefined && !MIGRATE_FORMATS.includes(format as MigrateFormat)) {
|
|
659
|
-
throw new Error(`invalid --migration-format '${format}'; expected: ${MIGRATE_FORMATS.join(", ")}`);
|
|
660
|
-
}
|
|
715
|
+
const format = parseMigrationFormat(values["migration-format"] as string | undefined);
|
|
661
716
|
|
|
662
717
|
const onAmb = values["on-ambiguous"] as string | undefined;
|
|
663
718
|
if (onAmb !== undefined && !ON_AMBIGUOUS.includes(onAmb as OnAmbiguous)) {
|
|
@@ -669,7 +724,7 @@ export function parseMigrateArgs(argv: string[]): MigrateFlags {
|
|
|
669
724
|
return {
|
|
670
725
|
db: values.db as string | undefined,
|
|
671
726
|
dialect: dialect as Dialect | undefined,
|
|
672
|
-
format
|
|
727
|
+
format,
|
|
673
728
|
outDir: values["out-dir"] as string | undefined,
|
|
674
729
|
slug: values.slug as string | undefined,
|
|
675
730
|
allow: allowTokens as AllowToken[],
|
|
@@ -749,7 +804,7 @@ export const EJECT_OPTIONS = {
|
|
|
749
804
|
} as const;
|
|
750
805
|
|
|
751
806
|
export function parseEjectArgs(argv: string[]): EjectFlags {
|
|
752
|
-
const { values, positionals } =
|
|
807
|
+
const { values, positionals } = parseCommandArgs("eject", {
|
|
753
808
|
args: argv,
|
|
754
809
|
options: EJECT_OPTIONS,
|
|
755
810
|
strict: true,
|
|
@@ -811,7 +866,7 @@ export const DEPS_OPTIONS = {
|
|
|
811
866
|
} as const;
|
|
812
867
|
|
|
813
868
|
export function parseDepsArgs(argv: string[]): DepsFlags {
|
|
814
|
-
const { values, positionals } =
|
|
869
|
+
const { values, positionals } = parseCommandArgs("deps", {
|
|
815
870
|
args: argv,
|
|
816
871
|
options: DEPS_OPTIONS,
|
|
817
872
|
strict: true,
|
|
@@ -25,11 +25,12 @@ import {
|
|
|
25
25
|
type GeneratorRegistryEntry,
|
|
26
26
|
type Layer,
|
|
27
27
|
type MetaobjectsGenConfig,
|
|
28
|
+
type RunGenOpts,
|
|
28
29
|
} from "@metaobjectsdev/codegen-ts";
|
|
29
30
|
import * as coreTpl from "@metaobjectsdev/codegen-ts";
|
|
30
31
|
import * as reactTpl from "@metaobjectsdev/codegen-ts-react";
|
|
31
32
|
import * as tanstackTpl from "@metaobjectsdev/codegen-ts-tanstack";
|
|
32
|
-
import { composeCatalog, listCatalog, packageOf } from "./catalog.js";
|
|
33
|
+
import { composeCatalog, listCatalog, packageOf, packagedWiring, type GeneratorWiring } from "./catalog.js";
|
|
33
34
|
import {
|
|
34
35
|
buildLibraryRows, renderLibraryText,
|
|
35
36
|
type LibraryCatalogRow, type LibraryProjectContext,
|
|
@@ -39,7 +40,8 @@ import {
|
|
|
39
40
|
RUNTIME_ENTRIES, resolveRuntimePackage, runtimeClosure, runtimeCopyStatus, runtimeInstall,
|
|
40
41
|
type RuntimeCopyRow,
|
|
41
42
|
} from "./runtime-eject.js";
|
|
42
|
-
import {
|
|
43
|
+
import { closureOf, packagedTemplates, templateCopyStatus, type TemplateCopyRow } from "./template-eject.js";
|
|
44
|
+
import { DEFAULT_DOCS_DIR, DOCS_TARGET_NAME, OWNED_RUNTIME_DIR } from "@metaobjectsdev/codegen-ts";
|
|
43
45
|
import { readPackageManifest, declaredDependencyNames } from "./package-manifest.js";
|
|
44
46
|
import { describeError } from "./error-text.js";
|
|
45
47
|
|
|
@@ -62,6 +64,8 @@ export interface GeneratorCatalogRow {
|
|
|
62
64
|
tier: "native" | "neutral";
|
|
63
65
|
package: string;
|
|
64
66
|
description: string;
|
|
67
|
+
/** The registry's one line a reader needs before wiring this entry. Printed under the row. */
|
|
68
|
+
note?: string;
|
|
65
69
|
/** From the reference template's `use-when:` header. Absent for a non-ejectable entry. */
|
|
66
70
|
useWhen?: string;
|
|
67
71
|
/** From the reference template's `emits:` header. Absent for a non-ejectable entry. */
|
|
@@ -69,6 +73,11 @@ export interface GeneratorCatalogRow {
|
|
|
69
73
|
requires?: readonly string[];
|
|
70
74
|
configKeys?: readonly string[];
|
|
71
75
|
install: { dev: string[]; runtime: string[] };
|
|
76
|
+
/**
|
|
77
|
+
* How to run this generator AS SHIPPED: the import line for its package factory. No
|
|
78
|
+
* copy involved; `meta eject` prints the local import for an owned one.
|
|
79
|
+
*/
|
|
80
|
+
wire?: GeneratorWiring;
|
|
72
81
|
source: {
|
|
73
82
|
kind: "reference-template" | "package-only";
|
|
74
83
|
ejectable: boolean;
|
|
@@ -81,6 +90,12 @@ export interface GeneratorCatalogRow {
|
|
|
81
90
|
* imports no adapter, or the project owns none of it.
|
|
82
91
|
*/
|
|
83
92
|
runtimeCopy?: RuntimeCopyRow[];
|
|
93
|
+
/**
|
|
94
|
+
* ADR-0034 Amendment 8: the template modules this generator calls, as far as the project
|
|
95
|
+
* owns a copy of them under `codegen/templates/` — each file compared to what the
|
|
96
|
+
* installed packages would write there. Absent when the project owns none of them.
|
|
97
|
+
*/
|
|
98
|
+
templateCopy?: TemplateCopyRow[];
|
|
84
99
|
};
|
|
85
100
|
project?: {
|
|
86
101
|
/** Wired in this project's `generators: [...]`. */
|
|
@@ -191,6 +206,10 @@ export interface CatalogListingOpts {
|
|
|
191
206
|
* "probe failed" on every fresh project, for a generator that would in fact run.
|
|
192
207
|
*/
|
|
193
208
|
sourceFiles?: readonly string[];
|
|
209
|
+
/** The metadata source directories, as `meta gen` supplies them: the docs site loads them. */
|
|
210
|
+
sourceRoots?: readonly string[];
|
|
211
|
+
/** The physical schema `agent/schema.md` describes, as `meta gen` supplies it. */
|
|
212
|
+
agentSchema?: RunGenOpts["agentSchema"];
|
|
194
213
|
};
|
|
195
214
|
}
|
|
196
215
|
|
|
@@ -205,10 +224,9 @@ export interface CatalogListingOpts {
|
|
|
205
224
|
async function probeOne(
|
|
206
225
|
entry: GeneratorRegistryEntry,
|
|
207
226
|
project: CatalogProject,
|
|
208
|
-
|
|
209
|
-
scope: ((fqn: string) => boolean) | undefined,
|
|
210
|
-
sourceFiles: readonly string[] | undefined,
|
|
227
|
+
probe: NonNullable<CatalogListingOpts["probe"]>,
|
|
211
228
|
): Promise<{ count: number; needsConfig?: string[] } | { error: string }> {
|
|
229
|
+
const { metadata, scope, sourceFiles, sourceRoots, agentSchema } = probe;
|
|
212
230
|
const count = async (config: MetaobjectsGenConfig): Promise<number> => {
|
|
213
231
|
const result = await runGen({
|
|
214
232
|
config: { ...config, generators: [entry.factory()] },
|
|
@@ -217,6 +235,8 @@ async function probeOne(
|
|
|
217
235
|
dryRun: true,
|
|
218
236
|
...(scope !== undefined ? { scope } : {}),
|
|
219
237
|
...(sourceFiles !== undefined ? { sourceFiles } : {}),
|
|
238
|
+
...(sourceRoots !== undefined ? { sourceRoots } : {}),
|
|
239
|
+
...(agentSchema !== undefined ? { agentSchema } : {}),
|
|
220
240
|
});
|
|
221
241
|
return result.files.length;
|
|
222
242
|
};
|
|
@@ -230,12 +250,23 @@ async function probeOne(
|
|
|
230
250
|
// report the key as needed rather than dropping the count: the listing used to show
|
|
231
251
|
// `routes … [fastify]` beside `routes-hono … [hono, would emit 3]` with no reason.
|
|
232
252
|
// Only a retry that SUCCEEDS with the key supplied attributes the failure to it.
|
|
253
|
+
//
|
|
254
|
+
// A documentation generator refuses to run while `targets.docs` is unset (ADR-0034
|
|
255
|
+
// Amendment 9) — again exactly the fresh project `--probe` is asked about — and the
|
|
256
|
+
// directory changes no file count either, so it is supplied the same way.
|
|
257
|
+
const needsConfig: string[] = [];
|
|
258
|
+
let retry: MetaobjectsGenConfig = project.config;
|
|
233
259
|
if (project.config.dbImport === undefined) {
|
|
260
|
+
retry = { ...retry, dbImport: PROBE_DB_IMPORT_PLACEHOLDER };
|
|
261
|
+
needsConfig.push("dbImport");
|
|
262
|
+
}
|
|
263
|
+
if (entry.factory().target === DOCS_TARGET_NAME && project.config.targets?.[DOCS_TARGET_NAME] === undefined) {
|
|
264
|
+
retry = { ...retry, targets: { ...retry.targets, [DOCS_TARGET_NAME]: { outDir: DEFAULT_DOCS_DIR } } };
|
|
265
|
+
needsConfig.push(`targets.${DOCS_TARGET_NAME}`);
|
|
266
|
+
}
|
|
267
|
+
if (needsConfig.length > 0) {
|
|
234
268
|
try {
|
|
235
|
-
return {
|
|
236
|
-
count: await count({ ...project.config, dbImport: PROBE_DB_IMPORT_PLACEHOLDER }),
|
|
237
|
-
needsConfig: ["dbImport"],
|
|
238
|
-
};
|
|
269
|
+
return { count: await count(retry), needsConfig };
|
|
239
270
|
} catch {
|
|
240
271
|
// Fall through: the original error is the one worth reporting.
|
|
241
272
|
}
|
|
@@ -275,12 +306,40 @@ async function ownedRuntimeByGenerator(
|
|
|
275
306
|
return out;
|
|
276
307
|
}
|
|
277
308
|
|
|
309
|
+
/**
|
|
310
|
+
* Per OWNED generator, the project's copies of the template modules it calls. Attributed by
|
|
311
|
+
* what each generator reaches and only for generators the project owns, as the adapter copy
|
|
312
|
+
* is: `queries` and `entity` share modules, and a project that ejected only one of them
|
|
313
|
+
* must not be told it owns the other's.
|
|
314
|
+
*/
|
|
315
|
+
async function ownedTemplatesByGenerator(
|
|
316
|
+
projectRoot: string,
|
|
317
|
+
ownedNames: ReadonlySet<string>,
|
|
318
|
+
): Promise<Map<string, TemplateCopyRow[]>> {
|
|
319
|
+
const out = new Map<string, TemplateCopyRow[]>();
|
|
320
|
+
const status = await templateCopyStatus(projectRoot, packagedTemplates());
|
|
321
|
+
if (status.length === 0) return out;
|
|
322
|
+
for (const name of ownedNames) {
|
|
323
|
+
let reached: Set<string>;
|
|
324
|
+
try {
|
|
325
|
+
reached = new Set(closureOf(name).templates.map((f) => f.path));
|
|
326
|
+
} catch {
|
|
327
|
+
continue; // not a reference generator
|
|
328
|
+
}
|
|
329
|
+
const files = status.filter((r) => reached.has(r.path));
|
|
330
|
+
if (files.length > 0) out.set(name, files);
|
|
331
|
+
}
|
|
332
|
+
return out;
|
|
333
|
+
}
|
|
334
|
+
|
|
278
335
|
export async function buildCatalogListing(opts: CatalogListingOpts = {}): Promise<CatalogRow[]> {
|
|
279
336
|
const rows: CatalogRow[] = [];
|
|
280
337
|
const runtimeCopies = opts.project === undefined
|
|
281
338
|
? new Map<string, { files: RuntimeCopyRow[]; packages: string[] }>()
|
|
282
339
|
: await ownedRuntimeByGenerator(opts.project.projectRoot, opts.project.ownedNames);
|
|
283
|
-
|
|
340
|
+
const templateCopies = opts.project === undefined
|
|
341
|
+
? new Map<string, TemplateCopyRow[]>()
|
|
342
|
+
: await ownedTemplatesByGenerator(opts.project.projectRoot, opts.project.ownedNames);
|
|
284
343
|
for (const entry of listCatalog()) {
|
|
285
344
|
const template = entry.ejectable ? readTemplate(entry.name) : undefined;
|
|
286
345
|
// A project that owns this generator's adapter copy installs what the COPY imports,
|
|
@@ -290,6 +349,11 @@ export async function buildCatalogListing(opts: CatalogListingOpts = {}): Promis
|
|
|
290
349
|
? installSetFor([entry])
|
|
291
350
|
: installSetFor([entry], [], { generators: new Set([entry.name]), ...runtimeInstall(owned.packages) });
|
|
292
351
|
const pkg = packageOf(entry.name) ?? "";
|
|
352
|
+
// The row keeps the stock wiring even when this project owns the copy: the JSON
|
|
353
|
+
// consumer reads `source.owned` to know what it runs today, and the package line is
|
|
354
|
+
// the fact it needs to go back to stock. `renderCatalogText` deliberately hides that
|
|
355
|
+
// line under an owned row — two imports in front of a human invite wiring both.
|
|
356
|
+
const wire = packagedWiring(entry);
|
|
293
357
|
|
|
294
358
|
const row: GeneratorCatalogRow = {
|
|
295
359
|
name: entry.name,
|
|
@@ -299,6 +363,7 @@ export async function buildCatalogListing(opts: CatalogListingOpts = {}): Promis
|
|
|
299
363
|
tier: entry.tier,
|
|
300
364
|
package: pkg,
|
|
301
365
|
description: entry.description,
|
|
366
|
+
...(entry.note !== undefined ? { note: entry.note } : {}),
|
|
302
367
|
...(template !== undefined && headerFacet(template, "use-when") !== undefined
|
|
303
368
|
? { useWhen: headerFacet(template, "use-when")! }
|
|
304
369
|
: {}),
|
|
@@ -308,11 +373,13 @@ export async function buildCatalogListing(opts: CatalogListingOpts = {}): Promis
|
|
|
308
373
|
...(entry.requires !== undefined ? { requires: entry.requires } : {}),
|
|
309
374
|
...(entry.configKeys !== undefined ? { configKeys: entry.configKeys } : {}),
|
|
310
375
|
install: { dev: install.dev, runtime: install.runtime },
|
|
376
|
+
...(wire !== undefined ? { wire } : {}),
|
|
311
377
|
source: {
|
|
312
378
|
kind: entry.ejectable ? "reference-template" : "package-only",
|
|
313
379
|
ejectable: entry.ejectable,
|
|
314
380
|
owned: opts.project === undefined ? null : opts.project.ownedNames.has(entry.name),
|
|
315
381
|
...(owned !== undefined ? { runtimeCopy: owned.files } : {}),
|
|
382
|
+
...(templateCopies.has(entry.name) ? { templateCopy: templateCopies.get(entry.name)! } : {}),
|
|
316
383
|
},
|
|
317
384
|
};
|
|
318
385
|
|
|
@@ -328,13 +395,7 @@ export async function buildCatalogListing(opts: CatalogListingOpts = {}): Promis
|
|
|
328
395
|
let probeError: string | undefined;
|
|
329
396
|
let needsConfig: string[] | undefined;
|
|
330
397
|
if (opts.probe !== undefined) {
|
|
331
|
-
const outcome = await probeOne(
|
|
332
|
-
entry,
|
|
333
|
-
project,
|
|
334
|
-
opts.probe.metadata,
|
|
335
|
-
opts.probe.scope,
|
|
336
|
-
opts.probe.sourceFiles,
|
|
337
|
-
);
|
|
398
|
+
const outcome = await probeOne(entry, project, opts.probe);
|
|
338
399
|
if ("count" in outcome) {
|
|
339
400
|
wouldEmit = outcome.count;
|
|
340
401
|
needsConfig = outcome.needsConfig;
|
|
@@ -421,18 +482,20 @@ const LAYER_BLURB: Record<Layer, string> = {
|
|
|
421
482
|
persistence: "how rows are read and written",
|
|
422
483
|
api: "the HTTP surface — pick ONE framework",
|
|
423
484
|
client: "the browser tier — form + hooks + grid compose, they do not conflict",
|
|
424
|
-
docs: "
|
|
485
|
+
docs: "pages about the model and the code — listed like the rest, written to the `docs` target",
|
|
425
486
|
capability: "chosen by your MODEL, not by browsing — run --probe",
|
|
426
487
|
};
|
|
427
488
|
|
|
428
489
|
/**
|
|
429
490
|
* ADR-0034 Amendment 3: every generator is a reference helper, not a guarantee. Said at
|
|
430
491
|
* the top of the catalog because this is where an adopter decides what to depend on.
|
|
492
|
+
* Amendment 5: both ways to run one are named here — import it, or own a copy.
|
|
431
493
|
*/
|
|
432
494
|
export const REFERENCE_HELPER_NOTE: readonly string[] = [
|
|
433
|
-
"Each generator is a reference helper, not a guarantee
|
|
434
|
-
"
|
|
435
|
-
"render) is not a generator and is not
|
|
495
|
+
"Each generator is a reference helper, not a guarantee. Import it from its package to run",
|
|
496
|
+
"it as shipped, or `meta eject <name>` to copy it into your repo and change what it emits.",
|
|
497
|
+
"What MetaObjects guarantees (migrate, verify, render) is not a generator and is not",
|
|
498
|
+
"listed here.",
|
|
436
499
|
"Your database, store or framework is not listed (MongoDB, DynamoDB, Express, NestJS, Vue, …)?",
|
|
437
500
|
"Model it anyway and write or retarget a generator: the metaobjects-codegen skill's",
|
|
438
501
|
"references/any-stack.md has the procedure. MySQL is `dialect: \"mysql\"`.",
|
|
@@ -440,8 +503,8 @@ export const REFERENCE_HELPER_NOTE: readonly string[] = [
|
|
|
440
503
|
|
|
441
504
|
/** The footer line explaining the `package-only` row mark. */
|
|
442
505
|
export const PACKAGE_ONLY_NOTE =
|
|
443
|
-
"package-only = no reference template ships for it
|
|
444
|
-
"import
|
|
506
|
+
"package-only = no reference template ships for it, so `meta eject` cannot copy it. " +
|
|
507
|
+
"Run one as shipped by importing its factory — the import sits under its row.";
|
|
445
508
|
|
|
446
509
|
/** The human rendering: grouped by layer, because layer is the axis you select by. */
|
|
447
510
|
export function renderCatalogText(rows: CatalogRow[], probed: boolean): string {
|
|
@@ -473,6 +536,15 @@ export function renderCatalogText(rows: CatalogRow[], probed: boolean): string {
|
|
|
473
536
|
: `owned runtime: ${differing} file(s) DIFFER from the package — meta eject --list`,
|
|
474
537
|
);
|
|
475
538
|
}
|
|
539
|
+
if (r.source.templateCopy !== undefined) {
|
|
540
|
+
// The template modules this generator calls, compared to the packages.
|
|
541
|
+
const differing = r.source.templateCopy.filter((c) => c.verdict === "differs").length;
|
|
542
|
+
marks.push(
|
|
543
|
+
differing === 0
|
|
544
|
+
? "owned templates: identical to the package"
|
|
545
|
+
: `owned templates: ${differing} file(s) DIFFER from the package — meta eject --list`,
|
|
546
|
+
);
|
|
547
|
+
}
|
|
476
548
|
if (probed && r.project?.wouldEmit !== null && r.project?.wouldEmit !== undefined) {
|
|
477
549
|
const needs = r.project.needsConfig;
|
|
478
550
|
marks.push(
|
|
@@ -487,9 +559,16 @@ export function renderCatalogText(rows: CatalogRow[], probed: boolean): string {
|
|
|
487
559
|
}
|
|
488
560
|
const suffix = marks.length > 0 ? ` [${marks.join(", ")}]` : "";
|
|
489
561
|
lines.push(` ${r.name.padEnd(width)} — ${r.description}${suffix}`);
|
|
562
|
+
if (r.note !== undefined) lines.push(` ${" ".repeat(width)} ${r.note}`);
|
|
490
563
|
if (r.requires !== undefined && r.requires.length > 0) {
|
|
491
564
|
lines.push(` ${" ".repeat(width)} requires: ${r.requires.join(", ")}`);
|
|
492
565
|
}
|
|
566
|
+
// The import that runs it as shipped. Not shown once the project owns a copy: its
|
|
567
|
+
// wiring is then the local import `meta eject` printed, and showing the package's
|
|
568
|
+
// beside an `owned` mark invites wiring both.
|
|
569
|
+
if (r.wire !== undefined && r.source.owned !== true) {
|
|
570
|
+
lines.push(` ${" ".repeat(width)} ${r.wire.import}`);
|
|
571
|
+
}
|
|
493
572
|
}
|
|
494
573
|
|
|
495
574
|
// The library section sits between the generators and the footer: the footer's
|
|
@@ -498,8 +577,9 @@ export function renderCatalogText(rows: CatalogRow[], probed: boolean): string {
|
|
|
498
577
|
lines.push(...renderLibraryText(rows.filter((r): r is LibraryCatalogRow => r.kind === "library")));
|
|
499
578
|
|
|
500
579
|
lines.push("");
|
|
501
|
-
lines.push("
|
|
502
|
-
lines.push("
|
|
580
|
+
lines.push("To run a generator as shipped, add the import under its row and call it in");
|
|
581
|
+
lines.push("`generators: [...]`. To change what one emits, `meta eject <name...>` copies it into");
|
|
582
|
+
lines.push("codegen/generators/ and prints the import to swap in, the entry to wire, and what to install.");
|
|
503
583
|
if (generators.some((r) => !r.source.ejectable)) lines.push(PACKAGE_ONLY_NOTE);
|
|
504
584
|
if (!probed) {
|
|
505
585
|
lines.push("Add --probe to see how many files each would emit for YOUR model.");
|
package/src/lib/catalog.ts
CHANGED
|
@@ -21,11 +21,24 @@ import {
|
|
|
21
21
|
import { reactGeneratorRegistry } from "@metaobjectsdev/codegen-ts-react";
|
|
22
22
|
import { tanstackGeneratorRegistry } from "@metaobjectsdev/codegen-ts-tanstack";
|
|
23
23
|
|
|
24
|
-
/**
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
/**
|
|
25
|
+
* The engine package. Its factories are served from a `/generators` subpath rather than
|
|
26
|
+
* its root (the root is the engine plus the primitives an owned generator composes); the
|
|
27
|
+
* framework packages serve theirs from the root. Exported because `eject.ts`'s source
|
|
28
|
+
* table names the same package — one definition per CLI package, not two.
|
|
29
|
+
*/
|
|
30
|
+
export const CORE_CODEGEN_PACKAGE = "@metaobjectsdev/codegen-ts";
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The slices, in install-boundary order: the engine, then its framework packages. The
|
|
34
|
+
* third element is the module that package serves factories from — a per-package fact
|
|
35
|
+
* declared at registration, so {@link factoryModuleOf} is a lookup and a new slice
|
|
36
|
+
* carries its own fact instead of adding a case to a name-keyed branch.
|
|
37
|
+
*/
|
|
38
|
+
const SLICES: ReadonlyArray<readonly [string, Record<string, GeneratorRegistryEntry>, string]> = [
|
|
39
|
+
[CORE_CODEGEN_PACKAGE, generatorRegistry, `${CORE_CODEGEN_PACKAGE}/generators`],
|
|
40
|
+
["@metaobjectsdev/codegen-ts-react", reactGeneratorRegistry, "@metaobjectsdev/codegen-ts-react"],
|
|
41
|
+
["@metaobjectsdev/codegen-ts-tanstack", tanstackGeneratorRegistry, "@metaobjectsdev/codegen-ts-tanstack"],
|
|
29
42
|
];
|
|
30
43
|
|
|
31
44
|
/**
|
|
@@ -44,6 +57,38 @@ export function catalogPackages(): string[] {
|
|
|
44
57
|
return SLICES.map(([pkg]) => pkg);
|
|
45
58
|
}
|
|
46
59
|
|
|
60
|
+
/**
|
|
61
|
+
* The module a catalog entry's factory is imported from to run it as shipped — the third
|
|
62
|
+
* element of the slice that registers the name. Undefined for a name no slice registers.
|
|
63
|
+
*/
|
|
64
|
+
export function factoryModuleOf(name: string): string | undefined {
|
|
65
|
+
return SLICES.find(([, slice]) => name in slice)?.[2];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* How one generator reaches a config as shipped: the import line for its factory. The
|
|
70
|
+
* call is not derived here — a factory's options are documented with the generator.
|
|
71
|
+
*/
|
|
72
|
+
export interface GeneratorWiring {
|
|
73
|
+
import: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* How to wire a catalog entry AS SHIPPED: import its factory from the package, no copy.
|
|
78
|
+
*
|
|
79
|
+
* This is the half of "import by default, eject to customize" the catalog owns. The
|
|
80
|
+
* other half is `meta eject`, which prints the import for the owned copy — the symbol is
|
|
81
|
+
* the same in both (gated), so moving between them is one import line.
|
|
82
|
+
*
|
|
83
|
+
* Every entry has one, documentation included (ADR-0034 Amendment 9): there is one way to
|
|
84
|
+
* generate, and an entry is wired the same way whatever it writes.
|
|
85
|
+
*/
|
|
86
|
+
export function packagedWiring(entry: GeneratorRegistryEntry): GeneratorWiring | undefined {
|
|
87
|
+
const from = factoryModuleOf(entry.name);
|
|
88
|
+
if (from === undefined) return undefined;
|
|
89
|
+
return { import: `import { ${entry.factoryExport} } from "${from}";` };
|
|
90
|
+
}
|
|
91
|
+
|
|
47
92
|
/**
|
|
48
93
|
* The composed catalog, keyed by stable name.
|
|
49
94
|
*
|
|
@@ -54,7 +99,7 @@ export function catalogPackages(): string[] {
|
|
|
54
99
|
* another.
|
|
55
100
|
*/
|
|
56
101
|
export function composeCatalog(): Record<string, GeneratorRegistryEntry> {
|
|
57
|
-
return composeSlices(SLICES);
|
|
102
|
+
return composeSlices(SLICES.map(([pkg, slice]) => [pkg, slice] as const));
|
|
58
103
|
}
|
|
59
104
|
|
|
60
105
|
/**
|