@hominis/fireforge 0.9.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 (316) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/LICENSE.md +294 -0
  3. package/README.md +435 -0
  4. package/dist/bin/fireforge.d.ts +10 -0
  5. package/dist/bin/fireforge.js +29 -0
  6. package/dist/src/cli.d.ts +33 -0
  7. package/dist/src/cli.js +180 -0
  8. package/dist/src/commands/bootstrap.d.ts +9 -0
  9. package/dist/src/commands/bootstrap.js +73 -0
  10. package/dist/src/commands/build.d.ts +11 -0
  11. package/dist/src/commands/build.js +102 -0
  12. package/dist/src/commands/config.d.ts +13 -0
  13. package/dist/src/commands/config.js +135 -0
  14. package/dist/src/commands/discard.d.ts +12 -0
  15. package/dist/src/commands/discard.js +84 -0
  16. package/dist/src/commands/doctor.d.ts +18 -0
  17. package/dist/src/commands/doctor.js +356 -0
  18. package/dist/src/commands/download.d.ts +11 -0
  19. package/dist/src/commands/download.js +127 -0
  20. package/dist/src/commands/export-all.d.ts +11 -0
  21. package/dist/src/commands/export-all.js +122 -0
  22. package/dist/src/commands/export-shared.d.ts +48 -0
  23. package/dist/src/commands/export-shared.js +208 -0
  24. package/dist/src/commands/export.d.ts +13 -0
  25. package/dist/src/commands/export.js +178 -0
  26. package/dist/src/commands/furnace/apply.d.ts +7 -0
  27. package/dist/src/commands/furnace/apply.js +80 -0
  28. package/dist/src/commands/furnace/create.d.ts +8 -0
  29. package/dist/src/commands/furnace/create.js +377 -0
  30. package/dist/src/commands/furnace/deploy.d.ts +8 -0
  31. package/dist/src/commands/furnace/deploy.js +338 -0
  32. package/dist/src/commands/furnace/diff.d.ts +7 -0
  33. package/dist/src/commands/furnace/diff.js +119 -0
  34. package/dist/src/commands/furnace/index.d.ts +16 -0
  35. package/dist/src/commands/furnace/index.js +121 -0
  36. package/dist/src/commands/furnace/list.d.ts +5 -0
  37. package/dist/src/commands/furnace/list.js +65 -0
  38. package/dist/src/commands/furnace/override.d.ts +8 -0
  39. package/dist/src/commands/furnace/override.js +188 -0
  40. package/dist/src/commands/furnace/preview.d.ts +7 -0
  41. package/dist/src/commands/furnace/preview.js +96 -0
  42. package/dist/src/commands/furnace/remove.d.ts +8 -0
  43. package/dist/src/commands/furnace/remove.js +159 -0
  44. package/dist/src/commands/furnace/scan.d.ts +5 -0
  45. package/dist/src/commands/furnace/scan.js +112 -0
  46. package/dist/src/commands/furnace/status.d.ts +7 -0
  47. package/dist/src/commands/furnace/status.js +137 -0
  48. package/dist/src/commands/furnace/validate.d.ts +6 -0
  49. package/dist/src/commands/furnace/validate.js +91 -0
  50. package/dist/src/commands/furnace/validation-output.d.ts +7 -0
  51. package/dist/src/commands/furnace/validation-output.js +22 -0
  52. package/dist/src/commands/import.d.ts +11 -0
  53. package/dist/src/commands/import.js +241 -0
  54. package/dist/src/commands/lint.d.ts +10 -0
  55. package/dist/src/commands/lint.js +118 -0
  56. package/dist/src/commands/package.d.ts +11 -0
  57. package/dist/src/commands/package.js +80 -0
  58. package/dist/src/commands/re-export.d.ts +12 -0
  59. package/dist/src/commands/re-export.js +242 -0
  60. package/dist/src/commands/rebase/abort.d.ts +7 -0
  61. package/dist/src/commands/rebase/abort.js +49 -0
  62. package/dist/src/commands/rebase/confirm.d.ts +18 -0
  63. package/dist/src/commands/rebase/confirm.js +33 -0
  64. package/dist/src/commands/rebase/continue.d.ts +7 -0
  65. package/dist/src/commands/rebase/continue.js +81 -0
  66. package/dist/src/commands/rebase/index.d.ts +22 -0
  67. package/dist/src/commands/rebase/index.js +127 -0
  68. package/dist/src/commands/rebase/patch-loop.d.ts +9 -0
  69. package/dist/src/commands/rebase/patch-loop.js +135 -0
  70. package/dist/src/commands/rebase/summary.d.ts +12 -0
  71. package/dist/src/commands/rebase/summary.js +43 -0
  72. package/dist/src/commands/rebase.d.ts +4 -0
  73. package/dist/src/commands/rebase.js +6 -0
  74. package/dist/src/commands/register.d.ts +13 -0
  75. package/dist/src/commands/register.js +67 -0
  76. package/dist/src/commands/reset.d.ts +11 -0
  77. package/dist/src/commands/reset.js +83 -0
  78. package/dist/src/commands/resolve.d.ts +9 -0
  79. package/dist/src/commands/resolve.js +124 -0
  80. package/dist/src/commands/run.d.ts +9 -0
  81. package/dist/src/commands/run.js +91 -0
  82. package/dist/src/commands/setup-support.d.ts +23 -0
  83. package/dist/src/commands/setup-support.js +310 -0
  84. package/dist/src/commands/setup.d.ts +11 -0
  85. package/dist/src/commands/setup.js +94 -0
  86. package/dist/src/commands/status.d.ts +11 -0
  87. package/dist/src/commands/status.js +268 -0
  88. package/dist/src/commands/test.d.ts +12 -0
  89. package/dist/src/commands/test.js +182 -0
  90. package/dist/src/commands/token-coverage.d.ts +5 -0
  91. package/dist/src/commands/token-coverage.js +57 -0
  92. package/dist/src/commands/token.d.ts +14 -0
  93. package/dist/src/commands/token.js +121 -0
  94. package/dist/src/commands/watch.d.ts +9 -0
  95. package/dist/src/commands/watch.js +112 -0
  96. package/dist/src/commands/wire.d.ts +13 -0
  97. package/dist/src/commands/wire.js +149 -0
  98. package/dist/src/core/ast-utils.d.ts +47 -0
  99. package/dist/src/core/ast-utils.js +57 -0
  100. package/dist/src/core/brand-validation.d.ts +7 -0
  101. package/dist/src/core/brand-validation.js +15 -0
  102. package/dist/src/core/branding.d.ts +49 -0
  103. package/dist/src/core/branding.js +229 -0
  104. package/dist/src/core/browser-wire.d.ts +40 -0
  105. package/dist/src/core/browser-wire.js +66 -0
  106. package/dist/src/core/build-prepare.d.ts +25 -0
  107. package/dist/src/core/build-prepare.js +93 -0
  108. package/dist/src/core/config-mutate.d.ts +15 -0
  109. package/dist/src/core/config-mutate.js +51 -0
  110. package/dist/src/core/config-paths.d.ts +28 -0
  111. package/dist/src/core/config-paths.js +65 -0
  112. package/dist/src/core/config-state.d.ts +28 -0
  113. package/dist/src/core/config-state.js +152 -0
  114. package/dist/src/core/config-validate.d.ts +11 -0
  115. package/dist/src/core/config-validate.js +141 -0
  116. package/dist/src/core/config.d.ts +39 -0
  117. package/dist/src/core/config.js +70 -0
  118. package/dist/src/core/file-lock.d.ts +11 -0
  119. package/dist/src/core/file-lock.js +80 -0
  120. package/dist/src/core/firefox-archive.d.ts +40 -0
  121. package/dist/src/core/firefox-archive.js +63 -0
  122. package/dist/src/core/firefox-cache.d.ts +23 -0
  123. package/dist/src/core/firefox-cache.js +134 -0
  124. package/dist/src/core/firefox-download.d.ts +21 -0
  125. package/dist/src/core/firefox-download.js +129 -0
  126. package/dist/src/core/firefox-extract.d.ts +21 -0
  127. package/dist/src/core/firefox-extract.js +53 -0
  128. package/dist/src/core/firefox.d.ts +34 -0
  129. package/dist/src/core/firefox.js +78 -0
  130. package/dist/src/core/furnace-apply-helpers.d.ts +21 -0
  131. package/dist/src/core/furnace-apply-helpers.js +244 -0
  132. package/dist/src/core/furnace-apply.d.ts +16 -0
  133. package/dist/src/core/furnace-apply.js +147 -0
  134. package/dist/src/core/furnace-config.d.ts +94 -0
  135. package/dist/src/core/furnace-config.js +372 -0
  136. package/dist/src/core/furnace-constants.d.ts +4 -0
  137. package/dist/src/core/furnace-constants.js +6 -0
  138. package/dist/src/core/furnace-registration-ast.d.ts +24 -0
  139. package/dist/src/core/furnace-registration-ast.js +218 -0
  140. package/dist/src/core/furnace-registration-remove.d.ts +14 -0
  141. package/dist/src/core/furnace-registration-remove.js +89 -0
  142. package/dist/src/core/furnace-registration-validate.d.ts +20 -0
  143. package/dist/src/core/furnace-registration-validate.js +40 -0
  144. package/dist/src/core/furnace-registration.d.ts +29 -0
  145. package/dist/src/core/furnace-registration.js +96 -0
  146. package/dist/src/core/furnace-rollback.d.ts +20 -0
  147. package/dist/src/core/furnace-rollback.js +66 -0
  148. package/dist/src/core/furnace-scanner.d.ts +40 -0
  149. package/dist/src/core/furnace-scanner.js +143 -0
  150. package/dist/src/core/furnace-stories.d.ts +37 -0
  151. package/dist/src/core/furnace-stories.js +185 -0
  152. package/dist/src/core/furnace-validate-accessibility.d.ts +6 -0
  153. package/dist/src/core/furnace-validate-accessibility.js +32 -0
  154. package/dist/src/core/furnace-validate-checks.d.ts +4 -0
  155. package/dist/src/core/furnace-validate-checks.js +7 -0
  156. package/dist/src/core/furnace-validate-compatibility.d.ts +6 -0
  157. package/dist/src/core/furnace-validate-compatibility.js +57 -0
  158. package/dist/src/core/furnace-validate-helpers.d.ts +28 -0
  159. package/dist/src/core/furnace-validate-helpers.js +129 -0
  160. package/dist/src/core/furnace-validate-registration.d.ts +37 -0
  161. package/dist/src/core/furnace-validate-registration.js +220 -0
  162. package/dist/src/core/furnace-validate-structure.d.ts +6 -0
  163. package/dist/src/core/furnace-validate-structure.js +66 -0
  164. package/dist/src/core/furnace-validate.d.ts +16 -0
  165. package/dist/src/core/furnace-validate.js +103 -0
  166. package/dist/src/core/git-base.d.ts +47 -0
  167. package/dist/src/core/git-base.js +50 -0
  168. package/dist/src/core/git-diff.d.ts +63 -0
  169. package/dist/src/core/git-diff.js +246 -0
  170. package/dist/src/core/git-file-ops.d.ts +65 -0
  171. package/dist/src/core/git-file-ops.js +141 -0
  172. package/dist/src/core/git-status.d.ts +65 -0
  173. package/dist/src/core/git-status.js +163 -0
  174. package/dist/src/core/git.d.ts +113 -0
  175. package/dist/src/core/git.js +363 -0
  176. package/dist/src/core/license-headers.d.ts +36 -0
  177. package/dist/src/core/license-headers.js +83 -0
  178. package/dist/src/core/mach-build-artifacts.d.ts +29 -0
  179. package/dist/src/core/mach-build-artifacts.js +117 -0
  180. package/dist/src/core/mach-mozconfig.d.ts +17 -0
  181. package/dist/src/core/mach-mozconfig.js +50 -0
  182. package/dist/src/core/mach-python.d.ts +16 -0
  183. package/dist/src/core/mach-python.js +126 -0
  184. package/dist/src/core/mach.d.ts +106 -0
  185. package/dist/src/core/mach.js +166 -0
  186. package/dist/src/core/manifest-helpers.d.ts +25 -0
  187. package/dist/src/core/manifest-helpers.js +96 -0
  188. package/dist/src/core/manifest-register.d.ts +30 -0
  189. package/dist/src/core/manifest-register.js +65 -0
  190. package/dist/src/core/manifest-rules.d.ts +39 -0
  191. package/dist/src/core/manifest-rules.js +151 -0
  192. package/dist/src/core/manifest-tokenizers.d.ts +34 -0
  193. package/dist/src/core/manifest-tokenizers.js +84 -0
  194. package/dist/src/core/parser-fallback.d.ts +36 -0
  195. package/dist/src/core/parser-fallback.js +43 -0
  196. package/dist/src/core/patch-apply-fuzz.d.ts +29 -0
  197. package/dist/src/core/patch-apply-fuzz.js +70 -0
  198. package/dist/src/core/patch-apply.d.ts +46 -0
  199. package/dist/src/core/patch-apply.js +235 -0
  200. package/dist/src/core/patch-export.d.ts +99 -0
  201. package/dist/src/core/patch-export.js +314 -0
  202. package/dist/src/core/patch-files.d.ts +11 -0
  203. package/dist/src/core/patch-files.js +51 -0
  204. package/dist/src/core/patch-lint.d.ts +72 -0
  205. package/dist/src/core/patch-lint.js +403 -0
  206. package/dist/src/core/patch-lock.d.ts +8 -0
  207. package/dist/src/core/patch-lock.js +29 -0
  208. package/dist/src/core/patch-manifest-consistency.d.ts +24 -0
  209. package/dist/src/core/patch-manifest-consistency.js +135 -0
  210. package/dist/src/core/patch-manifest-io.d.ts +36 -0
  211. package/dist/src/core/patch-manifest-io.js +77 -0
  212. package/dist/src/core/patch-manifest-query.d.ts +48 -0
  213. package/dist/src/core/patch-manifest-query.js +124 -0
  214. package/dist/src/core/patch-manifest-validate.d.ts +22 -0
  215. package/dist/src/core/patch-manifest-validate.js +72 -0
  216. package/dist/src/core/patch-manifest.d.ts +11 -0
  217. package/dist/src/core/patch-manifest.js +12 -0
  218. package/dist/src/core/patch-parse.d.ts +43 -0
  219. package/dist/src/core/patch-parse.js +143 -0
  220. package/dist/src/core/patch-transform.d.ts +21 -0
  221. package/dist/src/core/patch-transform.js +138 -0
  222. package/dist/src/core/rebase-session.d.ts +47 -0
  223. package/dist/src/core/rebase-session.js +65 -0
  224. package/dist/src/core/register-browser-content.d.ts +11 -0
  225. package/dist/src/core/register-browser-content.js +116 -0
  226. package/dist/src/core/register-module.d.ts +11 -0
  227. package/dist/src/core/register-module.js +76 -0
  228. package/dist/src/core/register-shared-css.d.ts +11 -0
  229. package/dist/src/core/register-shared-css.js +117 -0
  230. package/dist/src/core/register-test-manifest.d.ts +18 -0
  231. package/dist/src/core/register-test-manifest.js +99 -0
  232. package/dist/src/core/state-file.d.ts +4 -0
  233. package/dist/src/core/state-file.js +25 -0
  234. package/dist/src/core/token-coverage.d.ts +12 -0
  235. package/dist/src/core/token-coverage.js +74 -0
  236. package/dist/src/core/token-manager.d.ts +55 -0
  237. package/dist/src/core/token-manager.js +387 -0
  238. package/dist/src/core/wire-destroy.d.ts +21 -0
  239. package/dist/src/core/wire-destroy.js +103 -0
  240. package/dist/src/core/wire-dom-fragment.d.ts +23 -0
  241. package/dist/src/core/wire-dom-fragment.js +129 -0
  242. package/dist/src/core/wire-init.d.ts +23 -0
  243. package/dist/src/core/wire-init.js +201 -0
  244. package/dist/src/core/wire-subscript.d.ts +20 -0
  245. package/dist/src/core/wire-subscript.js +134 -0
  246. package/dist/src/core/wire-targets.d.ts +7 -0
  247. package/dist/src/core/wire-targets.js +9 -0
  248. package/dist/src/core/wire-utils.d.ts +88 -0
  249. package/dist/src/core/wire-utils.js +279 -0
  250. package/dist/src/errors/base.d.ts +60 -0
  251. package/dist/src/errors/base.js +87 -0
  252. package/dist/src/errors/build.d.ts +52 -0
  253. package/dist/src/errors/build.js +114 -0
  254. package/dist/src/errors/codes.d.ts +29 -0
  255. package/dist/src/errors/codes.js +30 -0
  256. package/dist/src/errors/config.d.ts +31 -0
  257. package/dist/src/errors/config.js +61 -0
  258. package/dist/src/errors/download.d.ts +42 -0
  259. package/dist/src/errors/download.js +95 -0
  260. package/dist/src/errors/furnace.d.ts +10 -0
  261. package/dist/src/errors/furnace.js +22 -0
  262. package/dist/src/errors/git.d.ts +41 -0
  263. package/dist/src/errors/git.js +99 -0
  264. package/dist/src/errors/patch.d.ts +10 -0
  265. package/dist/src/errors/patch.js +26 -0
  266. package/dist/src/errors/rebase.d.ts +20 -0
  267. package/dist/src/errors/rebase.js +30 -0
  268. package/dist/src/index.d.ts +21 -0
  269. package/dist/src/index.js +21 -0
  270. package/dist/src/types/cli.d.ts +14 -0
  271. package/dist/src/types/cli.js +2 -0
  272. package/dist/src/types/commands/index.d.ts +6 -0
  273. package/dist/src/types/commands/index.js +6 -0
  274. package/dist/src/types/commands/options.d.ts +239 -0
  275. package/dist/src/types/commands/options.js +6 -0
  276. package/dist/src/types/commands/patches.d.ts +89 -0
  277. package/dist/src/types/commands/patches.js +6 -0
  278. package/dist/src/types/commands/project.d.ts +71 -0
  279. package/dist/src/types/commands/project.js +6 -0
  280. package/dist/src/types/config.d.ts +101 -0
  281. package/dist/src/types/config.js +2 -0
  282. package/dist/src/types/furnace.d.ts +158 -0
  283. package/dist/src/types/furnace.js +2 -0
  284. package/dist/src/types/index.d.ts +6 -0
  285. package/dist/src/types/index.js +6 -0
  286. package/dist/src/utils/errors.d.ts +2 -0
  287. package/dist/src/utils/errors.js +15 -0
  288. package/dist/src/utils/fs.d.ts +72 -0
  289. package/dist/src/utils/fs.js +179 -0
  290. package/dist/src/utils/logger.d.ts +58 -0
  291. package/dist/src/utils/logger.js +120 -0
  292. package/dist/src/utils/options.d.ts +8 -0
  293. package/dist/src/utils/options.js +16 -0
  294. package/dist/src/utils/package-root.d.ts +10 -0
  295. package/dist/src/utils/package-root.js +53 -0
  296. package/dist/src/utils/parse.d.ts +110 -0
  297. package/dist/src/utils/parse.js +200 -0
  298. package/dist/src/utils/paths.d.ts +10 -0
  299. package/dist/src/utils/paths.js +43 -0
  300. package/dist/src/utils/platform.d.ts +38 -0
  301. package/dist/src/utils/platform.js +56 -0
  302. package/dist/src/utils/process.d.ts +80 -0
  303. package/dist/src/utils/process.js +188 -0
  304. package/dist/src/utils/regex.d.ts +24 -0
  305. package/dist/src/utils/regex.js +40 -0
  306. package/dist/src/utils/validation.d.ts +133 -0
  307. package/dist/src/utils/validation.js +250 -0
  308. package/package.json +106 -0
  309. package/templates/configs/common.mozconfig +24 -0
  310. package/templates/configs/darwin.mozconfig +10 -0
  311. package/templates/configs/linux.mozconfig +12 -0
  312. package/templates/configs/win32.mozconfig +14 -0
  313. package/templates/licenses/0BSD.md +14 -0
  314. package/templates/licenses/EUPL-1.2.md +294 -0
  315. package/templates/licenses/GPL-2.0-or-later.md +339 -0
  316. package/templates/licenses/MPL-2.0.md +383 -0
