@fairfox/polly 0.85.1 → 0.86.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 (120) hide show
  1. package/dist/cli/polly.js.map +1 -1
  2. package/dist/gallery/gallery.css +1 -1
  3. package/dist/gallery/gallery.js +2 -27
  4. package/dist/scripts/build-extension.js.map +1 -1
  5. package/dist/src/actions/index.js +34 -32
  6. package/dist/src/actions/index.js.map +2 -2
  7. package/dist/src/background/index.js +24 -22
  8. package/dist/src/background/index.js.map +2 -2
  9. package/dist/src/background/message-router.js +21 -19
  10. package/dist/src/background/message-router.js.map +2 -2
  11. package/dist/src/client/index.js +9 -7
  12. package/dist/src/client/index.js.map +3 -3
  13. package/dist/src/client/wrapper.d.ts +3 -3
  14. package/dist/src/elysia/index.d.ts +1 -1
  15. package/dist/src/elysia/index.js +25 -23
  16. package/dist/src/elysia/index.js.map +2 -2
  17. package/dist/src/elysia/types.d.ts +11 -2
  18. package/dist/src/index.js +68 -64
  19. package/dist/src/index.js.map +3 -3
  20. package/dist/src/mesh-node.js +6 -6
  21. package/dist/src/mesh-node.js.map +1 -1
  22. package/dist/src/mesh.js +92 -90
  23. package/dist/src/mesh.js.map +2 -2
  24. package/dist/src/peer.js +83 -52
  25. package/dist/src/peer.js.map +3 -3
  26. package/dist/src/polly-ui/index.css +1 -1
  27. package/dist/src/polly-ui/index.js +37 -35
  28. package/dist/src/polly-ui/index.js.map +2 -2
  29. package/dist/src/polly-ui/markdown.js +233 -96
  30. package/dist/src/polly-ui/markdown.js.map +4 -4
  31. package/dist/src/polly-ui/styles.css +1 -1
  32. package/dist/src/shared/adapters/index.js +30 -28
  33. package/dist/src/shared/adapters/index.js.map +2 -2
  34. package/dist/src/shared/lib/context-helpers.js +23 -21
  35. package/dist/src/shared/lib/context-helpers.js.map +2 -2
  36. package/dist/src/shared/lib/errors.js +16 -14
  37. package/dist/src/shared/lib/errors.js.map +2 -2
  38. package/dist/src/shared/lib/guards.js +11 -9
  39. package/dist/src/shared/lib/guards.js.map +2 -2
  40. package/dist/src/shared/lib/message-bus.js +24 -22
  41. package/dist/src/shared/lib/message-bus.js.map +2 -2
  42. package/dist/src/shared/lib/peer-relay-adapter.d.ts +6 -0
  43. package/dist/src/shared/lib/resource.js +19 -15
  44. package/dist/src/shared/lib/resource.js.map +3 -3
  45. package/dist/src/shared/lib/state.js +26 -22
  46. package/dist/src/shared/lib/state.js.map +3 -3
  47. package/dist/src/shared/lib/test-helpers.js +11 -9
  48. package/dist/src/shared/lib/test-helpers.js.map +2 -2
  49. package/dist/src/shared/state/app-state.js +22 -18
  50. package/dist/src/shared/state/app-state.js.map +3 -3
  51. package/dist/src/shared/types/messages.js +11 -9
  52. package/dist/src/shared/types/messages.js.map +2 -2
  53. package/dist/tools/bdd/src/cli.js +44 -1
  54. package/dist/tools/bdd/src/cli.js.map +4 -4
  55. package/dist/tools/bdd/src/index.js +54 -11
  56. package/dist/tools/bdd/src/index.js.map +4 -4
  57. package/dist/tools/gallery/src/cli.js +1 -1
  58. package/dist/tools/gallery/src/cli.js.map +2 -2
  59. package/dist/tools/init/src/cli.js +1 -1
  60. package/dist/tools/init/src/cli.js.map +2 -2
  61. package/dist/tools/mutate/src/cli.js +1 -1
  62. package/dist/tools/mutate/src/cli.js.map +2 -2
  63. package/dist/tools/mutate/src/index.js +8 -8
  64. package/dist/tools/mutate/src/index.js.map +2 -2
  65. package/dist/tools/quality/src/cli.js +3 -2
  66. package/dist/tools/quality/src/cli.js.map +3 -3
  67. package/dist/tools/quality/src/index.js +37 -36
  68. package/dist/tools/quality/src/index.js.map +3 -3
  69. package/dist/tools/test/src/adapters/index.js +19 -17
  70. package/dist/tools/test/src/adapters/index.js.map +2 -2
  71. package/dist/tools/test/src/browser/index.js +15 -13
  72. package/dist/tools/test/src/browser/index.js.map +2 -2
  73. package/dist/tools/test/src/browser/run.js +12 -3
  74. package/dist/tools/test/src/browser/run.js.map +5 -4
  75. package/dist/tools/test/src/contrast/index.js +14 -12
  76. package/dist/tools/test/src/contrast/index.js.map +2 -2
  77. package/dist/tools/test/src/coverage-policy/cli.js +5 -5
  78. package/dist/tools/test/src/coverage-policy/cli.js.map +2 -2
  79. package/dist/tools/test/src/coverage-policy/index.js +12 -12
  80. package/dist/tools/test/src/coverage-policy/index.js.map +1 -1
  81. package/dist/tools/test/src/e2e-mesh/index.js +88 -50
  82. package/dist/tools/test/src/e2e-mesh/index.js.map +6 -5
  83. package/dist/tools/test/src/e2e-mesh/with-relay.d.ts +1 -1
  84. package/dist/tools/test/src/e2e-relay/index.js +3 -3
  85. package/dist/tools/test/src/e2e-relay/index.js.map +2 -2
  86. package/dist/tools/test/src/e2e-shared/ephemeral-port.d.ts +73 -0
  87. package/dist/tools/test/src/e2e-shared/index.d.ts +1 -0
  88. package/dist/tools/test/src/index.d.ts +1 -0
  89. package/dist/tools/test/src/index.js +68 -24
  90. package/dist/tools/test/src/index.js.map +4 -3
  91. package/dist/tools/test/src/test-utils.js +14 -12
  92. package/dist/tools/test/src/test-utils.js.map +2 -2
  93. package/dist/tools/test/src/tiers/budget.d.ts +32 -0
  94. package/dist/tools/test/src/tiers/cli.js +35 -5
  95. package/dist/tools/test/src/tiers/cli.js.map +6 -5
  96. package/dist/tools/test/src/tiers/index.d.ts +1 -0
  97. package/dist/tools/test/src/tiers/reporter.d.ts +0 -5
  98. package/dist/tools/test/src/tiers/types.d.ts +9 -0
  99. package/dist/tools/test/src/tiers/worker.js +1 -1
  100. package/dist/tools/test/src/tiers/worker.js.map +1 -1
  101. package/dist/tools/test/src/visual/index.js +121 -119
  102. package/dist/tools/test/src/visual/index.js.map +2 -2
  103. package/dist/tools/verify/specs/README.md +18 -0
  104. package/dist/tools/verify/specs/tla/MeshState.cfg +1 -1
  105. package/dist/tools/verify/specs/tla/MeshState.tla +7 -0
  106. package/dist/tools/verify/specs/tla/MessageRouter.cfg +4 -2
  107. package/dist/tools/verify/specs/tla/MessageRouter.tla +45 -10
  108. package/dist/tools/verify/specs/tla/PeerState.cfg +1 -1
  109. package/dist/tools/verify/specs/tla/PeerState.tla +7 -0
  110. package/dist/tools/verify/specs/tla/README.md +1 -1
  111. package/dist/tools/verify/src/cli.js +258 -202
  112. package/dist/tools/verify/src/cli.js.map +12 -11
  113. package/dist/tools/verify/src/config.d.ts +25 -0
  114. package/dist/tools/verify/src/config.js +18 -16
  115. package/dist/tools/verify/src/config.js.map +3 -3
  116. package/dist/tools/verify/src/stryker/index.js +6 -6
  117. package/dist/tools/verify/src/stryker/index.js.map +1 -1
  118. package/dist/tools/visualize/src/cli.js +439 -47
  119. package/dist/tools/visualize/src/cli.js.map +7 -5
  120. package/package.json +2 -2
