@hominis/fireforge 0.15.3 → 0.15.4
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/CHANGELOG.md +5 -0
- package/README.md +1 -1
- package/dist/src/commands/doctor-furnace.js +8 -1
- package/dist/src/commands/wire.js +59 -6
- package/dist/src/core/browser-wire.d.ts +8 -0
- package/dist/src/core/browser-wire.js +2 -2
- package/dist/src/core/wire-dom-fragment.d.ts +16 -4
- package/dist/src/core/wire-dom-fragment.js +32 -17
- package/dist/src/types/commands/options.d.ts +7 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -47,6 +47,11 @@
|
|
|
47
47
|
|
|
48
48
|
- `fireforge lint --since <git-rev>` tags each lint issue as `[introduced]` (file touched in the diff since `<git-rev>`) or `[cumulative]` (pre-existing patch-state drift). Output gains the tag prefix and the summary line splits counts (e.g. `Lint: 2 introduced error(s), 0 introduced warning(s); 5 cumulative error(s), 1 cumulative warning(s)`). Exit code semantics are unchanged — an introduced OR cumulative error still fails lint — but triage of "is the diff I just produced clean?" no longer requires mentally subtracting pre-existing noise from every report. Without `--since` the output is unchanged.
|
|
49
49
|
|
|
50
|
+
### Fork chrome-doc assumptions
|
|
51
|
+
|
|
52
|
+
- `fireforge doctor`'s `Furnace engine paths` check now reads `furnace.json.tokenHostDocuments` instead of hardcoding `browser/base/content/browser.xhtml`. Forks that replaced the stock chrome document were emitting a permanent "browser.xhtml missing" warning every doctor run; reusing the same field the `missing-token-link` validator already consumes means a fork configures chrome-doc paths once and both checks agree. Defaults to `['browser/base/content/browser.xhtml']` when unset — behaviour is unchanged for forks that ship the stock chrome document.
|
|
53
|
+
- `fireforge wire --dom` no longer hardcodes `browser/base/content/browser.xhtml` as the target chrome document. The target now resolves in this order: explicit `--target <path>` flag → first entry of `furnace.json.tokenHostDocuments` → upstream `browser/base/content/browser.xhtml`. Forks that replaced browser.xhtml were getting a cryptic "could not find insertion point in browser.xhtml" error that read like a FireForge bug; the resolved path now propagates into the dry-run plan, the success message, and the insertion-failure error so the actual target is surfaced. When the resolved target does not exist on disk, wire fails up-front with a pointer to `tokenHostDocuments` / `--target` rather than blowing up in the AST pass. The `addDomFragment` core now computes the `#include` directive relative to the target's own directory instead of a hardcoded `browser/base/content/`, so a target that lives elsewhere in the engine tree gets a correctly resolved include path.
|
|
54
|
+
|
|
50
55
|
### Furnace chrome-doc
|
|
51
56
|
|
|
52
57
|
- New `furnace chrome-doc create <name>` subcommand scaffolds a top-level chrome document (xhtml + js + css + ftl) plus the three jar.mn registrations (`browser/base/jar.mn`, `browser/themes/shared/jar.inc.mn`, `browser/locales/jar.mn`). Default emits titlebar-buttonbox markup and a `windowtype="navigator:browser"` shell; `--no-titlebar` produces a frameless overlay with the macOS `.titlebar-button { display: none }` carve-out. Mirrors the workflow for custom elements (`furnace create`) so hand-authoring mistakes — the `*` preprocessor flag, the startup-topic observer, the platform titlebar inheritance — are eliminated. All writes go through a rollback journal under the signal-handler pathway: a Ctrl+C mid-scaffold restores every touched file.
|
package/README.md
CHANGED
|
@@ -429,7 +429,7 @@ Mach build failures with known-cryptic mozbuild errors now print actionable hint
|
|
|
429
429
|
|
|
430
430
|
**`markerComment`** (optional). Appended as a ` // <marker>:` suffix to every line FireForge writes into upstream Firefox source files (starting with `customElements.js`). Keeps fork modifications discoverable and makes re-apply idempotent without hand-tagging entries after each `furnace apply`. Reject list: empty strings, leading/trailing whitespace, newlines, `*/` (would close an enclosing block comment), control characters.
|
|
431
431
|
|
|
432
|
-
**`furnace.json.tokenHostDocuments`** (optional). List of chrome XHTML documents the `missing-token-link` validator scans for the tokens CSS link. Forks with a second chrome host (e.g. `mybrowser.xhtml` alongside `browser.xhtml`) should list every document that may own the link — the rule fires only when NONE of them link the tokens CSS. Defaults to `["browser/base/content/browser.xhtml"]` when omitted.
|
|
432
|
+
**`furnace.json.tokenHostDocuments`** (optional). List of chrome XHTML documents the `missing-token-link` validator scans for the tokens CSS link. Forks with a second chrome host (e.g. `mybrowser.xhtml` alongside `browser.xhtml`) should list every document that may own the link — the rule fires only when NONE of them link the tokens CSS. Defaults to `["browser/base/content/browser.xhtml"]` when omitted. `fireforge doctor`'s engine-paths probe reads the same field when confirming the chrome document exists on disk, and `fireforge wire --dom` uses the first entry as the default target for its `#include` directive (override per-invocation with `--target <path>`). Forks that fully replaced `browser.xhtml` with a custom top-level chrome document configure this field once and both checks agree.
|
|
433
433
|
|
|
434
434
|
### `furnace create --localized` for `MozLitElement`
|
|
435
435
|
|
|
@@ -319,12 +319,19 @@ const furnaceEnginePathsCheck = {
|
|
|
319
319
|
dependsOn: ['Furnace configuration'],
|
|
320
320
|
skipIf: (ctx) => !ctx.furnaceConfigExists || !ctx.furnaceConfig || !ctx.engineExists,
|
|
321
321
|
run: async (ctx) => {
|
|
322
|
+
// Forks that replace browser.xhtml with a custom top-level chrome
|
|
323
|
+
// document enumerate their chrome docs in furnace.json.tokenHostDocuments.
|
|
324
|
+
// Reuse the same field for the engine-path probe so those forks stop
|
|
325
|
+
// seeing a permanent "browser.xhtml missing" warning.
|
|
326
|
+
const hostDocs = ctx.furnaceConfig?.tokenHostDocuments && ctx.furnaceConfig.tokenHostDocuments.length > 0
|
|
327
|
+
? ctx.furnaceConfig.tokenHostDocuments
|
|
328
|
+
: ['browser/base/content/browser.xhtml'];
|
|
322
329
|
const expectedPaths = [
|
|
323
330
|
CUSTOM_ELEMENTS_JS,
|
|
324
331
|
JAR_MN,
|
|
325
332
|
'toolkit/content/widgets',
|
|
326
333
|
resolveFtlDir(ctx.furnaceConfig?.ftlBasePath),
|
|
327
|
-
|
|
334
|
+
...hostDocs,
|
|
328
335
|
];
|
|
329
336
|
const missing = [];
|
|
330
337
|
for (const relative of expectedPaths) {
|
|
@@ -2,7 +2,9 @@
|
|
|
2
2
|
import { join, relative } from 'node:path';
|
|
3
3
|
import { DEFAULT_BROWSER_SUBSCRIPT_DIR, wireSubscript } from '../core/browser-wire.js';
|
|
4
4
|
import { getProjectPaths, loadConfig } from '../core/config.js';
|
|
5
|
+
import { furnaceConfigExists as checkFurnaceConfigExists, loadFurnaceConfig, } from '../core/furnace-config.js';
|
|
5
6
|
import { consumeParserFallbackEvents } from '../core/parser-fallback.js';
|
|
7
|
+
import { DEFAULT_DOM_TARGET } from '../core/wire-dom-fragment.js';
|
|
6
8
|
import { InvalidArgumentError } from '../errors/base.js';
|
|
7
9
|
import { toError } from '../utils/errors.js';
|
|
8
10
|
import { pathExists } from '../utils/fs.js';
|
|
@@ -10,7 +12,7 @@ import { info, intro, outro, success, warn } from '../utils/logger.js';
|
|
|
10
12
|
import { pickDefined } from '../utils/options.js';
|
|
11
13
|
import { isContainedRelativePath, isPathInsideRoot, toRootRelativePath } from '../utils/paths.js';
|
|
12
14
|
const BROWSER_BASE_DIR = 'browser/base';
|
|
13
|
-
function printWireDryRun(engineDir, name, subscriptDir, domFilePath, options) {
|
|
15
|
+
function printWireDryRun(engineDir, name, subscriptDir, domFilePath, domTargetPath, options) {
|
|
14
16
|
info('[dry-run] Would wire subscript:');
|
|
15
17
|
info(` source: ${subscriptDir}/${name}.js`);
|
|
16
18
|
info(` browser-main.js: loadSubScript("chrome://browser/content/${name}.js")`);
|
|
@@ -22,12 +24,45 @@ function printWireDryRun(engineDir, name, subscriptDir, domFilePath, options) {
|
|
|
22
24
|
}
|
|
23
25
|
if (domFilePath) {
|
|
24
26
|
const includePath = relative(join(engineDir, subscriptDir), join(engineDir, domFilePath)).replace(/\\/g, '/');
|
|
25
|
-
info(`
|
|
27
|
+
info(` ${domTargetPath}: #include ${includePath}`);
|
|
26
28
|
}
|
|
27
29
|
const relPath = relative(join(engineDir, BROWSER_BASE_DIR), join(engineDir, subscriptDir)).replace(/\\/g, '/');
|
|
28
30
|
info(` jar.mn: content/browser/${name}.js (${relPath}/${name}.js)`);
|
|
29
31
|
outro('Dry run complete');
|
|
30
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Resolves the chrome document the `#include` directive is inserted into.
|
|
35
|
+
*
|
|
36
|
+
* Preference order:
|
|
37
|
+
* 1. `--target <path>` CLI flag (explicit caller intent)
|
|
38
|
+
* 2. First entry of `furnace.json.tokenHostDocuments` (fork-configured
|
|
39
|
+
* chrome doc list; already consumed by the missing-token-link
|
|
40
|
+
* validator and the doctor check)
|
|
41
|
+
* 3. `browser/base/content/browser.xhtml` (upstream default)
|
|
42
|
+
*
|
|
43
|
+
* Step 2 is silent — a missing / invalid furnace.json falls through to the
|
|
44
|
+
* upstream default rather than surfacing a warning, because forks that don't
|
|
45
|
+
* use furnace shouldn't have to configure anything.
|
|
46
|
+
*/
|
|
47
|
+
async function resolveDomTargetPath(projectRoot, explicit) {
|
|
48
|
+
if (explicit !== undefined) {
|
|
49
|
+
return explicit;
|
|
50
|
+
}
|
|
51
|
+
if (await checkFurnaceConfigExists(projectRoot)) {
|
|
52
|
+
try {
|
|
53
|
+
const furnaceConfig = await loadFurnaceConfig(projectRoot);
|
|
54
|
+
const first = furnaceConfig.tokenHostDocuments?.[0];
|
|
55
|
+
if (first !== undefined && first.length > 0) {
|
|
56
|
+
return first;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
// Fall through to default — a broken furnace.json should not block
|
|
61
|
+
// the wire command. The doctor surfaces that issue separately.
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return DEFAULT_DOM_TARGET;
|
|
65
|
+
}
|
|
31
66
|
/**
|
|
32
67
|
* Validates a subscript name supplied on the command line. Subscripts are
|
|
33
68
|
* resolved into filenames under the subscript directory and registered in
|
|
@@ -90,6 +125,21 @@ export async function wireCommand(projectRoot, name, options = {}) {
|
|
|
90
125
|
}
|
|
91
126
|
domFilePath = toRootRelativePath(paths.engine, options.dom);
|
|
92
127
|
}
|
|
128
|
+
// Resolve the chrome document the `#include` directive will land in.
|
|
129
|
+
// Only consulted when `--dom` is supplied — we still resolve it here so
|
|
130
|
+
// the dry-run plan can print the target accurately.
|
|
131
|
+
if (options.target !== undefined && !isContainedRelativePath(options.target)) {
|
|
132
|
+
throw new InvalidArgumentError(`Target chrome document must stay within engine/: ${options.target}`, 'target');
|
|
133
|
+
}
|
|
134
|
+
const domTargetPath = await resolveDomTargetPath(projectRoot, options.target);
|
|
135
|
+
if (domFilePath) {
|
|
136
|
+
const paths = getProjectPaths(projectRoot);
|
|
137
|
+
if (!options.dryRun && !(await pathExists(join(paths.engine, domTargetPath)))) {
|
|
138
|
+
throw new InvalidArgumentError(`Chrome document not found in engine: ${domTargetPath}\n` +
|
|
139
|
+
'Set "tokenHostDocuments" in furnace.json (first entry is used by wire) ' +
|
|
140
|
+
'or pass --target <path>.', 'target');
|
|
141
|
+
}
|
|
142
|
+
}
|
|
93
143
|
// Verify the subscript file exists in engine/ (skip for dry-run)
|
|
94
144
|
if (!options.dryRun) {
|
|
95
145
|
const paths = getProjectPaths(projectRoot);
|
|
@@ -100,13 +150,14 @@ export async function wireCommand(projectRoot, name, options = {}) {
|
|
|
100
150
|
}
|
|
101
151
|
}
|
|
102
152
|
if (options.dryRun) {
|
|
103
|
-
printWireDryRun(getProjectPaths(projectRoot).engine, name, subscriptDir, domFilePath, options);
|
|
153
|
+
printWireDryRun(getProjectPaths(projectRoot).engine, name, subscriptDir, domFilePath, domTargetPath, options);
|
|
104
154
|
return;
|
|
105
155
|
}
|
|
106
156
|
const result = await wireSubscript(projectRoot, name, {
|
|
107
157
|
...(options.init !== undefined ? { init: options.init } : {}),
|
|
108
158
|
...(options.destroy !== undefined ? { destroy: options.destroy } : {}),
|
|
109
159
|
...(domFilePath !== undefined ? { domFilePath } : {}),
|
|
160
|
+
...(domFilePath !== undefined && domTargetPath !== DEFAULT_DOM_TARGET ? { domTargetPath } : {}),
|
|
110
161
|
...(options.after !== undefined ? { after: options.after } : {}),
|
|
111
162
|
...(subscriptDir !== DEFAULT_BROWSER_SUBSCRIPT_DIR ? { subscriptDir } : {}),
|
|
112
163
|
dryRun: false,
|
|
@@ -140,10 +191,10 @@ export async function wireCommand(projectRoot, name, options = {}) {
|
|
|
140
191
|
}
|
|
141
192
|
if (domFilePath) {
|
|
142
193
|
if (result.domInserted) {
|
|
143
|
-
success(`Inserted #include directive into
|
|
194
|
+
success(`Inserted #include directive into ${domTargetPath}`);
|
|
144
195
|
}
|
|
145
196
|
else {
|
|
146
|
-
info(`#include directive already present in
|
|
197
|
+
info(`#include directive already present in ${domTargetPath} (skipped)`);
|
|
147
198
|
}
|
|
148
199
|
}
|
|
149
200
|
if (result.jarMnResult.skipped) {
|
|
@@ -161,10 +212,12 @@ export function registerWire(program, { getProjectRoot, withErrorHandling }) {
|
|
|
161
212
|
.description('Wire a chrome subscript into the browser')
|
|
162
213
|
.option('--init <expression>', 'Init expression for browser-init.js onLoad()')
|
|
163
214
|
.option('--destroy <expression>', 'Destroy expression for browser-init.js onUnload()')
|
|
164
|
-
.option('--dom <file>', 'XHTML fragment file to insert into
|
|
215
|
+
.option('--dom <file>', 'XHTML fragment file to insert into the chrome document')
|
|
165
216
|
.option('--dry-run', 'Show what would be changed without writing')
|
|
166
217
|
.option('--after <name>', 'Insert init block after the block for this name')
|
|
167
218
|
.option('--subscript-dir <dir>', 'Subscript directory relative to engine/ (default: browser/base/content)')
|
|
219
|
+
.option('--target <path>', 'Chrome document to insert --dom into, relative to engine/ ' +
|
|
220
|
+
'(default: first entry of furnace.json tokenHostDocuments, else browser/base/content/browser.xhtml)')
|
|
168
221
|
.action(withErrorHandling(async (name, options) => {
|
|
169
222
|
await wireCommand(getProjectRoot(), name, pickDefined(options));
|
|
170
223
|
}));
|
|
@@ -22,6 +22,14 @@ export interface WireOptions {
|
|
|
22
22
|
destroy?: string | undefined;
|
|
23
23
|
/** Path to `.inc.xhtml` file relative to engine root */
|
|
24
24
|
domFilePath?: string | undefined;
|
|
25
|
+
/**
|
|
26
|
+
* Top-level chrome document the DOM fragment's `#include` directive is
|
|
27
|
+
* inserted into, relative to engine/. Defaults to
|
|
28
|
+
* `browser/base/content/browser.xhtml`. Forks that replace browser.xhtml
|
|
29
|
+
* with a custom chrome document (e.g. `mybrowser.xhtml`) pass the
|
|
30
|
+
* replacement path here.
|
|
31
|
+
*/
|
|
32
|
+
domTargetPath?: string | undefined;
|
|
25
33
|
/** Dry run — don't write any files */
|
|
26
34
|
dryRun?: boolean | undefined;
|
|
27
35
|
/** Insert init block after the block containing this name */
|
|
@@ -48,10 +48,10 @@ export async function wireSubscript(root, name, options = {}) {
|
|
|
48
48
|
if (options.destroy) {
|
|
49
49
|
destroyAdded = await addDestroyToBrowserInit(engineDir, options.destroy);
|
|
50
50
|
}
|
|
51
|
-
// 4. Add #include directive to
|
|
51
|
+
// 4. Add #include directive to the top-level chrome document (if provided)
|
|
52
52
|
let domInserted = false;
|
|
53
53
|
if (options.domFilePath) {
|
|
54
|
-
domInserted = await addDomFragment(engineDir, toRootRelativePath(engineDir, options.domFilePath));
|
|
54
|
+
domInserted = await addDomFragment(engineDir, toRootRelativePath(engineDir, options.domFilePath), options.domTargetPath);
|
|
55
55
|
}
|
|
56
56
|
// 5. Register in jar.mn
|
|
57
57
|
const jarMnResult = await registerBrowserContent(engineDir, `${name}.js`, undefined, jarMnSourcePath);
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Top-level chrome document — DOM fragment insertion.
|
|
3
|
+
*
|
|
4
|
+
* Default target is `browser/base/content/browser.xhtml`. Forks that replace
|
|
5
|
+
* browser.xhtml with a custom top-level chrome document pass the replacement
|
|
6
|
+
* path in via `targetPath`; the insertion logic is shape-agnostic (looks for
|
|
7
|
+
* `#include browser-sets.inc`, then falls back to `<html:body>`), so any
|
|
8
|
+
* browser.xhtml-shaped xhtml works.
|
|
3
9
|
*/
|
|
10
|
+
export declare const DEFAULT_DOM_TARGET = "browser/base/content/browser.xhtml";
|
|
4
11
|
/**
|
|
5
12
|
* Tokenizer-based implementation for DOM fragment insertion.
|
|
6
13
|
*/
|
|
@@ -10,14 +17,19 @@ export declare function addDomFragmentTokenized(content: string, includeDirectiv
|
|
|
10
17
|
*/
|
|
11
18
|
export declare function legacyAddDomFragment(content: string, includeDirective: string): string;
|
|
12
19
|
/**
|
|
13
|
-
* Inserts a `#include` directive for an `.inc.xhtml` file into
|
|
14
|
-
*
|
|
20
|
+
* Inserts a `#include` directive for an `.inc.xhtml` file into the top-level
|
|
21
|
+
* chrome document (default: `browser/base/content/browser.xhtml`), before
|
|
22
|
+
* `#include browser-sets.inc`.
|
|
15
23
|
*
|
|
16
24
|
* If the file's content was previously inlined (detected by root element id=),
|
|
17
25
|
* the inlined block is automatically replaced with the `#include` directive.
|
|
18
26
|
*
|
|
19
27
|
* @param engineDir - Engine source root
|
|
20
28
|
* @param domFilePath - Path to the `.inc.xhtml` file relative to engine root
|
|
29
|
+
* @param targetPath - Chrome document to insert into, relative to engine
|
|
30
|
+
* root. Defaults to {@link DEFAULT_DOM_TARGET}. Forks that replace
|
|
31
|
+
* browser.xhtml with a custom top-level chrome document pass the
|
|
32
|
+
* replacement path here.
|
|
21
33
|
* @returns true if inserted, false if already present
|
|
22
34
|
*/
|
|
23
|
-
export declare function addDomFragment(engineDir: string, domFilePath: string): Promise<boolean>;
|
|
35
|
+
export declare function addDomFragment(engineDir: string, domFilePath: string, targetPath?: string): Promise<boolean>;
|
|
@@ -1,15 +1,21 @@
|
|
|
1
1
|
// SPDX-License-Identifier: EUPL-1.2
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* Top-level chrome document — DOM fragment insertion.
|
|
4
|
+
*
|
|
5
|
+
* Default target is `browser/base/content/browser.xhtml`. Forks that replace
|
|
6
|
+
* browser.xhtml with a custom top-level chrome document pass the replacement
|
|
7
|
+
* path in via `targetPath`; the insertion logic is shape-agnostic (looks for
|
|
8
|
+
* `#include browser-sets.inc`, then falls back to `<html:body>`), so any
|
|
9
|
+
* browser.xhtml-shaped xhtml works.
|
|
4
10
|
*/
|
|
5
|
-
import { join, relative } from 'node:path';
|
|
11
|
+
import { dirname, join, relative } from 'node:path';
|
|
6
12
|
import { GeneralError } from '../errors/base.js';
|
|
7
13
|
import { pathExists, readText, writeText } from '../utils/fs.js';
|
|
8
14
|
import { toRootRelativePath } from '../utils/paths.js';
|
|
9
15
|
import { escapeRegex } from '../utils/regex.js';
|
|
10
16
|
import { withParserFallback } from './parser-fallback.js';
|
|
11
17
|
import { tokenizeXhtml } from './wire-utils.js';
|
|
12
|
-
const
|
|
18
|
+
export const DEFAULT_DOM_TARGET = 'browser/base/content/browser.xhtml';
|
|
13
19
|
/**
|
|
14
20
|
* Tokenizer-based implementation for DOM fragment insertion.
|
|
15
21
|
*/
|
|
@@ -36,7 +42,7 @@ export function addDomFragmentTokenized(content, includeDirective) {
|
|
|
36
42
|
}
|
|
37
43
|
}
|
|
38
44
|
if (insertIndex === -1) {
|
|
39
|
-
throw new GeneralError('Could not find insertion point in
|
|
45
|
+
throw new GeneralError('Could not find insertion point in chrome document');
|
|
40
46
|
}
|
|
41
47
|
lines.splice(insertIndex, 0, includeDirective);
|
|
42
48
|
return lines.join('\n');
|
|
@@ -64,32 +70,41 @@ export function legacyAddDomFragment(content, includeDirective) {
|
|
|
64
70
|
}
|
|
65
71
|
}
|
|
66
72
|
if (insertIndex === -1) {
|
|
67
|
-
throw new GeneralError('Could not find insertion point in
|
|
73
|
+
throw new GeneralError('Could not find insertion point in chrome document');
|
|
68
74
|
}
|
|
69
75
|
lines.splice(insertIndex, 0, includeDirective);
|
|
70
76
|
return lines.join('\n');
|
|
71
77
|
}
|
|
72
78
|
/**
|
|
73
|
-
* Inserts a `#include` directive for an `.inc.xhtml` file into
|
|
74
|
-
*
|
|
79
|
+
* Inserts a `#include` directive for an `.inc.xhtml` file into the top-level
|
|
80
|
+
* chrome document (default: `browser/base/content/browser.xhtml`), before
|
|
81
|
+
* `#include browser-sets.inc`.
|
|
75
82
|
*
|
|
76
83
|
* If the file's content was previously inlined (detected by root element id=),
|
|
77
84
|
* the inlined block is automatically replaced with the `#include` directive.
|
|
78
85
|
*
|
|
79
86
|
* @param engineDir - Engine source root
|
|
80
87
|
* @param domFilePath - Path to the `.inc.xhtml` file relative to engine root
|
|
88
|
+
* @param targetPath - Chrome document to insert into, relative to engine
|
|
89
|
+
* root. Defaults to {@link DEFAULT_DOM_TARGET}. Forks that replace
|
|
90
|
+
* browser.xhtml with a custom top-level chrome document pass the
|
|
91
|
+
* replacement path here.
|
|
81
92
|
* @returns true if inserted, false if already present
|
|
82
93
|
*/
|
|
83
|
-
export async function addDomFragment(engineDir, domFilePath) {
|
|
84
|
-
const
|
|
94
|
+
export async function addDomFragment(engineDir, domFilePath, targetPath = DEFAULT_DOM_TARGET) {
|
|
95
|
+
const targetAbsPath = join(engineDir, targetPath);
|
|
85
96
|
const safeDomFilePath = toRootRelativePath(engineDir, domFilePath);
|
|
86
|
-
if (!(await pathExists(
|
|
87
|
-
throw new GeneralError(`${
|
|
97
|
+
if (!(await pathExists(targetAbsPath))) {
|
|
98
|
+
throw new GeneralError(`${targetPath} not found in engine`);
|
|
88
99
|
}
|
|
89
|
-
// Compute include path relative to
|
|
90
|
-
|
|
100
|
+
// Compute include path relative to the target's directory — the `#include`
|
|
101
|
+
// directive is resolved by the preprocessor relative to the file that
|
|
102
|
+
// contains it, so this must track the chrome doc's location, not a
|
|
103
|
+
// hardcoded `browser/base/content/`.
|
|
104
|
+
const targetDir = dirname(targetPath);
|
|
105
|
+
const includePath = relative(targetDir, safeDomFilePath).replace(/\\/g, '/');
|
|
91
106
|
const includeDirective = `#include ${includePath}`;
|
|
92
|
-
let content = await readText(
|
|
107
|
+
let content = await readText(targetAbsPath);
|
|
93
108
|
// Idempotency: check if the #include directive already exists (line-anchored to avoid substring matches)
|
|
94
109
|
if (new RegExp(`^${escapeRegex(includeDirective)}$`, 'm').test(content)) {
|
|
95
110
|
return false;
|
|
@@ -116,14 +131,14 @@ export async function addDomFragment(engineDir, domFilePath) {
|
|
|
116
131
|
}
|
|
117
132
|
lines.splice(startIdx, endIdx - startIdx, includeDirective);
|
|
118
133
|
content = lines.join('\n');
|
|
119
|
-
await writeText(
|
|
134
|
+
await writeText(targetAbsPath, content);
|
|
120
135
|
return true;
|
|
121
136
|
}
|
|
122
137
|
}
|
|
123
138
|
}
|
|
124
139
|
// Normal insertion
|
|
125
|
-
const { value } = withParserFallback(() => addDomFragmentTokenized(content, includeDirective), () => legacyAddDomFragment(content, includeDirective),
|
|
126
|
-
await writeText(
|
|
140
|
+
const { value } = withParserFallback(() => addDomFragmentTokenized(content, includeDirective), () => legacyAddDomFragment(content, includeDirective), targetPath);
|
|
141
|
+
await writeText(targetAbsPath, value);
|
|
127
142
|
return true;
|
|
128
143
|
}
|
|
129
144
|
//# sourceMappingURL=wire-dom-fragment.js.map
|
|
@@ -309,6 +309,13 @@ export interface WireOptions {
|
|
|
309
309
|
dryRun?: boolean;
|
|
310
310
|
after?: string;
|
|
311
311
|
subscriptDir?: string;
|
|
312
|
+
/**
|
|
313
|
+
* Chrome document the DOM fragment's `#include` is inserted into, relative
|
|
314
|
+
* to engine/. Defaults to the first entry of
|
|
315
|
+
* `furnace.json.tokenHostDocuments` when set, otherwise
|
|
316
|
+
* `browser/base/content/browser.xhtml`.
|
|
317
|
+
*/
|
|
318
|
+
target?: string;
|
|
312
319
|
}
|
|
313
320
|
/**
|
|
314
321
|
* Options for the register command.
|