@hominis/fireforge 0.18.10 → 0.19.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 (34) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +21 -8
  3. package/dist/src/commands/doctor.js +1 -1
  4. package/dist/src/commands/furnace/index.js +1 -1
  5. package/dist/src/commands/manifest.js +2 -0
  6. package/dist/src/commands/package.js +1 -1
  7. package/dist/src/commands/test.js +8 -8
  8. package/dist/src/commands/typecheck.d.ts +52 -0
  9. package/dist/src/commands/typecheck.js +115 -0
  10. package/dist/src/core/config-paths.d.ts +2 -2
  11. package/dist/src/core/config-paths.js +7 -0
  12. package/dist/src/core/config-validate.js +111 -0
  13. package/dist/src/core/mach-build-artifacts.d.ts +2 -2
  14. package/dist/src/core/mach-build-artifacts.js +2 -2
  15. package/dist/src/core/mach-error-hints.js +7 -8
  16. package/dist/src/core/marionette-port.js +4 -4
  17. package/dist/src/core/patch-lint-checkjs.d.ts +30 -2
  18. package/dist/src/core/patch-lint-checkjs.js +78 -78
  19. package/dist/src/core/patch-lint-reexports.d.ts +9 -0
  20. package/dist/src/core/patch-lint-reexports.js +11 -0
  21. package/dist/src/core/patch-lint.d.ts +1 -5
  22. package/dist/src/core/patch-lint.js +6 -11
  23. package/dist/src/core/typecheck-shim.d.ts +70 -0
  24. package/dist/src/core/typecheck-shim.js +112 -0
  25. package/dist/src/core/typecheck.d.ts +65 -0
  26. package/dist/src/core/typecheck.js +302 -0
  27. package/dist/src/core/xpcshell-appdir.d.ts +2 -2
  28. package/dist/src/core/xpcshell-appdir.js +2 -2
  29. package/dist/src/types/commands/options.d.ts +1 -1
  30. package/dist/src/types/config.d.ts +61 -0
  31. package/dist/src/types/furnace.d.ts +1 -1
  32. package/dist/src/types/typecheck.d.ts +51 -0
  33. package/dist/src/types/typecheck.js +15 -0
  34. package/package.json +1 -1
