@nifrajs/cli 4.0.2 → 5.1.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 +10 -2
- package/dist/agent-files.d.ts +107 -0
- package/dist/agent-files.d.ts.map +1 -0
- package/dist/agent-files.js +162 -0
- package/dist/agent-files.js.map +1 -0
- package/dist/app-files.d.ts +6 -0
- package/dist/app-files.d.ts.map +1 -1
- package/dist/app-files.js +27 -2
- package/dist/app-files.js.map +1 -1
- package/dist/assure-hydration.d.ts.map +1 -1
- package/dist/assure-hydration.js +9 -2
- package/dist/assure-hydration.js.map +1 -1
- package/dist/assure.d.ts +12 -2
- package/dist/assure.d.ts.map +1 -1
- package/dist/assure.js +59 -8
- package/dist/assure.js.map +1 -1
- package/dist/capabilities-tool.d.ts.map +1 -1
- package/dist/capabilities-tool.js +36 -9
- package/dist/capabilities-tool.js.map +1 -1
- package/dist/check-diagnostics.d.ts +22 -2
- package/dist/check-diagnostics.d.ts.map +1 -1
- package/dist/check-diagnostics.js +54 -7
- package/dist/check-diagnostics.js.map +1 -1
- package/dist/check-scan.d.ts +83 -24
- package/dist/check-scan.d.ts.map +1 -1
- package/dist/check-scan.js +1516 -318
- package/dist/check-scan.js.map +1 -1
- package/dist/check.d.ts +2 -2
- package/dist/check.d.ts.map +1 -1
- package/dist/check.js +203 -70
- package/dist/check.js.map +1 -1
- package/dist/cli.d.ts +9 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +215 -50
- package/dist/cli.js.map +1 -1
- package/dist/client-module.d.ts +20 -0
- package/dist/client-module.d.ts.map +1 -0
- package/dist/client-module.js +73 -0
- package/dist/client-module.js.map +1 -0
- package/dist/command-catalog.d.ts +24 -5
- package/dist/command-catalog.d.ts.map +1 -1
- package/dist/command-catalog.js +194 -45
- package/dist/command-catalog.js.map +1 -1
- package/dist/component-check.d.ts +13 -0
- package/dist/component-check.d.ts.map +1 -0
- package/dist/component-check.js +59 -0
- package/dist/component-check.js.map +1 -0
- package/dist/contract-proof.d.ts +1 -1
- package/dist/contract-proof.d.ts.map +1 -1
- package/dist/contract-proof.js +2 -24
- package/dist/contract-proof.js.map +1 -1
- package/dist/contracts.d.ts +19 -0
- package/dist/contracts.d.ts.map +1 -1
- package/dist/contracts.js +50 -3
- package/dist/contracts.js.map +1 -1
- package/dist/db-tool.d.ts.map +1 -1
- package/dist/db-tool.js +4 -3
- package/dist/db-tool.js.map +1 -1
- package/dist/dev-bun-config.d.ts +5 -1
- package/dist/dev-bun-config.d.ts.map +1 -1
- package/dist/dev-bun-config.js +44 -11
- package/dist/dev-bun-config.js.map +1 -1
- package/dist/dev-feed-tool.d.ts +18 -1
- package/dist/dev-feed-tool.d.ts.map +1 -1
- package/dist/dev-feed-tool.js +93 -0
- package/dist/dev-feed-tool.js.map +1 -1
- package/dist/diagnostics.d.ts +3 -0
- package/dist/diagnostics.d.ts.map +1 -1
- package/dist/diagnostics.js.map +1 -1
- package/dist/diff-tool.d.ts +9 -8
- package/dist/diff-tool.d.ts.map +1 -1
- package/dist/diff-tool.js +28 -24
- package/dist/diff-tool.js.map +1 -1
- package/dist/doctor.d.ts +13 -0
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +23 -15
- package/dist/doctor.js.map +1 -1
- package/dist/env-file.d.ts +6 -0
- package/dist/env-file.d.ts.map +1 -1
- package/dist/env-file.js +6 -0
- package/dist/env-file.js.map +1 -1
- package/dist/fix-recipes.d.ts +2 -0
- package/dist/fix-recipes.d.ts.map +1 -1
- package/dist/fix-recipes.js +102 -2
- package/dist/fix-recipes.js.map +1 -1
- package/dist/hand-built-manifest.d.ts +27 -0
- package/dist/hand-built-manifest.d.ts.map +1 -0
- package/dist/hand-built-manifest.js +124 -0
- package/dist/hand-built-manifest.js.map +1 -0
- package/dist/hooks-report.d.ts +23 -0
- package/dist/hooks-report.d.ts.map +1 -0
- package/dist/hooks-report.js +104 -0
- package/dist/hooks-report.js.map +1 -0
- package/dist/init-agents.d.ts +18 -2
- package/dist/init-agents.d.ts.map +1 -1
- package/dist/init-agents.js +20 -13
- package/dist/init-agents.js.map +1 -1
- package/dist/internal/config-paths.d.ts +16 -0
- package/dist/internal/config-paths.d.ts.map +1 -0
- package/dist/internal/config-paths.js +124 -0
- package/dist/internal/config-paths.js.map +1 -0
- package/dist/internal/installed-package.d.ts +4 -0
- package/dist/internal/installed-package.d.ts.map +1 -0
- package/dist/internal/installed-package.js +17 -0
- package/dist/internal/installed-package.js.map +1 -0
- package/dist/internal/nifra-project.d.ts +41 -0
- package/dist/internal/nifra-project.d.ts.map +1 -0
- package/dist/internal/nifra-project.js +183 -0
- package/dist/internal/nifra-project.js.map +1 -0
- package/dist/internal/project-specifiers.d.ts +29 -0
- package/dist/internal/project-specifiers.d.ts.map +1 -0
- package/dist/internal/project-specifiers.js +435 -0
- package/dist/internal/project-specifiers.js.map +1 -0
- package/dist/internal/script-kind.d.ts.map +1 -1
- package/dist/internal/script-kind.js +2 -1
- package/dist/internal/script-kind.js.map +1 -1
- package/dist/internal/source-facts.d.ts +8 -1
- package/dist/internal/source-facts.d.ts.map +1 -1
- package/dist/internal/source-facts.js +22 -5
- package/dist/internal/source-facts.js.map +1 -1
- package/dist/internal/typescript-import.d.ts +1 -1
- package/dist/internal/typescript-import.d.ts.map +1 -1
- package/dist/internal/typescript-import.js +10 -6
- package/dist/internal/typescript-import.js.map +1 -1
- package/dist/introspect.d.ts +15 -6
- package/dist/introspect.d.ts.map +1 -1
- package/dist/introspect.js +87 -25
- package/dist/introspect.js.map +1 -1
- package/dist/levels-tool.d.ts.map +1 -1
- package/dist/levels-tool.js +98 -23
- package/dist/levels-tool.js.map +1 -1
- package/dist/load.d.ts +33 -10
- package/dist/load.d.ts.map +1 -1
- package/dist/load.js +60 -10
- package/dist/load.js.map +1 -1
- package/dist/mcp-context.d.ts +5 -5
- package/dist/mcp-context.d.ts.map +1 -1
- package/dist/mcp-context.js +8 -23
- package/dist/mcp-context.js.map +1 -1
- package/dist/mcp-delegate.d.ts +2 -2
- package/dist/mcp-delegate.d.ts.map +1 -1
- package/dist/mcp-delegate.js +19 -7
- package/dist/mcp-delegate.js.map +1 -1
- package/dist/mcp-exec.d.ts +13 -4
- package/dist/mcp-exec.d.ts.map +1 -1
- package/dist/mcp-exec.js +56 -14
- package/dist/mcp-exec.js.map +1 -1
- package/dist/mcp-http.js +1 -1
- package/dist/mcp-io.d.ts +30 -0
- package/dist/mcp-io.d.ts.map +1 -1
- package/dist/mcp-io.js +63 -0
- package/dist/mcp-io.js.map +1 -1
- package/dist/mcp-isolate.d.ts.map +1 -1
- package/dist/mcp-isolate.js +3 -2
- package/dist/mcp-isolate.js.map +1 -1
- package/dist/mcp-path.d.ts +2 -1
- package/dist/mcp-path.d.ts.map +1 -1
- package/dist/mcp-path.js +9 -24
- package/dist/mcp-path.js.map +1 -1
- package/dist/mcp-project-child.js +1 -1
- package/dist/mcp-project-child.js.map +1 -1
- package/dist/mcp-root.d.ts.map +1 -1
- package/dist/mcp-root.js +50 -10
- package/dist/mcp-root.js.map +1 -1
- package/dist/mcp-ws.d.ts.map +1 -1
- package/dist/mcp-ws.js +3 -1
- package/dist/mcp-ws.js.map +1 -1
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +48 -19
- package/dist/mcp.js.map +1 -1
- package/dist/migrate-layout.d.ts +47 -1
- package/dist/migrate-layout.d.ts.map +1 -1
- package/dist/migrate-layout.js +1972 -170
- package/dist/migrate-layout.js.map +1 -1
- package/dist/output-schemas.d.ts +128 -0
- package/dist/output-schemas.d.ts.map +1 -0
- package/dist/output-schemas.js +975 -0
- package/dist/output-schemas.js.map +1 -0
- package/dist/port.d.ts.map +1 -1
- package/dist/port.js +3 -2
- package/dist/port.js.map +1 -1
- package/dist/project-facts.d.ts +15 -4
- package/dist/project-facts.d.ts.map +1 -1
- package/dist/project-facts.js +1 -0
- package/dist/project-facts.js.map +1 -1
- package/dist/project-path.d.ts +6 -0
- package/dist/project-path.d.ts.map +1 -1
- package/dist/project-path.js +48 -14
- package/dist/project-path.js.map +1 -1
- package/dist/recipes/5.0.0.d.ts +11 -0
- package/dist/recipes/5.0.0.d.ts.map +1 -0
- package/dist/recipes/5.0.0.js +34 -0
- package/dist/recipes/5.0.0.js.map +1 -0
- package/dist/recipes/index.d.ts +7 -0
- package/dist/recipes/index.d.ts.map +1 -1
- package/dist/recipes/index.js +2 -0
- package/dist/recipes/index.js.map +1 -1
- package/dist/release-verification.d.ts +5 -0
- package/dist/release-verification.d.ts.map +1 -1
- package/dist/release-verification.js +14 -0
- package/dist/release-verification.js.map +1 -1
- package/dist/replay.d.ts.map +1 -1
- package/dist/replay.js +12 -3
- package/dist/replay.js.map +1 -1
- package/dist/review.d.ts +3 -1
- package/dist/review.d.ts.map +1 -1
- package/dist/review.js +43 -7
- package/dist/review.js.map +1 -1
- package/dist/rules/codes.d.ts +12 -0
- package/dist/rules/codes.d.ts.map +1 -1
- package/dist/rules/codes.js +12 -0
- package/dist/rules/codes.js.map +1 -1
- package/dist/rules/comment-markers.d.ts +16 -7
- package/dist/rules/comment-markers.d.ts.map +1 -1
- package/dist/rules/comment-markers.js +58 -19
- package/dist/rules/comment-markers.js.map +1 -1
- package/dist/rules/contract-visibility.d.ts +3 -0
- package/dist/rules/contract-visibility.d.ts.map +1 -0
- package/dist/rules/contract-visibility.js +337 -0
- package/dist/rules/contract-visibility.js.map +1 -0
- package/dist/rules/data-guard.d.ts +13 -0
- package/dist/rules/data-guard.d.ts.map +1 -1
- package/dist/rules/data-guard.js +356 -37
- package/dist/rules/data-guard.js.map +1 -1
- package/dist/rules/layout.d.ts +4 -0
- package/dist/rules/layout.d.ts.map +1 -0
- package/dist/rules/layout.js +19 -0
- package/dist/rules/layout.js.map +1 -0
- package/dist/rules/legacy.d.ts.map +1 -1
- package/dist/rules/legacy.js +178 -44
- package/dist/rules/legacy.js.map +1 -1
- package/dist/rules/pages.d.ts +50 -0
- package/dist/rules/pages.d.ts.map +1 -1
- package/dist/rules/pages.js +436 -4
- package/dist/rules/pages.js.map +1 -1
- package/dist/rules/routes.d.ts +6 -0
- package/dist/rules/routes.d.ts.map +1 -1
- package/dist/rules/routes.js +111 -16
- package/dist/rules/routes.js.map +1 -1
- package/dist/rules/secrets.js +2 -2
- package/dist/rules/secrets.js.map +1 -1
- package/dist/rules/security.d.ts +13 -1
- package/dist/rules/security.d.ts.map +1 -1
- package/dist/rules/security.js +313 -69
- package/dist/rules/security.js.map +1 -1
- package/dist/rules/zones.d.ts +13 -0
- package/dist/rules/zones.d.ts.map +1 -1
- package/dist/rules/zones.js +218 -44
- package/dist/rules/zones.js.map +1 -1
- package/dist/scaffold.d.ts.map +1 -1
- package/dist/scaffold.js +6 -4
- package/dist/scaffold.js.map +1 -1
- package/dist/sdk.d.ts.map +1 -1
- package/dist/sdk.js +14 -5
- package/dist/sdk.js.map +1 -1
- package/dist/stylex-migrate.d.ts.map +1 -1
- package/dist/stylex-migrate.js +290 -24
- package/dist/stylex-migrate.js.map +1 -1
- package/dist/test-tool.d.ts.map +1 -1
- package/dist/test-tool.js +6 -3
- package/dist/test-tool.js.map +1 -1
- package/dist/typecheck-coverage.d.ts +20 -0
- package/dist/typecheck-coverage.d.ts.map +1 -0
- package/dist/typecheck-coverage.js +129 -0
- package/dist/typecheck-coverage.js.map +1 -0
- package/dist/upgrade.d.ts +84 -0
- package/dist/upgrade.d.ts.map +1 -1
- package/dist/upgrade.js +498 -78
- package/dist/upgrade.js.map +1 -1
- package/dist/verification-plan.d.ts.map +1 -1
- package/dist/verification-plan.js +16 -2
- package/dist/verification-plan.js.map +1 -1
- package/dist/version-drift.d.ts +22 -0
- package/dist/version-drift.d.ts.map +1 -0
- package/dist/version-drift.js +94 -0
- package/dist/version-drift.js.map +1 -0
- package/dist/web-app-options.d.ts +1 -1
- package/dist/web-app-options.d.ts.map +1 -1
- package/dist/web-app-options.js +1 -1
- package/dist/web-app-options.js.map +1 -1
- package/dist/work-graph.d.ts.map +1 -1
- package/dist/work-graph.js +20 -8
- package/dist/work-graph.js.map +1 -1
- package/docs/examples.json +55 -7
- package/docs/llms-full.txt +2043 -222
- package/docs/types.json +1573 -246
- package/package.json +11 -12
- package/src/agent-files.ts +203 -0
- package/src/app-files.ts +34 -4
- package/src/assure-hydration.ts +18 -2
- package/src/assure.ts +88 -10
- package/src/capabilities-tool.ts +47 -9
- package/src/check-diagnostics.ts +75 -9
- package/src/check-scan.ts +1816 -377
- package/src/check.ts +258 -81
- package/src/cli.ts +242 -37
- package/src/client-module.ts +97 -0
- package/src/command-catalog.ts +237 -52
- package/src/component-check.ts +79 -0
- package/src/contract-proof.ts +3 -25
- package/src/contracts.ts +60 -3
- package/src/db-tool.ts +5 -2
- package/src/dev-bun-config.ts +51 -10
- package/src/dev-feed-tool.ts +112 -1
- package/src/diagnostics.ts +3 -0
- package/src/diff-tool.ts +33 -26
- package/src/doctor.ts +43 -21
- package/src/env-file.ts +7 -0
- package/src/fix-recipes.ts +116 -2
- package/src/hand-built-manifest.ts +144 -0
- package/src/hooks-report.ts +135 -0
- package/src/init-agents.ts +21 -14
- package/src/internal/config-paths.ts +154 -0
- package/src/internal/installed-package.ts +15 -0
- package/src/internal/nifra-project.ts +191 -0
- package/src/internal/project-specifiers.ts +477 -0
- package/src/internal/script-kind.ts +2 -1
- package/src/internal/source-facts.ts +48 -5
- package/src/internal/typescript-import.ts +15 -6
- package/src/introspect.ts +104 -28
- package/src/levels-tool.ts +124 -29
- package/src/load.ts +107 -17
- package/src/mcp-context.ts +12 -25
- package/src/mcp-delegate.ts +22 -10
- package/src/mcp-exec.ts +68 -18
- package/src/mcp-http.ts +1 -1
- package/src/mcp-io.ts +74 -0
- package/src/mcp-isolate.ts +9 -2
- package/src/mcp-path.ts +8 -22
- package/src/mcp-project-child.ts +1 -1
- package/src/mcp-root.ts +58 -8
- package/src/mcp-ws.ts +4 -2
- package/src/mcp.ts +56 -22
- package/src/migrate-layout.ts +2257 -176
- package/src/output-schemas.ts +1240 -0
- package/src/port.ts +3 -2
- package/src/project-facts.ts +17 -3
- package/src/project-path.ts +44 -13
- package/src/recipes/5.0.0.ts +35 -0
- package/src/recipes/index.ts +10 -0
- package/src/release-verification.ts +20 -0
- package/src/replay.ts +14 -3
- package/src/review.ts +44 -10
- package/src/rules/codes.ts +12 -0
- package/src/rules/comment-markers.ts +57 -21
- package/src/rules/contract-visibility.ts +383 -0
- package/src/rules/data-guard.ts +391 -42
- package/src/rules/layout.ts +22 -0
- package/src/rules/legacy.ts +206 -52
- package/src/rules/pages.ts +481 -4
- package/src/rules/routes.ts +124 -16
- package/src/rules/secrets.ts +2 -2
- package/src/rules/security.ts +391 -72
- package/src/rules/zones.ts +232 -42
- package/src/scaffold.ts +6 -4
- package/src/sdk.ts +14 -5
- package/src/stylex-migrate.ts +251 -24
- package/src/test-tool.ts +12 -3
- package/src/typecheck-coverage.ts +134 -0
- package/src/upgrade.ts +576 -72
- package/src/verification-plan.ts +33 -2
- package/src/version-drift.ts +118 -0
- package/src/web-app-options.ts +2 -2
- package/src/work-graph.ts +17 -12
package/dist/command-catalog.js
CHANGED
|
@@ -10,7 +10,7 @@ import { formatAssuranceReport } from "./assure.js";
|
|
|
10
10
|
import { cdnCheckSpec } from "./cdn-check.js";
|
|
11
11
|
import { renderCheckReport } from "./check.js";
|
|
12
12
|
import { dbAuditSpec, dbQuerySpec, dbRoleSpec, dbSchemaSpec } from "./db-tool.js";
|
|
13
|
-
import { errorsSpec, logsSpec } from "./dev-feed-tool.js";
|
|
13
|
+
import { errorsSpec, explainSpec, logsSpec } from "./dev-feed-tool.js";
|
|
14
14
|
import { diagnostic, normalizeSeverity, toSarifLog } from "./diagnostics.js";
|
|
15
15
|
import { i18nCheckPassed, renderI18nCheck } from "./i18n-check.js";
|
|
16
16
|
import { collectPortResult, renderReport } from "./port.js";
|
|
@@ -267,14 +267,19 @@ const ROUTES_SCHEMA = input(objectSchema({
|
|
|
267
267
|
json: { type: "boolean" },
|
|
268
268
|
graph: { type: "boolean" },
|
|
269
269
|
modes: { type: "boolean" },
|
|
270
|
+
hooks: { type: "boolean" },
|
|
271
|
+
since: { type: "string" },
|
|
270
272
|
target: { type: "string" },
|
|
271
273
|
dir: { type: "string" },
|
|
272
274
|
}), (value) => {
|
|
273
275
|
const raw = withDir(record(value));
|
|
274
|
-
if (raw.graph
|
|
275
|
-
throw new TypeError("graph and
|
|
276
|
+
if ([raw.graph, raw.modes, raw.hooks].filter((flag) => flag === true).length > 1)
|
|
277
|
+
throw new TypeError("graph, modes and hooks cannot be combined");
|
|
278
|
+
if (raw.since !== undefined && raw.hooks !== true)
|
|
279
|
+
throw new TypeError("since compares hook reports and needs hooks");
|
|
276
280
|
return {
|
|
277
|
-
...parseBooleanFlags(raw, ["json", "graph", "modes"]),
|
|
281
|
+
...parseBooleanFlags(raw, ["json", "graph", "modes", "hooks"]),
|
|
282
|
+
since: optionalString(raw.since, "since"),
|
|
278
283
|
target: optionalString(raw.target, "target"),
|
|
279
284
|
...(raw.dir === undefined ? {} : { dir: raw.dir }),
|
|
280
285
|
};
|
|
@@ -334,12 +339,13 @@ const MIGRATE_SCHEMA = input(objectSchema({
|
|
|
334
339
|
from: { type: "string", enum: ["tailwind"] },
|
|
335
340
|
to: { type: "string", enum: ["stylex"] },
|
|
336
341
|
write: { type: "boolean" },
|
|
342
|
+
zones: { type: "boolean" },
|
|
337
343
|
json: { type: "boolean" },
|
|
338
344
|
dir: { type: "string" },
|
|
339
345
|
}), (value) => {
|
|
340
346
|
const raw = withDir(record(value));
|
|
341
347
|
const flags = {
|
|
342
|
-
...parseBooleanFlags(raw, ["write", "json"]),
|
|
348
|
+
...parseBooleanFlags(raw, ["write", "zones", "json"]),
|
|
343
349
|
...(raw.dir === undefined ? {} : { dir: raw.dir }),
|
|
344
350
|
};
|
|
345
351
|
const kind = optionalString(raw.kind, "kind");
|
|
@@ -348,6 +354,8 @@ const MIGRATE_SCHEMA = input(objectSchema({
|
|
|
348
354
|
throw new TypeError("the migration must be `layout` (or --from tailwind --to stylex)");
|
|
349
355
|
return { kind, ...flags };
|
|
350
356
|
}
|
|
357
|
+
if (raw.zones === true)
|
|
358
|
+
throw new TypeError("--zones applies to `migrate layout` only");
|
|
351
359
|
const from = optionalString(raw.from, "from");
|
|
352
360
|
const to = optionalString(raw.to, "to");
|
|
353
361
|
if (from !== "tailwind")
|
|
@@ -372,6 +380,18 @@ const TYPES_SCHEMA = input(objectSchema({ check: { type: "boolean" }, json: { ty
|
|
|
372
380
|
...(raw.dir === undefined ? {} : { dir: raw.dir }),
|
|
373
381
|
};
|
|
374
382
|
});
|
|
383
|
+
const SCHEMAS_SCHEMA = input(objectSchema({
|
|
384
|
+
write: { type: "boolean" },
|
|
385
|
+
check: { type: "boolean" },
|
|
386
|
+
json: { type: "boolean" },
|
|
387
|
+
dir: { type: "string" },
|
|
388
|
+
}), (value) => {
|
|
389
|
+
const raw = withDir(record(value));
|
|
390
|
+
return {
|
|
391
|
+
...parseBooleanFlags(raw, ["write", "check", "json"]),
|
|
392
|
+
...(raw.dir === undefined ? {} : { dir: raw.dir }),
|
|
393
|
+
};
|
|
394
|
+
});
|
|
375
395
|
const SNAPSHOT_SCHEMA = input(objectSchema({ out: { type: "string" }, json: { type: "boolean" }, dir: { type: "string" } }), (value) => {
|
|
376
396
|
const raw = withDir(record(value));
|
|
377
397
|
return {
|
|
@@ -492,10 +512,11 @@ const I18N_SCHEMA = input(objectSchema({
|
|
|
492
512
|
...(raw.dir === undefined ? {} : { dir: raw.dir }),
|
|
493
513
|
};
|
|
494
514
|
});
|
|
495
|
-
|
|
515
|
+
/** The app as the backend readers see it: an API-only app is its `backend/app.ts` alone. */
|
|
516
|
+
function backendAppFor(ctx) {
|
|
496
517
|
if (ctx.loadApp !== undefined)
|
|
497
|
-
return ctx.loadApp();
|
|
498
|
-
return import("./load.js").then(({
|
|
518
|
+
return ctx.loadApp.backend();
|
|
519
|
+
return import("./load.js").then(({ loadBackendApp }) => loadBackendApp(ctx.cwd));
|
|
499
520
|
}
|
|
500
521
|
function structuredDiagnostics(out) {
|
|
501
522
|
if (out.structuredDiagnostics !== undefined)
|
|
@@ -709,7 +730,7 @@ const manifestSpec = {
|
|
|
709
730
|
};
|
|
710
731
|
const routesSpec = {
|
|
711
732
|
name: "routes",
|
|
712
|
-
summary: "List, graph, or target-check every page and API route the app serves.",
|
|
733
|
+
summary: "List, graph, or target-check every page and API route the app serves, or the hooks each runs.",
|
|
713
734
|
input: ROUTES_SCHEMA,
|
|
714
735
|
output: output({
|
|
715
736
|
type: "object",
|
|
@@ -723,12 +744,43 @@ const routesSpec = {
|
|
|
723
744
|
{ name: "json", field: "json", type: "boolean" },
|
|
724
745
|
{ name: "graph", field: "graph", type: "boolean" },
|
|
725
746
|
{ name: "modes", field: "modes", type: "boolean" },
|
|
747
|
+
{ name: "hooks", field: "hooks", type: "boolean" },
|
|
748
|
+
{ name: "since", field: "since", type: "string" },
|
|
726
749
|
{ name: "target", field: "target", type: "string" },
|
|
727
750
|
],
|
|
728
751
|
},
|
|
729
752
|
async run(value, ctx) {
|
|
730
|
-
|
|
753
|
+
if (value.hooks === true) {
|
|
754
|
+
const app = await backendAppFor(ctx);
|
|
755
|
+
const hooks = await import("./hooks-report.js");
|
|
756
|
+
const report = await hooks.collectHookReport(app.backend);
|
|
757
|
+
if (value.since === undefined) {
|
|
758
|
+
return { ok: true, mode: "hooks", data: report, text: hooks.renderHookReport(report) };
|
|
759
|
+
}
|
|
760
|
+
const saved = hooks.parseHookReport(await Bun.file(resolve(ctx.cwd, value.since))
|
|
761
|
+
.text()
|
|
762
|
+
.catch(() => ""));
|
|
763
|
+
if (saved === undefined) {
|
|
764
|
+
return {
|
|
765
|
+
ok: false,
|
|
766
|
+
mode: "hooks",
|
|
767
|
+
data: { report, error: `${value.since} is not a saved hook report` },
|
|
768
|
+
text: `[nifra] ${value.since} is not a saved hook report (write one with \`nifra routes --hooks --json\`)`,
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
const changes = hooks.diffHookReports(saved, report);
|
|
772
|
+
return {
|
|
773
|
+
ok: true,
|
|
774
|
+
mode: "hooks",
|
|
775
|
+
data: { report, changes },
|
|
776
|
+
text: hooks.renderHookDiff(changes),
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
const app = await backendAppFor(ctx);
|
|
731
780
|
if (value.modes === true) {
|
|
781
|
+
if (app.framework === undefined) {
|
|
782
|
+
throw new Error(`[nifra] routes --modes reads page routes, and ${ctx.cwd} is an API-only app (backend/app.ts, no web config)`);
|
|
783
|
+
}
|
|
732
784
|
const { buildRouteManifest, renderRouteManifest } = await import("@nifrajs/web/route-manifest");
|
|
733
785
|
const { discoverRoutes } = await import("@nifrajs/web/fs");
|
|
734
786
|
const data = await buildRouteManifest(discoverRoutes(app.routesDir), value.target === undefined ? {} : { target: value.target });
|
|
@@ -771,7 +823,7 @@ const contextSpec = {
|
|
|
771
823
|
async run(value, ctx) {
|
|
772
824
|
return {
|
|
773
825
|
ok: true,
|
|
774
|
-
text: (await import("./introspect.js")).describeProject(await
|
|
826
|
+
text: (await import("./introspect.js")).describeProject(await backendAppFor(ctx), {
|
|
775
827
|
...(value.path === undefined ? {} : { path: value.path }),
|
|
776
828
|
...(value.kind === undefined ? {} : { kind: value.kind }),
|
|
777
829
|
}),
|
|
@@ -797,9 +849,7 @@ const openApiSpec = {
|
|
|
797
849
|
],
|
|
798
850
|
},
|
|
799
851
|
async run(value, ctx) {
|
|
800
|
-
const app = ctx
|
|
801
|
-
? await ctx.loadApp()
|
|
802
|
-
: await import("./load.js").then(({ loadBackendApp }) => loadBackendApp(ctx.cwd));
|
|
852
|
+
const app = await backendAppFor(ctx);
|
|
803
853
|
const { renderOpenApiWithTypes } = await import("./openapi-tool.js");
|
|
804
854
|
const format = value.format ?? "json";
|
|
805
855
|
return {
|
|
@@ -858,6 +908,7 @@ const fixSpec = {
|
|
|
858
908
|
ok: { type: "boolean" },
|
|
859
909
|
changed: { type: "array" },
|
|
860
910
|
failed: { type: "array" },
|
|
911
|
+
skipped: { type: "array" },
|
|
861
912
|
diagnostics: { type: "array" },
|
|
862
913
|
},
|
|
863
914
|
required: ["ok", "diagnostics"],
|
|
@@ -872,26 +923,38 @@ const fixSpec = {
|
|
|
872
923
|
},
|
|
873
924
|
async run(value, ctx) {
|
|
874
925
|
const { collectCheckResult } = await import("./check.js");
|
|
875
|
-
const { applyDiagnosticRecipe } = await import("./fix-recipes.js");
|
|
926
|
+
const { applyDiagnosticRecipe, getFixRecipe } = await import("./fix-recipes.js");
|
|
876
927
|
const result = await collectCheckResult(ctx.cwd, {
|
|
877
928
|
lintsOnly: true,
|
|
878
929
|
...(ctx.signal === undefined ? {} : { signal: ctx.signal }),
|
|
879
930
|
});
|
|
880
931
|
const changed = [];
|
|
881
932
|
const failed = [];
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
failed.push({
|
|
933
|
+
const skipped = [];
|
|
934
|
+
for (const diagnostic of result.structuredDiagnostics ?? []) {
|
|
935
|
+
if (value.code !== undefined && diagnostic.code !== value.code)
|
|
936
|
+
continue;
|
|
937
|
+
const recipe = diagnostic.fix?.recipe === undefined ? undefined : getFixRecipe(diagnostic.fix.recipe);
|
|
938
|
+
if (value.code === undefined && recipe?.onlyWhenNamed === true) {
|
|
939
|
+
if (!skipped.some((entry) => entry.code === diagnostic.code))
|
|
940
|
+
skipped.push({
|
|
891
941
|
code: diagnostic.code,
|
|
892
|
-
reason:
|
|
942
|
+
reason: `${recipe.description} Review the finding, then run \`nifra fix --code ${diagnostic.code}\`.`,
|
|
893
943
|
});
|
|
894
|
-
|
|
944
|
+
continue;
|
|
945
|
+
}
|
|
946
|
+
// One recipe that cannot act must not cancel the others, and must not pass silently either:
|
|
947
|
+
// record why and keep going, so a run over many diagnostics still reports every outcome.
|
|
948
|
+
try {
|
|
949
|
+
changed.push(...(await applyDiagnosticRecipe(ctx.cwd, diagnostic)));
|
|
950
|
+
}
|
|
951
|
+
catch (error) {
|
|
952
|
+
failed.push({
|
|
953
|
+
code: diagnostic.code,
|
|
954
|
+
reason: error instanceof Error ? error.message : String(error),
|
|
955
|
+
});
|
|
956
|
+
}
|
|
957
|
+
}
|
|
895
958
|
const final = await collectCheckResult(ctx.cwd, {
|
|
896
959
|
lintsOnly: true,
|
|
897
960
|
...(ctx.signal === undefined ? {} : { signal: ctx.signal }),
|
|
@@ -900,6 +963,7 @@ const fixSpec = {
|
|
|
900
963
|
ok: final.ok,
|
|
901
964
|
changed,
|
|
902
965
|
failed,
|
|
966
|
+
skipped,
|
|
903
967
|
diagnostics: final.structuredDiagnostics ?? final.diagnostics,
|
|
904
968
|
};
|
|
905
969
|
},
|
|
@@ -907,6 +971,7 @@ const fixSpec = {
|
|
|
907
971
|
out.ok ? "✓ fixes applied" : "✖ unresolved diagnostics remain",
|
|
908
972
|
...out.changed.map((file) => ` changed ${file}`),
|
|
909
973
|
...out.failed.map((f) => ` could not fix ${f.code}: ${f.reason}`),
|
|
974
|
+
...out.skipped.map((s) => ` needs review ${s.code}: ${s.reason}`),
|
|
910
975
|
...out.diagnostics.map((d) => ` ${String(d.code ?? "diagnostic")}`),
|
|
911
976
|
],
|
|
912
977
|
success: (out) => out.ok,
|
|
@@ -931,6 +996,9 @@ const migrateSpec = {
|
|
|
931
996
|
splits: { type: "array" },
|
|
932
997
|
moves: { type: "array" },
|
|
933
998
|
rewritten: { type: "array" },
|
|
999
|
+
tooling: { type: "array" },
|
|
1000
|
+
followUps: { type: "array" },
|
|
1001
|
+
mode: { type: "string" },
|
|
934
1002
|
},
|
|
935
1003
|
required: ["ok", "write", "issues"],
|
|
936
1004
|
}),
|
|
@@ -942,6 +1010,7 @@ const migrateSpec = {
|
|
|
942
1010
|
{ name: "from", field: "from", type: "string" },
|
|
943
1011
|
{ name: "to", field: "to", type: "string" },
|
|
944
1012
|
{ name: "write", field: "write", type: "boolean" },
|
|
1013
|
+
{ name: "zones", field: "zones", type: "boolean" },
|
|
945
1014
|
{ name: "json", field: "json", type: "boolean" },
|
|
946
1015
|
{ name: "dir", field: "dir", type: "string" },
|
|
947
1016
|
],
|
|
@@ -951,7 +1020,8 @@ const migrateSpec = {
|
|
|
951
1020
|
const write = value.write === undefined ? {} : { write: value.write };
|
|
952
1021
|
if (value.kind === "layout") {
|
|
953
1022
|
const { migrateLayout } = await import("./migrate-layout.js");
|
|
954
|
-
|
|
1023
|
+
const options = { ...write, zones: value.zones === true };
|
|
1024
|
+
return { kind: "layout", ...(await migrateLayout(dir, options)) };
|
|
955
1025
|
}
|
|
956
1026
|
const { migrateTailwindToStylex } = await import("./stylex-migrate.js");
|
|
957
1027
|
return migrateTailwindToStylex(dir, write);
|
|
@@ -960,12 +1030,17 @@ const migrateSpec = {
|
|
|
960
1030
|
if (out.kind === "layout") {
|
|
961
1031
|
return [
|
|
962
1032
|
out.ok
|
|
963
|
-
? `✓ ${out.splits.length} route file${out.splits.length === 1 ? "" : "s"} split, ${out.moves.length} file${out.moves.length === 1 ? "" : "s"} moved`
|
|
1033
|
+
? `✓ ${out.mode === "api" ? "API-only app" : `${out.splits.length} route file${out.splits.length === 1 ? "" : "s"} split`}, ${out.moves.length} file${out.moves.length === 1 ? "" : "s"} moved`
|
|
964
1034
|
: `⚠ ${out.issues.length} issue${out.issues.length === 1 ? "" : "s"} need a decision; everything else is planned`,
|
|
965
|
-
...out.splits.map((split) => ` split ${split.file} → ${split.backend} (${split.moved.join(", ")})`),
|
|
1035
|
+
...out.splits.map((split) => ` split ${split.file} → ${split.backend} (${split.moved.join(", ")})${split.shared === undefined ? "" : `, shared data → ${split.shared}`}`),
|
|
966
1036
|
...out.moves.map((move) => ` move ${move.from} → ${move.to}`),
|
|
967
1037
|
...out.rewritten.map((file) => ` edit ${file} (imports)`),
|
|
1038
|
+
...out.tooling.map((edit) => ` edit ${edit.file} (${edit.change})`),
|
|
1039
|
+
...out.schemas
|
|
1040
|
+
.filter((entry) => entry.reason === undefined)
|
|
1041
|
+
.map((entry) => ` draft ${entry.file} ${entry.schema} - review what it lets the browser see${entry.omitted === undefined ? "" : `; leaves out ${entry.omitted.join(", ")}`}${entry.open === undefined ? "" : `; admits any value at ${entry.open.join(", ")}, typed any or unknown`}`),
|
|
968
1042
|
...out.issues.map((issue) => ` ⚠ ${issue.file}: ${issue.reason}`),
|
|
1043
|
+
...out.followUps.map((step) => ` next ${step.file}: ${step.reason} - \`${step.command}\``),
|
|
969
1044
|
...(out.write ? [] : [" dry run: pass --write to apply"]),
|
|
970
1045
|
];
|
|
971
1046
|
}
|
|
@@ -1078,6 +1153,82 @@ const typesSpec = {
|
|
|
1078
1153
|
],
|
|
1079
1154
|
success: (out) => out.ok,
|
|
1080
1155
|
};
|
|
1156
|
+
const SCHEMA_STATUS_LINE = {
|
|
1157
|
+
missing: "+ would write",
|
|
1158
|
+
generated: "+ wrote",
|
|
1159
|
+
stale: "↻ stale",
|
|
1160
|
+
regenerated: "↻ rewrote",
|
|
1161
|
+
current: "✓ current",
|
|
1162
|
+
declared: "· hand-written",
|
|
1163
|
+
"no-data": "· no data",
|
|
1164
|
+
unreadable: "⚠ unreadable",
|
|
1165
|
+
};
|
|
1166
|
+
const schemasSpec = {
|
|
1167
|
+
name: "schemas",
|
|
1168
|
+
summary: "Write a reviewable `loaderOutput`/`actionOutput` from the loader's or action's return type where a route has none (`--write`), keep generated ones current, and list returned fields a hand-written schema drops.",
|
|
1169
|
+
input: SCHEMAS_SCHEMA,
|
|
1170
|
+
output: output({
|
|
1171
|
+
type: "object",
|
|
1172
|
+
properties: {
|
|
1173
|
+
ok: { type: "boolean" },
|
|
1174
|
+
write: { type: "boolean" },
|
|
1175
|
+
entries: { type: "array" },
|
|
1176
|
+
written: { type: "array" },
|
|
1177
|
+
warnings: { type: "array" },
|
|
1178
|
+
},
|
|
1179
|
+
required: ["ok", "write", "entries", "written", "warnings"],
|
|
1180
|
+
}),
|
|
1181
|
+
transports: ["cli"],
|
|
1182
|
+
stability: "stable",
|
|
1183
|
+
argv: {
|
|
1184
|
+
flags: [
|
|
1185
|
+
{ name: "write", field: "write", type: "boolean" },
|
|
1186
|
+
{ name: "check", field: "check", type: "boolean" },
|
|
1187
|
+
{ name: "json", field: "json", type: "boolean" },
|
|
1188
|
+
{ name: "dir", field: "dir", type: "string" },
|
|
1189
|
+
],
|
|
1190
|
+
},
|
|
1191
|
+
async run(value, ctx) {
|
|
1192
|
+
const { outputSchemas } = await import("./output-schemas.js");
|
|
1193
|
+
return outputSchemas(resolve(ctx.cwd, value.dir ?? "."), {
|
|
1194
|
+
write: value.write === true,
|
|
1195
|
+
check: value.check === true,
|
|
1196
|
+
});
|
|
1197
|
+
},
|
|
1198
|
+
render: (out) => {
|
|
1199
|
+
const shown = out.entries.filter((entry) => (entry.status !== "current" || entry.open !== undefined) &&
|
|
1200
|
+
entry.status !== "no-data" &&
|
|
1201
|
+
(entry.status !== "declared" || entry.dropped.length > 0));
|
|
1202
|
+
const current = out.entries.filter((entry) => entry.status === "current").length;
|
|
1203
|
+
return [
|
|
1204
|
+
...out.warnings.map((warning) => `⚠ ${warning}`),
|
|
1205
|
+
`${out.ok ? "✓" : "✖"} ${out.entries.length} output schema${out.entries.length === 1 ? "" : "s"} read, ${current} generated and current`,
|
|
1206
|
+
...shown.map((entry) => {
|
|
1207
|
+
const detail = entry.reason ??
|
|
1208
|
+
(entry.edited === true
|
|
1209
|
+
? "edited by hand under its nifra:generated line"
|
|
1210
|
+
: entry.dropped.length > 0
|
|
1211
|
+
? `drops ${entry.dropped.join(", ")}`
|
|
1212
|
+
: entry.omitted !== undefined
|
|
1213
|
+
? `leaves out ${entry.omitted.join(", ")}`
|
|
1214
|
+
: undefined);
|
|
1215
|
+
const open = entry.open === undefined
|
|
1216
|
+
? []
|
|
1217
|
+
: [
|
|
1218
|
+
` admits any value at ${entry.open.join(", ")}: the type there is any or unknown, so the output guard drops nothing below it`,
|
|
1219
|
+
];
|
|
1220
|
+
return [
|
|
1221
|
+
` ${SCHEMA_STATUS_LINE[entry.status]} ${entry.file}:${entry.line} ${entry.schema}${detail === undefined ? "" : ` - ${detail}`}`,
|
|
1222
|
+
...open,
|
|
1223
|
+
].join("\n");
|
|
1224
|
+
}),
|
|
1225
|
+
...(out.write || !out.entries.some((e) => e.status === "missing" || e.status === "stale")
|
|
1226
|
+
? []
|
|
1227
|
+
: [" dry run: pass --write to apply"]),
|
|
1228
|
+
];
|
|
1229
|
+
},
|
|
1230
|
+
success: (out) => out.ok,
|
|
1231
|
+
};
|
|
1081
1232
|
const snapshotSpec = {
|
|
1082
1233
|
name: "snapshot",
|
|
1083
1234
|
summary: "Write the backend API contract as a versioned JSON baseline.",
|
|
@@ -1102,11 +1253,9 @@ const snapshotSpec = {
|
|
|
1102
1253
|
},
|
|
1103
1254
|
async run(value, ctx) {
|
|
1104
1255
|
const mod = await import("./diff-tool.js");
|
|
1105
|
-
const routes = await mod.snapshotBackend(ctx.cwd);
|
|
1106
1256
|
const file = value.out ?? mod.DEFAULT_SNAPSHOT_FILE;
|
|
1107
|
-
const snapshot =
|
|
1108
|
-
|
|
1109
|
-
return { ok: true, file, routes: routes.length, snapshot };
|
|
1257
|
+
const snapshot = await mod.writeSnapshot(ctx.cwd, file);
|
|
1258
|
+
return { ok: true, file, routes: snapshot.routes.length, snapshot };
|
|
1110
1259
|
},
|
|
1111
1260
|
render: (out) => [
|
|
1112
1261
|
`[nifra] wrote ${out.routes} route${out.routes === 1 ? "" : "s"} to ${out.file}`,
|
|
@@ -1129,19 +1278,17 @@ const diffSpec = {
|
|
|
1129
1278
|
stability: "stable",
|
|
1130
1279
|
argv: { positionals: ["baseline"], flags: [{ name: "json", field: "json", type: "boolean" }] },
|
|
1131
1280
|
async run(value, ctx) {
|
|
1132
|
-
const
|
|
1133
|
-
const
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1281
|
+
const { diffAgainstBaseline, formatDiff } = await import("./diff-tool.js");
|
|
1282
|
+
const diff = await diffAgainstBaseline(ctx.cwd, value.baseline);
|
|
1283
|
+
return {
|
|
1284
|
+
ok: !diff.hasBreaking,
|
|
1285
|
+
hasBreaking: diff.hasBreaking,
|
|
1286
|
+
changes: diff.changes,
|
|
1287
|
+
text: formatDiff(diff),
|
|
1288
|
+
};
|
|
1140
1289
|
},
|
|
1141
|
-
render: (out) => [
|
|
1142
|
-
|
|
1143
|
-
...out.changes.map((c) => `${c.method} ${c.path}: ${c.message}`),
|
|
1144
|
-
],
|
|
1290
|
+
render: (out) => [out.text],
|
|
1291
|
+
json: ({ ok, hasBreaking, changes }) => ({ ok, hasBreaking, changes }),
|
|
1145
1292
|
success: (out) => out.ok,
|
|
1146
1293
|
};
|
|
1147
1294
|
const contractsSpec = {
|
|
@@ -1354,6 +1501,7 @@ export const commandSpecs = Object.freeze([
|
|
|
1354
1501
|
migrateSpec,
|
|
1355
1502
|
targetSpec,
|
|
1356
1503
|
typesSpec,
|
|
1504
|
+
schemasSpec,
|
|
1357
1505
|
snapshotSpec,
|
|
1358
1506
|
diffSpec,
|
|
1359
1507
|
contractsSpec,
|
|
@@ -1365,6 +1513,7 @@ export const commandSpecs = Object.freeze([
|
|
|
1365
1513
|
portSpec,
|
|
1366
1514
|
i18nSpec,
|
|
1367
1515
|
errorsSpec,
|
|
1516
|
+
explainSpec,
|
|
1368
1517
|
logsSpec,
|
|
1369
1518
|
cdnCheckSpec,
|
|
1370
1519
|
dbSchemaSpec,
|