@@ -20,8 +20,8 @@ var __require = /* @__PURE__ */ createRequire(import.meta.url);
20
20
  // tools/analysis/src/extract/project-detector.ts
21
21
  var exports_project_detector = {};
22
22
  __export(exports_project_detector, {
23
- detectProjectConfig: () => detectProjectConfig,
24
- ProjectDetector: () => ProjectDetector
23
+ ProjectDetector: () => ProjectDetector,
24
+ detectProjectConfig: () => detectProjectConfig
25
25
  });
26
26
  import * as fs3 from "node:fs";
27
27
  import * as path3 from "node:path";
@@ -666,9 +666,293 @@ function detectProjectConfig(projectRoot) {
666
666
  }
667
667
  var init_project_detector = () => {};
668
668
 
669
+ // tools/verify/src/runner/container-name.ts
670
+ function mintContainerName(kind) {
671
+ counter += 1;
672
+ const unique = crypto.randomUUID().slice(0, 8);
673
+ return `${CONTAINER_NAME_PREFIX}${sanitizeKind(kind)}-${process.pid}-${counter}-${unique}`;
674
+ }
675
+ function sanitizeKind(kind) {
676
+ const cleaned = kind.replace(/[^a-zA-Z0-9_.-]/g, "-");
677
+ return cleaned.length > 0 ? cleaned : "run";
678
+ }
679
+ var CONTAINER_NAME_PREFIX = "polly-tla-", counter = 0;
680
+
681
+ // tools/verify/src/runner/docker.ts
682
+ var exports_docker = {};
683
+ __export(exports_docker, {
684
+ DockerRunner: () => DockerRunner,
685
+ removeContainer: () => removeContainer,
686
+ sweepOrphanedContainers: () => sweepOrphanedContainers,
687
+ sweepOrphanedContainersOnce: () => sweepOrphanedContainersOnce
688
+ });
689
+ import { spawn, spawnSync } from "node:child_process";
690
+ import * as fs6 from "node:fs";
691
+ import * as path5 from "node:path";
692
+ function removeContainer(name) {
693
+ try {
694
+ spawnSync("docker", ["rm", "-f", name], { timeout: 1e4, stdio: "ignore" });
695
+ } catch {}
696
+ }
697
+ function sweepOrphanedContainersOnce() {
698
+ if (swept)
699
+ return [];
700
+ swept = true;
701
+ return sweepOrphanedContainers();
702
+ }
703
+ function sweepOrphanedContainers() {
704
+ try {
705
+ const listed = spawnSync("docker", [
706
+ "ps",
707
+ "--all",
708
+ "--filter",
709
+ "status=created",
710
+ "--filter",
711
+ `name=${CONTAINER_NAME_PREFIX}`,
712
+ "--format",
713
+ "{{.Names}}"
714
+ ], { timeout: 1e4, encoding: "utf8" });
715
+ const names = (listed.stdout ?? "").split(`
716
+ `).map((line) => line.trim()).filter((line) => line.startsWith(CONTAINER_NAME_PREFIX));
717
+ for (const name of names) {
718
+ removeContainer(name);
719
+ }
720
+ return names;
721
+ } catch {
722
+ return [];
723
+ }
724
+ }
725
+
726
+ class DockerRunner {
727
+ IMAGE_NAME = "polly-tla:latest";
728
+ DOCKERFILE_PATH = path5.join(__dirname, "../../Dockerfile");
729
+ async isDockerAvailable() {
730
+ try {
731
+ const result = await this.runCommand("docker", ["info"], {
732
+ timeout: 5000
733
+ });
734
+ return result.exitCode === 0;
735
+ } catch (error) {
736
+ if (error instanceof Error && error.message.includes("timed out")) {
737
+ throw error;
738
+ }
739
+ return false;
740
+ }
741
+ }
742
+ async hasImage() {
743
+ try {
744
+ const result = await this.runCommand("docker", ["images", "-q", this.IMAGE_NAME], {
745
+ timeout: 1e4
746
+ });
747
+ return result.stdout.trim().length > 0;
748
+ } catch (error) {
749
+ if (error instanceof Error && error.message.includes("timed out")) {
750
+ throw error;
751
+ }
752
+ return false;
753
+ }
754
+ }
755
+ async buildImage(onProgress) {
756
+ const dockerfileDir = path5.dirname(this.DOCKERFILE_PATH);
757
+ await this.runCommandStreaming("docker", ["build", "-f", this.DOCKERFILE_PATH, "-t", this.IMAGE_NAME, dockerfileDir], onProgress, 300000);
758
+ }
759
+ async pullImage(onProgress) {
760
+ await this.buildImage(onProgress);
761
+ }
762
+ async runTLC(specPath, options) {
763
+ if (!fs6.existsSync(specPath)) {
764
+ throw new Error(`Spec file not found: ${specPath}`);
765
+ }
766
+ const specDir = path5.dirname(specPath);
767
+ const specName = path5.basename(specPath, ".tla");
768
+ const cfgPath = path5.join(specDir, `${specName}.cfg`);
769
+ if (!fs6.existsSync(cfgPath)) {
770
+ throw new Error(`Config file not found: ${cfgPath}`);
771
+ }
772
+ const statesDir = path5.join(specDir, "states");
773
+ if (fs6.existsSync(statesDir)) {
774
+ fs6.rmSync(statesDir, { recursive: true, force: true });
775
+ }
776
+ const containerName = mintContainerName("tlc");
777
+ sweepOrphanedContainersOnce();
778
+ const args = [
779
+ "run",
780
+ "--rm",
781
+ "--name",
782
+ containerName,
783
+ "-v",
784
+ `${specDir}:/work`,
785
+ this.IMAGE_NAME,
786
+ "tlc",
787
+ "-workers",
788
+ `${options?.workers || 1}`,
789
+ "-cleanup",
790
+ "-metadir",
791
+ "/tmp/states"
792
+ ];
793
+ if (options?.maxDepth !== undefined && options.maxDepth > 0) {
794
+ args.push("-depth", `${options.maxDepth}`);
795
+ }
796
+ args.push(`${specName}.tla`);
797
+ const result = await this.runCommand("docker", args, {
798
+ timeout: options?.timeout,
799
+ containerName
800
+ });
801
+ return this.parseTLCOutput(result);
802
+ }
803
+ parseTLCOutput(result) {
804
+ const output = result.stdout + result.stderr;
805
+ const violationMatch = output.match(/Error: Invariant (.*?) is violated/);
806
+ if (violationMatch) {
807
+ return {
808
+ success: false,
809
+ violation: {
810
+ type: "invariant",
811
+ name: violationMatch[1],
812
+ trace: this.extractTrace(output)
813
+ },
814
+ output
815
+ };
816
+ }
817
+ if (result.exitCode !== 0 || output.includes("Error:")) {
818
+ return {
819
+ success: false,
820
+ error: this.extractError(output),
821
+ output
822
+ };
823
+ }
824
+ const statesMatch = output.match(/(\d+) states generated/);
825
+ const distinctMatch = output.match(/(\d+) distinct states/);
826
+ return {
827
+ success: true,
828
+ stats: {
829
+ statesGenerated: statesMatch?.[1] ? Number.parseInt(statesMatch[1], 10) : 0,
830
+ distinctStates: distinctMatch?.[1] ? Number.parseInt(distinctMatch[1], 10) : 0
831
+ },
832
+ output
833
+ };
834
+ }
835
+ extractTrace(output) {
836
+ const lines = output.split(`
837
+ `);
838
+ const trace = [];
839
+ let inTrace = false;
840
+ for (const line of lines) {
841
+ if (line.includes("State ") && line.includes(":")) {
842
+ inTrace = true;
843
+ trace.push(line);
844
+ } else if (inTrace) {
845
+ if (line.trim() === "" || line.startsWith("Error:")) {
846
+ break;
847
+ }
848
+ trace.push(line);
849
+ }
850
+ }
851
+ return trace;
852
+ }
853
+ extractError(output) {
854
+ if (/StatePool\w*\.run/.test(output) && /states\/.*No such file or directory/.test(output)) {
855
+ return "TLC state-pool IO failure (states/.../<n>: No such file or directory). This is a Docker filesystem flake, not a spec error — re-run the verification. See issue #152.";
856
+ }
857
+ const errorMatch = output.match(/Error: (.*?)(?:\n|$)/);
858
+ if (errorMatch?.[1]) {
859
+ return errorMatch[1];
860
+ }
861
+ if (output.includes("Parse Error")) {
862
+ return "TLA+ syntax error in specification";
863
+ }
864
+ if (output.includes("Semantic Error")) {
865
+ return "Semantic error in specification";
866
+ }
867
+ return "Unknown error occurred during model checking";
868
+ }
869
+ runCommand(command, args, options) {
870
+ return new Promise((resolve3, reject) => {
871
+ const proc = spawn(command, args);
872
+ let stdout = "";
873
+ let stderr = "";
874
+ proc.stdout.on("data", (data) => {
875
+ stdout += data.toString();
876
+ });
877
+ proc.stderr.on("data", (data) => {
878
+ stderr += data.toString();
879
+ });
880
+ const timeoutValue = options?.timeout ?? 0;
881
+ const timeout = timeoutValue > 0 ? setTimeout(() => {
882
+ proc.kill("SIGKILL");
883
+ if (options?.containerName) {
884
+ removeContainer(options.containerName);
885
+ }
886
+ reject(new Error(`Command timed out after ${Math.floor(timeoutValue / 1000)}s. TLC was still making progress. Consider increasing the timeout or setting timeout: 0 for no timeout.`));
887
+ }, timeoutValue) : null;
888
+ proc.on("close", (exitCode) => {
889
+ if (timeout)
890
+ clearTimeout(timeout);
891
+ resolve3({
892
+ exitCode: exitCode || 0,
893
+ stdout,
894
+ stderr
895
+ });
896
+ });
897
+ proc.on("error", (error) => {
898
+ if (timeout)
899
+ clearTimeout(timeout);
900
+ reject(error);
901
+ });
902
+ });
903
+ }
904
+ runCommandStreaming(command, args, onOutput, timeout) {
905
+ return new Promise((resolve3, reject) => {
906
+ const proc = spawn(command, args);
907
+ const timeoutHandle = timeout && timeout > 0 ? setTimeout(() => {
908
+ proc.kill();
909
+ reject(new Error(`Command timed out after ${Math.floor(timeout / 1000)}s. Docker may be unresponsive.`));
910
+ }, timeout) : null;
911
+ proc.stdout.on("data", (data) => {
912
+ if (onOutput) {
913
+ const lines = data.toString().split(`
914
+ `);
915
+ for (const line of lines) {
916
+ if (line.trim()) {
917
+ onOutput(line.trim());
918
+ }
919
+ }
920
+ }
921
+ });
922
+ proc.stderr.on("data", (data) => {
923
+ if (onOutput) {
924
+ const lines = data.toString().split(`
925
+ `);
926
+ for (const line of lines) {
927
+ if (line.trim()) {
928
+ onOutput(line.trim());
929
+ }
930
+ }
931
+ }
932
+ });
933
+ proc.on("close", (exitCode) => {
934
+ if (timeoutHandle)
935
+ clearTimeout(timeoutHandle);
936
+ if (exitCode === 0) {
937
+ resolve3();
938
+ } else {
939
+ reject(new Error(`Command failed with exit code ${exitCode}`));
940
+ }
941
+ });
942
+ proc.on("error", (error) => {
943
+ if (timeoutHandle)
944
+ clearTimeout(timeoutHandle);
945
+ reject(error);
946
+ });
947
+ });
948
+ }
949
+ }
950
+ var __dirname = "/Users/AJT/projects/polly/packages/polly/tools/verify/src/runner", swept = false;
951
+ var init_docker = () => {};
952
+
669
953
  // tools/visualize/src/cli.ts
