@metaobjectsdev/cli 1.0.10 → 1.0.12
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/src/commands/eject.d.ts.map +1 -1
- package/dist/src/commands/eject.js +5 -1
- package/dist/src/commands/eject.js.map +1 -1
- package/dist/src/commands/fmt.d.ts +2 -0
- package/dist/src/commands/fmt.d.ts.map +1 -0
- package/dist/src/commands/fmt.js +80 -0
- package/dist/src/commands/fmt.js.map +1 -0
- package/dist/src/commands/gen.d.ts.map +1 -1
- package/dist/src/commands/gen.js +7 -0
- package/dist/src/commands/gen.js.map +1 -1
- package/dist/src/commands/migrate.d.ts.map +1 -1
- package/dist/src/commands/migrate.js +1 -0
- package/dist/src/commands/migrate.js.map +1 -1
- package/dist/src/commands/verify.d.ts.map +1 -1
- package/dist/src/commands/verify.js +74 -1
- package/dist/src/commands/verify.js.map +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +76 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/lib/args.d.ts +36 -0
- package/dist/src/lib/args.d.ts.map +1 -1
- package/dist/src/lib/args.js +20 -0
- package/dist/src/lib/args.js.map +1 -1
- package/dist/src/lib/deprecation-lint.d.ts +11 -0
- package/dist/src/lib/deprecation-lint.d.ts.map +1 -0
- package/dist/src/lib/deprecation-lint.js +273 -0
- package/dist/src/lib/deprecation-lint.js.map +1 -0
- package/dist/src/lib/fk-index-advisory.d.ts.map +1 -1
- package/dist/src/lib/fk-index-advisory.js +4 -1
- package/dist/src/lib/fk-index-advisory.js.map +1 -1
- package/dist/src/lib/fmt-engine.d.ts +22 -0
- package/dist/src/lib/fmt-engine.d.ts.map +1 -0
- package/dist/src/lib/fmt-engine.js +128 -0
- package/dist/src/lib/fmt-engine.js.map +1 -0
- package/dist/src/lib/name-lint.d.ts +12 -0
- package/dist/src/lib/name-lint.d.ts.map +1 -0
- package/dist/src/lib/name-lint.js +95 -0
- package/dist/src/lib/name-lint.js.map +1 -0
- package/dist/src/lib/runtime-boundary-advisory.d.ts +24 -0
- package/dist/src/lib/runtime-boundary-advisory.d.ts.map +1 -0
- package/dist/src/lib/runtime-boundary-advisory.js +47 -0
- package/dist/src/lib/runtime-boundary-advisory.js.map +1 -0
- package/package.json +10 -10
- package/src/commands/eject.ts +6 -1
- package/src/commands/fmt.ts +90 -0
- package/src/commands/gen.ts +9 -0
- package/src/commands/migrate.ts +1 -0
- package/src/commands/verify.ts +90 -1
- package/src/index.ts +76 -0
- package/src/lib/args.ts +47 -0
- package/src/lib/deprecation-lint.ts +327 -0
- package/src/lib/fk-index-advisory.ts +4 -1
- package/src/lib/fmt-engine.ts +179 -0
- package/src/lib/name-lint.ts +106 -0
- package/src/lib/runtime-boundary-advisory.ts +74 -0
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type MetaData } from "@metaobjectsdev/metadata";
|
|
2
|
+
import type { Diagnostic } from "./requirement-check.js";
|
|
3
|
+
/** Leading or trailing whitespace — the strong finding. */
|
|
4
|
+
export declare const WARN_NAME_SURROUNDING_WHITESPACE = "WARN_NAME_SURROUNDING_WHITESPACE";
|
|
5
|
+
/** Whitespace inside an otherwise trimmed name — the plain advisory. */
|
|
6
|
+
export declare const WARN_NAME_INTERNAL_WHITESPACE = "WARN_NAME_INTERNAL_WHITESPACE";
|
|
7
|
+
/**
|
|
8
|
+
* Lint the name of every named node in the loaded model, requirements excepted.
|
|
9
|
+
* Returns `[]` for a model with no whitespace in any name.
|
|
10
|
+
*/
|
|
11
|
+
export declare function lintNodeNames(root: MetaData): Diagnostic[];
|
|
12
|
+
//# sourceMappingURL=name-lint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"name-lint.d.ts","sourceRoot":"","sources":["../../../src/lib/name-lint.ts"],"names":[],"mappings":"AAyBA,OAAO,EAAmD,KAAK,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAC1G,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEzD,2DAA2D;AAC3D,eAAO,MAAM,gCAAgC,qCAAqC,CAAC;AACnF,wEAAwE;AACxE,eAAO,MAAM,6BAA6B,kCAAkC,CAAC;AAuD7E;;;GAGG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,QAAQ,GAAG,UAAU,EAAE,CAe1D"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
// `meta verify` — the node-name AUTHORING lint.
|
|
2
|
+
//
|
|
3
|
+
// The loader accepts any string as a node `name`, on every port. An adopter's metadata
|
|
4
|
+
// carried a field named `"defaultCurrencyId "` (a trailing space, copied from legacy XML)
|
|
5
|
+
// and an identity named `"account_defaultCurrencyId _fk"`; both loaded with no error.
|
|
6
|
+
//
|
|
7
|
+
// WHY THIS IS A WARNING AND NOT A LOAD ERROR. It was weighed against the correction bar
|
|
8
|
+
// in docs/compatibility-policy.md and does not pass it: whitespace names WORK today on
|
|
9
|
+
// the core path — `meta migrate` emits a quoted column (`"default_currency_id "`) and the
|
|
10
|
+
// ObjectManager round-trips the key — and multi-word requirement names are documented to
|
|
11
|
+
// load. Refusing them at load would break metadata that does what its author asked, so
|
|
12
|
+
// the honest instrument is an advisory that names the edit.
|
|
13
|
+
//
|
|
14
|
+
// EVERY FINDING IS A WARNING, BY CONSTRUCTION — the same rule, and the same reasoning,
|
|
15
|
+
// as requirement-lint.ts's header. Nothing here reaches the exit code.
|
|
16
|
+
//
|
|
17
|
+
// REQUIREMENTS ARE NOT LINTED HERE. A requirement's name is its dotted ADDRESS and the
|
|
18
|
+
// requirement lint already owns it (WARN_REQUIREMENT_NAME_NOT_ADDRESSABLE reports
|
|
19
|
+
// leading/trailing whitespace; a short multi-word label such as "Order Recording" is
|
|
20
|
+
// deliberately NOT reported, because renaming one moves its address and its emitted
|
|
21
|
+
// stub file for no gain). Reporting the same name twice under two codes would make
|
|
22
|
+
// one edit look like two problems.
|
|
23
|
+
//
|
|
24
|
+
// IT READS THE LOADED MODEL, NEVER THE FILES — and walks DECLARATIONS (see `walk`).
|
|
25
|
+
import { PACKAGE_SEPARATOR, TYPE_FIELD, TYPE_REQUIREMENT } from "@metaobjectsdev/metadata";
|
|
26
|
+
/** Leading or trailing whitespace — the strong finding. */
|
|
27
|
+
export const WARN_NAME_SURROUNDING_WHITESPACE = "WARN_NAME_SURROUNDING_WHITESPACE";
|
|
28
|
+
/** Whitespace inside an otherwise trimmed name — the plain advisory. */
|
|
29
|
+
export const WARN_NAME_INTERNAL_WHITESPACE = "WARN_NAME_INTERNAL_WHITESPACE";
|
|
30
|
+
/**
|
|
31
|
+
* What counts as whitespace: the ECMAScript `\s` class. That is ASCII space, tab, LF,
|
|
32
|
+
* CR, VT and FF, plus U+00A0 (no-break space), U+FEFF, U+1680, U+2000–U+200A, U+2028,
|
|
33
|
+
* U+2029, U+202F, U+205F and U+3000. The non-ASCII members matter for this lint's
|
|
34
|
+
* actual source of input: a no-break space survives a copy out of a document or a
|
|
35
|
+
* legacy export and is invisible in every editor.
|
|
36
|
+
*/
|
|
37
|
+
const WHITESPACE = /\s/u;
|
|
38
|
+
function warn(path, code, message) {
|
|
39
|
+
return { severity: "warn", code, path, message };
|
|
40
|
+
}
|
|
41
|
+
/** One segment of a node's address. A name with whitespace is quoted so the
|
|
42
|
+
* whitespace is visible in the printed path rather than vanishing into it. */
|
|
43
|
+
function segment(name) {
|
|
44
|
+
return WHITESPACE.test(name) ? JSON.stringify(name) : name;
|
|
45
|
+
}
|
|
46
|
+
function check(node, path, out) {
|
|
47
|
+
const name = node.name;
|
|
48
|
+
if (name === "" || !WHITESPACE.test(name))
|
|
49
|
+
return;
|
|
50
|
+
const kind = `${node.type}.${node.subType}`;
|
|
51
|
+
const quoted = JSON.stringify(name);
|
|
52
|
+
// @column is a FIELD attribute. Advising an object or identity author to pin it
|
|
53
|
+
// would send them looking for a slot that does not exist on the node.
|
|
54
|
+
const pin = node.type === TYPE_FIELD ? ", and pin @column if the physical column must keep its name" : "";
|
|
55
|
+
const trimmed = name.trim();
|
|
56
|
+
if (trimmed !== name) {
|
|
57
|
+
const inner = WHITESPACE.test(trimmed) ? " It also contains whitespace inside it." : "";
|
|
58
|
+
const target = trimmed === "" ? "" : ` (to ${JSON.stringify(trimmed)}, presumably)`;
|
|
59
|
+
out.push(warn(path, WARN_NAME_SURROUNDING_WHITESPACE, `${kind} name ${quoted} has leading or trailing whitespace, which is almost certainly ` +
|
|
60
|
+
`unintended — rename it${target}${pin}. The whitespace is carried into every identifier, ` +
|
|
61
|
+
`column and wire key derived from the name.${inner}`));
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
out.push(warn(path, WARN_NAME_INTERNAL_WHITESPACE, `${kind} name ${quoted} contains whitespace. A name is an identifier: derived column names ` +
|
|
65
|
+
`and wire keys carry the space, and generated code cannot use it as one. Consider ` +
|
|
66
|
+
`renaming it${pin}.`));
|
|
67
|
+
}
|
|
68
|
+
/** A root-level node's address: package-qualified the way `resolutionKey()` is, so the
|
|
69
|
+
* path reads like every other reference to the node. */
|
|
70
|
+
function topLevelAddress(node) {
|
|
71
|
+
const pkg = node.package ?? node.fileDefaultPackage;
|
|
72
|
+
return pkg !== undefined && pkg !== "" ? `${pkg}${PACKAGE_SEPARATOR}${segment(node.name)}` : segment(node.name);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Lint the name of every named node in the loaded model, requirements excepted.
|
|
76
|
+
* Returns `[]` for a model with no whitespace in any name.
|
|
77
|
+
*/
|
|
78
|
+
export function lintNodeNames(root) {
|
|
79
|
+
const out = [];
|
|
80
|
+
const walk = (n, prefix) => {
|
|
81
|
+
// OWN-ONLY (ADR-0039 sanctioned case): this reports each DECLARATION once, at the
|
|
82
|
+
// node that declares it. A field inherited through `extends` is one declaration and
|
|
83
|
+
// one rename; the resolving `children()` would repeat it on every subtype.
|
|
84
|
+
for (const c of n.ownChildren()) {
|
|
85
|
+
if (c.type === TYPE_REQUIREMENT)
|
|
86
|
+
continue; // owned by requirement-lint.ts — see header
|
|
87
|
+
const path = prefix === "" ? topLevelAddress(c) : `${prefix}.${segment(c.name)}`;
|
|
88
|
+
check(c, path, out);
|
|
89
|
+
walk(c, path);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
walk(root, "");
|
|
93
|
+
return out;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=name-lint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"name-lint.js","sourceRoot":"","sources":["../../../src/lib/name-lint.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generated code that imports the owned HTTP-adapter copy from OUTSIDE its own
|
|
3
|
+
* workspace package.
|
|
4
|
+
*
|
|
5
|
+
* Since 1.0.9 an ejected `entity` / `routes` / `routes-hono` generator points its output
|
|
6
|
+
* at `codegen/runtime/` (the adapter source `meta eject` copied) by a path relative to
|
|
7
|
+
* the output directory. In a single-package project that is exactly right. In a monorepo
|
|
8
|
+
* whose output sits inside a workspace package (`apps/api/src/generated`), the path climbs
|
|
9
|
+
* out of that package: `tsc` rejects the file (`TS6059 … is not under 'rootDir'`), and the
|
|
10
|
+
* copy's own bare imports (`qs`, `fastify`) do not resolve from the repository root. The
|
|
11
|
+
* `meta gen` run itself is green; the adopter's build is the first thing that disagrees.
|
|
12
|
+
*
|
|
13
|
+
* Found upgrading a pnpm monorepo. This names the package and the two ways out. It is a
|
|
14
|
+
* warning and never changes an exit code.
|
|
15
|
+
*/
|
|
16
|
+
export interface RuntimeBoundaryFinding {
|
|
17
|
+
/** Project-relative directory of the workspace package the generated file sits in. */
|
|
18
|
+
packageDir: string;
|
|
19
|
+
/** One generated file (project-relative) that crosses the boundary. */
|
|
20
|
+
example: string;
|
|
21
|
+
}
|
|
22
|
+
export declare function findRuntimeBoundaryCrossings(projectRoot: string, generatedFiles: readonly string[]): RuntimeBoundaryFinding[];
|
|
23
|
+
export declare function runtimeBoundaryWarnings(findings: readonly RuntimeBoundaryFinding[]): string[];
|
|
24
|
+
//# sourceMappingURL=runtime-boundary-advisory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-boundary-advisory.d.ts","sourceRoot":"","sources":["../../../src/lib/runtime-boundary-advisory.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,sBAAsB;IACrC,sFAAsF;IACtF,UAAU,EAAE,MAAM,CAAC;IACnB,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;CACjB;AAeD,wBAAgB,4BAA4B,CAC1C,WAAW,EAAE,MAAM,EACnB,cAAc,EAAE,SAAS,MAAM,EAAE,GAChC,sBAAsB,EAAE,CAqB1B;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,SAAS,sBAAsB,EAAE,GAAG,MAAM,EAAE,CAQ7F"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { dirname, join, relative, resolve, sep } from "node:path";
|
|
3
|
+
import { OWNED_RUNTIME_DIR, HTTP_RUNTIME_PACKAGE } from "@metaobjectsdev/codegen-ts";
|
|
4
|
+
const IMPORT_SPEC = /\bfrom\s+["'](\.{1,2}\/[^"']+)["']/g;
|
|
5
|
+
function nearestPackageDir(fileDir, projectRoot) {
|
|
6
|
+
for (let d = fileDir;; d = dirname(d)) {
|
|
7
|
+
if (d === projectRoot || !d.startsWith(projectRoot + sep))
|
|
8
|
+
return undefined;
|
|
9
|
+
if (existsSync(join(d, "package.json")))
|
|
10
|
+
return d;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
function isInside(child, parent) {
|
|
14
|
+
return child === parent || child.startsWith(parent + sep);
|
|
15
|
+
}
|
|
16
|
+
export function findRuntimeBoundaryCrossings(projectRoot, generatedFiles) {
|
|
17
|
+
const root = resolve(projectRoot);
|
|
18
|
+
const runtimeRoot = join(root, OWNED_RUNTIME_DIR);
|
|
19
|
+
const byPackage = new Map();
|
|
20
|
+
for (const file of generatedFiles) {
|
|
21
|
+
if (!/\.(ts|tsx|mts)$/.test(file) || !existsSync(file))
|
|
22
|
+
continue;
|
|
23
|
+
const abs = resolve(file);
|
|
24
|
+
const pkgDir = nearestPackageDir(dirname(abs), root);
|
|
25
|
+
if (pkgDir === undefined || isInside(runtimeRoot, pkgDir) || byPackage.has(pkgDir))
|
|
26
|
+
continue;
|
|
27
|
+
const text = readFileSync(abs, "utf8");
|
|
28
|
+
for (const m of text.matchAll(IMPORT_SPEC)) {
|
|
29
|
+
if (isInside(resolve(dirname(abs), m[1]), runtimeRoot)) {
|
|
30
|
+
byPackage.set(pkgDir, {
|
|
31
|
+
packageDir: relative(root, pkgDir).split(sep).join("/"),
|
|
32
|
+
example: relative(root, abs).split(sep).join("/"),
|
|
33
|
+
});
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return [...byPackage.values()];
|
|
39
|
+
}
|
|
40
|
+
export function runtimeBoundaryWarnings(findings) {
|
|
41
|
+
return findings.map((f) => `generated code in ${f.packageDir}/ imports the owned HTTP adapter from ${OWNED_RUNTIME_DIR}/, ` +
|
|
42
|
+
`outside that workspace package (e.g. ${f.example}); its build will not resolve it. ` +
|
|
43
|
+
`Either keep importing the published adapter — pass \`runtimeImport: "${HTTP_RUNTIME_PACKAGE}"\` ` +
|
|
44
|
+
`to the ejected entity/routes generators — or move ${OWNED_RUNTIME_DIR}/ inside ${f.packageDir}/ ` +
|
|
45
|
+
`and point \`runtimeImport\` at it.`);
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=runtime-boundary-advisory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runtime-boundary-advisory.js","sourceRoot":"","sources":["../../../src/lib/runtime-boundary-advisory.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metaobjectsdev/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.12",
|
|
4
4
|
"description": "CLI for MetaObjects: scaffold, codegen, migrate, and drift-detection commands.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/src/index.js",
|
|
@@ -51,15 +51,15 @@
|
|
|
51
51
|
"@biomejs/js-api": "^0.7.0",
|
|
52
52
|
"@biomejs/wasm-nodejs": "^1.9.4",
|
|
53
53
|
"@libsql/kysely-libsql": "^0.4.0",
|
|
54
|
-
"@metaobjectsdev/codegen-ts": "1.0.
|
|
55
|
-
"@metaobjectsdev/codegen-ts-react": "1.0.
|
|
56
|
-
"@metaobjectsdev/codegen-ts-tanstack": "1.0.
|
|
57
|
-
"@metaobjectsdev/docs-site": "1.0.
|
|
58
|
-
"@metaobjectsdev/metadata": "1.0.
|
|
59
|
-
"@metaobjectsdev/migrate-ts": "1.0.
|
|
60
|
-
"@metaobjectsdev/render": "1.0.
|
|
61
|
-
"@metaobjectsdev/runtime-ts": "1.0.
|
|
62
|
-
"@metaobjectsdev/sdk": "1.0.
|
|
54
|
+
"@metaobjectsdev/codegen-ts": "1.0.12",
|
|
55
|
+
"@metaobjectsdev/codegen-ts-react": "1.0.12",
|
|
56
|
+
"@metaobjectsdev/codegen-ts-tanstack": "1.0.12",
|
|
57
|
+
"@metaobjectsdev/docs-site": "1.0.12",
|
|
58
|
+
"@metaobjectsdev/metadata": "1.0.12",
|
|
59
|
+
"@metaobjectsdev/migrate-ts": "1.0.12",
|
|
60
|
+
"@metaobjectsdev/render": "1.0.12",
|
|
61
|
+
"@metaobjectsdev/runtime-ts": "1.0.12",
|
|
62
|
+
"@metaobjectsdev/sdk": "1.0.12",
|
|
63
63
|
"@toon-format/toon": "^2.3.0",
|
|
64
64
|
"jiti": "^2.4.0"
|
|
65
65
|
},
|
package/src/commands/eject.ts
CHANGED
|
@@ -256,7 +256,12 @@ export async function ejectGenerator(opts: EjectOptions): Promise<EjectResult> {
|
|
|
256
256
|
// The adapter source the OUTPUT imports is part of what is handed over — copied whether
|
|
257
257
|
// or not the generator file itself was already here, and under the same never-clobber
|
|
258
258
|
// rule, so re-running eject fills in a missing copy without touching a kept one.
|
|
259
|
-
|
|
259
|
+
// Except when the KEPT copy predates that hand-over (1.0.9): with no `runtimeImport`
|
|
260
|
+
// option its output imports the published package, so the copy would be dead code —
|
|
261
|
+
// a Drizzle adapter, and its dependencies, in a project that may have no database.
|
|
262
|
+
const keptCopyImportsPackage =
|
|
263
|
+
existing !== undefined && !opts.force && !existing.includes("runtimeImport");
|
|
264
|
+
const runtime = ejectsRuntime(opts.name) && !keptCopyImportsPackage
|
|
260
265
|
? await ejectRuntime(opts.cwd, [opts.name], opts.force === true)
|
|
261
266
|
: undefined;
|
|
262
267
|
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// `meta fmt` (#304) — rewrite metadata files into the canonical form the
|
|
2
|
+
// cross-port canonical serializer already produces. `--check` lists the
|
|
3
|
+
// files that are not canonical and exits non-zero without changing anything.
|
|
4
|
+
//
|
|
5
|
+
// All of the actual work — file resolution, standalone per-file formatting,
|
|
6
|
+
// the YAML skip, and the whole-project reload-and-compare safety check — lives
|
|
7
|
+
// in `../lib/fmt-engine.js`, kept framework-free so it is unit-testable without
|
|
8
|
+
// spawning the CLI. This module is the thin text/exit-code front end.
|
|
9
|
+
import { relative } from "node:path";
|
|
10
|
+
import { parseFmtArgs } from "../lib/args.js";
|
|
11
|
+
import { log } from "../lib/log.js";
|
|
12
|
+
import { describeError } from "../lib/error-text.js";
|
|
13
|
+
import { runFmt, type FmtFileReport } from "../lib/fmt-engine.js";
|
|
14
|
+
|
|
15
|
+
function describe(report: FmtFileReport, cwd: string, check: boolean): string {
|
|
16
|
+
const rel = relative(cwd, report.path) || report.path;
|
|
17
|
+
switch (report.status) {
|
|
18
|
+
case "formatted":
|
|
19
|
+
return ` reformatted ${rel}`;
|
|
20
|
+
case "would-format":
|
|
21
|
+
return ` not canonical ${rel}`;
|
|
22
|
+
case "unchanged":
|
|
23
|
+
return ` ok ${rel}`;
|
|
24
|
+
case "skipped-yaml":
|
|
25
|
+
return ` skipped (yaml) ${rel} — ${report.detail}`;
|
|
26
|
+
case "skipped-overlay":
|
|
27
|
+
return ` skipped (overlay) ${rel} — this file declares an overlay fmt cannot resolve standalone`;
|
|
28
|
+
case "error":
|
|
29
|
+
return ` error ${rel} — ${report.detail}`;
|
|
30
|
+
default: {
|
|
31
|
+
const _exhaustive: never = report.status;
|
|
32
|
+
return _exhaustive;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export async function fmtCommand(args: string[], cwd: string): Promise<number> {
|
|
38
|
+
let flags;
|
|
39
|
+
try {
|
|
40
|
+
flags = parseFmtArgs(args);
|
|
41
|
+
} catch (err) {
|
|
42
|
+
log.error(describeError(err));
|
|
43
|
+
return 2;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const result = await runFmt({
|
|
47
|
+
projectRoot: cwd,
|
|
48
|
+
check: flags.check,
|
|
49
|
+
files: flags.files,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
if (result.fatal !== undefined) {
|
|
53
|
+
log.error(result.fatal);
|
|
54
|
+
return 1;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (result.files.length === 0) {
|
|
58
|
+
log.info("meta fmt — no metadata files to format.");
|
|
59
|
+
return 0;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
for (const report of result.files) {
|
|
63
|
+
log.info(describe(report, cwd, flags.check));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const errored = result.files.filter((f) => f.status === "error");
|
|
67
|
+
const needsFormat = result.files.filter((f) => f.status === "would-format");
|
|
68
|
+
const reformatted = result.files.filter((f) => f.status === "formatted");
|
|
69
|
+
|
|
70
|
+
if (flags.check) {
|
|
71
|
+
if (needsFormat.length > 0 || errored.length > 0) {
|
|
72
|
+
log.error(
|
|
73
|
+
`meta fmt --check — ${needsFormat.length} file(s) not canonical` +
|
|
74
|
+
(errored.length > 0 ? `, ${errored.length} error(s)` : "") +
|
|
75
|
+
`. Run \`meta fmt\` to fix.`,
|
|
76
|
+
);
|
|
77
|
+
return 1;
|
|
78
|
+
}
|
|
79
|
+
log.info("meta fmt --check — every file is already canonical.");
|
|
80
|
+
return 0;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (errored.length > 0) {
|
|
84
|
+
log.error(`meta fmt — ${errored.length} file(s) could not be formatted safely (left unchanged).`);
|
|
85
|
+
return 1;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
log.info(`meta fmt — ${reformatted.length} file(s) reformatted.`);
|
|
89
|
+
return 0;
|
|
90
|
+
}
|
package/src/commands/gen.ts
CHANGED
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
import { emitStructured } from "../lib/format.js";
|
|
31
31
|
import { composeCatalog } from "../lib/catalog.js";
|
|
32
32
|
import { describeError } from "../lib/error-text.js";
|
|
33
|
+
import { findRuntimeBoundaryCrossings, runtimeBoundaryWarnings } from "../lib/runtime-boundary-advisory.js";
|
|
33
34
|
|
|
34
35
|
/**
|
|
35
36
|
* Print a load failure with everything the loader's ADR-0009 envelope carried — the stable
|
|
@@ -235,6 +236,14 @@ export async function genCommand(args: string[], cwd: string, fmt: OutputFormat
|
|
|
235
236
|
info: "",
|
|
236
237
|
}));
|
|
237
238
|
|
|
239
|
+
// Advisory: generated code importing the owned adapter copy from outside its own
|
|
240
|
+
// workspace package (a monorepo) will not build. Warning only.
|
|
241
|
+
if (!cliConfig.dryRun) {
|
|
242
|
+
for (const w of runtimeBoundaryWarnings(
|
|
243
|
+
findRuntimeBoundaryCrossings(projectRoot, result.files.map((f) => f.path)),
|
|
244
|
+
)) log.warn(`warning: ${w}`);
|
|
245
|
+
}
|
|
246
|
+
|
|
238
247
|
const targetDirs = Array.from(new Set(
|
|
239
248
|
(forgeConfig.targets ? Object.values(forgeConfig.targets).map((t) => t.outDir) : [])
|
|
240
249
|
.concat([forgeConfig.outDir]),
|
package/src/commands/migrate.ts
CHANGED
package/src/commands/verify.ts
CHANGED
|
@@ -39,6 +39,8 @@ import {
|
|
|
39
39
|
} from "../lib/requirement-check.js";
|
|
40
40
|
import { lintRequirements } from "../lib/requirement-lint.js";
|
|
41
41
|
import { lintOverlays } from "../lib/overlay-lint.js";
|
|
42
|
+
import { lintNodeNames } from "../lib/name-lint.js";
|
|
43
|
+
import { lintDeprecatedReferences } from "../lib/deprecation-lint.js";
|
|
42
44
|
import { FileSource } from "@metaobjectsdev/metadata/core";
|
|
43
45
|
import { resolveD1Config, resolveMigrateConfig } from "../lib/config.js";
|
|
44
46
|
import {
|
|
@@ -350,6 +352,14 @@ export async function verifyCommand(
|
|
|
350
352
|
// way every other advisory pass does.
|
|
351
353
|
let overlaySection: AdvisorySection<AdvisoryDiagnosticRow> =
|
|
352
354
|
skippedSection("the overlay lint did not run");
|
|
355
|
+
// The node-name authoring lint — its own section for the same reason: a model
|
|
356
|
+
// carrying a few hundred legacy names must not push another section's findings
|
|
357
|
+
// off the end of a capped run.
|
|
358
|
+
let nameSection: AdvisorySection<AdvisoryDiagnosticRow> =
|
|
359
|
+
skippedSection("the name lint did not run");
|
|
360
|
+
// #305 — the deprecated-reference authoring lint. Its own section, same reason.
|
|
361
|
+
let deprecationSection: AdvisorySection<AdvisoryDiagnosticRow> =
|
|
362
|
+
skippedSection("the deprecated-reference lint did not run");
|
|
353
363
|
// The ledger counts `meta verify` prints on every run. Undefined for a project
|
|
354
364
|
// declaring no requirement.* node at all (opt-in by declaration) — the payload
|
|
355
365
|
// then omits the block rather than reporting zeroes that would read as an empty
|
|
@@ -386,6 +396,15 @@ export async function verifyCommand(
|
|
|
386
396
|
// Warnings ONLY — never changes the exit code.
|
|
387
397
|
await runOverlayLintAdvisory();
|
|
388
398
|
|
|
399
|
+
// Whitespace in a node's `name` — loads clean on every port, almost never meant.
|
|
400
|
+
// Runs on every `meta verify`; warnings ONLY, never changes the exit code.
|
|
401
|
+
runNameLintAdvisory();
|
|
402
|
+
|
|
403
|
+
// #305 — a node that depends (extends/@objectRef/@references/origin
|
|
404
|
+
// @from/@of/@via) on a `deprecated` node. Runs on every `meta verify`;
|
|
405
|
+
// warnings ONLY, never changes the exit code.
|
|
406
|
+
runDeprecationLintAdvisory();
|
|
407
|
+
|
|
389
408
|
// Advisory verify-as-teacher pass: surface hand-rolled work the metadata could
|
|
390
409
|
// model. Warnings ONLY — never changes the exit code (bias to under-flagging).
|
|
391
410
|
// Suppressed with --no-antipatterns or META_NO_ANTIPATTERNS=1 for the rare
|
|
@@ -434,6 +453,8 @@ export async function verifyCommand(
|
|
|
434
453
|
requirementCounts,
|
|
435
454
|
antiPatterns: antiPatternSection,
|
|
436
455
|
overlays: overlaySection,
|
|
456
|
+
names: nameSection,
|
|
457
|
+
deprecations: deprecationSection,
|
|
437
458
|
}),
|
|
438
459
|
fmt,
|
|
439
460
|
);
|
|
@@ -808,6 +829,52 @@ export async function verifyCommand(
|
|
|
808
829
|
}
|
|
809
830
|
}
|
|
810
831
|
|
|
832
|
+
// -- node-name authoring lint (advisory) -----------------------------------
|
|
833
|
+
// Reads the LOADED model (see name-lint.ts). Its own section, its own cap, and
|
|
834
|
+
// a skip that carries its reason rather than looking like a clean scan.
|
|
835
|
+
function runNameLintAdvisory(): void {
|
|
836
|
+
if (flags.noNameLint) {
|
|
837
|
+
nameSection = skippedSection("suppressed by --no-name-lint");
|
|
838
|
+
return;
|
|
839
|
+
}
|
|
840
|
+
if (process.env.META_NO_NAME_LINT === "1") {
|
|
841
|
+
nameSection = skippedSection("suppressed by META_NO_NAME_LINT=1");
|
|
842
|
+
return;
|
|
843
|
+
}
|
|
844
|
+
const findings = lintNodeNames(root);
|
|
845
|
+
nameSection = ranSection(findings.map((d) => toDiagnosticRow(d, "lint")));
|
|
846
|
+
if (findings.length > 0) {
|
|
847
|
+
log.warn(
|
|
848
|
+
`meta verify — names: ${findings.length} authoring warning(s) ` +
|
|
849
|
+
`(advisory — does not fail the build):`,
|
|
850
|
+
);
|
|
851
|
+
warnCapped(findings.map(formatDiagnostic), flags.limit, { structured });
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
// -- deprecated-reference authoring lint (advisory) -------------------------
|
|
856
|
+
// #305 — reads the LOADED model (see deprecation-lint.ts). Its own section,
|
|
857
|
+
// its own cap, and a skip that carries its reason rather than looking clean.
|
|
858
|
+
function runDeprecationLintAdvisory(): void {
|
|
859
|
+
if (flags.noDeprecationLint) {
|
|
860
|
+
deprecationSection = skippedSection("suppressed by --no-deprecation-lint");
|
|
861
|
+
return;
|
|
862
|
+
}
|
|
863
|
+
if (process.env.META_NO_DEPRECATION_LINT === "1") {
|
|
864
|
+
deprecationSection = skippedSection("suppressed by META_NO_DEPRECATION_LINT=1");
|
|
865
|
+
return;
|
|
866
|
+
}
|
|
867
|
+
const findings = lintDeprecatedReferences(root);
|
|
868
|
+
deprecationSection = ranSection(findings.map((d) => toDiagnosticRow(d, "lint")));
|
|
869
|
+
if (findings.length > 0) {
|
|
870
|
+
log.warn(
|
|
871
|
+
`meta verify — deprecations: ${findings.length} reference(s) to a deprecated node ` +
|
|
872
|
+
`(advisory — does not fail the build):`,
|
|
873
|
+
);
|
|
874
|
+
warnCapped(findings.map(formatDiagnostic), flags.limit, { structured });
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
|
|
811
878
|
// -- verify-as-teacher (advisory) ------------------------------------------
|
|
812
879
|
// Records its result EITHER WAY — a skip carries its reason rather than looking
|
|
813
880
|
// like a clean scan. Warnings only; nothing here reaches the exit code (the
|
|
@@ -1821,6 +1888,8 @@ function buildVerifyPayload(input: {
|
|
|
1821
1888
|
requirementCounts: RequirementCounts | undefined;
|
|
1822
1889
|
antiPatterns: AdvisorySection<AdvisoryFindingRow>;
|
|
1823
1890
|
overlays: AdvisorySection<AdvisoryDiagnosticRow>;
|
|
1891
|
+
names: AdvisorySection<AdvisoryDiagnosticRow>;
|
|
1892
|
+
deprecations: AdvisorySection<AdvisoryDiagnosticRow>;
|
|
1824
1893
|
}): Record<string, unknown> {
|
|
1825
1894
|
const ran = input.gates.filter((g) => g.ran);
|
|
1826
1895
|
const failed = ran.filter((g) => !g.ok);
|
|
@@ -1840,6 +1909,12 @@ function buildVerifyPayload(input: {
|
|
|
1840
1909
|
if (input.overlays.status === "ran" && input.overlays.total > 0) {
|
|
1841
1910
|
parts.push(`${input.overlays.total} overlay authoring finding(s)`);
|
|
1842
1911
|
}
|
|
1912
|
+
if (input.names.status === "ran" && input.names.total > 0) {
|
|
1913
|
+
parts.push(`${input.names.total} name authoring finding(s)`);
|
|
1914
|
+
}
|
|
1915
|
+
if (input.deprecations.status === "ran" && input.deprecations.total > 0) {
|
|
1916
|
+
parts.push(`${input.deprecations.total} deprecated-reference finding(s)`);
|
|
1917
|
+
}
|
|
1843
1918
|
|
|
1844
1919
|
const help: string[] = [];
|
|
1845
1920
|
if (failed.length > 0) {
|
|
@@ -1855,11 +1930,23 @@ function buildVerifyPayload(input: {
|
|
|
1855
1930
|
`${input.overlays.total} unflagged cross-file redeclaration(s) — see overlays.rows[]; add overlay: true so a renamed or removed target fails loudly instead of silently becoming a new object`,
|
|
1856
1931
|
);
|
|
1857
1932
|
}
|
|
1933
|
+
if (input.names.total > 0) {
|
|
1934
|
+
help.push(
|
|
1935
|
+
`${input.names.total} node name(s) containing whitespace — see names.rows[]; rename each node, and pin @column on a field whose physical column must keep its name`,
|
|
1936
|
+
);
|
|
1937
|
+
}
|
|
1938
|
+
if (input.deprecations.total > 0) {
|
|
1939
|
+
help.push(
|
|
1940
|
+
`${input.deprecations.total} reference(s) to a deprecated node — see deprecations.rows[]; each names the deprecated target and, where declared, its replacement`,
|
|
1941
|
+
);
|
|
1942
|
+
}
|
|
1858
1943
|
if (
|
|
1859
1944
|
failed.length === 0 &&
|
|
1860
1945
|
input.antiPatterns.total === 0 &&
|
|
1861
1946
|
input.requirements.total === 0 &&
|
|
1862
|
-
input.overlays.total === 0
|
|
1947
|
+
input.overlays.total === 0 &&
|
|
1948
|
+
input.names.total === 0 &&
|
|
1949
|
+
input.deprecations.total === 0
|
|
1863
1950
|
) {
|
|
1864
1951
|
help.push("no drift and nothing advisory to answer — nothing to do");
|
|
1865
1952
|
}
|
|
@@ -1872,6 +1959,8 @@ function buildVerifyPayload(input: {
|
|
|
1872
1959
|
antiPatterns: input.antiPatterns,
|
|
1873
1960
|
requirements: input.requirements,
|
|
1874
1961
|
overlays: input.overlays,
|
|
1962
|
+
names: input.names,
|
|
1963
|
+
deprecations: input.deprecations,
|
|
1875
1964
|
...(input.requirementCounts !== undefined ? { requirementCounts: input.requirementCounts } : {}),
|
|
1876
1965
|
// The honest boundary. Everything named here is REACHABLE — it is printed as
|
|
1877
1966
|
// text on stderr — but it is not in this document, and a reader must not have
|