@@ -0,0 +1,302 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ /**
3
+ * Whole-project TypeScript type checking driven by user-supplied
4
+ * `jsconfig.json` paths. The engine behind the `fireforge typecheck`
5
+ * command.
6
+ *
7
+ * Distinct from `patch-lint-checkjs.ts` (patch-hygiene): patchLint is
8
+ * scoped, fireforge-controlled, and runs as part of `fireforge lint`;
9
+ * this command runs whole projects with user-controlled compiler
10
+ * options and is intended as a CI gate. The two share the Firefox
11
+ * globals shim and suppressed-code list (via `typecheck-shim.ts`) so
12
+ * a file that lints clean cannot fail typecheck for a reason the
13
+ * operator could not have inferred from the docs.
14
+ *
15
+ * Loads the TypeScript compiler API via dynamic import so it is only
16
+ * required when `typecheck.projects` is configured. TypeScript
17
+ * remains a dev-dependency — if a user invokes `fireforge typecheck`
18
+ * without installing it, the function returns a clear error pointing
19
+ * at `npm install typescript`.
20
+ */
21
+ import { dirname, isAbsolute, relative, resolve } from 'node:path';
22
+ import { pathExists } from '../utils/fs.js';
23
+ import { verbose } from '../utils/logger.js';
24
+ import { composeShimSource, SHIM_FILENAME, SUPPRESSED_DIAGNOSTIC_CODES } from './typecheck-shim.js';
25
+ /**
26
+ * Sentinel string surfaced as a `TypecheckIssue.message` when the
27
+ * project's jsconfig sets `checkJs: false`. Exported so tests can
28
+ * pin the contract — operators rely on it to spot opted-out projects
29
+ * in CI logs.
30
+ */
31
+ export const CHECK_JS_DISABLED_NOTICE = 'Project sets "checkJs: false" — skipping (override the jsconfig to enable typecheck).';
32
+ /**
33
+ * Runs `fireforge typecheck` against every project listed in `cfg.projects`.
34
+ *
35
+ * Per-project flow:
36
+ * 1. Read the jsconfig via the TS API. JSON parse / config-spec
37
+ * errors are surfaced as issues, not thrown — a single broken
38
+ * project must not abort the rest of the run.
39
+ * 2. Compute final compiler options from the user's options. We
40
+ * only force `noEmit: true` (this is a typecheck, not a build);
41
+ * we honour `strict`, `target`, `lib`, `module`, `paths`,
42
+ * `include`, `exclude`. `allowJs` and `checkJs` default to
43
+ * `true` only when the user has not set them — if the user set
44
+ * `checkJs: false` we treat that as an explicit opt-out and
45
+ * skip the project with a single notice (see {@link CHECK_JS_DISABLED_NOTICE}).
46
+ * 3. Inject the synthetic shim (built-in + optional extraShim) as
47
+ * a virtual root file that the custom CompilerHost serves.
48
+ * 4. Build the program; collect semantic, syntactic, options, and
49
+ * global diagnostics. The patchLint flow only reads semantic +
50
+ * syntactic — fine for hygiene, but a CI gate needs the full
51
+ * set so misconfigured `lib`/`paths` entries fail loudly.
52
+ * 5. Drop diagnostics whose code is in `SUPPRESSED_DIAGNOSTIC_CODES`
53
+ * and any diagnostic originating in the synthetic shim itself.
54
+ *
55
+ * @param projectRoot - Absolute project root. All paths in `cfg` are resolved against it.
56
+ * @param cfg - Validated `typecheck` block from `fireforge.json`.
57
+ * @returns One {@link TypecheckProjectResult} per entry in `cfg.projects`,
58
+ * in declared order. The CLI is responsible for printing the issues
59
+ * and computing the exit code.
60
+ */
61
+ export async function runTypecheck(projectRoot, cfg) {
62
+ // Dynamic import — typescript stays a dev dependency. Same pattern
63
+ // as `patch-lint-checkjs.ts`; the empty-projects-array case is
64
+ // already rejected by config-validate, so we don't gate the import
65
+ // on `cfg.projects.length`.
66
+ let ts;
67
+ try {
68
+ ts = await import('typescript');
69
+ }
70
+ catch {
71
+ return cfg.projects.map((project) => ({
72
+ project,
73
+ issues: [
74
+ {
75
+ file: '(typecheck)',
76
+ line: 1,
77
+ column: 1,
78
+ code: 0,
79
+ category: 'error',
80
+ message: 'fireforge typecheck requires the "typescript" package. Run "npm install typescript" to enable type checking.',
81
+ project,
82
+ },
83
+ ],
84
+ filesChecked: 0,
85
+ }));
86
+ }
87
+ // Compose the shim once — extraShim is shared across all projects.
88
+ // A missing or unreadable shim is a project-wide failure, so we
89
+ // surface it as one issue per project rather than letting one
90
+ // project's read failure silently affect the others' results.
91
+ let shimSource;
92
+ try {
93
+ const composed = await composeShimSource(projectRoot, cfg.extraShim);
94
+ shimSource = composed.source;
95
+ if (composed.extraShimAppended) {
96
+ verbose(`typecheck: extra shim ${cfg.extraShim ?? ''} appended to Firefox globals shim`);
97
+ }
98
+ }
99
+ catch (err) {
100
+ const message = err instanceof Error ? err.message : String(err);
101
+ return cfg.projects.map((project) => ({
102
+ project,
103
+ issues: [
104
+ {
105
+ file: cfg.extraShim ?? '(typecheck)',
106
+ line: 1,
107
+ column: 1,
108
+ code: 0,
109
+ category: 'error',
110
+ message,
111
+ project,
112
+ },
113
+ ],
114
+ filesChecked: 0,
115
+ }));
116
+ }
117
+ const results = [];
118
+ for (const projectPath of cfg.projects) {
119
+ results.push(await runTypecheckForProject(ts, projectRoot, projectPath, shimSource));
120
+ }
121
+ return results;
122
+ }
123
+ /** Runs typecheck for a single jsconfig path, isolating its failures. */
124
+ async function runTypecheckForProject(ts, projectRoot, projectPath, shimSource) {
125
+ const absConfig = resolve(projectRoot, projectPath);
126
+ if (!(await pathExists(absConfig))) {
127
+ return {
128
+ project: projectPath,
129
+ issues: [
130
+ {
131
+ file: projectPath,
132
+ line: 1,
133
+ column: 1,
134
+ code: 0,
135
+ category: 'error',
136
+ message: `jsconfig.json not found: ${projectPath} (resolved to ${absConfig})`,
137
+ project: projectPath,
138
+ },
139
+ ],
140
+ filesChecked: 0,
141
+ };
142
+ }
143
+ // 1) Read the JSON config. ts.readConfigFile reports JSON-shape
144
+ // errors via the returned diagnostic; missing files fall back to
145
+ // pathExists above, which gives a more directly actionable message.
146
+ const readResult = ts.readConfigFile(absConfig, (path) => ts.sys.readFile(path));
147
+ if (readResult.error) {
148
+ return {
149
+ project: projectPath,
150
+ issues: [diagnosticToIssue(ts, readResult.error, projectPath, projectPath)],
151
+ filesChecked: 0,
152
+ };
153
+ }
154
+ // 2) Parse the config content. This is what surfaces config-spec
155
+ // errors (unknown options, mismatched types in `compilerOptions`,
156
+ // bad `include` patterns, etc.) — TS5xxx codes. We surface them
157
+ // alongside semantic diagnostics so the operator sees the same
158
+ // output `tsc -p` would have produced.
159
+ const parsed = ts.parseJsonConfigFileContent(readResult.config, ts.sys, dirname(absConfig),
160
+ /* existingOptions */ undefined, absConfig);
161
+ const issues = [];
162
+ for (const diag of parsed.errors) {
163
+ if (SUPPRESSED_DIAGNOSTIC_CODES.has(diag.code))
164
+ continue;
165
+ issues.push(diagnosticToIssue(ts, diag, absConfig, projectPath));
166
+ }
167
+ // 3) Honour explicit `checkJs: false`. The user has opted out for
168
+ // an IDE reason (likely "checkJs floods my workflow with non-actionable
169
+ // notes"); flipping it on here would surface ~hundreds of issues that
170
+ // the operator already evaluated and rejected. Surface a single
171
+ // notice so it is visible in CI logs rather than silently passing.
172
+ const rawConfig = readResult.config;
173
+ if (rawConfig?.compilerOptions?.['checkJs'] === false) {
174
+ issues.push({
175
+ file: projectPath,
176
+ line: 1,
177
+ column: 1,
178
+ code: 0,
179
+ category: 'warning',
180
+ message: CHECK_JS_DISABLED_NOTICE,
181
+ project: projectPath,
182
+ });
183
+ return { project: projectPath, issues, filesChecked: parsed.fileNames.length };
184
+ }
185
+ // 4) Compute final compiler options. `noEmit: true` is forced — we
186
+ // never write artifacts. `allowJs` / `checkJs` default to true
187
+ // *only* when unset (so a user can flip them off without us
188
+ // overriding); if the user set `allowJs: false` they're saying
189
+ // "don't even include JS in this typecheck", which is rare but
190
+ // legitimate (e.g. an isolated `.d.ts`-only project).
191
+ const options = {
192
+ ...parsed.options,
193
+ noEmit: true,
194
+ allowJs: parsed.options.allowJs ?? true,
195
+ checkJs: parsed.options.checkJs ?? true,
196
+ // skipLibCheck is not forced; the user owns it via their jsconfig.
197
+ };
198
+ // 5) The synthetic shim file. Use a project-rooted path with a
199
+ // hidden-style prefix so it is unlikely to collide with any real
200
+ // file — and never write it to disk. The CompilerHost below serves
201
+ // it from `shimSource` for `fileExists`/`readFile`/`getSourceFile`.
202
+ const projectDir = dirname(absConfig);
203
+ const shimPath = resolve(projectDir, `.fireforge-${SHIM_FILENAME}`);
204
+ const rootFiles = [...parsed.fileNames, shimPath];
205
+ const defaultHost = ts.createCompilerHost(options);
206
+ const host = {
207
+ ...defaultHost,
208
+ getSourceFile(fileName, languageVersion, onError, shouldCreate) {
209
+ if (fileName === shimPath) {
210
+ return ts.createSourceFile(fileName, shimSource, languageVersion, true);
211
+ }
212
+ return defaultHost.getSourceFile(fileName, languageVersion, onError, shouldCreate);
213
+ },
214
+ fileExists(fileName) {
215
+ if (fileName === shimPath)
216
+ return true;
217
+ return defaultHost.fileExists(fileName);
218
+ },
219
+ readFile(fileName) {
220
+ if (fileName === shimPath)
221
+ return shimSource;
222
+ return defaultHost.readFile(fileName);
223
+ },
224
+ };
225
+ const program = ts.createProgram(rootFiles, options, host);
226
+ // Collect the full diagnostic set. patchLint reads only semantic +
227
+ // syntactic — fine for hygiene, wrong for CI: a misconfigured
228
+ // `lib: ["es2015"]` or a missing `paths` target should fail
229
+ // typecheck loudly via getOptionsDiagnostics / getGlobalDiagnostics.
230
+ const allDiagnostics = [
231
+ ...program.getOptionsDiagnostics(),
232
+ ...program.getGlobalDiagnostics(),
233
+ ...program.getSyntacticDiagnostics(),
234
+ ...program.getSemanticDiagnostics(),
235
+ ];
236
+ for (const diag of allDiagnostics) {
237
+ if (SUPPRESSED_DIAGNOSTIC_CODES.has(diag.code))
238
+ continue;
239
+ // Drop diagnostics that originate in the synthetic shim — operators
240
+ // can't act on them and they would clutter CI logs.
241
+ if (diag.file?.fileName === shimPath)
242
+ continue;
243
+ issues.push(diagnosticToIssue(ts, diag, absConfig, projectPath));
244
+ }
245
+ verbose(`typecheck: ${projectPath} — analyzed ${String(parsed.fileNames.length)} file(s), found ${String(issues.length)} issue(s)`);
246
+ return {
247
+ project: projectPath,
248
+ issues,
249
+ filesChecked: parsed.fileNames.length,
250
+ };
251
+ }
252
+ /**
253
+ * Converts a TS Diagnostic to a TypecheckIssue. The `fallbackFile`
254
+ * is used when the diagnostic carries no source file (typical for
255
+ * options diagnostics) — typically the absolute jsconfig path or
256
+ * the project-relative form for surface-level errors. `project` is
257
+ * threaded through so the CLI can group issues by project without
258
+ * a second pass.
259
+ */
260
+ function diagnosticToIssue(ts, diag, fallbackFile, project) {
261
+ let file = fallbackFile;
262
+ let line = 1;
263
+ let column = 1;
264
+ if (diag.file) {
265
+ file = diag.file.fileName;
266
+ if (typeof diag.start === 'number') {
267
+ const lc = diag.file.getLineAndCharacterOfPosition(diag.start);
268
+ line = lc.line + 1;
269
+ column = lc.character + 1;
270
+ }
271
+ }
272
+ const message = typeof diag.messageText === 'string'
273
+ ? diag.messageText
274
+ : ts.flattenDiagnosticMessageText(diag.messageText, '\n');
275
+ // Suggestion + Message categories collapse to 'warning'; only
276
+ // Error stays an error. This matches what the CLI then displays.
277
+ const category = diag.category === ts.DiagnosticCategory.Error ? 'error' : 'warning';
278
+ return {
279
+ file,
280
+ line,
281
+ column,
282
+ code: diag.code,
283
+ category,
284
+ message,
285
+ project,
286
+ };
287
+ }
288
+ /**
289
+ * Converts an absolute path to a path relative to the project root,
290
+ * for display in CLI output. Falls back to the absolute path when
291
+ * the path lies outside the root (e.g. a `node_modules` symlinked
292
+ * from elsewhere). Exposed for tests and the CLI.
293
+ */
294
+ export function relativeForDisplay(projectRoot, absoluteFile) {
295
+ if (!isAbsolute(absoluteFile))
296
+ return absoluteFile;
297
+ const rel = relative(projectRoot, absoluteFile);
298
+ if (rel === '' || rel.startsWith('..'))
299
+ return absoluteFile;
300
+ return rel;
301
+ }
302
+ //# sourceMappingURL=typecheck.js.map
@@ -8,8 +8,8 @@
8
8
  * The upstream xpcshell harness computes the manifest key for the appdir