670
- import * as fs7 from "node:fs";
671
- import * as path6 from "node:path";
954
+ import * as fs8 from "node:fs";
955
+ import * as path7 from "node:path";
672
956
 
673
957
  // tools/analysis/src/extract/architecture.ts
674
958
  import * as fs4 from "node:fs";
@@ -1326,7 +1610,8 @@ class FlowAnalyzer {
1326
1610
  import {
1327
1611
  Node as Node4,
1328
1612
  Project as Project3,
1329
- SyntaxKind
1613
+ SyntaxKind,
1614
+ VariableDeclarationKind
1330
1615
  } from "ts-morph";
1331
1616
 
1332
1617
  // tools/analysis/src/extract/relationships.ts
@@ -2712,16 +2997,116 @@ class HandlerExtractor {
2712
2997
  return;
2713
2998
  }
2714
2999
  if (this.isTranslatableInitializer(initializer)) {
2715
- assignments.push({ field, value: `EXPR:${initializer.getText()}` });
3000
+ const captured = this.resolveSignalAliases(this.unwrapParentheses(initializer));
3001
+ assignments.push({ field, value: `EXPR:${captured}` });
2716
3002
  return;
2717
3003
  }
2718
- if (process.env["POLLY_DEBUG"]) {
2719
- const on = signalName ? ` on ${signalName}.value` : "";
2720
- console.log(`[WARN] dropped object-literal property '${name}'${on} — initializer kind ${initializer.getKindName()} is not translatable to TLA+`);
2721
- }
3004
+ const on = signalName ? ` on ${signalName}.value` : "";
3005
+ console.log(`[WARN] dropped object-literal property '${name}'${on} — initializer \`${initializer.getText().replace(/\s+/g, " ").slice(0, 80)}\` (${initializer.getKindName()}) is not translatable to TLA+`);
3006
+ }
3007
+ resolveSignalAliases(initializer) {
3008
+ const aliases = this.collectSignalAliases(initializer);
3009
+ if (aliases.size === 0)
3010
+ return initializer.getText();
3011
+ const base = initializer.getStart();
3012
+ const edits = [];
3013
+ const visit = (node) => {
3014
+ if (!Node4.isPropertyAccessExpression(node))
3015
+ return;
3016
+ const target = node.getExpression();
3017
+ if (!Node4.isIdentifier(target))
3018
+ return;
3019
+ const signal = aliases.get(target.getText());
3020
+ if (!signal)
3021
+ return;
3022
+ edits.push({
3023
+ start: target.getStart() - base,
3024
+ end: target.getEnd() - base,
3025
+ text: `${signal}.value`
3026
+ });
3027
+ };
3028
+ visit(initializer);
3029
+ initializer.forEachDescendant(visit);
3030
+ if (edits.length === 0)
3031
+ return initializer.getText();
3032
+ let text = initializer.getText();
3033
+ for (const edit of edits.sort((a, b) => b.start - a.start)) {
3034
+ text = text.slice(0, edit.start) + edit.text + text.slice(edit.end);
3035
+ }
3036
+ return text;
3037
+ }
3038
+ collectSignalAliases(node) {
3039
+ const aliases = new Map;
3040
+ const fn = node.getFirstAncestor((a) => Node4.isArrowFunction(a) || Node4.isFunctionExpression(a) || Node4.isFunctionDeclaration(a));
3041
+ if (!fn)
3042
+ return aliases;
3043
+ const reassigned = this.collectReassignedIdentifiers(fn);
3044
+ fn.forEachDescendant((inner) => {
3045
+ if (!Node4.isVariableDeclaration(inner))
3046
+ return;
3047
+ const binding = this.readSignalAliasBinding(inner);
3048
+ if (!binding)
3049
+ return;
3050
+ if (aliases.has(binding.signal))
3051
+ return;
3052
+ if (reassigned.has(binding.alias))
3053
+ return;
3054
+ aliases.set(binding.alias, binding.signal);
3055
+ });
3056
+ return aliases;
3057
+ }
3058
+ collectReassignedIdentifiers(fn) {
3059
+ const reassigned = new Set;
3060
+ fn.forEachDescendant((inner) => {
3061
+ if (!Node4.isBinaryExpression(inner))
3062
+ return;
3063
+ if (inner.getOperatorToken().getText() !== "=")
3064
+ return;
3065
+ const left = inner.getLeft();
3066
+ if (Node4.isIdentifier(left))
3067
+ reassigned.add(left.getText());
3068
+ });
3069
+ return reassigned;
3070
+ }
3071
+ readSignalAliasBinding(decl) {
3072
+ const list = decl.getParent();
3073
+ if (!Node4.isVariableDeclarationList(list))
3074
+ return null;
3075
+ if (list.getDeclarationKind() !== VariableDeclarationKind.Const)
3076
+ return null;
3077
+ const nameNode = decl.getNameNode();
3078
+ if (!Node4.isIdentifier(nameNode))
3079
+ return null;
3080
+ const init = decl.getInitializer();
3081
+ if (!init || !Node4.isPropertyAccessExpression(init))
3082
+ return null;
3083
+ if (init.getName() !== "value")
3084
+ return null;
3085
+ const target = init.getExpression();
3086
+ if (!Node4.isIdentifier(target))
3087
+ return null;
3088
+ return { alias: nameNode.getText(), signal: target.getText() };
2722
3089
  }
