@metaobjectsdev/cli 0.23.2 → 0.24.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/README.md +78 -0
- package/dist/src/commands/docs.d.ts.map +1 -1
- package/dist/src/commands/docs.js +148 -50
- package/dist/src/commands/docs.js.map +1 -1
- package/dist/src/commands/export.d.ts.map +1 -1
- package/dist/src/commands/export.js +28 -6
- package/dist/src/commands/export.js.map +1 -1
- package/dist/src/commands/gen.d.ts.map +1 -1
- package/dist/src/commands/gen.js +61 -22
- package/dist/src/commands/gen.js.map +1 -1
- package/dist/src/commands/init.d.ts +8 -0
- package/dist/src/commands/init.d.ts.map +1 -1
- package/dist/src/commands/init.js +142 -52
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/migrate.d.ts +9 -2
- package/dist/src/commands/migrate.d.ts.map +1 -1
- package/dist/src/commands/migrate.js +399 -73
- package/dist/src/commands/migrate.js.map +1 -1
- package/dist/src/commands/prompt-snapshot.d.ts.map +1 -1
- package/dist/src/commands/prompt-snapshot.js +40 -18
- package/dist/src/commands/prompt-snapshot.js.map +1 -1
- package/dist/src/commands/upgrade.d.ts +2 -0
- package/dist/src/commands/upgrade.d.ts.map +1 -0
- package/dist/src/commands/upgrade.js +139 -0
- package/dist/src/commands/upgrade.js.map +1 -0
- package/dist/src/commands/verify.d.ts.map +1 -1
- package/dist/src/commands/verify.js +336 -48
- package/dist/src/commands/verify.js.map +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +46 -15
- package/dist/src/index.js.map +1 -1
- package/dist/src/lib/allow.d.ts.map +1 -1
- package/dist/src/lib/allow.js +4 -0
- package/dist/src/lib/allow.js.map +1 -1
- package/dist/src/lib/args.d.ts +16 -2
- package/dist/src/lib/args.d.ts.map +1 -1
- package/dist/src/lib/args.js +19 -3
- package/dist/src/lib/args.js.map +1 -1
- package/dist/src/lib/codegen-drift.d.ts +8 -1
- package/dist/src/lib/codegen-drift.d.ts.map +1 -1
- package/dist/src/lib/codegen-drift.js +9 -1
- package/dist/src/lib/codegen-drift.js.map +1 -1
- package/dist/src/lib/detect-stack.d.ts +1 -1
- package/dist/src/lib/detect-stack.d.ts.map +1 -1
- package/dist/src/lib/detect-stack.js +22 -37
- package/dist/src/lib/detect-stack.js.map +1 -1
- package/dist/src/lib/load-metaobjects-config.d.ts +48 -1
- package/dist/src/lib/load-metaobjects-config.d.ts.map +1 -1
- package/dist/src/lib/load-metaobjects-config.js +80 -1
- package/dist/src/lib/load-metaobjects-config.js.map +1 -1
- package/dist/src/lib/manifest-ignored-check.d.ts +12 -0
- package/dist/src/lib/manifest-ignored-check.d.ts.map +1 -0
- package/dist/src/lib/manifest-ignored-check.js +74 -0
- package/dist/src/lib/manifest-ignored-check.js.map +1 -0
- package/dist/src/lib/migrate-scope.d.ts +49 -0
- package/dist/src/lib/migrate-scope.d.ts.map +1 -0
- package/dist/src/lib/migrate-scope.js +92 -0
- package/dist/src/lib/migrate-scope.js.map +1 -0
- package/dist/src/lib/output.d.ts +1 -1
- package/dist/src/lib/output.d.ts.map +1 -1
- package/dist/src/lib/output.js +9 -3
- package/dist/src/lib/output.js.map +1 -1
- package/dist/src/lib/requirement-check.d.ts.map +1 -1
- package/dist/src/lib/requirement-check.js +10 -57
- package/dist/src/lib/requirement-check.js.map +1 -1
- package/package.json +11 -11
- package/src/commands/docs.ts +158 -49
- package/src/commands/export.ts +30 -6
- package/src/commands/gen.ts +62 -22
- package/src/commands/init.ts +161 -58
- package/src/commands/migrate.ts +423 -75
- package/src/commands/prompt-snapshot.ts +43 -18
- package/src/commands/upgrade.ts +156 -0
- package/src/commands/verify.ts +373 -48
- package/src/index.ts +46 -15
- package/src/lib/allow.ts +4 -0
- package/src/lib/args.ts +35 -4
- package/src/lib/codegen-drift.ts +9 -0
- package/src/lib/detect-stack.ts +20 -33
- package/src/lib/load-metaobjects-config.ts +84 -2
- package/src/lib/manifest-ignored-check.ts +75 -0
- package/src/lib/migrate-scope.ts +102 -0
- package/src/lib/output.ts +8 -4
- package/src/lib/requirement-check.ts +10 -58
- package/dist/src/lib/verified-by-scan.d.ts +0 -20
- package/dist/src/lib/verified-by-scan.d.ts.map +0 -1
- package/dist/src/lib/verified-by-scan.js +0 -344
- package/dist/src/lib/verified-by-scan.js.map +0 -1
- package/src/lib/verified-by-scan.ts +0 -375
|
@@ -14,8 +14,8 @@ import { parsePromptSnapshotArgs } from "../lib/args.js";
|
|
|
14
14
|
import { log } from "../lib/log.js";
|
|
15
15
|
import { FileProvider } from "../lib/file-provider.js";
|
|
16
16
|
import { snapshotPaths, unifiedDiff } from "../lib/snapshot.js";
|
|
17
|
-
import { loadMetaobjectsConfig } from "../lib/load-metaobjects-config.js";
|
|
18
|
-
import { loadMemory } from "@metaobjectsdev/sdk";
|
|
17
|
+
import { loadMemoryOptionsFrom, loadMetaobjectsConfig, resolveGenConfigDir } from "../lib/load-metaobjects-config.js";
|
|
18
|
+
import { loadMemory, resolveCollection } from "@metaobjectsdev/sdk";
|
|
19
19
|
import { TYPE_TEMPLATE, TEMPLATE_ATTR_TEXT_REF, TEMPLATE_ATTR_FORMAT } from "@metaobjectsdev/metadata";
|
|
20
20
|
import { render, ESCAPERS, type RenderFormat } from "@metaobjectsdev/render";
|
|
21
21
|
|
|
@@ -30,34 +30,59 @@ export async function promptSnapshotCommand(args: string[], cwd: string): Promis
|
|
|
30
30
|
return 2;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
//
|
|
34
|
-
//
|
|
33
|
+
// Where the metadata lives is `resolveCollection`'s decision, not this
|
|
34
|
+
// command's — `--check` is a drift GATE, so a project declaring `sources`
|
|
35
|
+
// elsewhere would otherwise gate against a stale `metaobjects/` (or report
|
|
36
|
+
// "no metaobjects/ found" for metadata it can see perfectly well). Discovery
|
|
37
|
+
// and load stay separate failure modes, the `meta gen` pattern: a broad catch
|
|
38
|
+
// around both reports a genuine ParseError as "no metadata found".
|
|
39
|
+
// `resolveCollection` raises ERR_COLLECTION_NOT_FOUND with its own message,
|
|
40
|
+
// replacing the hand-rolled ENOENT sniff that used to live here.
|
|
41
|
+
let collection;
|
|
42
|
+
try {
|
|
43
|
+
collection = await resolveCollection(cwd);
|
|
44
|
+
} catch (err) {
|
|
45
|
+
log.error((err as Error).message);
|
|
46
|
+
return 2;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Everything project-relative below hangs off the DECLARING directory, not
|
|
50
|
+
// ambient cwd: `.metaobjects/snapshots/` is that config's own state, and the
|
|
51
|
+
// prompt text belongs to the same project as the metadata that references it.
|
|
52
|
+
// Identical to cwd for a run from the project root, which is the only
|
|
53
|
+
// invocation that worked before metadata sources were resolvable at all.
|
|
54
|
+
const projectRoot = collection.configDir;
|
|
55
|
+
|
|
56
|
+
// Best-effort load of metaobjects.config.ts to pick up consumer-supplied providers
|
|
57
|
+
// and shipped `libraries`. prompt-snapshot doesn't require codegen config; if it's absent
|
|
35
58
|
// or invalid, fall back to defaults — the loader still works for any
|
|
36
59
|
// metadata that only uses core+forge subtypes.
|
|
37
|
-
let
|
|
60
|
+
let configLoadOptions: ReturnType<typeof loadMemoryOptionsFrom> = {};
|
|
38
61
|
try {
|
|
39
|
-
|
|
40
|
-
|
|
62
|
+
// `metaobjects.config.ts` gets its own nearest-ancestor walk, not `projectRoot`:
|
|
63
|
+
// it answers a different question from `.metaobjects/config.json` (design §4.6)
|
|
64
|
+
// and in a Maven- or pip-rooted monorepo the two legitimately sit in different
|
|
65
|
+
// directories, so reading it from the collection's would silently drop this
|
|
66
|
+
// package's providers (#326). Same path whenever the two files sit together.
|
|
67
|
+
configLoadOptions = loadMemoryOptionsFrom(
|
|
68
|
+
await loadMetaobjectsConfig(resolveGenConfigDir(cwd, projectRoot)),
|
|
69
|
+
);
|
|
41
70
|
} catch {
|
|
42
|
-
|
|
71
|
+
configLoadOptions = {};
|
|
43
72
|
}
|
|
44
73
|
|
|
45
74
|
let root;
|
|
46
75
|
try {
|
|
47
|
-
root = await loadMemory(
|
|
48
|
-
|
|
76
|
+
root = await loadMemory(collection.configDir, {
|
|
77
|
+
files: collection.files,
|
|
78
|
+
...configLoadOptions,
|
|
49
79
|
});
|
|
50
80
|
} catch (err) {
|
|
51
|
-
|
|
52
|
-
if (msg.includes("ENOENT") || msg.includes("no such") || msg.includes("cannot read")) {
|
|
53
|
-
log.error(`no metaobjects/ found in ${cwd}; run 'meta init' to scaffold`);
|
|
54
|
-
return 2;
|
|
55
|
-
}
|
|
56
|
-
log.error(`failed to load metadata: ${msg}`);
|
|
81
|
+
log.error(`failed to load metadata: ${(err as Error).message}`);
|
|
57
82
|
return 1;
|
|
58
83
|
}
|
|
59
84
|
|
|
60
|
-
const promptsDir = join(
|
|
85
|
+
const promptsDir = join(projectRoot, flags.prompts ?? DEFAULT_PROMPTS_DIR);
|
|
61
86
|
const provider = new FileProvider(promptsDir);
|
|
62
87
|
|
|
63
88
|
// ADR-0039: effective children — resolve rather than rely on root being unextended.
|
|
@@ -79,7 +104,7 @@ export async function promptSnapshotCommand(args: string[], cwd: string): Promis
|
|
|
79
104
|
// Absent/typeless required attrs are a loader-schema concern, not ours.
|
|
80
105
|
if (typeof textRef !== "string") continue;
|
|
81
106
|
|
|
82
|
-
const { dir, payloadPath, snapPath } = snapshotPaths(
|
|
107
|
+
const { dir, payloadPath, snapPath } = snapshotPaths(projectRoot, tmpl.name);
|
|
83
108
|
if (!existsSync(payloadPath)) {
|
|
84
109
|
log.info(`[${tmpl.name}] skipped — no payload at ${payloadPath}`);
|
|
85
110
|
skipped++;
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
// server/typescript/packages/cli/src/commands/upgrade.ts
|
|
2
|
+
//
|
|
3
|
+
// `meta upgrade` — rewrite retired vocabulary in this project's metadata.
|
|
4
|
+
//
|
|
5
|
+
// DELIBERATELY NOT `meta migrate`. That command owns DATABASE SCHEMA (ADR-0015) and an
|
|
6
|
+
// adopter reading `migrate` expects DDL. Overloading it with a metadata rewrite would make
|
|
7
|
+
// the most destructive command in the toolchain ambiguous about what it touches.
|
|
8
|
+
//
|
|
9
|
+
// IT DOES NOT LOAD THE METADATA, and cannot. Once vocabulary is deregistered, metadata
|
|
10
|
+
// carrying it fails the load — which is exactly the state this command exists to repair. So
|
|
11
|
+
// it resolves the file SET through `resolveCollection` (the single authority on where
|
|
12
|
+
// metadata lives) and hands each file's RAW TEXT to the rewriter. See
|
|
13
|
+
// `metadata/src/vocabulary-rewrite.ts` for why that is the only workable shape.
|
|
14
|
+
//
|
|
15
|
+
// DRY-RUN BY DEFAULT, per this repo's convention for anything that edits committed files.
|
|
16
|
+
// `--apply` writes. Refusals exit NON-ZERO even when every mechanical change succeeded, so
|
|
17
|
+
// CI cannot mistake a partial upgrade for a finished one.
|
|
18
|
+
|
|
19
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
20
|
+
import { extname, relative } from "node:path";
|
|
21
|
+
import { resolveCollection } from "@metaobjectsdev/sdk";
|
|
22
|
+
import { rewriteDocument } from "@metaobjectsdev/metadata";
|
|
23
|
+
import { log } from "../lib/log.js";
|
|
24
|
+
|
|
25
|
+
/** Authoring formats the rewriter cannot edit — see `vocabulary-rewrite.ts` for why. */
|
|
26
|
+
const UNREWRITABLE_EXTENSIONS = new Set([".yaml", ".yml"]);
|
|
27
|
+
|
|
28
|
+
interface UpgradeFlags {
|
|
29
|
+
apply: boolean;
|
|
30
|
+
maxVersion?: string;
|
|
31
|
+
projectRoot?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function parseArgs(argv: string[]): UpgradeFlags {
|
|
35
|
+
const flags: UpgradeFlags = { apply: false };
|
|
36
|
+
for (let i = 0; i < argv.length; i++) {
|
|
37
|
+
const a = argv[i] as string;
|
|
38
|
+
if (a === "--apply") flags.apply = true;
|
|
39
|
+
else if (a === "--to") {
|
|
40
|
+
const v = argv[++i];
|
|
41
|
+
if (v === undefined) throw new Error("--to needs a version");
|
|
42
|
+
flags.maxVersion = v;
|
|
43
|
+
} else if (a.startsWith("--to=")) flags.maxVersion = a.slice("--to=".length);
|
|
44
|
+
else if (a === "--help" || a === "-h") throw new Error("__help__");
|
|
45
|
+
else if (!a.startsWith("-")) flags.projectRoot = a;
|
|
46
|
+
else throw new Error(`unknown option: ${a}`);
|
|
47
|
+
}
|
|
48
|
+
return flags;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export async function upgradeCommand(args: string[], cwd: string): Promise<number> {
|
|
52
|
+
let flags: UpgradeFlags;
|
|
53
|
+
try {
|
|
54
|
+
flags = parseArgs(args);
|
|
55
|
+
} catch (err) {
|
|
56
|
+
if ((err as Error).message === "__help__") {
|
|
57
|
+
log.info(
|
|
58
|
+
"meta upgrade [<project>] [--to <version>] [--apply]\n\n" +
|
|
59
|
+
" Rewrites retired metadata vocabulary. Previews by default; --apply writes.\n" +
|
|
60
|
+
" Retirements needing a human decision are REFUSED and listed with their guide.",
|
|
61
|
+
);
|
|
62
|
+
return 0;
|
|
63
|
+
}
|
|
64
|
+
log.error((err as Error).message);
|
|
65
|
+
return 2;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const projectRoot = flags.projectRoot ?? cwd;
|
|
69
|
+
|
|
70
|
+
let files: readonly string[];
|
|
71
|
+
try {
|
|
72
|
+
files = (await resolveCollection(projectRoot)).files;
|
|
73
|
+
} catch (err) {
|
|
74
|
+
log.error((err as Error).message);
|
|
75
|
+
return 1;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
let totalChanges = 0;
|
|
79
|
+
let totalRefusals = 0;
|
|
80
|
+
let filesChanged = 0;
|
|
81
|
+
const skipped: string[] = [];
|
|
82
|
+
|
|
83
|
+
for (const file of files) {
|
|
84
|
+
const rel = relative(projectRoot, file);
|
|
85
|
+
|
|
86
|
+
// A file we cannot rewrite is NAMED, never passed over. Silently skipping it is the
|
|
87
|
+
// failure this command exists to prevent: the adopter runs the documented migration,
|
|
88
|
+
// reads "no retired vocabulary found", and ships metadata that does not load.
|
|
89
|
+
if (UNREWRITABLE_EXTENSIONS.has(extname(file).toLowerCase())) {
|
|
90
|
+
skipped.push(rel);
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const before = await readFile(file, "utf8");
|
|
95
|
+
const r = rewriteDocument(before, {
|
|
96
|
+
...(flags.maxVersion !== undefined ? { maxVersion: flags.maxVersion } : {}),
|
|
97
|
+
});
|
|
98
|
+
if (r.changes.length === 0 && r.refusals.length === 0) continue;
|
|
99
|
+
|
|
100
|
+
log.info(`\n${rel}`);
|
|
101
|
+
for (const c of r.changes) log.info(` ${c.line}: @${c.from} → ${c.to}`);
|
|
102
|
+
for (const f of r.refusals) {
|
|
103
|
+
log.warn(
|
|
104
|
+
` ${f.line}: ${f.subject}${f.value !== undefined ? `: ${f.value}` : ""} — needs a decision. ` +
|
|
105
|
+
`Retired in ${f.since}. ${f.migration !== undefined ? `See ${f.migration}` : f.why}`,
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
totalChanges += r.changes.length;
|
|
110
|
+
totalRefusals += r.refusals.length;
|
|
111
|
+
if (r.changes.length > 0) {
|
|
112
|
+
filesChanged++;
|
|
113
|
+
if (flags.apply) await writeFile(file, r.text, "utf8");
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
log.info("");
|
|
118
|
+
if (skipped.length > 0) {
|
|
119
|
+
log.warn(
|
|
120
|
+
`${skipped.length} YAML file(s) cannot be rewritten automatically and were NOT ` +
|
|
121
|
+
`checked — migrate them by hand:\n ${skipped.join("\n ")}`,
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (totalChanges === 0 && totalRefusals === 0) {
|
|
126
|
+
log.info(
|
|
127
|
+
skipped.length > 0
|
|
128
|
+
? "meta upgrade — no retired vocabulary found in the JSON metadata."
|
|
129
|
+
: "meta upgrade — no retired vocabulary found.",
|
|
130
|
+
);
|
|
131
|
+
} else if (totalChanges === 0) {
|
|
132
|
+
// Refusals only. Reporting "rewrote 0 declarations", or advertising `--apply`, both
|
|
133
|
+
// promise an action guaranteed to change nothing and bury the fact that the remaining
|
|
134
|
+
// work is entirely human.
|
|
135
|
+
log.info("meta upgrade — nothing here can be rewritten automatically.");
|
|
136
|
+
} else if (flags.apply) {
|
|
137
|
+
log.info(`meta upgrade — rewrote ${totalChanges} declaration(s) across ${filesChanged} file(s).`);
|
|
138
|
+
} else {
|
|
139
|
+
log.info(
|
|
140
|
+
`meta upgrade — ${totalChanges} declaration(s) in ${filesChanged} file(s) can be rewritten. ` +
|
|
141
|
+
`Re-run with --apply to write.`,
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Non-zero while ANY refusal stands, applied or not. A partial upgrade that exited 0 would
|
|
146
|
+
// let CI record the migration as done while metadata still fails to load. A file we could
|
|
147
|
+
// not read at all counts the same way, for the same reason.
|
|
148
|
+
if (totalRefusals > 0) {
|
|
149
|
+
log.error(
|
|
150
|
+
`${totalRefusals} declaration(s) need a human decision and were left untouched — ` +
|
|
151
|
+
`see the guides listed above.`,
|
|
152
|
+
);
|
|
153
|
+
return 1;
|
|
154
|
+
}
|
|
155
|
+
return skipped.length > 0 ? 1 : 0;
|
|
156
|
+
}
|