@nifrajs/cli 2.10.0 → 2.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +1 -1
  2. package/dist/check.d.ts +9 -1
  3. package/dist/check.d.ts.map +1 -1
  4. package/dist/check.js +38 -6
  5. package/dist/check.js.map +1 -1
  6. package/dist/cli.d.ts +2 -18
  7. package/dist/cli.d.ts.map +1 -1
  8. package/dist/cli.js +95 -64
  9. package/dist/cli.js.map +1 -1
  10. package/dist/dev-bun-config.d.ts +17 -6
  11. package/dist/dev-bun-config.d.ts.map +1 -1
  12. package/dist/dev-bun-config.js +51 -14
  13. package/dist/dev-bun-config.js.map +1 -1
  14. package/dist/doctor.d.ts +10 -0
  15. package/dist/doctor.d.ts.map +1 -1
  16. package/dist/doctor.js +17 -1
  17. package/dist/doctor.js.map +1 -1
  18. package/dist/introspect.d.ts.map +1 -1
  19. package/dist/introspect.js +7 -1
  20. package/dist/introspect.js.map +1 -1
  21. package/dist/load.d.ts +4 -0
  22. package/dist/load.d.ts.map +1 -1
  23. package/dist/load.js +1 -0
  24. package/dist/load.js.map +1 -1
  25. package/dist/mcp-http.js +1 -1
  26. package/dist/mcp.js +2 -2
  27. package/dist/mcp.js.map +1 -1
  28. package/dist/pipeline-guard.d.ts +25 -10
  29. package/dist/pipeline-guard.d.ts.map +1 -1
  30. package/dist/pipeline-guard.js +35 -15
  31. package/dist/pipeline-guard.js.map +1 -1
  32. package/dist/pipeline-report.d.ts +34 -0
  33. package/dist/pipeline-report.d.ts.map +1 -0
  34. package/dist/pipeline-report.js +282 -0
  35. package/dist/pipeline-report.js.map +1 -0
  36. package/docs/llms-full.txt +200 -13
  37. package/docs/types.json +88 -5
  38. package/package.json +9 -9
  39. package/src/check.ts +54 -5
  40. package/src/cli.ts +99 -65
  41. package/src/dev-bun-config.ts +57 -14
  42. package/src/doctor.ts +28 -1
  43. package/src/introspect.ts +6 -0
  44. package/src/load.ts +5 -0
  45. package/src/mcp-http.ts +1 -1
  46. package/src/mcp.ts +2 -2
  47. package/src/pipeline-guard.ts +44 -14
  48. package/src/pipeline-report.ts +341 -0
