@hominis/fireforge 0.35.0 → 0.37.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.
- package/CHANGELOG.md +42 -0
- package/README.md +34 -9
- package/dist/bin/fireforge.js +21 -6
- package/dist/src/cli.js +22 -5
- package/dist/src/commands/bootstrap-checks.js +0 -1
- package/dist/src/commands/bootstrap.d.ts +2 -1
- package/dist/src/commands/bootstrap.js +16 -7
- package/dist/src/commands/build.js +5 -4
- package/dist/src/commands/config.js +30 -10
- package/dist/src/commands/discard.js +18 -3
- package/dist/src/commands/doctor/post-rebase-audit.js +0 -1
- package/dist/src/commands/doctor-check-core.js +0 -1
- package/dist/src/commands/doctor-external-toolchains.d.ts +3 -0
- package/dist/src/commands/doctor-external-toolchains.js +54 -0
- package/dist/src/commands/doctor-furnace-jar.js +0 -1
- package/dist/src/commands/doctor-furnace-manifest-sync.js +0 -1
- package/dist/src/commands/doctor-furnace.js +2 -2
- package/dist/src/commands/doctor-orphaned-harness.d.ts +52 -0
- package/dist/src/commands/doctor-orphaned-harness.js +132 -0
- package/dist/src/commands/doctor-working-tree.js +0 -1
- package/dist/src/commands/doctor.js +6 -1
- package/dist/src/commands/download.js +28 -13
- package/dist/src/commands/export-all.js +5 -3
- package/dist/src/commands/export-flow.js +12 -7
- package/dist/src/commands/export-placement-gate.js +0 -1
- package/dist/src/commands/export-placement-policy.js +0 -1
- package/dist/src/commands/export-shared.d.ts +5 -1
- package/dist/src/commands/export-shared.js +18 -6
- package/dist/src/commands/export.js +22 -10
- package/dist/src/commands/furnace/apply.js +22 -6
- package/dist/src/commands/furnace/chrome-doc-remove.js +0 -1
- package/dist/src/commands/furnace/chrome-doc-templates.js +0 -1
- package/dist/src/commands/furnace/chrome-doc-tests.js +0 -1
- package/dist/src/commands/furnace/chrome-doc.js +0 -1
- package/dist/src/commands/furnace/create-browser-test.js +0 -1
- package/dist/src/commands/furnace/create-dry-run.js +0 -1
- package/dist/src/commands/furnace/create-features.js +0 -1
- package/dist/src/commands/furnace/create-mochikit.js +0 -1
- package/dist/src/commands/furnace/create-readback.js +0 -1
- package/dist/src/commands/furnace/create-templates.js +0 -1
- package/dist/src/commands/furnace/create-validation.js +0 -1
- package/dist/src/commands/furnace/create-xpcshell.js +0 -1
- package/dist/src/commands/furnace/create.js +0 -1
- package/dist/src/commands/furnace/deploy.js +7 -83
- package/dist/src/commands/furnace/diff.js +0 -1
- package/dist/src/commands/furnace/index.js +59 -25
- package/dist/src/commands/furnace/init.js +0 -1
- package/dist/src/commands/furnace/list.js +0 -1
- package/dist/src/commands/furnace/override.js +0 -1
- package/dist/src/commands/furnace/preview.js +3 -3
- package/dist/src/commands/furnace/refresh.js +0 -1
- package/dist/src/commands/furnace/remove-state.d.ts +15 -0
- package/dist/src/commands/furnace/remove-state.js +47 -1
- package/dist/src/commands/furnace/remove.js +3 -9
- package/dist/src/commands/furnace/rename-browser-test.js +1 -5
- package/dist/src/commands/furnace/rename-helpers.d.ts +6 -0
- package/dist/src/commands/furnace/rename-helpers.js +30 -1
- package/dist/src/commands/furnace/rename-xpcshell.js +7 -6
- package/dist/src/commands/furnace/rename.js +15 -36
- package/dist/src/commands/furnace/scan.js +0 -1
- package/dist/src/commands/furnace/status.js +0 -1
- package/dist/src/commands/furnace/sync.js +76 -4
- package/dist/src/commands/furnace/validate.js +0 -1
- package/dist/src/commands/furnace/validation-output.js +0 -1
- package/dist/src/commands/import.js +35 -9
- package/dist/src/commands/lint-per-patch.js +19 -7
- package/dist/src/commands/lint.js +13 -3
- package/dist/src/commands/manifest.js +1 -2
- package/dist/src/commands/package.js +2 -1
- package/dist/src/commands/patch/compact.js +1 -1
- package/dist/src/commands/patch/delete.js +1 -1
- package/dist/src/commands/patch/index.js +1 -1
- package/dist/src/commands/patch/lint-ignore.js +21 -6
- package/dist/src/commands/patch/move-files.js +1 -1
- package/dist/src/commands/patch/patch-context.js +0 -1
- package/dist/src/commands/patch/rename.js +4 -4
- package/dist/src/commands/patch/reorder.js +3 -4
- package/dist/src/commands/patch/split-plan.js +2 -1
- package/dist/src/commands/patch/split.js +4 -4
- package/dist/src/commands/patch/staged-dependency.d.ts +1 -1
- package/dist/src/commands/patch/staged-dependency.js +114 -52
- package/dist/src/commands/patch/tier.js +18 -5
- package/dist/src/commands/re-export-bulk-scan.js +0 -1
- package/dist/src/commands/re-export-files.js +5 -1
- package/dist/src/commands/re-export-options.js +0 -1
- package/dist/src/commands/re-export-scan.js +0 -1
- package/dist/src/commands/re-export.js +14 -4
- package/dist/src/commands/rebase/abort.js +2 -9
- package/dist/src/commands/rebase/confirm.js +0 -1
- package/dist/src/commands/rebase/conflict-summary.js +0 -1
- package/dist/src/commands/rebase/continue.js +0 -1
- package/dist/src/commands/rebase/index.d.ts +1 -1
- package/dist/src/commands/rebase/index.js +10 -15
- package/dist/src/commands/rebase/patch-loop.js +38 -7
- package/dist/src/commands/rebase/summary.js +2 -3
- package/dist/src/commands/rebase.js +0 -1
- package/dist/src/commands/register.js +1 -1
- package/dist/src/commands/reset.js +16 -9
- package/dist/src/commands/resolve.js +2 -2
- package/dist/src/commands/run.js +4 -4
- package/dist/src/commands/setup-support.js +0 -1
- package/dist/src/commands/setup.js +1 -2
- package/dist/src/commands/source.js +1 -2
- package/dist/src/commands/status-output.js +1 -12
- package/dist/src/commands/status.js +147 -133
- package/dist/src/commands/test-appdir.js +0 -1
- package/dist/src/commands/test-diagnose.js +38 -3
- package/dist/src/commands/test-modes.d.ts +15 -0
- package/dist/src/commands/test-modes.js +61 -0
- package/dist/src/commands/test-register.d.ts +4 -0
- package/dist/src/commands/test-register.js +64 -0
- package/dist/src/commands/test-run.d.ts +23 -7
- package/dist/src/commands/test-run.js +15 -14
- package/dist/src/commands/test.d.ts +0 -4
- package/dist/src/commands/test.js +147 -96
- package/dist/src/commands/token-coverage.js +0 -1
- package/dist/src/commands/token.js +1 -2
- package/dist/src/commands/typecheck.js +1 -1
- package/dist/src/commands/verify.js +3 -9
- package/dist/src/commands/watch.js +5 -1
- package/dist/src/commands/wire.js +1 -1
- package/dist/src/core/ast-utils.js +0 -1
- package/dist/src/core/brand-validation.js +0 -1
- package/dist/src/core/branding.js +0 -1
- package/dist/src/core/browser-wire.js +0 -1
- package/dist/src/core/build-audit-platform.js +0 -1
- package/dist/src/core/build-audit-registration.js +0 -1
- package/dist/src/core/build-audit-resolve.js +0 -1
- package/dist/src/core/build-audit-transforms.js +0 -1
- package/dist/src/core/build-audit.js +0 -1
- package/dist/src/core/build-baseline-types.d.ts +24 -0
- package/dist/src/core/build-baseline-types.js +0 -1
- package/dist/src/core/build-baseline.d.ts +5 -2
- package/dist/src/core/build-baseline.js +5 -2
- package/dist/src/core/build-prepare.js +2 -2
- package/dist/src/core/config-mutate.js +0 -1
- package/dist/src/core/config-paths.d.ts +2 -2
- package/dist/src/core/config-paths.js +6 -1
- package/dist/src/core/config-state.js +0 -1
- package/dist/src/core/config-validate-patch-policy.js +0 -1
- package/dist/src/core/config-validate-test-toolchains.d.ts +8 -0
- package/dist/src/core/config-validate-test-toolchains.js +105 -0
- package/dist/src/core/config-validate.js +3 -1
- package/dist/src/core/config.js +0 -1
- package/dist/src/core/destructive.js +0 -1
- package/dist/src/core/diff-hunks.js +13 -7
- package/dist/src/core/engine-changes.js +0 -1
- package/dist/src/core/engine-session-lock.d.ts +12 -0
- package/dist/src/core/engine-session-lock.js +45 -0
- package/dist/src/core/file-lock.d.ts +8 -0
- package/dist/src/core/file-lock.js +157 -48
- package/dist/src/core/firefox-archive.d.ts +4 -0
- package/dist/src/core/firefox-archive.js +6 -1
- package/dist/src/core/firefox-cache.js +60 -4
- package/dist/src/core/firefox-download.js +0 -1
- package/dist/src/core/firefox-extract.js +75 -16
- package/dist/src/core/firefox-ignorefile.js +0 -1
- package/dist/src/core/firefox.d.ts +12 -0
- package/dist/src/core/firefox.js +64 -2
- package/dist/src/core/furnace-apply-dry-run.js +0 -1
- package/dist/src/core/furnace-apply-ftl.d.ts +7 -3
- package/dist/src/core/furnace-apply-ftl.js +10 -5
- package/dist/src/core/furnace-apply-helpers.js +0 -1
- package/dist/src/core/furnace-apply-output.js +2 -2
- package/dist/src/core/furnace-apply.d.ts +7 -1
- package/dist/src/core/furnace-apply.js +47 -13
- package/dist/src/core/furnace-checksum-utils.js +0 -1
- package/dist/src/core/furnace-config-array-utils.js +0 -1
- package/dist/src/core/furnace-config-custom.js +10 -1
- package/dist/src/core/furnace-config-order.js +0 -1
- package/dist/src/core/furnace-config-tokens.js +0 -1
- package/dist/src/core/furnace-config-validate.js +0 -1
- package/dist/src/core/furnace-config.d.ts +11 -0
- package/dist/src/core/furnace-config.js +37 -1
- package/dist/src/core/furnace-constants.js +0 -1
- package/dist/src/core/furnace-css-fragments.js +0 -1
- package/dist/src/core/furnace-graph-utils.js +0 -1
- package/dist/src/core/furnace-jsconfig.d.ts +2 -3
- package/dist/src/core/furnace-jsconfig.js +25 -18
- package/dist/src/core/furnace-marker.js +0 -1
- package/dist/src/core/furnace-operation.js +0 -1
- package/dist/src/core/furnace-refresh.js +0 -1
- package/dist/src/core/furnace-registration-ast.d.ts +14 -0
- package/dist/src/core/furnace-registration-ast.js +1 -2
- package/dist/src/core/furnace-registration-remove.js +0 -1
- package/dist/src/core/furnace-registration-validate.js +1 -5
- package/dist/src/core/furnace-registration.js +0 -1
- package/dist/src/core/furnace-rollback.js +0 -1
- package/dist/src/core/furnace-scanner.js +0 -1
- package/dist/src/core/furnace-stale-export.d.ts +59 -0
- package/dist/src/core/furnace-stale-export.js +123 -0
- package/dist/src/core/furnace-staleness.js +0 -1
- package/dist/src/core/furnace-state-persist.d.ts +72 -0
- package/dist/src/core/furnace-state-persist.js +118 -0
- package/dist/src/core/furnace-step-errors.d.ts +23 -0
- package/dist/src/core/furnace-step-errors.js +25 -0
- package/dist/src/core/furnace-stories.js +0 -1
- package/dist/src/core/furnace-validate-accessibility.js +0 -1
- package/dist/src/core/furnace-validate-checks.js +0 -1
- package/dist/src/core/furnace-validate-compatibility.js +9 -3
- package/dist/src/core/furnace-validate-helpers.js +0 -1
- package/dist/src/core/furnace-validate-registration.js +7 -7
- package/dist/src/core/furnace-validate-structure.d.ts +8 -0
- package/dist/src/core/furnace-validate-structure.js +14 -4
- package/dist/src/core/furnace-validate.js +0 -1
- package/dist/src/core/furnace-version-drift.d.ts +6 -3
- package/dist/src/core/furnace-version-drift.js +6 -4
- package/dist/src/core/git-base.js +0 -1
- package/dist/src/core/git-diff.js +0 -1
- package/dist/src/core/git-file-ops.js +0 -1
- package/dist/src/core/git-status.d.ts +13 -0
- package/dist/src/core/git-status.js +32 -2
- package/dist/src/core/git.d.ts +10 -1
- package/dist/src/core/git.js +63 -6
- package/dist/src/core/license-headers.js +0 -1
- package/dist/src/core/lint-cache.js +0 -1
- package/dist/src/core/lint-projection.js +0 -1
- package/dist/src/core/mach-build-artifacts.js +0 -1
- package/dist/src/core/mach-error-hints.js +0 -1
- package/dist/src/core/mach-known-noise-filter.d.ts +60 -0
- package/dist/src/core/mach-known-noise-filter.js +193 -0
- package/dist/src/core/mach-mozconfig.js +0 -1
- package/dist/src/core/mach-python.js +0 -1
- package/dist/src/core/mach-resource-shim.js +0 -1
- package/dist/src/core/mach.d.ts +8 -0
- package/dist/src/core/mach.js +36 -4
- package/dist/src/core/manifest-helpers.js +0 -1
- package/dist/src/core/manifest-register.js +0 -1
- package/dist/src/core/manifest-rules.js +0 -1
- package/dist/src/core/manifest-tokenizers.js +0 -1
- package/dist/src/core/marionette-port.d.ts +8 -0
- package/dist/src/core/marionette-port.js +34 -3
- package/dist/src/core/marionette-preflight.js +0 -1
- package/dist/src/core/markdown-table.js +0 -1
- package/dist/src/core/ownership-table.js +2 -9
- package/dist/src/core/parser-fallback.js +0 -1
- package/dist/src/core/patch-apply-fuzz.d.ts +27 -9
- package/dist/src/core/patch-apply-fuzz.js +71 -34
- package/dist/src/core/patch-apply.d.ts +30 -0
- package/dist/src/core/patch-apply.js +101 -18
- package/dist/src/core/patch-artifact-normalize.d.ts +18 -5
- package/dist/src/core/patch-artifact-normalize.js +19 -15
- package/dist/src/core/patch-export-coverage.js +0 -1
- package/dist/src/core/patch-export-metadata.js +0 -1
- package/dist/src/core/patch-export-update.js +2 -3
- package/dist/src/core/patch-export.d.ts +2 -6
- package/dist/src/core/patch-export.js +24 -48
- package/dist/src/core/patch-files.js +0 -1
- package/dist/src/core/patch-identifier-suggest.js +0 -1
- package/dist/src/core/patch-lint-checkjs.js +0 -1
- package/dist/src/core/patch-lint-chrome-jsdoc.js +0 -1
- package/dist/src/core/patch-lint-cross.js +80 -3
- package/dist/src/core/patch-lint-css.js +0 -1
- package/dist/src/core/patch-lint-diff-tag.js +0 -1
- package/dist/src/core/patch-lint-diff.d.ts +2 -1
- package/dist/src/core/patch-lint-diff.js +17 -32
- package/dist/src/core/patch-lint-imports.js +0 -1
- package/dist/src/core/patch-lint-jsdoc.js +0 -1
- package/dist/src/core/patch-lint-observer.js +0 -1
- package/dist/src/core/patch-lint-ownership.js +0 -1
- package/dist/src/core/patch-lint-reexports.js +0 -1
- package/dist/src/core/patch-lint.d.ts +37 -2
- package/dist/src/core/patch-lint.js +47 -34
- package/dist/src/core/patch-lock.js +0 -1
- package/dist/src/core/patch-manifest-consistency.js +9 -1
- package/dist/src/core/patch-manifest-io.d.ts +19 -2
- package/dist/src/core/patch-manifest-io.js +57 -21
- package/dist/src/core/patch-manifest-query.js +18 -10
- package/dist/src/core/patch-manifest-resolve.js +0 -1
- package/dist/src/core/patch-manifest-validate.js +24 -1
- package/dist/src/core/patch-manifest.d.ts +1 -1
- package/dist/src/core/patch-manifest.js +1 -2
- package/dist/src/core/patch-parse.d.ts +59 -0
- package/dist/src/core/patch-parse.js +209 -92
- package/dist/src/core/patch-policy.js +0 -1
- package/dist/src/core/patch-registration-refs.js +16 -26
- package/dist/src/core/patch-source-metadata.js +0 -1
- package/dist/src/core/patch-transform.d.ts +4 -0
- package/dist/src/core/patch-transform.js +30 -38
- package/dist/src/core/rebase-session.js +0 -1
- package/dist/src/core/register-browser-content.js +0 -1
- package/dist/src/core/register-module.js +0 -1
- package/dist/src/core/register-result.js +0 -1
- package/dist/src/core/register-scaffold.js +0 -1
- package/dist/src/core/register-shared-css.js +0 -1
- package/dist/src/core/register-test-manifest.js +0 -1
- package/dist/src/core/register-xpcshell-test.js +0 -1
- package/dist/src/core/shared-ftl.js +0 -1
- package/dist/src/core/signal-critical.js +0 -1
- package/dist/src/core/smoke-patterns.js +0 -1
- package/dist/src/core/state-file.js +0 -1
- package/dist/src/core/status-classify.d.ts +16 -0
- package/dist/src/core/status-classify.js +24 -16
- package/dist/src/core/test-harness-crash.d.ts +80 -7
- package/dist/src/core/test-harness-crash.js +251 -15
- package/dist/src/core/test-harness-output.js +0 -1
- package/dist/src/core/test-path-scope.d.ts +21 -13
- package/dist/src/core/test-path-scope.js +43 -28
- package/dist/src/core/test-stale-check.d.ts +29 -1
- package/dist/src/core/test-stale-check.js +59 -1
- package/dist/src/core/test-stale-symlink.js +0 -1
- package/dist/src/core/test-xpcshell-retry.js +0 -1
- package/dist/src/core/token-coverage.js +0 -1
- package/dist/src/core/token-dark-mode.js +0 -1
- package/dist/src/core/token-docs.js +0 -1
- package/dist/src/core/token-manager.js +0 -1
- package/dist/src/core/token-scaffold.js +0 -1
- package/dist/src/core/token-variant.js +0 -1
- package/dist/src/core/toolchain-preflight.d.ts +31 -10
- package/dist/src/core/toolchain-preflight.js +97 -36
- package/dist/src/core/typecheck-shim.js +13 -1
- package/dist/src/core/typecheck.js +0 -1
- package/dist/src/core/wire-destroy.js +0 -1
- package/dist/src/core/wire-dom-fragment.js +0 -1
- package/dist/src/core/wire-init.js +0 -1
- package/dist/src/core/wire-subscript.js +0 -1
- package/dist/src/core/wire-targets.js +0 -1
- package/dist/src/core/wire-utils.js +0 -1
- package/dist/src/core/xpcshell-appdir.js +1 -4
- package/dist/src/errors/base.d.ts +29 -0
- package/dist/src/errors/base.js +35 -1
- package/dist/src/errors/build.js +0 -1
- package/dist/src/errors/codes.d.ts +6 -0
- package/dist/src/errors/codes.js +6 -1
- package/dist/src/errors/config.js +0 -1
- package/dist/src/errors/download.js +0 -1
- package/dist/src/errors/furnace.d.ts +11 -1
- package/dist/src/errors/furnace.js +6 -5
- package/dist/src/errors/git.js +0 -1
- package/dist/src/errors/patch.d.ts +17 -0
- package/dist/src/errors/patch.js +29 -1
- package/dist/src/errors/rebase.js +0 -1
- package/dist/src/errors/run.js +1 -1
- package/dist/src/index.js +0 -1
- package/dist/src/types/cli.js +0 -1
- package/dist/src/types/commands/index.d.ts +1 -1
- package/dist/src/types/commands/index.js +0 -1
- package/dist/src/types/commands/options.d.ts +40 -9
- package/dist/src/types/commands/options.js +0 -1
- package/dist/src/types/commands/patches.d.ts +37 -0
- package/dist/src/types/commands/patches.js +0 -1
- package/dist/src/types/commands/project.d.ts +11 -2
- package/dist/src/types/commands/project.js +0 -1
- package/dist/src/types/config.d.ts +32 -0
- package/dist/src/types/config.js +0 -1
- package/dist/src/types/furnace.d.ts +23 -0
- package/dist/src/types/furnace.js +0 -1
- package/dist/src/types/index.js +0 -1
- package/dist/src/types/typecheck.js +0 -1
- package/dist/src/utils/elapsed.js +0 -1
- package/dist/src/utils/errors.js +0 -1
- package/dist/src/utils/fs.js +37 -5
- package/dist/src/utils/logger.d.ts +7 -0
- package/dist/src/utils/logger.js +85 -3
- package/dist/src/utils/options.d.ts +15 -0
- package/dist/src/utils/options.js +25 -1
- package/dist/src/utils/package-root.js +11 -4
- package/dist/src/utils/parse.js +0 -1
- package/dist/src/utils/paths.js +0 -1
- package/dist/src/utils/platform.js +0 -1
- package/dist/src/utils/process-group.d.ts +33 -0
- package/dist/src/utils/process-group.js +161 -0
- package/dist/src/utils/process.d.ts +48 -4
- package/dist/src/utils/process.js +258 -59
- package/dist/src/utils/regex.d.ts +13 -3
- package/dist/src/utils/regex.js +53 -4
- package/dist/src/utils/validation.d.ts +0 -12
- package/dist/src/utils/validation.js +13 -26
- package/package.json +9 -8
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Pure parsing functions for extracting information from patch files.
|
|
4
4
|
* All functions are synchronous and operate on string content.
|
|
5
|
+
*
|
|
6
|
+
* This module is the ONE unified-diff walker in the codebase. Before
|
|
7
|
+
* {@link parseDiffSections} existed, six hand-rolled `diff --git` walkers
|
|
8
|
+
* lived across patch-parse, patch-lint-diff, patch-registration-refs, and
|
|
9
|
+
* patch-transform — with divergent CRLF handling (a CRLF-saved patch file
|
|
10
|
+
* silently failed target-file matching and `\ No newline` detection on
|
|
11
|
+
* Windows), no quoted-path support, and greedy path captures that
|
|
12
|
+
* mis-split any path containing ` b/`. New diff-shaped parsing must build
|
|
13
|
+
* on {@link parseDiffSections} rather than re-walking lines.
|
|
5
14
|
*/
|
|
6
15
|
/**
|
|
7
16
|
* Extracts the order number from a patch filename.
|
|
@@ -17,87 +26,155 @@ export function extractOrder(filename) {
|
|
|
17
26
|
return Infinity;
|
|
18
27
|
}
|
|
19
28
|
/**
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
29
|
+
* Un-escapes a path from git's C-style quoted form (`"a/pfad m\303\244..."`).
|
|
30
|
+
* Handles the escapes git emits: `\\`, `\"`, `\t`, `\n`, `\r` and three-digit
|
|
31
|
+
* octal byte escapes. Octal bytes are decoded through a byte buffer so
|
|
32
|
+
* multibyte UTF-8 sequences (git's default `core.quotePath=true` encodes any
|
|
33
|
+
* non-ASCII path this way) come back as the real characters.
|
|
25
34
|
*/
|
|
26
|
-
|
|
27
|
-
const
|
|
28
|
-
let
|
|
29
|
-
|
|
30
|
-
if (
|
|
31
|
-
|
|
32
|
-
|
|
35
|
+
function unquoteGitPath(quoted) {
|
|
36
|
+
const bytes = [];
|
|
37
|
+
for (let i = 0; i < quoted.length; i++) {
|
|
38
|
+
const ch = quoted[i];
|
|
39
|
+
if (ch !== '\\') {
|
|
40
|
+
// Plain character — may itself be multi-byte when the diff already
|
|
41
|
+
// contains raw UTF-8; push its bytes.
|
|
42
|
+
const encoded = Buffer.from(quoted[i] ?? '', 'utf-8');
|
|
43
|
+
for (const b of encoded)
|
|
44
|
+
bytes.push(b);
|
|
33
45
|
continue;
|
|
34
46
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
// Found hunk header — stop scanning metadata for this file section
|
|
38
|
-
if (line.startsWith('@@'))
|
|
47
|
+
const next = quoted[i + 1];
|
|
48
|
+
if (next === undefined)
|
|
39
49
|
break;
|
|
40
|
-
if (
|
|
41
|
-
|
|
50
|
+
if (next >= '0' && next <= '7') {
|
|
51
|
+
const octal = quoted.slice(i + 1, i + 4);
|
|
52
|
+
bytes.push(parseInt(octal, 8));
|
|
53
|
+
i += 3;
|
|
54
|
+
continue;
|
|
42
55
|
}
|
|
56
|
+
const mapped = next === 'n' ? 0x0a : next === 't' ? 0x09 : next === 'r' ? 0x0d : next.charCodeAt(0);
|
|
57
|
+
bytes.push(mapped);
|
|
58
|
+
i += 1;
|
|
43
59
|
}
|
|
44
|
-
return
|
|
60
|
+
return Buffer.from(bytes).toString('utf-8');
|
|
45
61
|
}
|
|
46
62
|
/**
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
63
|
+
* Parses a `diff --git` line into its two paths.
|
|
64
|
+
*
|
|
65
|
+
* Handles the quoted form git emits for paths with special characters
|
|
66
|
+
* (`diff --git "a/x y" "b/x y"`), and disambiguates the unquoted form for
|
|
67
|
+
* paths that themselves contain ` b/`: for the overwhelmingly common
|
|
68
|
+
* non-rename case the two paths are identical, so a symmetric split
|
|
69
|
+
* (`a/<p> b/<p>`) is tried first — the previous greedy regex
|
|
70
|
+
* (`a\/.+ b\/(.+)$`) split such lines at the LAST ` b/` and returned a
|
|
71
|
+
* truncated path. Falls back to a non-greedy split for renames.
|
|
72
|
+
*
|
|
73
|
+
* @returns null when the line is not a diff --git header.
|
|
50
74
|
*/
|
|
51
|
-
export function
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
75
|
+
export function parseDiffGitHeader(line) {
|
|
76
|
+
const stripped = line.endsWith('\r') ? line.slice(0, -1) : line;
|
|
77
|
+
if (!stripped.startsWith('diff --git '))
|
|
78
|
+
return null;
|
|
79
|
+
const body = stripped.slice('diff --git '.length);
|
|
80
|
+
// Quoted form (either or both sides may be quoted).
|
|
81
|
+
const quoted = /^(?:"a\/((?:[^"\\]|\\.)*)"|a\/(\S+)) (?:"b\/((?:[^"\\]|\\.)*)"|b\/(.+))$/.exec(body);
|
|
82
|
+
if (quoted && (quoted[1] !== undefined || quoted[3] !== undefined)) {
|
|
83
|
+
const sourcePath = quoted[1] !== undefined ? unquoteGitPath(quoted[1]) : (quoted[2] ?? '');
|
|
84
|
+
const targetPath = quoted[3] !== undefined ? unquoteGitPath(quoted[3]) : (quoted[4] ?? '');
|
|
85
|
+
return { sourcePath, targetPath };
|
|
86
|
+
}
|
|
87
|
+
if (!body.startsWith('a/'))
|
|
88
|
+
return null;
|
|
89
|
+
const rest = body.slice(2);
|
|
90
|
+
// Symmetric split: body === `a/<p> b/<p>`. Correct even when <p>
|
|
91
|
+
// contains ` b/`, which defeats any single-regex approach.
|
|
92
|
+
if ((rest.length - 3) % 2 === 0) {
|
|
93
|
+
const pathLength = (rest.length - 3) / 2;
|
|
94
|
+
const candidate = rest.slice(0, pathLength);
|
|
95
|
+
if (rest === `${candidate} b/${candidate}`) {
|
|
96
|
+
return { sourcePath: candidate, targetPath: candidate };
|
|
65
97
|
}
|
|
66
98
|
}
|
|
67
|
-
|
|
99
|
+
// Rename/copy (differing paths): non-greedy split at the first ` b/`.
|
|
100
|
+
const asymmetric = /^(.+?) b\/(.+)$/.exec(rest);
|
|
101
|
+
if (asymmetric?.[1] !== undefined && asymmetric[2] !== undefined) {
|
|
102
|
+
return { sourcePath: asymmetric[1], targetPath: asymmetric[2] };
|
|
103
|
+
}
|
|
104
|
+
return null;
|
|
68
105
|
}
|
|
69
106
|
/**
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
107
|
+
* Splits raw diff content into lines, tolerating CRLF-saved patch files.
|
|
108
|
+
*
|
|
109
|
+
* The distinction matters: a patch file saved with CRLF endings (Windows
|
|
110
|
+
* editor, `core.autocrlf` checkout) has `\r` on EVERY line including
|
|
111
|
+
* structural ones — strip it, or headers, `@@` lines and the
|
|
112
|
+
* `` marker all fail to match. But an LF patch
|
|
113
|
+
* of a file whose CONTENT is CRLF has `\r` only on payload lines, where it
|
|
114
|
+
* is significant and must be preserved. Detect the former by checking the
|
|
115
|
+
* structural lines themselves for a trailing `\r`.
|
|
74
116
|
*/
|
|
75
|
-
|
|
76
|
-
const
|
|
77
|
-
const
|
|
78
|
-
|
|
117
|
+
function splitDiffLines(diffContent) {
|
|
118
|
+
const lines = diffContent.split('\n');
|
|
119
|
+
const isCrlfPatchFile = lines.some((line) => (line.startsWith('diff --git') || line.startsWith('@@ ')) &&
|
|
120
|
+
line.endsWith('\r') &&
|
|
121
|
+
line.length > 1);
|
|
122
|
+
if (!isCrlfPatchFile)
|
|
123
|
+
return lines;
|
|
124
|
+
return lines.map((line) => (line.endsWith('\r') ? line.slice(0, -1) : line));
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Parses a unified diff into structured per-file sections — the single
|
|
128
|
+
* shared walker every diff consumer builds on.
|
|
129
|
+
*/
|
|
130
|
+
export function parseDiffSections(diffContent) {
|
|
131
|
+
const sections = [];
|
|
132
|
+
const lines = splitDiffLines(diffContent);
|
|
133
|
+
let current = null;
|
|
79
134
|
let currentHunk = null;
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
135
|
+
const finishHunk = () => {
|
|
136
|
+
if (current && currentHunk) {
|
|
137
|
+
current.hunks.push(currentHunk);
|
|
138
|
+
}
|
|
139
|
+
currentHunk = null;
|
|
140
|
+
};
|
|
141
|
+
for (const line of lines) {
|
|
142
|
+
const header = parseDiffGitHeader(line);
|
|
143
|
+
if (header) {
|
|
144
|
+
finishHunk();
|
|
145
|
+
current = {
|
|
146
|
+
targetPath: header.targetPath,
|
|
147
|
+
sourcePath: header.sourcePath,
|
|
148
|
+
isNewFile: false,
|
|
149
|
+
isDeletedFile: false,
|
|
150
|
+
isBinary: false,
|
|
151
|
+
hunks: [],
|
|
152
|
+
};
|
|
153
|
+
sections.push(current);
|
|
91
154
|
continue;
|
|
92
155
|
}
|
|
93
|
-
if (!
|
|
156
|
+
if (!current)
|
|
157
|
+
continue;
|
|
158
|
+
if (currentHunk === null) {
|
|
159
|
+
// File metadata zone (between the header and the first hunk).
|
|
160
|
+
if (line.startsWith('new file mode')) {
|
|
161
|
+
current.isNewFile = true;
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
if (line.startsWith('deleted file mode')) {
|
|
165
|
+
current.isDeletedFile = true;
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
if (line === 'GIT binary patch' || /^Binary files .* differ$/.test(line)) {
|
|
169
|
+
current.isBinary = true;
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (current.isBinary)
|
|
94
174
|
continue;
|
|
95
|
-
// Check for hunk header
|
|
96
175
|
const hunkMatch = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/.exec(line);
|
|
97
176
|
if (hunkMatch) {
|
|
98
|
-
|
|
99
|
-
hunks.push(currentHunk);
|
|
100
|
-
}
|
|
177
|
+
finishHunk();
|
|
101
178
|
currentHunk = {
|
|
102
179
|
oldStart: parseInt(hunkMatch[1] ?? '0', 10),
|
|
103
180
|
oldCount: parseInt(hunkMatch[2] ?? '1', 10),
|
|
@@ -109,41 +186,82 @@ export function parseHunksForFile(patchContent, targetFile) {
|
|
|
109
186
|
};
|
|
110
187
|
continue;
|
|
111
188
|
}
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
126
|
-
else if (previous.startsWith(' ')) {
|
|
127
|
-
// Context line: present in both sides, so the trailing-newline
|
|
128
|
-
// absence applies to both. This is rare (it only happens when
|
|
129
|
-
// the hunk ends on an unchanged line that itself is the last
|
|
130
|
-
// line of the file) but real — git emits it.
|
|
131
|
-
currentHunk.noNewlineAtEndOld = true;
|
|
132
|
-
currentHunk.noNewlineAtEndNew = true;
|
|
133
|
-
}
|
|
134
|
-
// If the marker appears with no preceding body line (malformed
|
|
135
|
-
// diff), leave both flags false — the downstream apply logic
|
|
136
|
-
// will still produce a defined result.
|
|
189
|
+
if (!currentHunk)
|
|
190
|
+
continue;
|
|
191
|
+
if (line === '\') {
|
|
192
|
+
// The marker is an annotation on the immediately preceding body
|
|
193
|
+
// line. Peek the last collected line to decide which side(s) the
|
|
194
|
+
// annotation applies to — a single boolean cannot represent the
|
|
195
|
+
// asymmetric case where only one side lacks the trailing newline.
|
|
196
|
+
const previous = currentHunk.lines[currentHunk.lines.length - 1] ?? '';
|
|
197
|
+
if (previous.startsWith('-')) {
|
|
198
|
+
currentHunk.noNewlineAtEndOld = true;
|
|
199
|
+
}
|
|
200
|
+
else if (previous.startsWith('+')) {
|
|
201
|
+
currentHunk.noNewlineAtEndNew = true;
|
|
137
202
|
}
|
|
138
|
-
else if (
|
|
139
|
-
|
|
203
|
+
else if (previous.startsWith(' ')) {
|
|
204
|
+
// Context line: present in both sides, so the trailing-newline
|
|
205
|
+
// absence applies to both. This is rare (it only happens when
|
|
206
|
+
// the hunk ends on an unchanged line that itself is the last
|
|
207
|
+
// line of the file) but real — git emits it.
|
|
208
|
+
currentHunk.noNewlineAtEndOld = true;
|
|
209
|
+
currentHunk.noNewlineAtEndNew = true;
|
|
140
210
|
}
|
|
211
|
+
// If the marker appears with no preceding body line (malformed
|
|
212
|
+
// diff), leave both flags false — the downstream apply logic
|
|
213
|
+
// will still produce a defined result.
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
if (line.startsWith('+') || line.startsWith('-') || line.startsWith(' ')) {
|
|
217
|
+
currentHunk.lines.push(line);
|
|
141
218
|
}
|
|
142
219
|
}
|
|
143
|
-
|
|
144
|
-
|
|
220
|
+
finishHunk();
|
|
221
|
+
return sections;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Checks whether a specific file is a new-file addition within a patch.
|
|
225
|
+
* For multi-file patches, only inspects the section belonging to targetFile.
|
|
226
|
+
* @param patchContent - The full patch content
|
|
227
|
+
* @param targetFile - The file path to check
|
|
228
|
+
* @returns true if the patch creates targetFile as a new file
|
|
229
|
+
*/
|
|
230
|
+
export function isNewFileInPatch(patchContent, targetFile) {
|
|
231
|
+
return parseDiffSections(patchContent).some((section) => section.targetPath === targetFile && section.isNewFile);
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Extracts affected file paths from a diff/patch content.
|
|
235
|
+
* @param diffContent - The diff content to parse
|
|
236
|
+
* @returns Array of file paths
|
|
237
|
+
*/
|
|
238
|
+
export function extractAffectedFiles(diffContent) {
|
|
239
|
+
const files = new Set();
|
|
240
|
+
for (const section of parseDiffSections(diffContent)) {
|
|
241
|
+
files.add(section.targetPath);
|
|
242
|
+
}
|
|
243
|
+
if (files.size === 0) {
|
|
244
|
+
// Header-less unified diff (no `diff --git` lines, e.g. hand-written
|
|
245
|
+
// or `diff -u` output): fall back to the `+++ b/<path>` markers.
|
|
246
|
+
for (const line of splitDiffLines(diffContent)) {
|
|
247
|
+
const addMatch = /^\+\+\+ b\/(.+)$/.exec(line);
|
|
248
|
+
if (addMatch?.[1] && addMatch[1] !== '/dev/null') {
|
|
249
|
+
files.add(addMatch[1]);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
145
252
|
}
|
|
146
|
-
return
|
|
253
|
+
return Array.from(files).sort();
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Parses hunks from a patch file for a specific target file.
|
|
257
|
+
* @param patchContent - The full patch content
|
|
258
|
+
* @param targetFile - The file path to extract hunks for
|
|
259
|
+
* @returns Array of hunk objects with line info and changes
|
|
260
|
+
*/
|
|
261
|
+
export function parseHunksForFile(patchContent, targetFile) {
|
|
262
|
+
return parseDiffSections(patchContent)
|
|
263
|
+
.filter((section) => section.targetPath === targetFile)
|
|
264
|
+
.flatMap((section) => section.hunks);
|
|
147
265
|
}
|
|
148
266
|
/**
|
|
149
267
|
* Extracts conflicting file paths from git apply error message.
|
|
@@ -162,4 +280,3 @@ export function extractConflictingFiles(error) {
|
|
|
162
280
|
}
|
|
163
281
|
return files;
|
|
164
282
|
}
|
|
165
|
-
//# sourceMappingURL=patch-parse.js.map
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* references (widget tag names, locale fluent names). Unrelated jar.mn
|
|
15
15
|
* or customElements.js edits pass through without spurious warnings.
|
|
16
16
|
*/
|
|
17
|
+
import { parseDiffSections } from './patch-parse.js';
|
|
17
18
|
/** Canonical file paths that registration-shaped diffs touch. */
|
|
18
19
|
const REGISTRATION_FILE_PATHS = new Set([
|
|
19
20
|
'toolkit/content/customElements.js',
|
|
@@ -36,32 +37,22 @@ export function collectPatchRegistrationReferences(patchBody) {
|
|
|
36
37
|
if (!patchBody)
|
|
37
38
|
return [];
|
|
38
39
|
const refs = [];
|
|
39
|
-
|
|
40
|
-
//
|
|
41
|
-
//
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
// ignored for the purposes of tracking the current file.
|
|
45
|
-
const lines = patchBody.split(/\r?\n/);
|
|
46
|
-
for (const line of lines) {
|
|
47
|
-
const diffHeader = /^diff --git a\/(.+?) b\/(.+)$/.exec(line);
|
|
48
|
-
if (diffHeader?.[2]) {
|
|
49
|
-
currentFile = diffHeader[2];
|
|
40
|
+
// Key the file state off the `b/` path because that names the target
|
|
41
|
+
// side and is stable against renames. Only real hunk adds count —
|
|
42
|
+
// parseDiffSections has already filtered out header/metadata lines.
|
|
43
|
+
for (const section of parseDiffSections(patchBody)) {
|
|
44
|
+
if (!REGISTRATION_FILE_PATHS.has(section.targetPath))
|
|
50
45
|
continue;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const added = line.slice(1);
|
|
62
|
-
const extracted = extractTargetPathsFromRegistrationLine(currentFile, added);
|
|
63
|
-
for (const target of extracted) {
|
|
64
|
-
refs.push({ targetPath: target, source: currentFile, lineText: added });
|
|
46
|
+
for (const hunk of section.hunks) {
|
|
47
|
+
for (const line of hunk.lines) {
|
|
48
|
+
if (!line.startsWith('+'))
|
|
49
|
+
continue;
|
|
50
|
+
const added = line.slice(1);
|
|
51
|
+
const extracted = extractTargetPathsFromRegistrationLine(section.targetPath, added);
|
|
52
|
+
for (const target of extracted) {
|
|
53
|
+
refs.push({ targetPath: target, source: section.targetPath, lineText: added });
|
|
54
|
+
}
|
|
55
|
+
}
|
|
65
56
|
}
|
|
66
57
|
}
|
|
67
58
|
return refs;
|
|
@@ -114,4 +105,3 @@ function extractTargetPathsFromRegistrationLine(sourceFile, added) {
|
|
|
114
105
|
}
|
|
115
106
|
return [];
|
|
116
107
|
}
|
|
117
|
-
//# sourceMappingURL=patch-registration-refs.js.map
|
|
@@ -12,6 +12,10 @@
|
|
|
12
12
|
* @param diff - Raw unified-diff content
|
|
13
13
|
* @param targetFile - Optional target file to scope extraction to
|
|
14
14
|
* @returns The file content that the patch would create
|
|
15
|
+
* @throws PatchError for binary sections — a `GIT binary patch` payload is
|
|
16
|
+
* base85 (whose alphabet includes `+`), so "extract the + lines" would
|
|
17
|
+
* silently write garbage text over a binary target. Callers must treat
|
|
18
|
+
* binary new-file conflicts as unresolvable rather than auto-resolving.
|
|
15
19
|
*/
|
|
16
20
|
export declare function extractNewFileContentFromDiff(diff: string, targetFile?: string): string;
|
|
17
21
|
/**
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { PatchError } from '../errors/patch.js';
|
|
7
7
|
import { readText } from '../utils/fs.js';
|
|
8
|
-
import { isNewFileInPatch, parseHunksForFile } from './patch-parse.js';
|
|
8
|
+
import { isNewFileInPatch, parseDiffSections, parseHunksForFile } from './patch-parse.js';
|
|
9
9
|
/**
|
|
10
10
|
* Extracts the complete file content from a "new file" patch given a raw
|
|
11
11
|
* diff string already in memory. Callers with a patch file path should
|
|
@@ -16,48 +16,37 @@ import { isNewFileInPatch, parseHunksForFile } from './patch-parse.js';
|
|
|
16
16
|
* @param diff - Raw unified-diff content
|
|
17
17
|
* @param targetFile - Optional target file to scope extraction to
|
|
18
18
|
* @returns The file content that the patch would create
|
|
19
|
+
* @throws PatchError for binary sections — a `GIT binary patch` payload is
|
|
20
|
+
* base85 (whose alphabet includes `+`), so "extract the + lines" would
|
|
21
|
+
* silently write garbage text over a binary target. Callers must treat
|
|
22
|
+
* binary new-file conflicts as unresolvable rather than auto-resolving.
|
|
19
23
|
*/
|
|
20
24
|
export function extractNewFileContentFromDiff(diff, targetFile) {
|
|
21
|
-
const
|
|
25
|
+
const sections = parseDiffSections(diff).filter((section) => !targetFile || section.targetPath === targetFile);
|
|
26
|
+
const binary = sections.find((section) => section.isBinary);
|
|
27
|
+
if (binary) {
|
|
28
|
+
throw new PatchError(`Cannot extract text content from binary patch section for ${binary.targetPath}`, binary.targetPath);
|
|
29
|
+
}
|
|
30
|
+
// An empty new file is a legitimate git diff: `new file mode` with no
|
|
31
|
+
// hunks at all. It must extract as '' — the historical line-walker
|
|
32
|
+
// returned '\n' for it, creating a one-byte file that failed checksum
|
|
33
|
+
// and drift comparisons against the truly empty file the patch creates.
|
|
34
|
+
const hunks = sections.flatMap((section) => section.hunks);
|
|
35
|
+
if (hunks.length === 0) {
|
|
36
|
+
return '';
|
|
37
|
+
}
|
|
22
38
|
const contentLines = [];
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
// Track which file section we're in
|
|
28
|
-
if (line.startsWith('diff --git')) {
|
|
29
|
-
if (targetFile) {
|
|
30
|
-
const match = /^diff --git a\/.+ b\/(.+)$/.exec(line);
|
|
31
|
-
const wasInTarget = inTargetFile;
|
|
32
|
-
inTargetFile = match?.[1] === targetFile;
|
|
33
|
-
// If we were in the target file and hit a new diff header, we're done
|
|
34
|
-
if (wasInTarget && !inTargetFile)
|
|
35
|
-
break;
|
|
36
|
-
}
|
|
37
|
-
inHunk = false;
|
|
38
|
-
continue;
|
|
39
|
-
}
|
|
40
|
-
if (!inTargetFile)
|
|
41
|
-
continue;
|
|
42
|
-
// Start of hunk
|
|
43
|
-
if (line.startsWith('@@')) {
|
|
44
|
-
inHunk = true;
|
|
45
|
-
continue;
|
|
46
|
-
}
|
|
47
|
-
if (inHunk) {
|
|
48
|
-
// Check for "No newline at end of file" marker
|
|
49
|
-
if (line === '\') {
|
|
50
|
-
hasNoNewlineMarker = true;
|
|
51
|
-
continue;
|
|
52
|
-
}
|
|
53
|
-
// Lines starting with + are added content (skip the + prefix)
|
|
39
|
+
for (const hunk of hunks) {
|
|
40
|
+
for (const line of hunk.lines) {
|
|
41
|
+
// Lines starting with + are added content (skip the + prefix).
|
|
42
|
+
// `-`/context lines shouldn't exist in new-file patches.
|
|
54
43
|
if (line.startsWith('+')) {
|
|
55
44
|
contentLines.push(line.slice(1));
|
|
56
45
|
}
|
|
57
|
-
// Lines starting with - are removed (shouldn't exist in new file patches)
|
|
58
|
-
// Context lines (no prefix) shouldn't exist in new file patches
|
|
59
46
|
}
|
|
60
47
|
}
|
|
48
|
+
const lastHunk = hunks[hunks.length - 1];
|
|
49
|
+
const hasNoNewlineMarker = lastHunk?.noNewlineAtEndNew ?? false;
|
|
61
50
|
// Join lines and handle trailing newline
|
|
62
51
|
const result = contentLines.join('\n');
|
|
63
52
|
return hasNoNewlineMarker ? result : result + '\n';
|
|
@@ -129,8 +118,12 @@ export async function applyPatchToContent(content, patchPath, targetFile) {
|
|
|
129
118
|
if (actualOldCount !== hunk.oldCount) {
|
|
130
119
|
throw new PatchError(`Patch hunk header mismatch for ${targetFile}: header says ${hunk.oldCount} old lines but body has ${actualOldCount}`, targetFile);
|
|
131
120
|
}
|
|
132
|
-
// Replace the old lines with new lines
|
|
133
|
-
|
|
121
|
+
// Replace the old lines with new lines. Unified-diff convention: for a
|
|
122
|
+
// pure-insertion hunk (`@@ -N,0 +M,k @@`), N names the line BEFORE the
|
|
123
|
+
// insertion point, so content is spliced at index N (after line N) —
|
|
124
|
+
// `N - 1` inserted one line too early, and `@@ -0,0` (insert at top of
|
|
125
|
+
// file) produced splice(-1, …), which inserts before the LAST element.
|
|
126
|
+
const startIndex = hunk.oldCount === 0 ? hunk.oldStart : hunk.oldStart - 1;
|
|
134
127
|
// Verify context lines match before applying
|
|
135
128
|
let verifyIndex = startIndex;
|
|
136
129
|
for (const hunkLine of hunk.lines) {
|
|
@@ -152,4 +145,3 @@ export async function applyPatchToContent(content, patchPath, targetFile) {
|
|
|
152
145
|
}
|
|
153
146
|
return contentLines.join('\n') + '\n';
|
|
154
147
|
}
|
|
155
|
-
//# sourceMappingURL=patch-transform.js.map
|
|
@@ -41,6 +41,22 @@ export interface ClassifiedFile extends StatusFile {
|
|
|
41
41
|
*/
|
|
42
42
|
claimedBy?: string[];
|
|
43
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* Builds the file → owning-patch-filenames multimap from manifest rows.
|
|
46
|
+
* Single source of truth for cross-patch claim detection — status
|
|
47
|
+
* classification, verify's cross-claim check, and the ownership table all
|
|
48
|
+
* consume this builder (they used to each rebuild it, one drift away from
|
|
49
|
+
* disagreeing about what "claimed" means).
|
|
50
|
+
*/
|
|
51
|
+
export declare function buildPatchClaims(manifestPatches: ReadonlyArray<{
|
|
52
|
+
filename: string;
|
|
53
|
+
filesAffected: string[];
|
|
54
|
+
}>): Map<string, string[]>;
|
|
55
|
+
/**
|
|
56
|
+
* Reduces a two-character porcelain XY status to its primary code.
|
|
57
|
+
* Single source of truth — status-output.ts renders from the same logic.
|
|
58
|
+
*/
|
|
59
|
+
export declare function getPrimaryStatusCode(status: string): string;
|
|
44
60
|
/**
|
|
45
61
|
* Classifies files into patch-backed, unmanaged, branding, furnace, or
|
|
46
62
|
* conflict buckets.
|