2723
3090
  isTranslatableInitializer(node) {
2724
- return Node4.isBinaryExpression(node) || Node4.isPropertyAccessExpression(node) || Node4.isElementAccessExpression(node) || Node4.isPrefixUnaryExpression(node) || Node4.isPostfixUnaryExpression(node) || Node4.isParenthesizedExpression(node);
3091
+ const kindAllowed = Node4.isBinaryExpression(node) || Node4.isPropertyAccessExpression(node) || Node4.isElementAccessExpression(node) || Node4.isPrefixUnaryExpression(node) || Node4.isPostfixUnaryExpression(node) || Node4.isParenthesizedExpression(node) || Node4.isConditionalExpression(node);
3092
+ if (!kindAllowed)
3093
+ return false;
3094
+ if (this.containsComment(node))
3095
+ return false;
3096
+ if (node.getFirstDescendantByKind(SyntaxKind.CallExpression))
3097
+ return false;
3098
+ return this.unwrapParentheses(node).getFirstDescendantByKind(SyntaxKind.ConditionalExpression) === undefined;
3099
+ }
3100
+ unwrapParentheses(node) {
3101
+ let current = node;
3102
+ while (Node4.isParenthesizedExpression(current)) {
3103
+ current = current.getExpression();
3104
+ }
3105
+ return current;
3106
+ }
3107
+ containsComment(node) {
3108
+ const text = node.getText();
3109
+ return text.includes("//") || text.includes("/*");
2725
3110
  }
