@hominis/fireforge 0.18.2 → 0.18.5

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 (36) hide show
  1. package/README.md +29 -16
  2. package/dist/src/commands/build.js +27 -12
  3. package/dist/src/commands/config.js +56 -3
  4. package/dist/src/commands/discard.js +93 -1
  5. package/dist/src/commands/doctor.js +17 -4
  6. package/dist/src/commands/download.js +21 -0
  7. package/dist/src/commands/export-all.js +35 -6
  8. package/dist/src/commands/furnace/chrome-doc-templates.d.ts +59 -8
  9. package/dist/src/commands/furnace/chrome-doc-templates.js +95 -12
  10. package/dist/src/commands/furnace/chrome-doc.js +24 -2
  11. package/dist/src/commands/furnace/deploy.js +10 -1
  12. package/dist/src/commands/furnace/init.js +28 -2
  13. package/dist/src/commands/furnace/remove.js +68 -0
  14. package/dist/src/commands/import.js +9 -1
  15. package/dist/src/commands/lint.js +78 -13
  16. package/dist/src/commands/patch/delete.js +2 -4
  17. package/dist/src/commands/patch/lint-ignore.js +2 -4
  18. package/dist/src/commands/patch/reorder.js +2 -4
  19. package/dist/src/commands/patch/tier.js +2 -4
  20. package/dist/src/commands/status.js +39 -1
  21. package/dist/src/commands/test.js +20 -1
  22. package/dist/src/commands/token.js +1 -1
  23. package/dist/src/core/furnace-apply.js +11 -3
  24. package/dist/src/core/furnace-config.js +19 -0
  25. package/dist/src/core/furnace-marker.d.ts +16 -0
  26. package/dist/src/core/furnace-marker.js +23 -0
  27. package/dist/src/core/git.js +66 -10
  28. package/dist/src/core/license-headers.d.ts +8 -0
  29. package/dist/src/core/license-headers.js +15 -1
  30. package/dist/src/core/manifest-rules.js +9 -1
  31. package/dist/src/core/patch-identifier-suggest.d.ts +25 -0
  32. package/dist/src/core/patch-identifier-suggest.js +108 -0
  33. package/dist/src/core/patch-lint.js +8 -0
  34. package/dist/src/core/register-shared-css.d.ts +28 -0
  35. package/dist/src/core/register-shared-css.js +67 -3
  36. package/package.json +1 -1
@@ -83,11 +83,68 @@ function legacyRegisterSharedCSS(content, name, entry, after) {
83
83
  lines.splice(insertIndex, 0, entry);
84
84
  return { result: lines.join('\n'), previousEntry, afterFallback };
85
85
  }