@@ -0,0 +1,117 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ import { readdir } from 'node:fs/promises';
3
+ import { join, resolve } from 'node:path';
4
+ import { toError } from '../utils/errors.js';
5
+ import { pathExists, readJson } from '../utils/fs.js';
6
+ import { verbose } from '../utils/logger.js';
7
+ import { isObject, isString } from '../utils/validation.js';
8
+ function validateBuildMozinfo(data) {
9
+ if (!isObject(data)) {
10
+ throw new Error('mozinfo metadata must be an object');
11
+ }
12
+ const mozinfo = {};
13
+ if (data['topsrcdir'] !== undefined) {
14
+ if (!isString(data['topsrcdir'])) {
15
+ throw new Error('mozinfo.topsrcdir must be a string');
16
+ }
17
+ mozinfo.topsrcdir = data['topsrcdir'];
18
+ }
19
+ if (data['topobjdir'] !== undefined) {
20
+ if (!isString(data['topobjdir'])) {
21
+ throw new Error('mozinfo.topobjdir must be a string');
22
+ }
23
+ mozinfo.topobjdir = data['topobjdir'];
24
+ }
25
+ if (data['mozconfig'] !== undefined) {
26
+ if (!isString(data['mozconfig'])) {
27
+ throw new Error('mozinfo.mozconfig must be a string');
28
+ }
29
+ mozinfo.mozconfig = data['mozconfig'];
30
+ }
31
+ return mozinfo;
32
+ }
33
+ /**
34
+ * Checks if build artifacts exist in the engine directory.
35
+ * Looks for obj-* directories with a dist subdirectory.
36
+ * @param engineDir - Path to the engine directory
37
+ * @returns Build artifact check result
38
+ */
39
+ export async function hasBuildArtifacts(engineDir) {
40
+ try {
41
+ const entries = await readdir(engineDir);
42
+ const objDirs = entries.filter((e) => e.startsWith('obj-')).sort();
43
+ if (objDirs.length === 0) {
44
+ return { exists: false };
45
+ }
46
+ const validObjDirs = [];
47
+ for (const objDir of objDirs) {
48
+ const distPath = join(engineDir, objDir, 'dist');
49
+ if (await pathExists(distPath)) {
50
+ validObjDirs.push(objDir);
51
+ }
52
+ }
53
+ if (validObjDirs.length === 0) {
54
+ const firstObjDir = objDirs[0];
55
+ return firstObjDir ? { exists: false, objDir: firstObjDir } : { exists: false };
56
+ }
57
+ if (validObjDirs.length > 1) {
58
+ return { exists: true, ambiguous: true, objDirs: validObjDirs };
59
+ }
60
+ const selectedObjDir = validObjDirs[0];
61
+ if (!selectedObjDir) {
62
+ return { exists: false };
63
+ }
64
+ const mozinfoPath = join(engineDir, selectedObjDir, 'mozinfo.json');
65
+ if (await pathExists(mozinfoPath)) {
66
+ try {
67
+ const mozinfo = validateBuildMozinfo(await readJson(mozinfoPath));
68
+ const expectedSrcDir = resolve(engineDir);
69
+ const expectedObjDir = resolve(engineDir, selectedObjDir);
70
+ const actualSrcDir = mozinfo.topsrcdir ? resolve(mozinfo.topsrcdir) : undefined;
71
+ const actualObjDir = mozinfo.topobjdir ? resolve(mozinfo.topobjdir) : undefined;
72
+ if ((actualSrcDir !== undefined && actualSrcDir !== expectedSrcDir) ||
73
+ (actualObjDir !== undefined && actualObjDir !== expectedObjDir)) {
74
+ return {
75
+ exists: true,
76
+ objDir: selectedObjDir,
77
+ metadataMismatch: {
78
+ objDir: selectedObjDir,
79
+ ...(mozinfo.topsrcdir ? { topsrcdir: mozinfo.topsrcdir } : {}),
80
+ ...(mozinfo.topobjdir ? { topobjdir: mozinfo.topobjdir } : {}),
81
+ ...(mozinfo.mozconfig ? { mozconfig: mozinfo.mozconfig } : {}),
82
+ },
83
+ };
84
+ }
85
+ }
86
+ catch (error) {
87
+ verbose(`Ignoring invalid mozinfo metadata in ${selectedObjDir}: ${toError(error).message}`);
88
+ }
89
+ }
90
+ return { exists: true, objDir: selectedObjDir };
91
+ }
92
+ catch (error) {
93
+ void error;
94
+ return { exists: false };
95
+ }
96
+ }
97
+ /** Builds a user-facing explanation when detected build artifacts belong to another workspace. */
98
+ export function buildArtifactMismatchMessage(engineDir, buildCheck, commandName) {
99
+ if (!buildCheck.metadataMismatch || !buildCheck.objDir) {
100
+ return undefined;
101
+ }
102
+ const expectedObjDir = join(engineDir, buildCheck.objDir);
103
+ const details = [`Current engine: ${engineDir}`, `Detected objdir: ${expectedObjDir}`];
104
+ if (buildCheck.metadataMismatch.topsrcdir) {
105
+ details.push(`mozinfo topsrcdir: ${buildCheck.metadataMismatch.topsrcdir}`);
106
+ }
107
+ if (buildCheck.metadataMismatch.topobjdir) {
108
+ details.push(`mozinfo topobjdir: ${buildCheck.metadataMismatch.topobjdir}`);
109
+ }
110
+ if (buildCheck.metadataMismatch.mozconfig) {
111
+ details.push(`mozinfo mozconfig: ${buildCheck.metadataMismatch.mozconfig}`);
112
+ }
113
+ return (`${commandName} cannot use copied or relocated build artifacts whose metadata still points at a different Firefox workspace.\n\n` +
114
+ `${details.join('\n')}\n\n` +
115
+ 'Delete the stale obj-* directory in this workspace and run "fireforge build" again so mach regenerates build metadata for the current checkout.');
116
+ }
117
+ //# sourceMappingURL=mach-build-artifacts.js.map
@@ -0,0 +1,17 @@
1
+ import type { FireForgeConfig } from '../types/config.js';
2
+ /**
3
+ * Template variables for mozconfig generation.
4
+ */
5
+ export interface MozconfigVariables {
6
+ name: string;
7
+ vendor: string;
8
+ appId: string;
9
+ binaryName: string;
10
+ }
11
+ /**
12
+ * Generates a mozconfig file from templates.
13
+ * @param configsDir - Path to the configs directory
14
+ * @param engineDir - Path to the engine directory
15
+ * @param config - FireForge configuration
16
+ */
17
+ export declare function generateMozconfig(configsDir: string, engineDir: string, config: FireForgeConfig): Promise<void>;
@@ -0,0 +1,50 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ import { join } from 'node:path';
3
+ import { MozconfigError } from '../errors/build.js';
4
+ import { pathExists, readText, writeText } from '../utils/fs.js';
5
+ import { getPlatform } from '../utils/platform.js';
6
+ /**
7
+ * Replaces template variables in a string.
8
+ * @param content - Content with ${variable} placeholders
9
+ * @param variables - Variables to substitute
10
+ * @returns Content with variables replaced
11
+ */
12
+ function replaceVariables(content, variables) {
13
+ return content
14
+ .replace(/\$\{name\}/g, variables.name)
15
+ .replace(/\$\{vendor\}/g, variables.vendor)
16
+ .replace(/\$\{appId\}/g, variables.appId)
17
+ .replace(/\$\{binaryName\}/g, variables.binaryName);
18
+ }
19
+ /**
20
+ * Generates a mozconfig file from templates.
21
+ * @param configsDir - Path to the configs directory
22
+ * @param engineDir - Path to the engine directory
23
+ * @param config - FireForge configuration
24
+ */
25
+ export async function generateMozconfig(configsDir, engineDir, config) {
26
+ const platform = getPlatform();
27
+ const commonPath = join(configsDir, 'common.mozconfig');
28
+ const platformPath = join(configsDir, `${platform}.mozconfig`);
29
+ const outputPath = join(engineDir, 'mozconfig');
30
+ const variables = {
31
+ name: config.name,
32
+ vendor: config.vendor,
33
+ appId: config.appId,
34
+ binaryName: config.binaryName,
35
+ };
36
+ let content = '';
37
+ // Read common config if it exists
38
+ if (await pathExists(commonPath)) {
39
+ const commonContent = await readText(commonPath);
40
+ content += `# Common configuration\n${replaceVariables(commonContent, variables)}\n\n`;
41
+ }
42
+ // Read platform-specific config
43
+ if (!(await pathExists(platformPath))) {
44
+ throw new MozconfigError(`Platform mozconfig not found: ${platformPath}`);
45
+ }
46
+ const platformContent = await readText(platformPath);
47
+ content += `# Platform configuration (${platform})\n${replaceVariables(platformContent, variables)}`;
48
+ await writeText(outputPath, content);
49
+ }
50
+ //# sourceMappingURL=mach-mozconfig.js.map
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Resets the resolved Python executable. Primarily useful for testing.
3
+ */
4
+ export declare function resetResolvedPython(): void;
5
+ /**
6
+ * Dynamically resolves the python executable and ensures it is available.
7
+ * Checks the Python version range declared by engine/mach when available.
8
+ * @throws PythonNotFoundError if no suitable python is installed
9
+ */
10
+ export declare function ensurePython(engineDir?: string): Promise<void>;
11
+ /**
12
+ * Gets the resolved Python executable name.
13
+ * @param engineDir - Optional engine directory for engine-specific Python requirements
14
+ * @returns The resolved Python executable name
15
+ */
16
+ export declare function getPython(engineDir?: string): Promise<string>;
@@ -0,0 +1,126 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ import { join } from 'node:path';
3
+ import { PythonNotFoundError } from '../errors/build.js';
4
+ import { toError } from '../utils/errors.js';
5
+ import { pathExists, readText } from '../utils/fs.js';
6
+ import { verbose } from '../utils/logger.js';
7
+ import { exec, executableExists } from '../utils/process.js';
8
+ /** Cached Python resolution state */
9
+ const pythonCache = {};
10
+ const DEFAULT_MACH_PYTHON_REQUIREMENTS = {
11
+ min: { major: 3, minor: 8 },
12
+ max: { major: 3, minor: 12 },
13
+ };
14
+ function formatPythonMinor(version) {
15
+ return `${version.major}.${version.minor}`;
16
+ }
17
+ function formatRequirementsKey(requirements) {
18
+ return `${formatPythonMinor(requirements.min)}-${formatPythonMinor(requirements.max)}`;
19
+ }
20
+ function comparePythonVersions(left, right) {
21
+ if (left.major !== right.major)
22
+ return left.major - right.major;
23
+ if (left.minor !== right.minor)
24
+ return left.minor - right.minor;
25
+ return (left.micro ?? 0) - (right.micro ?? 0);
26
+ }
27
+ function isVersionWithinRequirements(version, requirements) {
28
+ return (comparePythonVersions({ major: version.major, minor: version.minor }, requirements.min) >= 0 &&
29
+ comparePythonVersions({ major: version.major, minor: version.minor }, requirements.max) <= 0);
30
+ }
31
+ function parsePythonVersion(output) {
32
+ const match = /(\d+)\.(\d+)\.(\d+)/.exec(output.trim());
33
+ if (!match)
34
+ return undefined;
35
+ return {
36
+ major: Number(match[1]),
37
+ minor: Number(match[2]),
38
+ micro: Number(match[3]),
39
+ };
40
+ }
41
+ async function readMachPythonRequirements(engineDir) {
42
+ if (!engineDir) {
43
+ return DEFAULT_MACH_PYTHON_REQUIREMENTS;
44
+ }
45
+ const machPath = join(engineDir, 'mach');
46
+ if (!(await pathExists(machPath))) {
47
+ return DEFAULT_MACH_PYTHON_REQUIREMENTS;
48
+ }
49
+ try {
50
+ const machContent = await readText(machPath);
51
+ const minMatch = /MIN_PYTHON_VERSION\s*=\s*\((\d+),\s*(\d+)\)/.exec(machContent);
52
+ const maxMatch = /MAX_PYTHON_VERSION_TO_CONSIDER\s*=\s*\((\d+),\s*(\d+)\)/.exec(machContent);
53
+ if (!minMatch || !maxMatch) {
54
+ return DEFAULT_MACH_PYTHON_REQUIREMENTS;
55
+ }
56
+ return {
57
+ min: { major: Number(minMatch[1]), minor: Number(minMatch[2]) },
58
+ max: { major: Number(maxMatch[1]), minor: Number(maxMatch[2]) },
59
+ };
60
+ }
61
+ catch (error) {
62
+ verbose(`Using default mach python requirements because engine/mach could not be read: ${toError(error).message}`);
63
+ return DEFAULT_MACH_PYTHON_REQUIREMENTS;
64
+ }
65
+ }
66
+ function buildPythonCandidates(requirements) {
67
+ const candidates = [];
68
+ for (let minor = requirements.max.minor; minor >= requirements.min.minor; minor--) {
69
+ candidates.push(`python${requirements.min.major}.${minor}`);
70
+ }
71
+ candidates.push(`python${requirements.min.major}`, 'python');
72
+ return [...new Set(candidates)];
73
+ }
74
+ /**
75
+ * Resets the resolved Python executable. Primarily useful for testing.
76
+ */
77
+ export function resetResolvedPython() {
78
+ delete pythonCache.python;
79
+ delete pythonCache.requirementsKey;
80
+ }
81
+ /**
82
+ * Dynamically resolves the python executable and ensures it is available.
83
+ * Checks the Python version range declared by engine/mach when available.
84
+ * @throws PythonNotFoundError if no suitable python is installed
85
+ */
86
+ export async function ensurePython(engineDir) {
87
+ const requirements = await readMachPythonRequirements(engineDir);
88
+ const requirementsKey = formatRequirementsKey(requirements);
89
+ if (pythonCache.python && pythonCache.requirementsKey === requirementsKey) {
90
+ return;
91
+ }
92
+ const candidates = buildPythonCandidates(requirements);
93
+ for (const candidate of candidates) {
94
+ if (await executableExists(candidate)) {
95
+ try {
96
+ const { stdout } = await exec(candidate, [
97
+ '-c',
98
+ 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}")',
99
+ ]);
100
+ const version = parsePythonVersion(stdout);
101
+ if (version && isVersionWithinRequirements(version, requirements)) {
102
+ pythonCache.python = candidate;
103
+ pythonCache.requirementsKey = requirementsKey;
104
+ return;
105
+ }
106
+ }
107
+ catch (error) {
108
+ verbose(`Python candidate ${candidate} was not usable: ${toError(error).message}`);
109
+ }
110
+ }
111
+ }
112
+ throw new PythonNotFoundError(formatPythonMinor(requirements.min), formatPythonMinor(requirements.max));
113
+ }
114
+ /**
115
+ * Gets the resolved Python executable name.
116
+ * @param engineDir - Optional engine directory for engine-specific Python requirements
117
+ * @returns The resolved Python executable name
118
+ */
119
+ export async function getPython(engineDir) {
120
+ await ensurePython(engineDir);
121
+ if (!pythonCache.python) {
122
+ throw new PythonNotFoundError();
123
+ }
124
+ return pythonCache.python;
125
+ }
126
+ //# sourceMappingURL=mach-python.js.map
@@ -0,0 +1,106 @@
1
+ export { type BuildArtifactCheck, buildArtifactMismatchMessage, hasBuildArtifacts, } from './mach-build-artifacts.js';
2
+ export { generateMozconfig, type MozconfigVariables } from './mach-mozconfig.js';
3
+ export { ensurePython, resetResolvedPython } from './mach-python.js';
4
+ /**
5
+ * Ensures mach is available in the engine directory.
6
+ * @param engineDir - Path to the engine directory
7
+ * @throws MachNotFoundError if mach is not found
8
+ */
9
+ export declare function ensureMach(engineDir: string): Promise<void>;
10
+ /**
11
+ * Options for running mach commands.
12
+ */
13
+ export interface MachOptions {
14
+ /** Additional environment variables */
15
+ env?: Record<string, string>;
16
+ /** Whether to inherit stdio (show output directly) */
17
+ inherit?: boolean;
18
+ }
19
+ /**
20
+ * Result of running a mach command while capturing streamed output.
21
+ */
22
+ export interface MachCommandResult {
23
+ stdout: string;
24
+ stderr: string;
25
+ exitCode: number;
26
+ }
27
+ /**
28
+ * Runs a mach command in the engine directory.
29
+ * @param args - mach command and arguments
30
+ * @param engineDir - Path to the engine directory
31
+ * @param options - Command options
32
+ * @returns Exit code
33
+ */
34
+ export declare function runMach(args: string[], engineDir: string, options?: MachOptions): Promise<number>;
35
+ /**
36
+ * Runs a mach command while streaming output to the terminal and capturing it
37
+ * for post-run diagnostics.
38
+ */
39
+ export declare function runMachCapture(args: string[], engineDir: string, options?: Omit<MachOptions, 'inherit'>): Promise<MachCommandResult>;
40
+ /**
41
+ * Runs a mach command while inheriting stdin, streaming output live, and
42
+ * capturing stdout/stderr for post-run diagnostics.
43
+ */
44
+ export declare function runMachInheritCapture(args: string[], engineDir: string, options?: Omit<MachOptions, 'inherit'>): Promise<MachCommandResult>;
45
+ /**
46
+ * Runs mach bootstrap to install build dependencies.
47
+ * @param engineDir - Path to the engine directory
48
+ * @returns Exit code
49
+ */
50
+ export declare function bootstrap(engineDir: string): Promise<number>;
51
+ /**
52
+ * Runs mach bootstrap while preserving stdin and capturing the emitted output.
53
+ * @param engineDir - Path to the engine directory
54
+ * @returns Captured output and exit code
55
+ */
56
+ export declare function bootstrapWithOutput(engineDir: string): Promise<MachCommandResult>;
57
+ /**
58
+ * Runs a full mach build.
59
+ * @param engineDir - Path to the engine directory
60
+ * @param jobs - Number of parallel jobs (optional)
61
+ * @returns Exit code
62
+ */
63
+ export declare function build(engineDir: string, jobs?: number): Promise<number>;
64
+ /**
65
+ * Runs a fast UI-only build.
66
+ * @param engineDir - Path to the engine directory
67
+ * @returns Exit code
68
+ */
69
+ export declare function buildUI(engineDir: string): Promise<number>;
70
+ /**
71
+ * Runs the built browser.
72
+ * @param engineDir - Path to the engine directory
73
+ * @param args - Additional arguments to pass to the browser
74
+ * @returns Exit code
75
+ */
76
+ export declare function run(engineDir: string, args?: string[]): Promise<number>;
77
+ /**
78
+ * Creates a distribution package.
79
+ * @param engineDir - Path to the engine directory
80
+ * @returns Exit code
81
+ */
82
+ export declare function machPackage(engineDir: string): Promise<number>;
83
+ /**
84
+ * Runs mach watch for auto-rebuilding.
85
+ * @param engineDir - Path to the engine directory
86
+ * @returns Exit code
87
+ */
88
+ export declare function watch(engineDir: string): Promise<number>;
89
+ /**
90
+ * Runs mach watch while preserving stdin and capturing emitted output.
91
+ * @param engineDir - Path to the engine directory
92
+ * @returns Captured output and exit code
93
+ */
94
+ export declare function watchWithOutput(engineDir: string): Promise<MachCommandResult>;
95
+ /**
96
+ * Runs mach test with the given test paths.
97
+ * @param engineDir - Path to the engine directory
98
+ * @param testPaths - Test file or directory paths (relative to engine)
99
+ * @param args - Additional arguments to pass to mach test
100
+ * @returns Exit code
101
+ */
102
+ export declare function test(engineDir: string, testPaths?: string[], args?: string[]): Promise<number>;
103
+ /**
104
+ * Runs mach test while capturing streamed output for better diagnostics.
105
+ */
106
+ export declare function testWithOutput(engineDir: string, testPaths?: string[], args?: string[]): Promise<MachCommandResult>;
@@ -0,0 +1,166 @@
1
+ // SPDX-License-Identifier: EUPL-1.2
2
+ import { join } from 'node:path';
3
+ import { MachNotFoundError } from '../errors/build.js';
4
+ import { pathExists } from '../utils/fs.js';
5
+ import { exec, execInherit, execInheritCapture, execStream } from '../utils/process.js';
6
+ import { getPython } from './mach-python.js';
7
+ // Re-export sub-modules so existing `from './mach.js'` imports keep working.
8
+ export { buildArtifactMismatchMessage, hasBuildArtifacts, } from './mach-build-artifacts.js';
9
+ export { generateMozconfig } from './mach-mozconfig.js';
10
+ export { ensurePython, resetResolvedPython } from './mach-python.js';
11
+ /**
12
+ * Ensures mach is available in the engine directory.
13
+ * @param engineDir - Path to the engine directory
14
+ * @throws MachNotFoundError if mach is not found
15
+ */
16
+ export async function ensureMach(engineDir) {
17
+ const machPath = join(engineDir, 'mach');
18
+ if (!(await pathExists(machPath))) {
19
+ throw new MachNotFoundError(engineDir);
20
+ }
21
+ }
22
+ /**
23
+ * Runs a mach command in the engine directory.
24
+ * @param args - mach command and arguments
25
+ * @param engineDir - Path to the engine directory
26
+ * @param options - Command options
27
+ * @returns Exit code
28
+ */
29
+ export async function runMach(args, engineDir, options = {}) {
30
+ const python = await getPython(engineDir);
31
+ await ensureMach(engineDir);
32
+ const machPath = join(engineDir, 'mach');
33
+ const execOptions = {
34
+ cwd: engineDir,
35
+ ...(options.env ? { env: options.env } : {}),
36
+ };
37
+ if (options.inherit) {
38
+ return execInherit(python, [machPath, ...args], execOptions);
39
+ }
40
+ const result = await exec(python, [machPath, ...args], execOptions);
41
+ return result.exitCode;
42
+ }
43
+ /**
44
+ * Runs a mach command while streaming output to the terminal and capturing it
45
+ * for post-run diagnostics.
46
+ */
47
+ export async function runMachCapture(args, engineDir, options = {}) {
48
+ const python = await getPython(engineDir);
49
+ await ensureMach(engineDir);
50
+ const machPath = join(engineDir, 'mach');
51
+ let stdout = '';
52
+ let stderr = '';
53
+ const exitCode = await execStream(python, [machPath, ...args], {
54
+ cwd: engineDir,
55
+ ...(options.env ? { env: options.env } : {}),
56
+ onStdout: (data) => {
57
+ stdout += data;
58
+ process.stdout.write(data);
59
+ },
60
+ onStderr: (data) => {
61
+ stderr += data;
62
+ process.stderr.write(data);
63
+ },
64
+ });
65
+ return { stdout, stderr, exitCode };
66
+ }
67
+ /**
68
+ * Runs a mach command while inheriting stdin, streaming output live, and
69
+ * capturing stdout/stderr for post-run diagnostics.
70
+ */
71
+ export async function runMachInheritCapture(args, engineDir, options = {}) {
72
+ const python = await getPython(engineDir);
73
+ await ensureMach(engineDir);
74
+ const machPath = join(engineDir, 'mach');
75
+ return execInheritCapture(python, [machPath, ...args], {
76
+ cwd: engineDir,
77
+ ...(options.env ? { env: options.env } : {}),
78
+ });
79
+ }
80
+ /**
81
+ * Runs mach bootstrap to install build dependencies.
82
+ * @param engineDir - Path to the engine directory
83
+ * @returns Exit code
84
+ */
85
+ export async function bootstrap(engineDir) {
86
+ return runMach(['bootstrap', '--application-choice', 'browser'], engineDir, { inherit: true });
87
+ }
88
+ /**
89
+ * Runs mach bootstrap while preserving stdin and capturing the emitted output.
90
+ * @param engineDir - Path to the engine directory
91
+ * @returns Captured output and exit code
92
+ */
93
+ export async function bootstrapWithOutput(engineDir) {
94
+ return runMachInheritCapture(['bootstrap', '--application-choice', 'browser'], engineDir);
95
+ }
96
+ /**
97
+ * Runs a full mach build.
98
+ * @param engineDir - Path to the engine directory
99
+ * @param jobs - Number of parallel jobs (optional)
100
+ * @returns Exit code
101
+ */
102
+ export async function build(engineDir, jobs) {
103
+ const args = ['build'];
104
+ if (jobs !== undefined) {
105
+ args.push('-j', String(jobs));
106
+ }
107
+ return runMach(args, engineDir, { inherit: true });
108
+ }
109
+ /**
110
+ * Runs a fast UI-only build.
111
+ * @param engineDir - Path to the engine directory
112
+ * @returns Exit code
113
+ */
114
+ export async function buildUI(engineDir) {
115
+ return runMach(['build', 'faster'], engineDir, { inherit: true });
116
+ }
117
+ /**
118
+ * Runs the built browser.
119
+ * @param engineDir - Path to the engine directory
120
+ * @param args - Additional arguments to pass to the browser
121
+ * @returns Exit code
122
+ */
123
+ export async function run(engineDir, args = []) {
124
+ return runMach(['run', ...args], engineDir, { inherit: true });
125
+ }
126
+ /**
127
+ * Creates a distribution package.
128
+ * @param engineDir - Path to the engine directory
129
+ * @returns Exit code
130
+ */
131
+ export async function machPackage(engineDir) {
132
+ return runMach(['package'], engineDir, { inherit: true });
133
+ }
134
+ /**
135
+ * Runs mach watch for auto-rebuilding.
136
+ * @param engineDir - Path to the engine directory
137
+ * @returns Exit code
138
+ */
139
+ export async function watch(engineDir) {
140
+ return runMach(['watch'], engineDir, { inherit: true });
141
+ }
142
+ /**
143
+ * Runs mach watch while preserving stdin and capturing emitted output.
144
+ * @param engineDir - Path to the engine directory
145
+ * @returns Captured output and exit code
146
+ */
147
+ export async function watchWithOutput(engineDir) {
148
+ return runMachInheritCapture(['watch'], engineDir);
149
+ }
150
+ /**
151
+ * Runs mach test with the given test paths.
152
+ * @param engineDir - Path to the engine directory
153
+ * @param testPaths - Test file or directory paths (relative to engine)
154
+ * @param args - Additional arguments to pass to mach test
155
+ * @returns Exit code
156
+ */
157
+ export async function test(engineDir, testPaths = [], args = []) {
158
+ return runMach(['test', ...testPaths, ...args], engineDir, { inherit: true });
159
+ }
160
+ /**
161
+ * Runs mach test while capturing streamed output for better diagnostics.
162
+ */
163
+ export async function testWithOutput(engineDir, testPaths = [], args = []) {
164
+ return runMachCapture(['test', ...testPaths, ...args], engineDir);
165
+ }
166
+ //# sourceMappingURL=mach.js.map
@@ -0,0 +1,25 @@
1
+ import type { JarMnToken, MozBuildToken } from './manifest-tokenizers.js';
2
+ /**
3
+ * Inserts a line into an array of lines in alphabetical order within a
4
+ * specified range. The comparison key is extracted from each line.
5
+ *
6
+ * @returns Object with insertIndex and previousEntry
7
+ */
8
+ export declare function findAlphabeticalPosition(lines: string[], startLine: number, endLine: number, newKey: string, extractKey: (line: string) => string | undefined): {
9
+ insertIndex: number;
10
+ previousEntry: string | undefined;
11
+ };
12
+ /**
13
+ * Find alphabetical position within a tokenized jar.mn section.
14
+ */
15
+ export declare function findAlphabeticalTokenPosition(tokens: JarMnToken[], sectionTargetPattern: RegExp, newKey: string): {
16
+ insertIndex: number;
17
+ previousEntry: string | undefined;
18
+ };
19
+ /**
20
+ * Find alphabetical position within tokenized moz.build list items.
21
+ */
22
+ export declare function findAlphabeticalMozBuildPosition(tokens: MozBuildToken[], newKey: string): {
23
+ insertIndex: number;
24
+ previousEntry: string | undefined;
25
+ };