@animus-ui/extract 0.1.16 → 0.1.18

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 (44) hide show
  1. package/README.md +3 -1
  2. package/crates/extract-v2/animus-extract-v2.darwin-arm64.node +0 -0
  3. package/crates/extract-v2/animus-extract-v2.linux-arm64-gnu.node +0 -0
  4. package/crates/extract-v2/animus-extract-v2.linux-x64-gnu.node +0 -0
  5. package/crates/extract-v2/index.d.ts +20 -2
  6. package/dist/index.cjs +4 -1
  7. package/dist/index.mjs +2 -2
  8. package/dist/pipeline/analyze-project-args.d.ts +8 -1
  9. package/dist/pipeline/analyze-project-args.d.ts.map +1 -1
  10. package/dist/pipeline/core-options.d.ts +10 -2
  11. package/dist/pipeline/core-options.d.ts.map +1 -1
  12. package/dist/pipeline/dynamic-prop-config.d.ts +31 -4
  13. package/dist/pipeline/dynamic-prop-config.d.ts.map +1 -1
  14. package/dist/pipeline/engine-adapter.d.ts +1 -1
  15. package/dist/pipeline/engine-adapter.d.ts.map +1 -1
  16. package/dist/pipeline/index.d.ts +3 -3
  17. package/dist/pipeline/index.d.ts.map +1 -1
  18. package/dist/pipeline/manifest-diagnostics.d.ts +10 -2
  19. package/dist/pipeline/manifest-diagnostics.d.ts.map +1 -1
  20. package/dist/pipeline/manifest-schema.d.ts +7 -0
  21. package/dist/pipeline/manifest-schema.d.ts.map +1 -1
  22. package/dist/pipeline/prefix.d.ts +2 -0
  23. package/dist/pipeline/prefix.d.ts.map +1 -1
  24. package/dist/pipeline/property-registrations.d.ts +16 -0
  25. package/dist/pipeline/property-registrations.d.ts.map +1 -0
  26. package/dist/pipeline/run-analysis.d.ts.map +1 -1
  27. package/dist/pipeline/source-corpus.d.ts +11 -0
  28. package/dist/pipeline/source-corpus.d.ts.map +1 -1
  29. package/dist/pipeline/source-ingestion.d.ts +12 -0
  30. package/dist/pipeline/source-ingestion.d.ts.map +1 -1
  31. package/dist/pipeline/system-config.d.ts +12 -2
  32. package/dist/pipeline/system-config.d.ts.map +1 -1
  33. package/dist/pipeline/system-props-module.d.ts +3 -1
  34. package/dist/pipeline/system-props-module.d.ts.map +1 -1
  35. package/dist/pipeline/unit-fallback.d.ts.map +1 -1
  36. package/dist/{pipeline-DeEENy5C.mjs → pipeline-Dr-I4Xhl.mjs} +211 -19
  37. package/dist/{pipeline-x1yBZ2UP.cjs → pipeline-OKnmnyFu.cjs} +228 -18
  38. package/dist/session/extraction-session.d.ts +16 -7
  39. package/dist/session/extraction-session.d.ts.map +1 -1
  40. package/dist/session/index.d.ts +1 -1
  41. package/dist/session/index.d.ts.map +1 -1
  42. package/dist/session.cjs +70 -40
  43. package/dist/session.mjs +70 -41
  44. package/package.json +4 -4
package/dist/session.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_pipeline = require("./pipeline-x1yBZ2UP.cjs");
2
+ const require_pipeline = require("./pipeline-OKnmnyFu.cjs");
3
3
  let crypto = require("crypto");
4
4
  let fs = require("fs");
5
5
  let path = require("path");