9
9
  * override as `mozInfo["appname"] + "-appdir"`. On a stock Firefox build the
10
10
  * key is `firefox-appdir`, so the very common `firefox-appdir = "browser"`
11
- * directive is honoured. On a rebranded fork (appname=`hominis`,
12
- * `mybrowser`, …) the harness looks for `hominis-appdir` / `mybrowser-appdir`
11
+ * directive is honoured. On a rebranded fork (appname=`mybrowser`, …) the
12
+ * harness looks for `mybrowser-appdir`
13
13
  * — the literal `firefox-appdir` line is silently ignored, `appPath` falls
14
14
  * back to `xrePath`, and every `resource:///modules/…` import throws
15
15
  * `Failed to load resource:///modules/<name>.sys.mjs` because xpcshell now
@@ -9,8 +9,8 @@
9
9
  * The upstream xpcshell harness computes the manifest key for the appdir
10
10
  * override as `mozInfo["appname"] + "-appdir"`. On a stock Firefox build the
11
11
  * key is `firefox-appdir`, so the very common `firefox-appdir = "browser"`
12
- * directive is honoured. On a rebranded fork (appname=`hominis`,
13
- * `mybrowser`, …) the harness looks for `hominis-appdir` / `mybrowser-appdir`
12
+ * directive is honoured. On a rebranded fork (appname=`mybrowser`, …) the
13
+ * harness looks for `mybrowser-appdir`
14
14
  * — the literal `firefox-appdir` line is silently ignored, `appPath` falls
