@hominis/fireforge 0.26.0 → 0.27.1
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 +12 -0
- package/README.md +1 -1
- package/dist/src/commands/doctor/post-rebase-audit.d.ts +2 -0
- package/dist/src/commands/doctor/post-rebase-audit.js +86 -0
- package/dist/src/commands/doctor.js +3 -0
- package/dist/src/commands/download.js +4 -1
- package/dist/src/commands/manifest.js +2 -0
- package/dist/src/commands/re-export-files.js +44 -26
- package/dist/src/commands/re-export.js +53 -14
- package/dist/src/commands/rebase/conflict-summary.d.ts +12 -0
- package/dist/src/commands/rebase/conflict-summary.js +38 -0
- package/dist/src/commands/rebase/patch-loop.js +24 -6
- package/dist/src/commands/setup-support.js +6 -2
- package/dist/src/commands/setup.js +1 -0
- package/dist/src/commands/source.d.ts +9 -0
- package/dist/src/commands/source.js +92 -0
- package/dist/src/commands/verify.js +27 -0
- package/dist/src/core/branding.js +54 -7
- package/dist/src/core/config-validate.js +1 -1
- package/dist/src/core/firefox-extract.d.ts +1 -1
- package/dist/src/core/firefox-extract.js +13 -1
- package/dist/src/core/firefox.d.ts +2 -1
- package/dist/src/core/firefox.js +2 -2
- package/dist/src/core/furnace-registration-ast.js +32 -4
- package/dist/src/core/furnace-registration-validate.d.ts +7 -0
- package/dist/src/core/furnace-registration-validate.js +48 -6
- package/dist/src/core/furnace-validate-registration.js +8 -17
- package/dist/src/core/git.js +46 -16
- package/dist/src/core/patch-artifact-normalize.d.ts +9 -0
- package/dist/src/core/patch-artifact-normalize.js +13 -0
- package/dist/src/core/patch-export-update.js +2 -1
- package/dist/src/core/patch-export.js +3 -2
- package/dist/src/core/status-classify.js +19 -4
- package/dist/src/types/commands/index.d.ts +1 -1
- package/dist/src/types/commands/options.d.ts +22 -1
- package/dist/src/types/config.d.ts +1 -1
- package/dist/src/utils/elapsed.d.ts +4 -0
- package/dist/src/utils/elapsed.js +15 -0
- package/dist/src/utils/validation.d.ts +2 -2
- package/dist/src/utils/validation.js +5 -5
- package/package.json +2 -2
|
@@ -6,6 +6,7 @@ import { pathExists, readText, removeFile, writeText } from '../utils/fs.js';
|
|
|
6
6
|
import { warn } from '../utils/logger.js';
|
|
7
7
|
import { PATCH_CATEGORIES } from '../utils/validation.js';
|
|
8
8
|
import { discoverPatches, withPatchDirectoryLock } from './patch-apply.js';
|
|
9
|
+
import { normalizePatchArtifact } from './patch-artifact-normalize.js';
|
|
9
10
|
import { findAllPatchesForFilesWithDetails, } from './patch-export-coverage.js';
|
|
10
11
|
import { addPatchToManifest, loadPatchesManifest, PATCHES_MANIFEST, savePatchesManifest, } from './patch-manifest.js';
|
|
11
12
|
import { allocatePolicyOrder, enforcePatchPolicy } from './patch-policy.js';
|
|
@@ -95,7 +96,7 @@ export async function commitExportedPatch(input) {
|
|
|
95
96
|
}
|
|
96
97
|
}
|
|
97
98
|
try {
|
|
98
|
-
await writeText(patchPath, input.diff);
|
|
99
|
+
await writeText(patchPath, normalizePatchArtifact(input.diff));
|
|
99
100
|
await addPatchToManifest(input.patchesDir, plan.metadata, plan.supersededPatches.map((p) => p.filename));
|
|
100
101
|
for (const oldPatch of plan.supersededPatches) {
|
|
101
102
|
await removeFile(oldPatch.path);
|
|
@@ -195,7 +196,7 @@ export async function findExistingPatchForFile(patchesDir, filePath) {
|
|
|
195
196
|
* @param newContent - New patch content
|
|
196
197
|
*/
|
|
197
198
|
export async function updatePatch(patchPath, newContent) {
|
|
198
|
-
await writeText(patchPath, newContent);
|
|
199
|
+
await writeText(patchPath, normalizePatchArtifact(newContent));
|
|
199
200
|
}
|
|
200
201
|
/**
|
|
201
202
|
* Deletes a patch file and removes it from the manifest.
|
|
@@ -25,6 +25,14 @@ function getPrimaryStatusCode(status) {
|
|
|
25
25
|
}
|
|
26
26
|
return status;
|
|
27
27
|
}
|
|
28
|
+
function isGeneratedBrandingPath(file, binaryName) {
|
|
29
|
+
const normalized = file.replace(/\\/g, '/');
|
|
30
|
+
const brandingRoot = `browser/branding/${binaryName}`;
|
|
31
|
+
return (normalized === 'browser/moz.configure' ||
|
|
32
|
+
normalized === `${brandingRoot}/configure.sh` ||
|
|
33
|
+
normalized === `${brandingRoot}/locales/en-US/brand.properties` ||
|
|
34
|
+
normalized === `${brandingRoot}/locales/en-US/brand.ftl`);
|
|
35
|
+
}
|
|
28
36
|
/**
|
|
29
37
|
* Classifies files into patch-backed, unmanaged, branding, furnace, or
|
|
30
38
|
* conflict buckets.
|
|
@@ -63,8 +71,17 @@ export async function classifyFiles(files, engineDir, patchesDir, binaryName, fu
|
|
|
63
71
|
}
|
|
64
72
|
const results = [];
|
|
65
73
|
for (const entry of files) {
|
|
66
|
-
|
|
67
|
-
|
|
74
|
+
const owners = patchClaims.get(entry.file);
|
|
75
|
+
const primaryCode = getPrimaryStatusCode(entry.status);
|
|
76
|
+
// Branding paths are tool-managed for generated edits, but a brand-new
|
|
77
|
+
// unowned branding asset must not disappear from `status --unmanaged`.
|
|
78
|
+
// The Hominis Firefox 152 side-grade added Assets.car under the active
|
|
79
|
+
// branding tree; classifying every branding path before checking
|
|
80
|
+
// ownership hid that new patch candidate as "branding" even though no
|
|
81
|
+
// patch claimed it yet.
|
|
82
|
+
const isUnownedNewFile = owners === undefined && (primaryCode === '?' || primaryCode === 'A');
|
|
83
|
+
if (isBrandingManagedPath(entry.file, binaryName) &&
|
|
84
|
+
(!isUnownedNewFile || isGeneratedBrandingPath(entry.file, binaryName))) {
|
|
68
85
|
results.push({ ...entry, classification: 'branding' });
|
|
69
86
|
continue;
|
|
70
87
|
}
|
|
@@ -82,7 +99,6 @@ export async function classifyFiles(files, engineDir, patchesDir, binaryName, fu
|
|
|
82
99
|
continue;
|
|
83
100
|
}
|
|
84
101
|
}
|
|
85
|
-
const owners = patchClaims.get(entry.file);
|
|
86
102
|
// Multiple patches claim this file — surface the cross-patch
|
|
87
103
|
// ownership conflict regardless of whether the current content
|
|
88
104
|
// matches any single claim. `--ownership` reports the same state
|
|
@@ -102,7 +118,6 @@ export async function classifyFiles(files, engineDir, patchesDir, binaryName, fu
|
|
|
102
118
|
continue;
|
|
103
119
|
}
|
|
104
120
|
// File is claimed by exactly one patch — compare content.
|
|
105
|
-
const primaryCode = getPrimaryStatusCode(entry.status);
|
|
106
121
|
if (primaryCode === 'D') {
|
|
107
122
|
// Deleted file: patch-backed only if patch expects deletion
|
|
108
123
|
const expected = await computePatchedContent(patchesDir, engineDir, entry.file);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Re-exports all command-related types from focused sub-modules.
|
|
3
3
|
*/
|
|
4
|
-
export type { BuildOptions, DiscardOptions, DoctorOptions, DownloadOptions, ExportOptions, FurnaceApplyOptions, FurnaceCreateOptions, FurnaceDeployOptions, FurnaceOverrideOptions, FurnacePreviewOptions, FurnaceRefreshOptions, FurnaceRemoveOptions, FurnaceSyncOptions, FurnaceValidateOptions, GlobalOptions, ImportOptions, PackageOptions, PatchCompactOptions, PatchDeleteOptions, PatchLintIgnoreOptions, PatchMoveFilesOptions, PatchRenameOptions, PatchReorderOptions, PatchStagedDependencyOptions, PatchTierOptions, RebaseOptions, ReExportOptions, RegisterOptions, ResetOptions, RunOptions, SetupOptions, StatusOptions, TestOptions, TokenAddOptions, WireOptions, } from './options.js';
|
|
4
|
+
export type { BuildOptions, DiscardOptions, DoctorOptions, DownloadOptions, ExportOptions, FurnaceApplyOptions, FurnaceCreateOptions, FurnaceDeployOptions, FurnaceOverrideOptions, FurnacePreviewOptions, FurnaceRefreshOptions, FurnaceRemoveOptions, FurnaceSyncOptions, FurnaceValidateOptions, GlobalOptions, ImportOptions, PackageOptions, PatchCompactOptions, PatchDeleteOptions, PatchLintIgnoreOptions, PatchMoveFilesOptions, PatchRenameOptions, PatchReorderOptions, PatchStagedDependencyOptions, PatchTierOptions, RebaseOptions, ReExportOptions, RegisterOptions, ResetOptions, RunOptions, SetupOptions, SourceSetOptions, StatusOptions, TestOptions, TokenAddOptions, WireOptions, } from './options.js';
|
|
5
5
|
export type { ImportSummary, PatchCategory, PatchesManifest, PatchInfo, PatchLintIssue, PatchMetadata, PatchResult, PatchStagedDependencies, PatchStagedForwardImport, } from './patches.js';
|
|
6
6
|
export type { DoctorCheck, ProjectStatus, TokenCoverageFileEntry, TokenCoverageReport, } from './project.js';
|
|
@@ -17,7 +17,7 @@ export interface SetupOptions {
|
|
|
17
17
|
binaryName?: string;
|
|
18
18
|
/** Firefox version to base on */
|
|
19
19
|
firefoxVersion?: string;
|
|
20
|
-
/** Firefox product type (firefox, firefox-esr, firefox-beta) */
|
|
20
|
+
/** Firefox product type (firefox, firefox-esr, firefox-beta, firefox-devedition) */
|
|
21
21
|
product?: FirefoxProduct;
|
|
22
22
|
/** Overwrite existing configuration without prompting */
|
|
23
23
|
force?: boolean;
|
|
@@ -31,6 +31,19 @@ export interface DownloadOptions {
|
|
|
31
31
|
/** Force re-download, deleting existing engine/ */
|
|
32
32
|
force?: boolean;
|
|
33
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* Options for the source command.
|
|
36
|
+
*/
|
|
37
|
+
export interface SourceSetOptions {
|
|
38
|
+
/** Firefox version to set */
|
|
39
|
+
version: string;
|
|
40
|
+
/** Firefox product type */
|
|
41
|
+
product: FirefoxProduct;
|
|
42
|
+
/** Optional pinned SHA-256 for the resolved source archive */
|
|
43
|
+
sha256?: string;
|
|
44
|
+
/** Clear any existing pinned SHA-256 */
|
|
45
|
+
clearSha256?: boolean;
|
|
46
|
+
}
|
|
34
47
|
/**
|
|
35
48
|
* Options for the build command.
|
|
36
49
|
*/
|
|
@@ -184,6 +197,12 @@ export interface ReExportOptions {
|
|
|
184
197
|
skipLint?: boolean;
|
|
185
198
|
/** Skip confirmation prompt on shrink (required for non-TTY) */
|
|
186
199
|
yes?: boolean;
|
|
200
|
+
/**
|
|
201
|
+
* Explicitly allow `--files` to remove paths that are currently owned by
|
|
202
|
+
* the patch. Without this acknowledgement, non-dry-run shrinks are refused
|
|
203
|
+
* before the interactive/`--yes` confirmation path.
|
|
204
|
+
*/
|
|
205
|
+
allowShrink?: boolean;
|
|
187
206
|
/** Bypass cross-patch lint refusal on projected shrink state */
|
|
188
207
|
forceUnsafe?: boolean;
|
|
189
208
|
/**
|
|
@@ -645,6 +664,8 @@ export interface DoctorOptions {
|
|
|
645
664
|
* and side-effect-free.
|
|
646
665
|
*/
|
|
647
666
|
repairFurnace?: boolean;
|
|
667
|
+
/** Run extra post-rebase checks for common Firefox registration surfaces. */
|
|
668
|
+
postRebaseAudit?: boolean;
|
|
648
669
|
}
|
|
649
670
|
/**
|
|
650
671
|
* Global CLI options available to all commands.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Firefox product type for downloads.
|
|
3
3
|
*/
|
|
4
|
-
export type FirefoxProduct = 'firefox' | 'firefox-esr' | 'firefox-beta';
|
|
4
|
+
export type FirefoxProduct = 'firefox' | 'firefox-esr' | 'firefox-beta' | 'firefox-devedition';
|
|
5
5
|
/**
|
|
6
6
|
* Firefox version configuration.
|
|
7
7
|
*/
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
2
|
+
/** Formats elapsed milliseconds for progress messages. */
|
|
3
|
+
export function formatElapsed(ms) {
|
|
4
|
+
const totalSeconds = Math.max(0, Math.round(ms / 1000));
|
|
5
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
6
|
+
const seconds = totalSeconds % 60;
|
|
7
|
+
if (minutes === 0)
|
|
8
|
+
return `${seconds}s`;
|
|
9
|
+
return `${minutes}m ${seconds}s`;
|
|
10
|
+
}
|
|
11
|
+
/** Returns formatted elapsed time since a start timestamp from Date.now(). */
|
|
12
|
+
export function elapsedSince(startedAt) {
|
|
13
|
+
return formatElapsed(Date.now() - startedAt);
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=elapsed.js.map
|
|
@@ -71,7 +71,7 @@ export declare function assertObject(value: unknown, name: string): asserts valu
|
|
|
71
71
|
export declare function isValidFirefoxVersion(version: string): boolean;
|
|
72
72
|
/**
|
|
73
73
|
* Validates a Firefox product string.
|
|
74
|
-
* Accepts: firefox, firefox-esr, firefox-beta
|
|
74
|
+
* Accepts: firefox, firefox-esr, firefox-beta, firefox-devedition
|
|
75
75
|
*/
|
|
76
76
|
export declare function isValidFirefoxProduct(product: string): boolean;
|
|
77
77
|
/**
|
|
@@ -108,7 +108,7 @@ export declare function inferProductFromVersion(version: string): 'firefox' | 'f
|
|
|
108
108
|
*
|
|
109
109
|
* Rules:
|
|
110
110
|
* - `firefox-esr` requires an ESR version (e.g. "140.9.0esr", "128.0.1esr").
|
|
111
|
-
* - `firefox-beta`
|
|
111
|
+
* - `firefox-beta` and `firefox-devedition` require a beta version (e.g. "147.0b1").
|
|
112
112
|
* - `firefox` (stable) rejects both ESR and beta version strings.
|
|
113
113
|
*
|
|
114
114
|
* @returns An error message if incompatible, or undefined if valid.
|
|
@@ -106,10 +106,10 @@ export function isValidFirefoxVersion(version) {
|
|
|
106
106
|
}
|
|
107
107
|
/**
|
|
108
108
|
* Validates a Firefox product string.
|
|
109
|
-
* Accepts: firefox, firefox-esr, firefox-beta
|
|
109
|
+
* Accepts: firefox, firefox-esr, firefox-beta, firefox-devedition
|
|
110
110
|
*/
|
|
111
111
|
export function isValidFirefoxProduct(product) {
|
|
112
|
-
return ['firefox', 'firefox-esr', 'firefox-beta'].includes(product);
|
|
112
|
+
return ['firefox', 'firefox-esr', 'firefox-beta', 'firefox-devedition'].includes(product);
|
|
113
113
|
}
|
|
114
114
|
/**
|
|
115
115
|
* Valid project license SPDX identifiers.
|
|
@@ -161,7 +161,7 @@ export function inferProductFromVersion(version) {
|
|
|
161
161
|
*
|
|
162
162
|
* Rules:
|
|
163
163
|
* - `firefox-esr` requires an ESR version (e.g. "140.9.0esr", "128.0.1esr").
|
|
164
|
-
* - `firefox-beta`
|
|
164
|
+
* - `firefox-beta` and `firefox-devedition` require a beta version (e.g. "147.0b1").
|
|
165
165
|
* - `firefox` (stable) rejects both ESR and beta version strings.
|
|
166
166
|
*
|
|
167
167
|
* @returns An error message if incompatible, or undefined if valid.
|
|
@@ -177,9 +177,9 @@ export function validateFirefoxProductVersionCompatibility(version, product) {
|
|
|
177
177
|
}
|
|
178
178
|
break;
|
|
179
179
|
case 'firefox-beta':
|
|
180
|
+
case 'firefox-devedition':
|
|
180
181
|
if (!versionIsBeta) {
|
|
181
|
-
return (`Product "
|
|
182
|
-
`but got "${version}"`);
|
|
182
|
+
return (`Product "${product}" requires a beta version (e.g. "147.0b1"), ` + `but got "${version}"`);
|
|
183
183
|
}
|
|
184
184
|
break;
|
|
185
185
|
case 'firefox':
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hominis/fireforge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.1",
|
|
4
4
|
"description": "FireForge — a build tool for customizing Firefox",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/src/index.js",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"@clack/prompts": "^1.2.0",
|
|
55
55
|
"acorn": "^8.14.0",
|
|
56
|
-
"commander": "^
|
|
56
|
+
"commander": "^15.0.0",
|
|
57
57
|
"estree-walker": "^3.0.3",
|
|
58
58
|
"magic-string": "^0.30.17",
|
|
59
59
|
"picocolors": "^1.1.0"
|