@@ -550,6 +550,8 @@ const LEGACY_FLAT_ARTIFACTS = [
550
550
  function isDiskString(value) {
551
551
  return Object(value) !== value && Object.prototype.toString.call(value) === "[object String]";
552
552
  }
553
+ /** Rejection of an attempt whose corpus holds an aborted parse. */
554
+ var AbortedParseRejection = class extends Error {};
553
555
  function isDiskNumber(value) {
554
556
  return Object(value) !== value && Object.prototype.toString.call(value) === "[object Number]";
555
557
  }
@@ -609,9 +611,6 @@ var ExtractionSession = class {
609
611
  options;
610
612
  staticCssJson;
611
613
  system = null;
612
- /** Vocabulary witness diagnostics from the sealed system's registration
613
- * record, awaiting the shared surfacing pass. */
614
- systemVocabularyDiagnostics = [];
615
614
  /** Configured external files that could not be read. Incremental passes
616
615
  * re-collect nothing, so they replay these instead of passing strict. */
617
616
  ingestionFailureDiagnostics = [];
@@ -654,6 +653,14 @@ var ExtractionSession = class {
654
653
  onArtifactWrite = null;
655
654
  statusAttemptId = 0;
656
655
  statusAttemptOpen = false;
656
+ /** Message of the aborted-parse rejection holding publication. While set,
657
+ * the cache keeps every observed source so the repair publishes them in
658
+ * one generation; a successful publication clears it. */
659
+ heldRejection = null;
660
+ /** A system reload an aborted parse rejected. Its dependency hashes already
661
+ * advanced, so the first batch that passes the parse check publishes
662
+ * through the full pipeline, which loads the latest system. */
663
+ systemReloadOwed = false;
657
664
  /** Monotonic readiness witness: flips true on the first complete
658
665
  * publication and never regresses; every later status write carries it. */
659
666
  firstEmissionComplete = false;
@@ -669,7 +676,7 @@ var ExtractionSession = class {
669
676
  return sessionArtifactDir(this.rootDir, this.sessionId);
670
677
  }
671
678
  get verbose() {
672
- return this.options.verbose === true || process.env.ANIMUS_DEBUG === "1" || process.env.ANIMUS_DEBUG === "true";
679
+ return require_pipeline.resolveVerbosity(this.options.verbose, process.env.ANIMUS_DEBUG) !== "quiet";
673
680
  }
674
681
  log(msg) {
675
682
  if (this.verbose) console.error(`[animus] ${msg}`);
@@ -716,8 +723,8 @@ var ExtractionSession = class {
716
723
  }
717
724
  return this.scanConfigMemo;
718
725
  }
719
- /** One single-flight analysis transaction per event batch: concurrent
720
- * entries join the in-flight promise; each settled entry reports outcome. */
726
+ /** Concurrent entries wait for publication, then ingest their own batch;
727
+ * content hashes coalesce observations the prior analysis covered. */
721
728
  async handleWatchUpdate(changes) {
722
729
  try {
723
730
  await this.routeWatchUpdate(changes);
@@ -728,27 +735,21 @@ var ExtractionSession = class {
728
735
  this.onCycleSettled?.(null);
729
736
  }
730
737
  async routeWatchUpdate(changes) {
738
+ const hasBatch = (changes.modifiedFiles?.size ?? 0) > 0 || (changes.removedFiles?.size ?? 0) > 0;
731
739
  const inflight = getWatchTransaction();
732
740
  if (inflight) {
733
741
  await inflight;
734
- return;
742
+ if (!hasBatch) return;
735
743
  }
736
744
  if (!this.system) {
737
745
  const owner = getOwningWatchSession();
738
- const hasBatch = (changes.modifiedFiles?.size ?? 0) > 0 || (changes.removedFiles?.size ?? 0) > 0;
739
746
  if (owner && owner !== this && hasBatch) await owner.ingestForwardedBatch(changes);
740
747
  return;
741
748
  }
742
- const transaction = this.processWatchUpdate(changes);
743
- setWatchTransaction(transaction);
744
- try {
745
- await transaction;
746
- } finally {
747
- setWatchTransaction(null);
748
- }
749
+ await this.ingestForwardedBatch(changes);
749
750
  }
750
- /** Owner-side entry for a batch a non-owning compiler observed. Serializes
751
- * behind any in-flight transaction — it has no other delivery. */
751
+ /** The shared owner gate for local and forwarded batches. Every waiter
752
+ * rechecks the slot so distinct batches publish in arrival order. */
752
753
  async ingestForwardedBatch(changes) {
753
754
  if (!this.system) return;
754
755
  for (;;) {
@@ -756,7 +757,7 @@ var ExtractionSession = class {
756
757
  if (!inflight) break;
757
758
  await inflight;
758
759
  }
759
- const transaction = this.processWatchUpdate(changes);
760
+ const transaction = Promise.resolve().then(() => this.processWatchUpdate(changes));
760
761
  setWatchTransaction(transaction);
761
762
  try {
762
763
  await transaction;
@@ -796,7 +797,9 @@ var ExtractionSession = class {
796
797
  const promise = this.runFullPipeline(this.pendingFromBatch(changes));
797
798
  setAnalysisStartedPromise(promise);
798
799
  await promise;
800
+ this.systemReloadOwed = false;
799
801
  } catch (err) {
802
+ if (err instanceof AbortedParseRejection) this.systemReloadOwed = true;
800
803
  try {
801
804
  this.beginStatusAttempt();
802
805
  this.writeAnalysisStatus("failed", this.pendingFromBatch(changes), String(err));
@@ -895,6 +898,21 @@ var ExtractionSession = class {
895
898
  }
896
899
  if (changedPaths.length > 0 || removedAny || assetChanged) {
897
900
  const pending = changedPaths.map((rel) => [rel, this.fileCache.get(rel).hash]);
901
+ const commitObservedBatch = () => {
902
+ for (const update of inventoryUpdates) {
903
+ let inventory = this.externalInventory.get(update.root);
904
+ if (!inventory) {
905
+ inventory = /* @__PURE__ */ new Map();
906
+ this.externalInventory.set(update.root, inventory);
907
+ }
908
+ if (update.hash === null) inventory.delete(update.key);
909
+ else inventory.set(update.key, {
910
+ hash: update.hash,
911
+ abs: update.abs
912
+ });
913
+ }
914
+ for (const key of ownerRemovals) delete this.externalFileOwners[key];
915
+ };
898
916
  let ingested;
899
917
  try {
900
918
  this.beginStatusAttempt();
@@ -902,15 +920,26 @@ var ExtractionSession = class {
902
920
  fileCache: this.fileCache,
903
921
  externalFileOwners: this.externalFileOwners
904
922
  });
923
+ this.throwOnAbortedParse(ingested);
924
+ if (this.systemReloadOwed) {
925
+ this.log("system reload: publishing the reload a parse hold deferred");
926
+ this.resetForHmr();
927
+ await this.runFullPipeline(pending);
928
+ this.systemReloadOwed = false;
929
+ return;
930
+ }
905
931
  this.externalFileOwners = require_pipeline.projectExternalFileOwners(ingested, this.externalFileOwners);
906
932
  resetAnalysisStartedPromise();
907
933
  const promise = this.runIncrementalPipeline(ingested.analysisEntries, pending);
908
934
  setAnalysisStartedPromise(promise);
909
935
  await promise;
910
936
  } catch (err) {
911
- for (const [key, prior] of priorCacheEntries) if (prior === null) this.fileCache.delete(key);
912
- else this.fileCache.set(key, prior);
913
- this.externalFileOwners = priorExternalFileOwners;
937
+ if (err instanceof AbortedParseRejection) commitObservedBatch();
938
+ else {
939
+ for (const [key, prior] of priorCacheEntries) if (prior === null) this.fileCache.delete(key);
940
+ else this.fileCache.set(key, prior);
941
+ this.externalFileOwners = priorExternalFileOwners;
942
+ }
914
943
  if (this.statusAttemptOpen) {
915
944
  this.debouncePending.clear();
916
945
  this.writeAnalysisStatus("failed", pending, String(err));
@@ -918,25 +947,24 @@ var ExtractionSession = class {
918
947
  throw err;
919
948
  }
920
949
  this.publishSourceIngestion(ingested);
921
- for (const update of inventoryUpdates) {
922
- let inventory = this.externalInventory.get(update.root);
923
- if (!inventory) {
924
- inventory = /* @__PURE__ */ new Map();
925
- this.externalInventory.set(update.root, inventory);
926
- }
927
- if (update.hash === null) inventory.delete(update.key);
928
- else inventory.set(update.key, {
929
- hash: update.hash,
930
- abs: update.abs
931
- });
932
- }
933
- for (const key of ownerRemovals) delete this.externalFileOwners[key];
950
+ commitObservedBatch();
934
951
  } else if (this.statusAttemptOpen) {
935
952
  this.debouncePending.clear();
936
- this.writeAnalysisStatus("idle", []);
953
+ if (this.heldRejection === null) this.writeAnalysisStatus("idle", []);
954
+ else this.writeAnalysisStatus("failed", [], this.heldRejection);
937
955
  }
938
956
  }
957
+ /** An aborted parse fails the attempt in every mode with a terminal
958
+ * `failed` status, so the last commit stays current, and holds publication
959
+ * until an attempt without one publishes. */
960
+ throwOnAbortedParse(prepared) {
961
+ const rejection = this.corpus.rejection(prepared);
962
+ if (!rejection) return;
963
+ this.heldRejection = rejection.message;
964
+ throw new AbortedParseRejection(rejection.message);
965
+ }
939
966
  publishSourceIngestion(result) {
967
+ this.heldRejection = null;
940
968
  this.fileCache = new Map(result.originalEntries.map((entry) => [entry.path, {
941
969
  hash: entry.hash,
942
970
  source: entry.source
@@ -982,7 +1010,6 @@ var ExtractionSession = class {
982
1010
  rootDir,
983
1011
  prefix: this.options.prefix
984
1012
  });
985
- this.systemVocabularyDiagnostics = require_pipeline.vocabularyWitnessDiagnostics(this.system.vocabularyWitnessesJson);
986
1013
  this.assetCopyCache.clear();
987
1014
  this.assetDependencyPaths.clear();
988
1015
  this.assetDependencyKeys.clear();
@@ -1119,6 +1146,7 @@ var ExtractionSession = class {
1119
1146
  let accepted;
1120
1147
  try {
1121
1148
  accepted = await this.corpus.prepare(rawEntries);
1149
+ this.throwOnAbortedParse(accepted);
1122
1150
  } catch (err) {
1123
1151
  this.debouncePending.clear();
1124
1152
  this.writeAnalysisStatus("failed", pending, String(err));
@@ -1152,7 +1180,6 @@ var ExtractionSession = class {
1152
1180
  externalFileOwners: this.externalFileOwners,
1153
1181
  externalSourceEntries: this.externalSourceEntries,
1154
1182
  externalPackageDirs: this.externalPackageDirs,
1155
- systemVocabularyDiagnostics: this.systemVocabularyDiagnostics,
1156
1183
  ingestionFailureDiagnostics: this.ingestionFailureDiagnostics
1157
1184
  };
1158
1185
  }
@@ -1325,7 +1352,7 @@ var ExtractionSession = class {
1325
1352
  ...analysisOptions,
1326
1353
  warn: (message) => this.warn(message),
1327
1354
  strict: this.options.strict,
1328
- extraDiagnostics: [...this.systemVocabularyDiagnostics, ...this.ingestionFailureDiagnostics]
1355
+ extraDiagnostics: this.ingestionFailureDiagnostics
1329
1356
  });
1330
1357
  require_pipeline.assertNoErrorDiagnostics(result.manifest?.diagnostics);
1331
1358
  require_pipeline.enforceExternalTokenContracts({
@@ -1368,7 +1395,9 @@ var ExtractionSession = class {
1368
1395
  const systemPropsContent = require_pipeline.buildSystemPropsModule({
1369
1396
  systemPropMapJson: JSON.stringify(manifest?.system_prop_map ?? {}),
1370
1397
  groupRegistryJson: system.groupRegistryJson,
1371
- dynamicProps: manifest?.dynamic_props ?? {}
1398
+ dynamicProps: manifest?.dynamic_props ?? {},
1399
+ admittedTransforms: manifest?.admitted_transforms ?? {},
1400
+ typedSystemProps: manifest?.typed_system_props ?? []
1372
1401
  });
1373
1402
  setSharedSystemProps(systemPropsContent);
1374
1403
  setManifestJson(result.manifestJson);
@@ -1989,6 +2018,7 @@ exports.pruneStaleAssets = pruneStaleAssets;
1989
2018
  exports.readCliLockRecord = readCliLockRecord;
1990
2019
  exports.readJsonEnvelope = readJsonEnvelope;
1991
2020
  exports.replacementEpochPath = replacementEpochPath;
2021
+ exports.resetAnalysisStartedPromise = resetAnalysisStartedPromise;
1992
2022
  exports.runSessionPipeline = runSessionPipeline;
1993
2023
  exports.sessionArtifactDir = sessionArtifactDir;
1994
2024
  exports.setAnalysisStartedPromise = setAnalysisStartedPromise;
package/dist/session.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { A as enforceExternalTokenContracts, B as firstOwners, D as postProcessCss, E as vocabularyWitnessDiagnostics, F as createSourceCorpus, G as walkPackageSources, I as collectExternalPackageSources, J as sharesVolumeRoot, K as createSourceIdentity, L as excludeCollectedPackages, N as findAssetSpecifiers, O as resolveLightningTargets, P as substituteAssetPlaceholders, R as extractSystemFilePackages, U as staleDistIncludesMessage, V as isExcludedPackageRelativePath, W as unresolvableIncludesMessage, X as discoverFiles, _ as clearEngineCache, a as assertNoErrorDiagnostics, at as resolveMode, c as buildSystemPropsModule, ct as createV2EngineApi, d as loadSystemConfig, ft as projectExternalFileOwners, i as snapshotFilePlans, it as createExcludeMatcher, j as resolveAssetFile, mt as DEFAULT_EXTENSIONS, p as serializeStaticCss, q as isPathWithinRoot, r as hashReplacementPlans, s as formatRustTimingWaterfall, t as toWatchKeys, v as runProjectAnalysis, vt as contentHash, w as unreadableSourceDiagnostic, wt as __require, xt as assembleStylesheet, z as findPackageRoot } from "./pipeline-DeEENy5C.mjs";
1
+ import { A as resolveLightningTargets, B as extractSystemFilePackages, Dt as __require, E as unreadableSourceDiagnostic, F as findAssetSpecifiers, G as staleDistIncludesMessage, H as firstOwners, I as substituteAssetPlaceholders, J as createSourceIdentity, K as unresolvableIncludesMessage, L as createSourceCorpus, M as enforceExternalTokenContracts, N as resolveAssetFile, Q as discoverFiles, R as collectExternalPackageSources, U as isExcludedPackageRelativePath, V as findPackageRoot, X as sharesVolumeRoot, Y as isPathWithinRoot, _ as clearEngineCache, _t as DEFAULT_EXTENSIONS, a as assertNoErrorDiagnostics, c as buildSystemPropsModule, ct as resolveVerbosity, d as loadSystemConfig, dt as createV2EngineApi, ht as projectExternalFileOwners, i as snapshotFilePlans, k as postProcessCss, ot as createExcludeMatcher, p as serializeStaticCss, q as walkPackageSources, r as hashReplacementPlans, s as formatRustTimingWaterfall, st as resolveMode, t as toWatchKeys, v as runProjectAnalysis, wt as assembleStylesheet, xt as contentHash, z as excludeCollectedPackages } from "./pipeline-Dr-I4Xhl.mjs";
2
2
  import { randomUUID } from "crypto";
3
3
  import { existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, unlinkSync, watch, writeFileSync } from "fs";
4
4
  import { basename, extname, join, relative, resolve } from "path";
@@ -549,6 +549,8 @@ const LEGACY_FLAT_ARTIFACTS = [
549
549
  function isDiskString(value) {
550
550
  return Object(value) !== value && Object.prototype.toString.call(value) === "[object String]";
551
551
  }
552
+ /** Rejection of an attempt whose corpus holds an aborted parse. */
553
+ var AbortedParseRejection = class extends Error {};
552
554
  function isDiskNumber(value) {
553
555
  return Object(value) !== value && Object.prototype.toString.call(value) === "[object Number]";
554
556
  }
@@ -608,9 +610,6 @@ var ExtractionSession = class {
608
610
  options;
609
611
  staticCssJson;
610
612
  system = null;
611
- /** Vocabulary witness diagnostics from the sealed system's registration
612
- * record, awaiting the shared surfacing pass. */
613
- systemVocabularyDiagnostics = [];
614
613
  /** Configured external files that could not be read. Incremental passes
615
614
  * re-collect nothing, so they replay these instead of passing strict. */
616
615
  ingestionFailureDiagnostics = [];
@@ -653,6 +652,14 @@ var ExtractionSession = class {
653
652
  onArtifactWrite = null;
654
653
  statusAttemptId = 0;
655
654
  statusAttemptOpen = false;
655
+ /** Message of the aborted-parse rejection holding publication. While set,
656
+ * the cache keeps every observed source so the repair publishes them in
657
+ * one generation; a successful publication clears it. */
658
+ heldRejection = null;
659
+ /** A system reload an aborted parse rejected. Its dependency hashes already
660
+ * advanced, so the first batch that passes the parse check publishes
661
+ * through the full pipeline, which loads the latest system. */
662
+ systemReloadOwed = false;
656
663
  /** Monotonic readiness witness: flips true on the first complete
657
664
  * publication and never regresses; every later status write carries it. */
658
665
  firstEmissionComplete = false;
@@ -668,7 +675,7 @@ var ExtractionSession = class {
668
675
  return sessionArtifactDir(this.rootDir, this.sessionId);
669
676
  }
670
677
  get verbose() {
671
- return this.options.verbose === true || process.env.ANIMUS_DEBUG === "1" || process.env.ANIMUS_DEBUG === "true";
678
+ return resolveVerbosity(this.options.verbose, process.env.ANIMUS_DEBUG) !== "quiet";
672
679
  }
673
680
  log(msg) {
674
681
  if (this.verbose) console.error(`[animus] ${msg}`);
@@ -715,8 +722,8 @@ var ExtractionSession = class {
715
722
  }
716
723
  return this.scanConfigMemo;
717
724
  }
718
- /** One single-flight analysis transaction per event batch: concurrent
719
- * entries join the in-flight promise; each settled entry reports outcome. */
725
+ /** Concurrent entries wait for publication, then ingest their own batch;
726
+ * content hashes coalesce observations the prior analysis covered. */
720
727
  async handleWatchUpdate(changes) {
721
728
  try {
722
729
  await this.routeWatchUpdate(changes);
@@ -727,27 +734,21 @@ var ExtractionSession = class {
727
734
  this.onCycleSettled?.(null);
728
735
  }
729
736
  async routeWatchUpdate(changes) {
737
+ const hasBatch = (changes.modifiedFiles?.size ?? 0) > 0 || (changes.removedFiles?.size ?? 0) > 0;
730
738
  const inflight = getWatchTransaction();
731
739
  if (inflight) {
732
740
  await inflight;
733
- return;
741
+ if (!hasBatch) return;
734
742
  }
735
743
  if (!this.system) {
736
744
  const owner = getOwningWatchSession();
737
- const hasBatch = (changes.modifiedFiles?.size ?? 0) > 0 || (changes.removedFiles?.size ?? 0) > 0;
738
745
  if (owner && owner !== this && hasBatch) await owner.ingestForwardedBatch(changes);
739
746
  return;
740
747
  }
741
- const transaction = this.processWatchUpdate(changes);
742
- setWatchTransaction(transaction);
743
- try {
744
- await transaction;
745
- } finally {
746
- setWatchTransaction(null);
747
- }
748
+ await this.ingestForwardedBatch(changes);
748
749
  }
749
- /** Owner-side entry for a batch a non-owning compiler observed. Serializes
750
- * behind any in-flight transaction — it has no other delivery. */
750
+ /** The shared owner gate for local and forwarded batches. Every waiter
751
+ * rechecks the slot so distinct batches publish in arrival order. */
751
752
  async ingestForwardedBatch(changes) {
752
753
  if (!this.system) return;
753
754
  for (;;) {
@@ -755,7 +756,7 @@ var ExtractionSession = class {
755
756
  if (!inflight) break;
756
757
  await inflight;
757
758
  }
758
- const transaction = this.processWatchUpdate(changes);
759
+ const transaction = Promise.resolve().then(() => this.processWatchUpdate(changes));
759
760
  setWatchTransaction(transaction);
760
761
  try {
761
762
  await transaction;
@@ -795,7 +796,9 @@ var ExtractionSession = class {
795
796
  const promise = this.runFullPipeline(this.pendingFromBatch(changes));
796
797
  setAnalysisStartedPromise(promise);
797
798
  await promise;
799
+ this.systemReloadOwed = false;
798
800
  } catch (err) {
801
+ if (err instanceof AbortedParseRejection) this.systemReloadOwed = true;
799
802
  try {
800
803
  this.beginStatusAttempt();
801
804
  this.writeAnalysisStatus("failed", this.pendingFromBatch(changes), String(err));
@@ -894,6 +897,21 @@ var ExtractionSession = class {
894
897
  }
895
898
  if (changedPaths.length > 0 || removedAny || assetChanged) {
896
899
  const pending = changedPaths.map((rel) => [rel, this.fileCache.get(rel).hash]);
900
+ const commitObservedBatch = () => {
901
+ for (const update of inventoryUpdates) {
902
+ let inventory = this.externalInventory.get(update.root);
903
+ if (!inventory) {
904
+ inventory = /* @__PURE__ */ new Map();
905
+ this.externalInventory.set(update.root, inventory);
906
+ }
907
+ if (update.hash === null) inventory.delete(update.key);
908
+ else inventory.set(update.key, {
909
+ hash: update.hash,
910
+ abs: update.abs
911
+ });
912
+ }
913
+ for (const key of ownerRemovals) delete this.externalFileOwners[key];
914
+ };
897
915
  let ingested;
898
916
  try {
899
917
  this.beginStatusAttempt();
@@ -901,15 +919,26 @@ var ExtractionSession = class {
901
919
  fileCache: this.fileCache,
902
920
  externalFileOwners: this.externalFileOwners
903
921
  });
922
+ this.throwOnAbortedParse(ingested);
923
+ if (this.systemReloadOwed) {
924
+ this.log("system reload: publishing the reload a parse hold deferred");
925
+ this.resetForHmr();
926
+ await this.runFullPipeline(pending);
927
+ this.systemReloadOwed = false;
928
+ return;
929
+ }
904
930
  this.externalFileOwners = projectExternalFileOwners(ingested, this.externalFileOwners);
905
931
  resetAnalysisStartedPromise();
906
932
  const promise = this.runIncrementalPipeline(ingested.analysisEntries, pending);
907
933
  setAnalysisStartedPromise(promise);
908
934
  await promise;
909
935
  } catch (err) {
910
- for (const [key, prior] of priorCacheEntries) if (prior === null) this.fileCache.delete(key);
911
- else this.fileCache.set(key, prior);
912
- this.externalFileOwners = priorExternalFileOwners;
936
+ if (err instanceof AbortedParseRejection) commitObservedBatch();
937
+ else {
938
+ for (const [key, prior] of priorCacheEntries) if (prior === null) this.fileCache.delete(key);
939
+ else this.fileCache.set(key, prior);
940
+ this.externalFileOwners = priorExternalFileOwners;
941
+ }
913
942
  if (this.statusAttemptOpen) {
914
943
  this.debouncePending.clear();
915
944
  this.writeAnalysisStatus("failed", pending, String(err));
@@ -917,25 +946,24 @@ var ExtractionSession = class {
917
946
  throw err;
918
947
  }
919
948
  this.publishSourceIngestion(ingested);
920
- for (const update of inventoryUpdates) {
921
- let inventory = this.externalInventory.get(update.root);
922
- if (!inventory) {
923
- inventory = /* @__PURE__ */ new Map();
924
- this.externalInventory.set(update.root, inventory);
925
- }
926
- if (update.hash === null) inventory.delete(update.key);
927
- else inventory.set(update.key, {
928
- hash: update.hash,
929
- abs: update.abs
930
- });
931
- }
932
- for (const key of ownerRemovals) delete this.externalFileOwners[key];
949
+ commitObservedBatch();
933
950
  } else if (this.statusAttemptOpen) {
934
951
  this.debouncePending.clear();
935
- this.writeAnalysisStatus("idle", []);
952
+ if (this.heldRejection === null) this.writeAnalysisStatus("idle", []);
953
+ else this.writeAnalysisStatus("failed", [], this.heldRejection);
936
954
  }
937
955
  }
956
+ /** An aborted parse fails the attempt in every mode with a terminal
957
+ * `failed` status, so the last commit stays current, and holds publication
958
+ * until an attempt without one publishes. */
959
+ throwOnAbortedParse(prepared) {
960
+ const rejection = this.corpus.rejection(prepared);
961
+ if (!rejection) return;
962
+ this.heldRejection = rejection.message;
963
+ throw new AbortedParseRejection(rejection.message);
964
+ }
938
965
  publishSourceIngestion(result) {
966
+ this.heldRejection = null;
939
967
  this.fileCache = new Map(result.originalEntries.map((entry) => [entry.path, {
940
968
  hash: entry.hash,
941
969
  source: entry.source
@@ -981,7 +1009,6 @@ var ExtractionSession = class {
981
1009
  rootDir,
982
1010
  prefix: this.options.prefix
983
1011
  });
984
- this.systemVocabularyDiagnostics = vocabularyWitnessDiagnostics(this.system.vocabularyWitnessesJson);
985
1012
  this.assetCopyCache.clear();
986
1013
  this.assetDependencyPaths.clear();
987
1014
  this.assetDependencyKeys.clear();
@@ -1118,6 +1145,7 @@ var ExtractionSession = class {
1118
1145
  let accepted;
1119
1146
  try {
1120
1147
  accepted = await this.corpus.prepare(rawEntries);
1148
+ this.throwOnAbortedParse(accepted);
1121
1149
  } catch (err) {
1122
1150
  this.debouncePending.clear();
1123
1151
  this.writeAnalysisStatus("failed", pending, String(err));
@@ -1151,7 +1179,6 @@ var ExtractionSession = class {
1151
1179
  externalFileOwners: this.externalFileOwners,
1152
1180
  externalSourceEntries: this.externalSourceEntries,
1153
1181
  externalPackageDirs: this.externalPackageDirs,
1154
- systemVocabularyDiagnostics: this.systemVocabularyDiagnostics,
1155
1182
  ingestionFailureDiagnostics: this.ingestionFailureDiagnostics
1156
1183
  };
1157
1184
  }
@@ -1324,7 +1351,7 @@ var ExtractionSession = class {
1324
1351
  ...analysisOptions,
1325
1352
  warn: (message) => this.warn(message),
1326
1353
  strict: this.options.strict,
1327
- extraDiagnostics: [...this.systemVocabularyDiagnostics, ...this.ingestionFailureDiagnostics]
1354
+ extraDiagnostics: this.ingestionFailureDiagnostics
1328
1355
  });
1329
1356
  assertNoErrorDiagnostics(result.manifest?.diagnostics);
1330
1357
  enforceExternalTokenContracts({
@@ -1367,7 +1394,9 @@ var ExtractionSession = class {
1367
1394
  const systemPropsContent = buildSystemPropsModule({
1368
1395
  systemPropMapJson: JSON.stringify(manifest?.system_prop_map ?? {}),
1369
1396
  groupRegistryJson: system.groupRegistryJson,
1370
- dynamicProps: manifest?.dynamic_props ?? {}
1397
+ dynamicProps: manifest?.dynamic_props ?? {},
1398
+ admittedTransforms: manifest?.admitted_transforms ?? {},
1399
+ typedSystemProps: manifest?.typed_system_props ?? []
1371
1400
  });
1372
1401
  setSharedSystemProps(systemPropsContent);
1373
1402
  setManifestJson(result.manifestJson);
@@ -1952,4 +1981,4 @@ function startTurbopackWatcher(session, rootDir, options = {}) {
1952
1981
  };
1953
1982
  }
1954
1983
  //#endregion
1955
- export { ANIMUS_ARTIFACT_DIR, ANIMUS_CSS_MODULE_ID, CLI_COMMIT_ARTIFACT, CLI_LOCK_ARTIFACT, CLI_LOCK_HEARTBEAT_INTERVAL_MS, CLI_LOCK_STALE_AFTER_MS, ExtractionSession, MANIFEST_ARTIFACT, SESSION_ASSETS_DIR, STYLES_ARTIFACT, SYSTEM_PROPS_ARTIFACT, TURBOPACK_SYSTEM_PROPS_ID, analysisCommitPath, analysisInputsPath, analysisStatusPath, checkLockLiveness, collectSessionAssets, decodeCommitRecord, engineApi, getAnalysisStartedPromise, getAnalyzedHashes, getManifestJson, getReplacementEpoch, getSessionArtifactDir, getSharedCss, getSharedExternalDirs, getSharedExternalEntries, getSharedSystemProps, holdDirectoryClaim, isLockHolderAlive, lockRecordBytes, manifestPath, pruneStaleAssets, readCliLockRecord, readJsonEnvelope, replacementEpochPath, runSessionPipeline, sessionArtifactDir, setAnalysisStartedPromise, setSharedEngine, startTurbopackWatcher, stylesPath, systemPropsPath, verifyCommitRecord };
1984
+ export { ANIMUS_ARTIFACT_DIR, ANIMUS_CSS_MODULE_ID, CLI_COMMIT_ARTIFACT, CLI_LOCK_ARTIFACT, CLI_LOCK_HEARTBEAT_INTERVAL_MS, CLI_LOCK_STALE_AFTER_MS, ExtractionSession, MANIFEST_ARTIFACT, SESSION_ASSETS_DIR, STYLES_ARTIFACT, SYSTEM_PROPS_ARTIFACT, TURBOPACK_SYSTEM_PROPS_ID, analysisCommitPath, analysisInputsPath, analysisStatusPath, checkLockLiveness, collectSessionAssets, decodeCommitRecord, engineApi, getAnalysisStartedPromise, getAnalyzedHashes, getManifestJson, getReplacementEpoch, getSessionArtifactDir, getSharedCss, getSharedExternalDirs, getSharedExternalEntries, getSharedSystemProps, holdDirectoryClaim, isLockHolderAlive, lockRecordBytes, manifestPath, pruneStaleAssets, readCliLockRecord, readJsonEnvelope, replacementEpochPath, resetAnalysisStartedPromise, runSessionPipeline, sessionArtifactDir, setAnalysisStartedPromise, setSharedEngine, startTurbopackWatcher, stylesPath, systemPropsPath, verifyCommitRecord };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@animus-ui/extract",
3
- "version": "0.1.16",
3
+ "version": "0.1.18",
4
4
  "description": "Animus static CSS extraction pipeline (Rust/NAPI)",
5
5
  "keywords": [
6
6
  "animus",
@@ -55,13 +55,13 @@
55
55
  "build:v2:debug": "cd crates/extract-v2 && bunx napi build --platform --no-js"
56
56
  },
57
57
  "dependencies": {
58
- "@animus-ui/properties": "0.1.16",
58
+ "@animus-ui/properties": "0.1.18",
59
59
  "browserslist": "^4.28.8",
60
60
  "lightningcss": "^1.33.0"
61
61
  },
62
62
  "devDependencies": {
63
- "@animus-ui/assertions": "0.1.16",
64
- "@animus-ui/system": "0.1.16",
63
+ "@animus-ui/assertions": "0.1.18",
64
+ "@animus-ui/system": "0.1.18",
65
65
  "@mdx-js/mdx": "3.1.1",
66
66
  "@napi-rs/cli": "^3.10.5",
67
67
  "svelte": "5.57.0"