15
15
  * back to `xrePath`, and every `resource:///modules/…` import throws
16
16
  * `Failed to load resource:///modules/<name>.sys.mjs` because xpcshell now
@@ -440,7 +440,7 @@ export interface FurnaceCreateOptions {
440
440
  compose?: string[];
441
441
  /**
442
442
  * Participate in a pre-existing feature-scoped Fluent bundle at this
443
- * path (as used by `insertFTLIfNeeded`, e.g. `browser/hominis-dock.ftl`)
443
+ * path (as used by `insertFTLIfNeeded`, e.g. `browser/mybrowser-dock.ftl`)
444
444
  * instead of scaffolding a per-component `.ftl`. Implies `localized`.
445
445
  * Persists onto the furnace.json entry so validation and apply skip the
446
446
  * per-component paths.
@@ -44,6 +44,8 @@ export interface FireForgeConfig {
44
44
  wire?: WireConfig;
45
45
  /** Patch lint configuration */
46
46
  patchLint?: PatchLintConfig;
47
+ /** Typecheck command configuration (CI-grade, whole-project) */
48
+ typecheck?: TypecheckConfig;
47
49
  /**
48
50
  * Project marker prefix appended to lines FireForge writes into
49
51
  * upstream Firefox source files (e.g. the `customElements.js` tag list).
@@ -52,6 +54,29 @@ export interface FireForgeConfig {
52
54
  */
53
55
  markerComment?: string;
54
56
  }