@@ -47,6 +47,13 @@ export declare function checkPipelineSeparation(slots: {
47
47
  export type BuildPipeline = "bun" | "vite";
48
48
  export interface PipelineDecision {
49
49
  readonly pipeline: BuildPipeline;
50
+ /**
51
+ * How the pipeline was arrived at. Always set, because "which bundler am I on" is a question every
52
+ * `dev`/`build` run should answer without the user reading this source: `default` is the plain Bun
53
+ * default, `auto` means the config forced nifra's hand (see {@link reason}), `forced` is `--vite` /
54
+ * `--bun`.
55
+ */
56
+ readonly why: "default" | "auto" | "forced";
50
57
  /**
51
58
  * Why this pipeline, for the `nifra build` log line - so an auto-selected Vite build never looks
52
59
  * like the user got the default. `undefined` when the choice was the plain default or was forced.
@@ -60,16 +67,14 @@ export interface PipelineSlots {
60
67
  readonly serverPlugins?: readonly unknown[];
61
68
  }
62
69
  /**
63
- * Pick the bundler for `nifra build`, per app rather than per global default.
70
+ * Pick the bundler for `nifra build` and `nifra dev`, per app rather than per global default.
64
71
  *
65
- * The phase defaults are deliberately asymmetric - `nifra dev` is Vite (for the plugin ecosystem, and
66
- * because Bun's DEV-server bundler cannot compile CSS Modules), `nifra build` is Bun (faster and
67
- * Bun-native). For an app with no transforms that asymmetry is free: there is nothing to disagree about.
68
- * For an app whose ONLY transforms are Vite plugins it is not. Those plugins run in dev and are then
69
- * dropped by the Bun build - `buildForTarget` reads `clientPlugins`/`serverPlugins`, never `vitePlugins`
70
- * - so the build succeeds, the output looks plausible, and the transform simply did not happen. That is
71
- * the same failure {@link checkPipelineSeparation} exists to prevent, reached by crossing PHASES instead
72
- * of slots, and the slot check cannot see it because the plugins are correctly placed.
72
+ * The phase defaults are Bun (faster and Bun-native). For an app with no transforms that is direct and
73
+ * predictable. For an app whose ONLY transforms are Vite plugins it is not: those plugins are required in
74
+ * both dev and production, while the Bun build reads `clientPlugins`/`serverPlugins`, never `vitePlugins`.
75
+ * Selecting Bun would make the build succeed with the transform omitted. That is the same failure
76
+ * {@link checkPipelineSeparation} exists to prevent, reached by crossing PHASES instead of slots, and the
77
+ * slot check cannot see it because the plugins are correctly placed.
73
78
  *
74
79
  * So the default follows the app: Vite plugins with no Bun counterpart means the app has exactly one
75
80
  * pipeline that can build it, and that is the one used. An app declaring BOTH has supplied the Bun
@@ -79,5 +84,15 @@ export interface PipelineSlots {
79
84
  * work, which throws instead. Refusing rather than warning matches the slot guard: a build that succeeds
80
85
  * and omits the transform is worse than one that stops and says so.
81
86
  */
82
- export declare function chooseBuildPipeline(slots: PipelineSlots, forced?: BuildPipeline): PipelineDecision;
87
+ export declare function chooseBuildPipeline(slots: PipelineSlots, forced?: BuildPipeline, command?: "build" | "dev"): PipelineDecision;
88
+ /**
89
+ * The one-line "which bundler, and why" note `nifra dev` and `nifra build` print under their banner.
90
+ *
91
+ * Printed on EVERY run, not only the surprising ones. A pipeline that announces itself only when it
92
+ * deviates teaches nobody which pipeline they are normally on, and every gotcha in the dev docs -
93
+ * plugin slots, resolve conditions, which compiler owns a `.svelte` file - is answerable only once you
94
+ * know that. The line also names the flag that switches, so the answer to "can I try the other one"
95
+ * is on screen rather than in the docs.
96
+ */
97
+ export declare function describePipeline(decision: PipelineDecision): string;
83
98
  //# sourceMappingURL=pipeline-guard.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline-guard.d.ts","sourceRoot":"","sources":["../src/pipeline-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,wCAAwC;AACxC,MAAM,MAAM,YAAY,GAAG,aAAa,GAAG,eAAe,GAAG,eAAe,CAAA;AAE5E,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAA;IAC3B,mEAAmE;IACnE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,mCAAmC;IACnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,CAAA;IACjC,yDAAyD;IACzD,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,CAAA;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CACrB;AAmCD;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,YAAY,EAClB,OAAO,EAAE,SAAS,OAAO,EAAE,GAC1B,gBAAgB,EAAE,CAqBpB;AAED,uDAAuD;AACvD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE;IAC7C,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,OAAO,EAAE,CAAA;IACzC,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,OAAO,EAAE,CAAA;IAC3C,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,OAAO,EAAE,CAAA;CAC5C,GAAG,gBAAgB,EAAE,CAMrB;AAED,qCAAqC;AACrC,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,MAAM,CAAA;AAE1C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAA;IAChC;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,2DAA2D;AAC3D,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,OAAO,EAAE,CAAA;IACzC,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,OAAO,EAAE,CAAA;IAC3C,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,OAAO,EAAE,CAAA;CAC5C;AAUD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,aAAa,EACpB,MAAM,CAAC,EAAE,aAAa,GACrB,gBAAgB,CAsBlB"}
1
+ {"version":3,"file":"pipeline-guard.d.ts","sourceRoot":"","sources":["../src/pipeline-guard.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,wCAAwC;AACxC,MAAM,MAAM,YAAY,GAAG,aAAa,GAAG,eAAe,GAAG,eAAe,CAAA;AAE5E,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAA;IAC3B,mEAAmE;IACnE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,mCAAmC;IACnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,CAAA;IACjC,yDAAyD;IACzD,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,KAAK,CAAA;IAC/B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CACrB;AAmCD;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,YAAY,EAClB,OAAO,EAAE,SAAS,OAAO,EAAE,GAC1B,gBAAgB,EAAE,CAqBpB;AAED,uDAAuD;AACvD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE;IAC7C,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,OAAO,EAAE,CAAA;IACzC,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,OAAO,EAAE,CAAA;IAC3C,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,OAAO,EAAE,CAAA;CAC5C,GAAG,gBAAgB,EAAE,CAMrB;AAED,qCAAqC;AACrC,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,MAAM,CAAA;AAE1C,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAA;IAChC;;;;;OAKG;IACH,QAAQ,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,GAAG,QAAQ,CAAA;IAC3C;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,2DAA2D;AAC3D,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,OAAO,EAAE,CAAA;IACzC,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,OAAO,EAAE,CAAA;IAC3C,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,OAAO,EAAE,CAAA;CAC5C;AAUD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,aAAa,EACpB,MAAM,CAAC,EAAE,aAAa,EACtB,OAAO,GAAE,OAAO,GAAG,KAAe,GACjC,gBAAgB,CA0BlB;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,gBAAgB,GAAG,MAAM,CASnE"}
@@ -93,16 +93,14 @@ const pluginNames = (plugins) => plugins
93
93
  })
94
94
  .join(", ");
95
95
  /**
96
- * Pick the bundler for `nifra build`, per app rather than per global default.
96
+ * Pick the bundler for `nifra build` and `nifra dev`, per app rather than per global default.
97
97
  *
98
- * The phase defaults are deliberately asymmetric - `nifra dev` is Vite (for the plugin ecosystem, and
99
- * because Bun's DEV-server bundler cannot compile CSS Modules), `nifra build` is Bun (faster and
100
- * Bun-native). For an app with no transforms that asymmetry is free: there is nothing to disagree about.
101
- * For an app whose ONLY transforms are Vite plugins it is not. Those plugins run in dev and are then
102
- * dropped by the Bun build - `buildForTarget` reads `clientPlugins`/`serverPlugins`, never `vitePlugins`
103
- * - so the build succeeds, the output looks plausible, and the transform simply did not happen. That is
104
- * the same failure {@link checkPipelineSeparation} exists to prevent, reached by crossing PHASES instead
105
- * of slots, and the slot check cannot see it because the plugins are correctly placed.
98
+ * The phase defaults are Bun (faster and Bun-native). For an app with no transforms that is direct and
99
+ * predictable. For an app whose ONLY transforms are Vite plugins it is not: those plugins are required in
100
+ * both dev and production, while the Bun build reads `clientPlugins`/`serverPlugins`, never `vitePlugins`.
101
+ * Selecting Bun would make the build succeed with the transform omitted. That is the same failure
102
+ * {@link checkPipelineSeparation} exists to prevent, reached by crossing PHASES instead of slots, and the
103
+ * slot check cannot see it because the plugins are correctly placed.
106
104
  *
107
105
  * So the default follows the app: Vite plugins with no Bun counterpart means the app has exactly one
108
106
  * pipeline that can build it, and that is the one used. An app declaring BOTH has supplied the Bun
@@ -112,25 +110,47 @@ const pluginNames = (plugins) => plugins
112
110
  * work, which throws instead. Refusing rather than warning matches the slot guard: a build that succeeds
113
111
  * and omits the transform is worse than one that stops and says so.
114
112
  */
115
- export function chooseBuildPipeline(slots, forced) {
113
+ export function chooseBuildPipeline(slots, forced, command = "build") {
116
114
  const vitePlugins = slots.vitePlugins ?? [];
117
115
  const bunPlugins = [...(slots.clientPlugins ?? []), ...(slots.serverPlugins ?? [])];
118
116
  const viteOnly = vitePlugins.length > 0 && bunPlugins.length === 0;
119
117
  if (forced === "bun" && viteOnly) {
120
- throw new Error("[nifra] `nifra build --bun` would silently drop this app's only transforms. `vitePlugins` are " +
121
- "read by the Vite build; the Bun build reads `clientPlugins`/`serverPlugins`, so these would " +
118
+ // Named for the command the user actually typed - a `nifra dev --bun` failure that talks about
119
+ // `nifra build` sends them looking at the wrong command.
120
+ const phase = command === "dev" ? "dev server" : "build";
121
+ throw new Error(`[nifra] \`nifra ${command} --bun\` would silently drop this app's only transforms. \`vitePlugins\` are ` +
122
+ `read by the Vite ${phase}; the Bun ${phase} reads \`clientPlugins\`/\`serverPlugins\`, so these would ` +
122
123
  "never run and the output would look plausible without them.\n" +
123
124
  ` Would be dropped: ${pluginNames(vitePlugins)}\n` +
124
- " Drop the flag to build with Vite, or add the Bun equivalents to `clientPlugins`/`serverPlugins`.");
125
+ ` Drop the flag to use Vite, or add the Bun equivalents to \`clientPlugins\`/\`serverPlugins\`.`);
125
126
  }
126
127
  if (forced !== undefined)
127
- return { pipeline: forced };
128
+ return { pipeline: forced, why: "forced" };
128
129
  if (viteOnly) {
129
130
  return {
130
131
  pipeline: "vite",
132
+ why: "auto",
131
133
  reason: `auto: this app's only transforms are \`vitePlugins\` (${pluginNames(vitePlugins)}), which the Bun build cannot run`,
132
134
  };
133
135
  }
134
- return { pipeline: "bun" };
136
+ return { pipeline: "bun", why: "default" };
137
+ }
138
+ /**
139
+ * The one-line "which bundler, and why" note `nifra dev` and `nifra build` print under their banner.
140
+ *
141
+ * Printed on EVERY run, not only the surprising ones. A pipeline that announces itself only when it
142
+ * deviates teaches nobody which pipeline they are normally on, and every gotcha in the dev docs -
143
+ * plugin slots, resolve conditions, which compiler owns a `.svelte` file - is answerable only once you
144
+ * know that. The line also names the flag that switches, so the answer to "can I try the other one"
145
+ * is on screen rather than in the docs.
146
+ */
147
+ export function describePipeline(decision) {
148
+ const other = decision.pipeline === "bun" ? "--vite" : "--bun";
149
+ const detail = decision.why === "forced"
150
+ ? `forced by --${decision.pipeline}`
151
+ : decision.why === "auto"
152
+ ? (decision.reason ?? "auto")
153
+ : `default; ${other} to switch`;
154
+ return `bundler: ${decision.pipeline} (${detail})`;
135
155
  }
136
156
  //# sourceMappingURL=pipeline-guard.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline-guard.js","sourceRoot":"","sources":["../src/pipeline-guard.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pipeline-guard.js","sourceRoot":"","sources":["../src/pipeline-guard.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import type { BuildPipeline } from "./pipeline-guard.js";
2
+ export interface PipelineFinding {
3
+ readonly rule: "adapter-entry" | "plugin-slot" | "bun-client-conditions";
4
+ readonly severity: "error" | "warning";
5
+ /** Project-relative file the finding is in. */
6
+ readonly file: string;
7
+ readonly line?: number;
8
+ readonly message: string;
9
+ readonly fix: string;
10
+ }
11
+ export interface PipelineReport {
12
+ /** `false` when the directory holds no `nifra.config.ts` or `framework.ts` - nothing to report on. */
13
+ readonly ran: boolean;
14
+ /** The bundler `nifra dev` and `nifra build` will use, or `unknown` when the source can't say. */
15
+ readonly pipeline: BuildPipeline | "unknown";
16
+ /** Plain-language "why this bundler", in the same words the CLI prints. */
17
+ readonly reason: string;
18
+ /**
19
+ * Whether the config states its plugin slots outright. `false` when a slot is a thunk, an identifier,
20
+ * or a re-export - the pipeline shown is then nifra's best reading, and `nifra dev` prints the real one.
21
+ */
22
+ readonly certain: boolean;
23
+ /** The config file read, project-relative. */
24
+ readonly configFile?: string;
25
+ /** The file `nifra build` imports the adapter from - `framework.ts`, else the config. */
26
+ readonly adapterEntry?: string;
27
+ readonly findings: readonly PipelineFinding[];
28
+ }
29
+ /**
30
+ * Report the pipeline and its config hazards for the app at `cwd`, without executing anything.
31
+ * Total: a missing or unreadable config yields `ran: false`, never a throw.
32
+ */
33
+ export declare function collectPipelineReport(cwd: string): Promise<PipelineReport>;
34
+ //# sourceMappingURL=pipeline-report.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline-report.d.ts","sourceRoot":"","sources":["../src/pipeline-report.ts"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAA;AAaxD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,aAAa,GAAG,uBAAuB,CAAA;IACxE,QAAQ,CAAC,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAA;IACtC,+CAA+C;IAC/C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAA;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,sGAAsG;IACtG,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAA;IACrB,kGAAkG;IAClG,QAAQ,CAAC,QAAQ,EAAE,aAAa,GAAG,SAAS,CAAA;IAC5C,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB;;;OAGG;IACH,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAA;IACzB,8CAA8C;IAC9C,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAA;IAC5B,yFAAyF;IACzF,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,QAAQ,EAAE,SAAS,eAAe,EAAE,CAAA;CAC9C;AA0JD;;;GAGG;AACH,wBAAsB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC,CAgHhF"}
@@ -0,0 +1,282 @@
1
+ /**
2
+ * The two-pipeline rule, reported STATICALLY - which bundler this app runs on, and the config hazards
3
+ * that only exist because nifra supports two.
4
+ *
5
+ * `loadApp` already refuses a plugin in the wrong slot ({@link ./load.ts}), and `nifra dev`/`nifra build`
6
+ * print the chosen bundler. Both of those need the app's config to be IMPORTED, which is code execution -
7
+ * something `nifra check` deliberately never does, and something an agent inspecting a repo it has not
8
+ * installed cannot do at all. So this reads the config as text instead.
9
+ *
10
+ * Text, not types, so the rules are chosen for the ones that survive being read rather than run:
11
+ *
12
+ * - Which pipeline the app is on. `chooseBuildPipeline` decides from whether the plugin slots are
13
+ * empty, and "does this file declare a non-empty `vitePlugins`" is a question the source answers.
14
+ * - The adapter-entry hazard. `nifra build` imports the adapter from `framework.ts`, or from
15
+ * `nifra.config.ts` when there is no `framework.ts`, and bundles everything that file imports into
16
+ * the production server. A Vite plugin or an SFC compiler reached that way builds cleanly and then
17
+ * dies at startup on a missing native binding. Nothing runtime-side catches it: by then the build
18
+ * has already succeeded.
19
+ * - A plugin in the wrong slot, for the subset whose import specifier names its pipeline. The load
20
+ * guard classifies by hook shape and is authoritative; this catches the same thing earlier, before
21
+ * anything is installed or started.
22
+ * - `conditions` on the Bun pipeline, which reach SSR and cannot reach the dev client bundle.
23
+ *
24
+ * Everything here degrades to silence rather than guessing. A config that computes its plugins, or
25
+ * re-exports them from elsewhere, yields `certain: false` and no findings - a static reader that
26
+ * invents a pipeline is worse than one that says it could not tell.
27
+ */
28
+ import { existsSync } from "node:fs";
29
+ import { join } from "node:path";
30
+ import { codePositionMask, stripComments } from "./check.js";
31
+ /** A plugin slot, and the pipeline it feeds. */
32
+ const SLOT_PIPELINE = {
33
+ vitePlugins: "vite",
34
+ clientPlugins: "bun",
35
+ serverPlugins: "bun",
36
+ };
37
+ const SLOTS = Object.keys(SLOT_PIPELINE);
38
+ /**
39
+ * Specifiers that carry a dev toolchain: Vite itself, a Vite/Rollup plugin, or a framework's SFC
40
+ * compiler plugin (`@nifrajs/web-vue/plugin` and friends, which import the compiler). A relative
41
+ * `./plugin` is NOT matched - a local file of that name is as likely to be the app's own tiny plugin as
42
+ * a compiler, and this rule fails a gate.
43
+ */
44
+ const DEV_TOOLCHAIN = /^vite$|^vite\/|^@vitejs\/|vite-plugin|^rollup$|^@rollup\/|^esbuild$|^(?:@[^/]+\/)?[^./][^/]*\/(?:.*\/)?plugin(?:\.ts)?$/;
45
+ /** Specifiers that name the Vite pipeline outright. */
46
+ const VITE_SPECIFIER = /^vite$|^vite\/|^@vitejs\/|vite-plugin/;
47
+ /** Specifiers whose package subpath is nifra's Bun-plugin convention (`@nifrajs/web-vue/plugin`). */
48
+ const BUN_SPECIFIER = /^(?:@[^/]+\/)?[^./][^/]*\/(?:.*\/)?plugin(?:\.ts)?$/;
49
+ const lineAt = (src, index) => {
50
+ let line = 1;
51
+ for (let i = 0; i < index && i < src.length; i++)
52
+ if (src[i] === "\n")
53
+ line++;
54
+ return line;
55
+ };
56
+ /** Local binding names introduced by one import clause (`a`, `{ b as c }`, `* as ns`). */
57
+ function localNames(clause) {
58
+ const names = [];
59
+ const braced = /\{([^}]*)\}/.exec(clause);
60
+ if (braced !== null) {
61
+ for (const part of (braced[1] ?? "").split(",")) {
62
+ const named = /([A-Za-z_$][\w$]*)\s*$/.exec(part.trim());
63
+ if (named?.[1] !== undefined)
64
+ names.push(named[1]);
65
+ }
66
+ }
67
+ const head = clause.replace(/\{[^}]*\}/, " ").replace(/,/g, " ");
68
+ const star = /\*\s*as\s+([A-Za-z_$][\w$]*)/.exec(head);
69
+ if (star?.[1] !== undefined)
70
+ names.push(star[1]);
71
+ else {
72
+ const def = /^\s*([A-Za-z_$][\w$]*)\s*$/.exec(head);
73
+ if (def?.[1] !== undefined)
74
+ names.push(def[1]);
75
+ }
76
+ return names;
77
+ }
78
+ /**
79
+ * Every value-importing binding in a module, mapped to the specifier it came from. `import type` is
80
+ * skipped: a type has no runtime cost, so it is neither a bundled toolchain nor a plugin in a slot.
81
+ */
82
+ function importedBindings(stripped) {
83
+ const out = new Map();
84
+ const re = /(?<![.\w$])import\s+(?!type[\s{])([^'";]+?)\s+from\s*['"]([^'"]+)['"]/g;
85
+ for (let m = re.exec(stripped); m !== null; m = re.exec(stripped)) {
86
+ const specifier = m[2];
87
+ if (specifier === undefined)
88
+ continue;
89
+ for (const name of localNames(m[1] ?? ""))
90
+ out.set(name, { specifier, index: m.index });
91
+ }
92
+ return out;
93
+ }
94
+ /** Every specifier a module imports for its side effects or bindings, with the position to report. */
95
+ function importedSpecifiers(stripped) {
96
+ const out = [];
97
+ const re = /(?<![.\w$])import\s+(?:(?!type[\s{])[^'";]*?\s+from\s*)?['"]([^'"]+)['"]/g;
98
+ for (let m = re.exec(stripped); m !== null; m = re.exec(stripped)) {
99
+ if (m[1] !== undefined)
100
+ out.push({ specifier: m[1], index: m.index });
101
+ }
102
+ return out;
103
+ }
104
+ /** Index just past the `]` matching the `[` at `open`, or `undefined` when it never closes. */
105
+ function closeBracket(masked, open) {
106
+ let depth = 0;
107
+ for (let i = open; i < masked.length; i++) {
108
+ const c = masked[i];
109
+ if (c === "[")
110
+ depth++;
111
+ else if (c === "]") {
112
+ depth--;
113
+ if (depth === 0)
114
+ return i;
115
+ }
116
+ }
117
+ return undefined;
118
+ }
119
+ const ABSENT = { present: false, certain: true };
120
+ /**
121
+ * Read one exported binding as a plugin slot.
122
+ *
123
+ * Only an array LITERAL is read precisely; a thunk (`() => import(…)`), a bare identifier or a
124
+ * re-export is recorded as present-but-uncertain. That asymmetry is deliberate: `[]` and `[vue()]`
125
+ * decide the pipeline, and anything else is a promise the source cannot keep.
126
+ */
127
+ function readSlot(masked, stripped, name) {
128
+ const declaration = new RegExp(`(?<![.\\w$])export\\s+(?:const|let|var)\\s+${name}\\b[^=\\n]*=\\s*`);
129
+ const m = declaration.exec(masked);
130
+ if (m !== null) {
131
+ const start = m.index + m[0].length;
132
+ if (masked[start] === "[") {
133
+ const end = closeBracket(masked, start);
134
+ if (end !== undefined) {
135
+ // Both views are offset-preserving, and each answers a different question: the mask has string
136
+ // CONTENTS blanked, so identifiers found in it are real code; the stripped source keeps them, so
137
+ // it is the one that can tell `["solid"]` from `[]`.
138
+ const code = masked.slice(start + 1, end);
139
+ const text = stripped.slice(start + 1, end);
140
+ const items = [...code.matchAll(/(?<![.\w$])([A-Za-z_$][\w$]*)/g)].map((i) => i[1] ?? "");
141
+ return { present: text.trim() !== "", certain: true, index: m.index, items };
142
+ }
143
+ }
144
+ return { present: true, certain: false, index: m.index };
145
+ }
146
+ // `export { vitePlugins } from "./plugins.ts"` - present, but its contents live in another file.
147
+ const reexport = new RegExp(`(?<![.\\w$])export\\s*\\{[^}]*\\b${name}\\b[^}]*\\}`);
148
+ const r = reexport.exec(stripped);
149
+ if (r !== null)
150
+ return { present: true, certain: false, index: r.index };
151
+ // `export * from …` could carry the slot; say so rather than reporting an absence that isn't one.
152
+ if (/(?<![.\w$])export\s*\*\s*from/.test(stripped))
153
+ return { present: false, certain: false };
154
+ return ABSENT;
155
+ }
156
+ /** Which pipeline a plugin reference belongs to, or `undefined` when its name and origin say nothing. */
157
+ function classifyRef(name, specifier) {
158
+ // nifra's own Bun plugins are named for what they are, and the name survives an alias-free import.
159
+ if (/BunPlugin$/.test(name))
160
+ return "bun";
161
+ if (specifier === undefined)
162
+ return undefined;
163
+ if (VITE_SPECIFIER.test(specifier))
164
+ return "vite";
165
+ if (BUN_SPECIFIER.test(specifier))
166
+ return "bun";
167
+ return undefined;
168
+ }
169
+ /** Read one file as text, or `undefined` when it is missing or unreadable. */
170
+ async function readSource(path) {
171
+ try {
172
+ return await Bun.file(path).text();
173
+ }
174
+ catch {
175
+ return undefined;
176
+ }
177
+ }
178
+ /**
179
+ * Report the pipeline and its config hazards for the app at `cwd`, without executing anything.
180
+ * Total: a missing or unreadable config yields `ran: false`, never a throw.
181
+ */
182
+ export async function collectPipelineReport(cwd) {
183
+ const configFile = existsSync(join(cwd, "nifra.config.ts")) ? "nifra.config.ts" : "framework.ts";
184
+ const source = await readSource(join(cwd, configFile));
185
+ if (source === undefined) {
186
+ return {
187
+ ran: false,
188
+ pipeline: "unknown",
189
+ reason: "no nifra.config.ts or framework.ts here",
190
+ certain: false,
191
+ findings: [],
192
+ };
193
+ }
194
+ const masked = codePositionMask(source);
195
+ const stripped = stripComments(source);
196
+ const bindings = importedBindings(stripped);
197
+ const slots = Object.fromEntries(SLOTS.map((slot) => [slot, readSlot(masked, stripped, slot)]));
198
+ const findings = [];
199
+ // A plugin whose specifier names the other pipeline. The load-time guard classifies by hook shape and
200
+ // remains the authority; this is the half of it that can run on a repo nobody has installed yet.
201
+ for (const slot of SLOTS) {
202
+ const state = slots[slot];
203
+ const expected = SLOT_PIPELINE[slot];
204
+ for (const item of state.items ?? []) {
205
+ const binding = bindings.get(item);
206
+ const actual = classifyRef(item, binding?.specifier);
207
+ if (actual === undefined || actual === expected)
208
+ continue;
209
+ const from = binding !== undefined ? ` (imported from "${binding.specifier}")` : "";
210
+ findings.push({
211
+ rule: "plugin-slot",
212
+ severity: "error",
213
+ file: configFile,
214
+ line: lineAt(source, state.index ?? 0),
215
+ message: `\`${item}\`${from} is a ${actual === "vite" ? "Vite" : "Bun"} plugin but sits in \`${slot}\`, which feeds ` +
216
+ `${expected === "vite" ? "Vite" : "Bun.build"}. The wrong bundler never calls its hooks, so the transform silently does not run and the build still succeeds.`,
217
+ fix: actual === "vite"
218
+ ? `move \`${item}\` to \`vitePlugins\``
219
+ : `move \`${item}\` to \`clientPlugins\` (client bundle) or \`serverPlugins\` (SSR)`,
220
+ });
221
+ }
222
+ }
223
+ // Which bundler this app gets, by the same rule `chooseBuildPipeline` applies to the loaded config.
224
+ const viteOnly = slots.vitePlugins.present && !slots.clientPlugins.present && !slots.serverPlugins.present;
225
+ const certain = SLOTS.every((slot) => slots[slot].certain);
226
+ const pipeline = viteOnly ? "vite" : "bun";
227
+ const reason = viteOnly
228
+ ? "auto: this app's only transforms are `vitePlugins`, which the Bun build cannot run"
229
+ : slots.clientPlugins.present || slots.serverPlugins.present
230
+ ? "default: this app declares Bun plugins, so both phases stay on Bun"
231
+ : "default: no transforms to place, so both phases stay on Bun";
232
+ // The adapter entry is bundled into every `nifra build` server entry. Whatever it imports goes with it.
233
+ const adapterEntry = existsSync(join(cwd, "framework.ts")) ? "framework.ts" : configFile;
234
+ const entrySource = adapterEntry === configFile ? source : await readSource(join(cwd, adapterEntry));
235
+ if (entrySource !== undefined) {
236
+ const seen = new Set();
237
+ for (const { specifier, index } of importedSpecifiers(stripComments(entrySource))) {
238
+ if (!DEV_TOOLCHAIN.test(specifier) || seen.has(specifier))
239
+ continue;
240
+ seen.add(specifier);
241
+ findings.push({
242
+ rule: "adapter-entry",
243
+ severity: "error",
244
+ file: adapterEntry,
245
+ line: lineAt(entrySource, index),
246
+ message: `${adapterEntry} imports "${specifier}", and \`nifra build\` imports the adapter from ${adapterEntry} - ` +
247
+ "so the dev toolchain is bundled into the production server entry. The build succeeds and the server then fails at startup on a dependency of the bundler (a missing native binding, typically), which reads like a broken install rather than a config split.",
248
+ fix: adapterEntry === "framework.ts"
249
+ ? 'move "' +
250
+ specifier +
251
+ '" to `nifra.config.ts`, which only the CLI imports, and keep `framework.ts` to the adapter'
252
+ : 'add a `framework.ts` exporting just the adapter, re-export it from `nifra.config.ts` (`export { adapter } from "./framework"`), and leave the toolchain imports in the config',
253
+ });
254
+ }
255
+ }
256
+ // `conditions` reach SSR on the Bun pipeline and cannot reach the client bundle Bun's dev server
257
+ // serves - it takes no resolve conditions from bunfig or anywhere else. `nifra dev` says so at
258
+ // startup; a project whose CI only runs `nifra check` would otherwise never hear it.
259
+ const conditions = readSlot(masked, stripped, "conditions");
260
+ if (conditions.present && pipeline === "bun") {
261
+ findings.push({
262
+ rule: "bun-client-conditions",
263
+ severity: "warning",
264
+ file: configFile,
265
+ line: lineAt(source, conditions.index ?? 0),
266
+ message: "`conditions` are honoured by SSR and by `nifra build`, but Bun's dev-server bundler accepts no resolve conditions - so under `nifra dev` a package with an `exports` map can resolve to one file in the browser and another everywhere else.",
267
+ fix: "run `nifra dev --vite` when the client bundle must resolve exactly as production does",
268
+ });
269
+ }
270
+ return {
271
+ ran: true,
272
+ pipeline: certain ? pipeline : "unknown",
273
+ reason: certain
274
+ ? reason
275
+ : "the config states its plugins indirectly (a thunk, an identifier or a re-export), so the bundler can only be read by loading it - `nifra dev` and `nifra build` print the real one",
276
+ certain,
277
+ configFile,
278
+ adapterEntry,
279
+ findings,
280
+ };
281
+ }
282
+ //# sourceMappingURL=pipeline-report.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pipeline-report.js","sourceRoot":"","sources":["../src/pipeline-report.ts"],"names":[],"mappings":"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"}