86
+ /** Minimum gap between the target path and the source parenthesis. */
87
+ const MIN_SOURCE_GAP = 4;
88
+ /**
89
+ * Measures the column at which the `(source)` parenthesis opens in
90
+ * adjacent `skin/classic/browser/<x>.css (...)` entries inside an
91
+ * existing jar.inc.mn body, and returns the maximum so a newly inserted
92
+ * entry can align its source column to match.
93
+ *
94
+ * 2026-04-26 eval Finding 3: pre-fix `registerSharedCSS` always emitted
95
+ * a four-space gap between the target path and the parenthesis,
96
+ * regardless of how the rest of the file was aligned. Adjacent Firefox
97
+ * entries are typically padded to a wider column, so a freshly
98
+ * registered file landed at the wrong column and produced avoidable
99
+ * formatting churn. Returns `undefined` when no existing entries
100
+ * provide an alignment signal — callers fall back to the four-space
101
+ * default in that case.
102
+ */
103
+ export function measureSourceColumn(content) {
104
+ const lines = content.split('\n');
105
+ let maxColumn = 0;
106
+ let sampled = 0;
107
+ // The regex guarantees `(` appears in the matched line, so the index
108
+ // lookup below is always >= 0. The `match` body's leading-whitespace
109
+ // and target-path captures are likewise guaranteed by the pattern, so
110
+ // we can take the literal `match[0]` (full match) length minus one to
111
+ // locate the `(` column without a fragile per-group lookup.
112
+ const lineRe = /^\s*skin\/classic\/browser\/[^\s()]+\s+\(/;
113
+ for (const line of lines) {
114
+ const match = lineRe.exec(line);
115
+ if (!match)
116
+ continue;
117
+ const parenIndex = match[0].length - 1;
118
+ if (parenIndex > maxColumn)
119
+ maxColumn = parenIndex;
120
+ sampled++;
121
+ }
122
+ return sampled > 0 ? maxColumn : undefined;
123
+ }
124
+ /**
125
+ * Builds a `skin/classic/browser/<name>.css (../shared/<name>.css)`
126
+ * line padded so the parenthesis lands at {@link sourceColumn} (when
127
+ * supplied) or at the default four-space gap (when {@link sourceColumn}
128
+ * is `undefined` or would force the parenthesis closer to the target
129
+ * than {@link MIN_SOURCE_GAP}).
130
+ */
131
+ export function buildEntry(name, sourceColumn) {
132
+ const indent = ' ';
133
+ const target = `${indent}skin/classic/browser/${name}.css`;
134
+ const minColumn = target.length + MIN_SOURCE_GAP;
135
+ const column = sourceColumn !== undefined && sourceColumn >= minColumn ? sourceColumn : minColumn;
136
+ const padding = ' '.repeat(column - target.length);
137
+ return `${target}${padding}(../shared/${name}.css)`.replace(/\\/g, '/');
138
+ }
86
139
  /**
87
140
  * Registers a CSS file in browser/themes/shared/jar.inc.mn.
88
141
  *
89
142
  * Entry format:
90
143
  * skin/classic/browser/{name}.css (../shared/{name}.css)
144
+ *
145
+ * The gap between target and source is sized to align with adjacent
146
+ * entries when the manifest already uses a wider column; falls back to
147
+ * a four-space minimum otherwise.
91
148
  */
92
149
  export async function registerSharedCSS(engineDir, fileName, after, dryRun = false) {
93
150
  const manifest = 'browser/themes/shared/jar.inc.mn';
@@ -96,10 +153,17 @@ export async function registerSharedCSS(engineDir, fileName, after, dryRun = fal
96
153
  throw new GeneralError(`Manifest not found: ${manifest}`);
97
154
  }
98
155
  const name = basename(fileName, '.css');
99
- const entry = ` skin/classic/browser/${name}.css (../shared/${name}.css)`.replace(/\\/g, '/');
100
156
  const content = await readText(manifestPath);
101
- // Idempotency check
102
- if (content.includes(`skin/classic/browser/${name}.css`)) {
157
+ const sourceColumn = measureSourceColumn(content);
158
+ const entry = buildEntry(name, sourceColumn);
159
+ // Idempotency check. `furnace chrome-doc create` writes its CSS as a
160
+ // `content/browser/<name>.css` entry rather than the canonical
161
+ // `skin/classic/browser/<name>.css` form `register` produces; recognise
162
+ // both shapes so a follow-up `register` invocation against an
163
+ // already-chrome-doc-registered file reports `skipped` instead of
164
+ // appending a duplicate `skin/classic/browser/...` row.
165
+ if (content.includes(`skin/classic/browser/${name}.css`) ||
166
+ content.includes(`content/browser/${name}.css`)) {
103
167
  return { manifest, entry, skipped: true };
104
168
  }
105
169
  const { value } = withParserFallback(() => registerSharedCSSTokenized(content, name, entry, after), () => legacyRegisterSharedCSS(content, name, entry, after), manifest);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hominis/fireforge",
3
- "version": "0.18.2",
3
+ "version": "0.18.5",
4
4
  "description": "FireForge — a build tool for customizing Firefox",
5
5
  "type": "module",
6
6
  "main": "./dist/src/index.js",