57
+ /**
58
+ * Configuration for the `fireforge typecheck` command. Distinct from
59
+ * `patchLint.checkJs`: patch-lint runs every time `fireforge lint` runs
60
+ * and is scoped to patch-owned `.sys.mjs`; typecheck runs whole projects
61
+ * the operator points at via `projects` and is intended as a CI gate.
62
+ */
63
+ export interface TypecheckConfig {
64
+ /**
65
+ * Project-relative paths to jsconfig.json (or tsconfig.json) files
66
+ * the typecheck command should run. Must be non-empty when the
67
+ * `typecheck` block is present — an empty array would silently turn
68
+ * the command into a no-op.
69
+ */
70
+ projects: string[];
71
+ /**
72
+ * Optional project-relative path to an additional `.d.ts` file whose
73
+ * contents are concatenated to the built-in `FIREFOX_GLOBALS_SHIM`.
74
+ * Lets projects declare component patterns like `MozLitElement` /
75
+ * `MozXULElement` once instead of per-file. Concat order is
76
+ * built-in shim first, extraShim second — augment, don't redeclare.
77
+ */
78
+ extraShim?: string;
79
+ }
55
80
  /**
56
81
  * Wire command configuration.
57
82
  */
@@ -64,12 +89,48 @@ export interface WireConfig {
64
89
  * `'warning'` and `'error'` emit issues at the matching severity.
65
90
  */
66
91
  export type PatchLintSeverityGate = 'off' | 'warning' | 'error';
92
+ /**
93
+ * Allowlisted TypeScript `compilerOptions` overrides for the patch
94
+ * `checkJs` pass when {@link PatchLintConfig.checkJsStrict} is true.
95
+ * Merged after the strict preset; only boolean flags — no `paths`,
96
+ * `rootDir`, or other options that would fight the synthetic program.
97
+ */
98
+ export interface PatchLintCheckJsCompilerOptions {
99
+ strictNullChecks?: boolean;
100
+ strictFunctionTypes?: boolean;
101
+ strictBindCallApply?: boolean;
102
+ noImplicitThis?: boolean;
103
+ useUnknownInCatchVariables?: boolean;
104
+ strictPropertyInitialization?: boolean;
105
+ noUnusedLocals?: boolean;
106
+ noUnusedParameters?: boolean;
107
+ }
67
108
  /**
68
109
  * Configuration for patch lint rules.
69
110
  */
70
111
  export interface PatchLintConfig {
71
112
  /** Enable TypeScript checkJs pass on patch-owned .sys.mjs files */
72
113
  checkJs?: boolean;
114
+ /**
115
+ * When true with `checkJs: true`, run checkJs with `strict` and
116
+ * `noImplicitAny` enabled (CI-style). Default false preserves the
117
+ * historical loose preset. Optional {@link checkJsCompilerOptions}
118
+ * can relax individual strict flags (e.g. `strictNullChecks: false`).
119
+ */
120
+ checkJsStrict?: boolean;
121
+ /**
122
+ * Boolean overrides merged after the strict preset; only valid when
123
+ * `checkJsStrict` is true. Requires `checkJs: true`.
124
+ */
125
+ checkJsCompilerOptions?: PatchLintCheckJsCompilerOptions;
126
+ /**
127
+ * Project-relative path to an additional `.d.ts` file whose contents
128
+ * are concatenated to the built-in `FIREFOX_GLOBALS_SHIM` for the
129
+ * `patchLint.checkJs` pass. Same semantics as `typecheck.extraShim`
130
+ * but scoped to the patch-hygiene flow. Default unset = current
131
+ * behaviour (built-in shim only).
132
+ */
133
+ checkJsExtraShim?: string;
73
134
  /** File paths exempt from the raw-color-value check (exact or basename match) */
74
135
  rawColorAllowlist?: string[];
75
136
  /** Enforce JSDoc on class-method exports in patch-owned .sys.mjs files. Default: 'off'. */
@@ -70,7 +70,7 @@ export interface CustomComponentConfig {
70
70
  /**
71
71
  * Path of a pre-existing feature-scoped Fluent bundle this component
72
72
  * participates in, in the same form used by `insertFTLIfNeeded` (for
73
- * example `browser/hominis-dock.ftl`). When set:
73
+ * example `browser/mybrowser-dock.ftl`). When set:
74
74
  *
75
75
  * - `furnace create --localized` does NOT scaffold a per-component
76
76
  * `.ftl` stub — the component shares the feature bundle.
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Types for the `fireforge typecheck` command.
3
+ *
4
+ * Kept separate from `PatchLintIssue` because the two flows model
5
+ * different things: patch-lint issues are keyed on a stable `check`
6
+ * rule ID (consumed by `lintIgnore`, severity gates, and the
7
+ * cross-patch tagger), while typecheck issues carry a raw TypeScript
8
+ * diagnostic code that should never enter the patch-lint vocabulary.
9
+ * Conflating them would let `lintIgnore` accidentally suppress TS
10
+ * errors and would force `PatchLintIssue` to grow line / column /
11
+ * code fields that have no meaning for patch-hygiene rules.
12
+ */
13
+ /**
14
+ * A single diagnostic produced by `runTypecheck` for one source file.
15
+ */
16
+ export interface TypecheckIssue {
17
+ /** Absolute path to the source file the diagnostic originated in. */
18
+ file: string;
19
+ /** 1-based line number. */
20
+ line: number;
21
+ /** 1-based column number. */
22
+ column: number;
23
+ /** Raw TypeScript diagnostic code (e.g. 2322 for a type mismatch). */
24
+ code: number;
25
+ /**
26
+ * Severity bucket — TS reports `Suggestion` and `Message` categories
27
+ * too, but `runTypecheck` collapses both into `'warning'` so the CLI
28
+ * has only two visible levels.
29
+ */
30
+ category: 'error' | 'warning';
31
+ /** Human-readable message text (already flattened from chains). */
32
+ message: string;
33
+ /**
34
+ * Project-relative path of the originating jsconfig.json. Useful
35
+ * when typecheck.projects names multiple projects and the operator
36
+ * needs to know which one fired.
37
+ */
38
+ project: string;
39
+ }
40
+ /**
41
+ * Per-project typecheck output. One entry per `typecheck.projects`
42
+ * jsconfig path, in the order the projects were declared.
43
+ */
44
+ export interface TypecheckProjectResult {
45
+ /** Project-relative path of the jsconfig.json. */
46
+ project: string;
47
+ /** All issues from this project (errors + warnings). */
48
+ issues: TypecheckIssue[];
49
+ /** How many root files the program was built against (excludes the synthetic shim). */
50
+ filesChecked: number;
51
+ }
@@ -0,0 +1,15 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ /**
3
+ * Types for the `fireforge typecheck` command.
4
+ *
5
+ * Kept separate from `PatchLintIssue` because the two flows model
6
+ * different things: patch-lint issues are keyed on a stable `check`
7
+ * rule ID (consumed by `lintIgnore`, severity gates, and the
8
+ * cross-patch tagger), while typecheck issues carry a raw TypeScript
9
+ * diagnostic code that should never enter the patch-lint vocabulary.
10
+ * Conflating them would let `lintIgnore` accidentally suppress TS
11
+ * errors and would force `PatchLintIssue` to grow line / column /
12
+ * code fields that have no meaning for patch-hygiene rules.
13
+ */
14
+ export {};
15
+ //# sourceMappingURL=typecheck.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hominis/fireforge",
3
- "version": "0.18.10",
3
+ "version": "0.19.0",
4
4
  "description": "FireForge — a build tool for customizing Firefox",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",