2726
3111
  extractPayloadPropertyParam(initializer) {
2727
3112
  if (!Node4.isPropertyAccessExpression(initializer))
@@ -6486,24 +6871,25 @@ function generateStructurizrDSL(analysis, options) {
6486
6871
  }
6487
6872
 
6488
6873
  // tools/visualize/src/runner/export.ts
6489
- import { spawn } from "node:child_process";
6490
- import * as fs6 from "node:fs";
6491
- import * as path5 from "node:path";
6874
+ init_docker();
6875
+ import { spawn as spawn2 } from "node:child_process";
6876
+ import * as fs7 from "node:fs";
6877
+ import * as path6 from "node:path";
6492
6878
 
6493
6879
  class DiagramExporter {
6494
6880
  static DOCKER_IMAGE = "structurizr/structurizr:latest";
6495
6881
  static DEFAULT_TIMEOUT = 120000;
6496
6882
  async export(options) {
6497
6883
  const { dslPath, outputDir, timeout = DiagramExporter.DEFAULT_TIMEOUT } = options;
6498
- if (!fs6.existsSync(dslPath)) {
6884
+ if (!fs7.existsSync(dslPath)) {
6499
6885
  return {
6500
6886
  success: false,
6501
6887
  siteDir: "",
6502
6888
  error: `DSL file not found: ${dslPath}`
6503
6889
  };
6504
6890
  }
6505
- if (!fs6.existsSync(outputDir)) {
6506
- fs6.mkdirSync(outputDir, { recursive: true });
6891
+ if (!fs7.existsSync(outputDir)) {
6892
+ fs7.mkdirSync(outputDir, { recursive: true });
6507
6893
  }
6508
6894
  const dockerAvailable = await this.isDockerAvailable();
6509
6895
  if (!dockerAvailable) {
@@ -6536,13 +6922,16 @@ class DiagramExporter {
6536
6922
  }
6537
6923
  }
6538
6924
  async exportStaticSite(dslPath, outputDir, timeout) {
6539
- const dslDir = path5.dirname(dslPath);
6540
- const dslFileName = path5.basename(dslPath);
6925
+ const dslDir = path6.dirname(dslPath);
6926
+ const dslFileName = path6.basename(dslPath);
6541
6927
  const workspaceMount = `${dslDir}:/usr/local/structurizr`;
6542
6928
  const outputMount = `${outputDir}:/output`;
6929
+ const containerName = mintContainerName("structurizr");
6543
6930
  const args = [
6544
6931
  "run",
6545
6932
  "--rm",
6933
+ "--name",
6934
+ containerName,
6546
6935
  "-v",
6547
6936
  workspaceMount,
6548
6937
  "-v",
@@ -6556,7 +6945,7 @@ class DiagramExporter {
6556
6945
  "-o",
6557
6946
  "/output"
6558
6947
  ];
6559
- await this.runDocker(args, timeout);
6948
+ await this.runDocker(args, timeout, containerName);
6560
6949
  }
6561
6950
  async isDockerAvailable() {
6562
6951
  try {
@@ -6576,7 +6965,7 @@ class DiagramExporter {
6576
6965
  }
6577
6966
  async pullImage(onProgress) {
6578
6967
  return new Promise((resolve3, reject) => {
6579
- const proc = spawn("docker", ["pull", DiagramExporter.DOCKER_IMAGE]);
6968
+ const proc = spawn2("docker", ["pull", DiagramExporter.DOCKER_IMAGE]);
6580
6969
  proc.stdout.on("data", (data) => {
6581
6970
  onProgress?.(data.toString().trim());
6582
6971
  });
@@ -6595,16 +6984,19 @@ class DiagramExporter {
6595
6984
  });
6596
6985
  });
6597
6986
  }
6598
- async runDocker(args, timeout) {
6599
- return this.runCommand("docker", args, timeout);
6987
+ async runDocker(args, timeout, containerName) {
6988
+ return this.runCommand("docker", args, timeout, containerName);
6600
6989
  }
6601
- async runCommand(command, args, timeout) {
6990
+ async runCommand(command, args, timeout, containerName) {
6602
6991
  return new Promise((resolve3, reject) => {
6603
- const proc = spawn(command, args);
6992
+ const proc = spawn2(command, args);
6604
6993
  let stdout = "";
6605
6994
  let stderr = "";
6606
6995
  const timer = setTimeout(() => {
6607
- proc.kill();
6996
+ proc.kill("SIGKILL");
6997
+ if (containerName) {
6998
+ removeContainer(containerName);
6999
+ }
6608
7000
  reject(new Error(`Command timed out after ${timeout}ms`));
6609
7001
  }, timeout);
6610
7002
  proc.stdout.on("data", (data) => {
@@ -6741,7 +7133,7 @@ function findAndDisplayProjectConfig() {
6741
7133
  return { tsConfigPath, projectRoot };
6742
7134
  }
6743
7135
  function displayProjectType(projectRoot) {
6744
- const hasManifest = fs7.existsSync(path6.join(projectRoot, "manifest.json"));
7136
+ const hasManifest = fs8.existsSync(path7.join(projectRoot, "manifest.json"));
6745
7137
  const projectType = hasManifest ? "Chrome Extension" : "Detecting from project structure...";
6746
7138
  console.log(color(` Type: ${projectType}`, COLORS.gray));
6747
7139
  }
@@ -6786,16 +7178,16 @@ function generateAndWriteDSL(analysis, snapshot) {
6786
7178
  componentDiagramContexts: contextTypes.length > 0 ? contextTypes : ["background"],
6787
7179
  snapshot
6788
7180
  });
6789
- const outputDir = path6.join(process.cwd(), "docs");
6790
- if (!fs7.existsSync(outputDir)) {
6791
- fs7.mkdirSync(outputDir, { recursive: true });
7181
+ const outputDir = path7.join(process.cwd(), "docs");
7182
+ if (!fs8.existsSync(outputDir)) {
7183
+ fs8.mkdirSync(outputDir, { recursive: true });
6792
7184
  }
6793
- const dslPath = path6.join(outputDir, "architecture.dsl");
6794
- fs7.writeFileSync(dslPath, dsl, "utf-8");
7185
+ const dslPath = path7.join(outputDir, "architecture.dsl");
7186
+ fs8.writeFileSync(dslPath, dsl, "utf-8");
6795
7187
  return dslPath;
6796
7188
  }
6797
7189
  function displayNextSteps(dslPath) {
6798
- const outputDir = path6.join(process.cwd(), "docs");
7190
+ const outputDir = path7.join(process.cwd(), "docs");
6799
7191
  console.log(color(`✅ Architecture documentation generated!
6800
7192
  `, COLORS.green));
6801
7193
  console.log(` File: ${color(dslPath, COLORS.blue)}`);
@@ -6826,11 +7218,11 @@ async function exportCommand(_args) {
6826
7218
  \uD83D\uDCE4 Generating static site...
6827
7219
  `, COLORS.blue));
6828
7220
  try {
6829
- const dslPath = path6.join(process.cwd(), "docs", "architecture.dsl");
6830
- if (!fs7.existsSync(dslPath)) {
7221
+ const dslPath = path7.join(process.cwd(), "docs", "architecture.dsl");
7222
+ if (!fs8.existsSync(dslPath)) {
6831
7223
  process.exit(1);
6832
7224
  }
6833
- const outputDir = path6.join(process.cwd(), "docs", "site");
7225
+ const outputDir = path7.join(process.cwd(), "docs", "site");
6834
7226
  console.log(color(` DSL: ${dslPath}`, COLORS.gray));
6835
7227
  console.log(color(` Output: ${outputDir}`, COLORS.gray));
6836
7228
  console.log();
@@ -6863,9 +7255,9 @@ async function serveCommand(args) {
6863
7255
  \uD83C\uDF10 Starting static site server...
6864
7256
  `, COLORS.blue));
6865
7257
  try {
6866
- const siteDir = path6.join(process.cwd(), "docs", "site");
6867
- const indexPath = path6.join(siteDir, "index.html");
6868
- if (!fs7.existsSync(indexPath)) {
7258
+ const siteDir = path7.join(process.cwd(), "docs", "site");
7259
+ const indexPath = path7.join(siteDir, "index.html");
7260
+ if (!fs8.existsSync(indexPath)) {
6869
7261
  process.exit(1);
6870
7262
  }
6871
7263
  const portArg = args.find((arg) => arg.startsWith("--port="));
@@ -6881,8 +7273,8 @@ async function serveCommand(args) {
6881
7273
  port,
6882
7274
  fetch(req) {
6883
7275
  const url = new URL(req.url);
6884
- const filePath = path6.join(siteDir, url.pathname === "/" ? "index.html" : url.pathname);
6885
- if (fs7.existsSync(filePath) && fs7.statSync(filePath).isFile()) {
7276
+ const filePath = path7.join(siteDir, url.pathname === "/" ? "index.html" : url.pathname);
7277
+ if (fs8.existsSync(filePath) && fs8.statSync(filePath).isFile()) {
6886
7278
  const file = BunGlobal.file(filePath);
6887
7279
  return new Response(file);
6888
7280
  }
@@ -6966,20 +7358,20 @@ ${color("Learn More:", COLORS.blue)}
6966
7358
  }
6967
7359
  function findTsConfig() {
6968
7360
  const locations = [
6969
- path6.join(process.cwd(), "tsconfig.json"),
6970
- path6.join(process.cwd(), "..", "tsconfig.json")
7361
+ path7.join(process.cwd(), "tsconfig.json"),
7362
+ path7.join(process.cwd(), "..", "tsconfig.json")
6971
7363
  ];
6972
7364
  for (const loc of locations) {
6973
- if (fs7.existsSync(loc)) {
7365
+ if (fs8.existsSync(loc)) {
6974
7366
  return loc;
6975
7367
  }
6976
7368
  }
6977
7369
  return null;
6978
7370
  }
6979
7371
  function findProjectRoot() {
6980
- const locations = [process.cwd(), path6.join(process.cwd(), "..")];
7372
+ const locations = [process.cwd(), path7.join(process.cwd(), "..")];
6981
7373
  for (const loc of locations) {
6982
- if (fs7.existsSync(path6.join(loc, "manifest.json")) || fs7.existsSync(path6.join(loc, "package.json")) || fs7.existsSync(path6.join(loc, "tsconfig.json"))) {
7374
+ if (fs8.existsSync(path7.join(loc, "manifest.json")) || fs8.existsSync(path7.join(loc, "package.json")) || fs8.existsSync(path7.join(loc, "tsconfig.json"))) {
6983
7375
  return loc;
6984
7376
  }
6985
7377
  }
@@ -6989,4 +7381,4 @@ main().catch((_error) => {
6989
7381
  process.exit(1);
6990
7382
  });
6991
7383
 
6992
- //# debugId=4CA1C5520447E2E464756E2164756E21
7384
+ //# debugId=B0F08E74B7BC706B64756E2164756E21