@stackables/bridge-compiler 0.0.1 → 1.0.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/README.md ADDED
@@ -0,0 +1,49 @@
1
+ [![github](https://img.shields.io/badge/github-stackables/bridge-blue?logo=github)](https://github.com/stackables/bridge)
2
+
3
+ # The Bridge Compiler
4
+
5
+ The parser for [The Bridge](https://github.com/stackables/bridge) — turns `.bridge` source files into executable instructions.
6
+
7
+ ## Installing
8
+
9
+ ```bash
10
+ npm install @stackables/bridge-compiler
11
+ ```
12
+
13
+ ## Parsing a Bridge File
14
+
15
+ The most common thing you'll do — read a `.bridge` file and get instructions the engine can run:
16
+
17
+ ```ts
18
+ import { parseBridge } from "@stackables/bridge-compiler";
19
+ import { readFileSync } from "node:fs";
20
+
21
+ const source = readFileSync("logic.bridge", "utf8");
22
+ const instructions = parseBridge(source);
23
+
24
+ // → Instruction[] — feed this to executeBridge() or bridgeTransform()
25
+ ```
26
+
27
+ ## Serializing Back to `.bridge`
28
+
29
+ Round-trip support — parse a bridge file, then serialize the AST back into clean `.bridge` text:
30
+
31
+ ```ts
32
+ import {
33
+ parseBridgeFormat,
34
+ serializeBridge,
35
+ } from "@stackables/bridge-compiler";
36
+
37
+ const ast = parseBridgeFormat(source);
38
+ const formatted = serializeBridge(ast);
39
+ ```
40
+
41
+ ## Part of the Bridge Ecosystem
42
+
43
+ | Package | What it does |
44
+ | ---------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
45
+ | [`@stackables/bridge`](https://www.npmjs.com/package/@stackables/bridge) | **The All-in-One** — everything in a single install |
46
+ | [`@stackables/bridge-core`](https://www.npmjs.com/package/@stackables/bridge-core) | **The Engine** — runs the instructions this package produces |
47
+ | [`@stackables/bridge-graphql`](https://www.npmjs.com/package/@stackables/bridge-graphql) | **The Adapter** — wires bridges into a GraphQL schema |
48
+ | [`@stackables/bridge-stdlib`](https://www.npmjs.com/package/@stackables/bridge-stdlib) | **The Standard Library** — httpCall, strings, arrays, and more |
49
+ | [`@stackables/bridge-types`](https://www.npmjs.com/package/@stackables/bridge-types) | **Shared Types** — `ToolCallFn`, `ToolMap`, `CacheStore` |
@@ -1,8 +1,8 @@
1
- import type { Instruction } from "@stackables/bridge-core";
1
+ import type { BridgeDocument } from "@stackables/bridge-core";
2
2
  export { parsePath } from "@stackables/bridge-core";
3
3
  /**
4
4
  * Parse .bridge text — delegates to the Chevrotain parser.
5
5
  */
6
- export declare function parseBridge(text: string): Instruction[];
7
- export declare function serializeBridge(instructions: Instruction[]): string;
6
+ export declare function parseBridge(text: string): BridgeDocument;
7
+ export declare function serializeBridge(doc: BridgeDocument): string;
8
8
  //# sourceMappingURL=bridge-format.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"bridge-format.d.ts","sourceRoot":"","sources":["../src/bridge-format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAKV,WAAW,EAIZ,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEpD;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,EAAE,CAEvD;AAcD,wBAAgB,eAAe,CAAC,YAAY,EAAE,WAAW,EAAE,GAAG,MAAM,CAgCnE"}
1
+ {"version":3,"file":"bridge-format.d.ts","sourceRoot":"","sources":["../src/bridge-format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,cAAc,EAOf,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAEpD;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAExD;AAcD,wBAAgB,eAAe,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,CAkC3D"}
@@ -19,7 +19,9 @@ function serializeControl(ctrl) {
19
19
  return "break";
20
20
  }
21
21
  // ── Serializer ───────────────────────────────────────────────────────────────
22
- export function serializeBridge(instructions) {
22
+ export function serializeBridge(doc) {
23
+ const version = doc.version ?? BRIDGE_VERSION;
24
+ const { instructions } = doc;
23
25
  const bridges = instructions.filter((i) => i.kind === "bridge");
24
26
  const tools = instructions.filter((i) => i.kind === "tool");
25
27
  const consts = instructions.filter((i) => i.kind === "const");
@@ -43,7 +45,7 @@ export function serializeBridge(instructions) {
43
45
  for (const bridge of bridges) {
44
46
  blocks.push(serializeBridgeBlock(bridge));
45
47
  }
46
- return `version ${BRIDGE_VERSION}\n\n` + blocks.join("\n\n") + "\n";
48
+ return `version ${version}\n\n` + blocks.join("\n\n") + "\n";
47
49
  }
48
50
  /**
49
51
  * Whether a value string needs quoting to be re-parseable as a bare value.
@@ -100,7 +102,8 @@ function serializeToolBlock(tool) {
100
102
  }
101
103
  }
102
104
  else {
103
- lines.push(` with ${dep.tool} as ${dep.handle}`);
105
+ const depVTag = dep.version ? `@${dep.version}` : "";
106
+ lines.push(` with ${dep.tool}${depVTag} as ${dep.handle}`);
104
107
  }
105
108
  }
106
109
  // Wires
@@ -210,11 +213,12 @@ function serializeBridgeBlock(bridge) {
210
213
  // Short form `with <name>` when handle == last segment of name
211
214
  const lastDot = h.name.lastIndexOf(".");
212
215
  const defaultHandle = lastDot !== -1 ? h.name.substring(lastDot + 1) : h.name;
213
- if (h.handle === defaultHandle) {
216
+ const vTag = h.version ? `@${h.version}` : "";
217
+ if (h.handle === defaultHandle && !vTag) {
214
218
  lines.push(` with ${h.name}`);
215
219
  }
216
220
  else {
217
- lines.push(` with ${h.name} as ${h.handle}`);
221
+ lines.push(` with ${h.name}${vTag} as ${h.handle}`);
218
222
  }
219
223
  break;
220
224
  }
package/build/index.d.ts CHANGED
@@ -1,13 +1,13 @@
1
1
  /**
2
2
  * @stackables/bridge-compiler — Bridge DSL parser, serializer, and language service.
3
3
  *
4
- * Turns `.bridge` source text into `Instruction[]` (JSON AST) and provides
4
+ * Turns `.bridge` source text into `BridgeDocument` (JSON AST) and provides
5
5
  * IDE intelligence (diagnostics, completions, hover).
6
6
  */
7
- export { parseBridgeChevrotain as parseBridge, parseBridgeChevrotain, parseBridgeDiagnostics, } from "./parser/index.ts";
7
+ export { parseBridgeChevrotain as parseBridge, parseBridgeChevrotain, parseBridgeDiagnostics, PARSER_VERSION, } from "./parser/index.ts";
8
8
  export type { BridgeDiagnostic, BridgeParseResult } from "./parser/index.ts";
9
9
  export { BridgeLexer, allTokens } from "./parser/index.ts";
10
- export { parseBridge as parseBridgeFormat, serializeBridge } from "./bridge-format.ts";
10
+ export { parseBridge as parseBridgeFormat, serializeBridge, } from "./bridge-format.ts";
11
11
  export { BridgeLanguageService } from "./language-service.ts";
12
12
  export type { BridgeCompletion, BridgeHover, CompletionKind, Position, Range, } from "./language-service.ts";
13
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EACL,qBAAqB,IAAI,WAAW,EACpC,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC7E,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAI3D,OAAO,EAAE,WAAW,IAAI,iBAAiB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAIvF,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,YAAY,EACV,gBAAgB,EAChB,WAAW,EACX,cAAc,EACd,QAAQ,EACR,KAAK,GACN,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EACL,qBAAqB,IAAI,WAAW,EACpC,qBAAqB,EACrB,sBAAsB,EACtB,cAAc,GACf,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC7E,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAI3D,OAAO,EACL,WAAW,IAAI,iBAAiB,EAChC,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAI5B,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAC9D,YAAY,EACV,gBAAgB,EAChB,WAAW,EACX,cAAc,EACd,QAAQ,EACR,KAAK,GACN,MAAM,uBAAuB,CAAC"}
package/build/index.js CHANGED
@@ -1,13 +1,13 @@
1
1
  /**
2
2
  * @stackables/bridge-compiler — Bridge DSL parser, serializer, and language service.
3
3
  *
4
- * Turns `.bridge` source text into `Instruction[]` (JSON AST) and provides
4
+ * Turns `.bridge` source text into `BridgeDocument` (JSON AST) and provides
5
5
  * IDE intelligence (diagnostics, completions, hover).
6
6
  */
7
7
  // ── Parser ──────────────────────────────────────────────────────────────────
8
- export { parseBridgeChevrotain as parseBridge, parseBridgeChevrotain, parseBridgeDiagnostics, } from "./parser/index.js";
8
+ export { parseBridgeChevrotain as parseBridge, parseBridgeChevrotain, parseBridgeDiagnostics, PARSER_VERSION, } from "./parser/index.js";
9
9
  export { BridgeLexer, allTokens } from "./parser/index.js";
10
10
  // ── Serializer ──────────────────────────────────────────────────────────────
11
- export { parseBridge as parseBridgeFormat, serializeBridge } from "./bridge-format.js";
11
+ export { parseBridge as parseBridgeFormat, serializeBridge, } from "./bridge-format.js";
12
12
  // ── Language service ────────────────────────────────────────────────────────
13
13
  export { BridgeLanguageService } from "./language-service.js";
@@ -1 +1 @@
1
- {"version":3,"file":"language-service.d.ts","sourceRoot":"","sources":["../src/language-service.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAU1D,MAAM,MAAM,QAAQ,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAC3D,MAAM,MAAM,KAAK,GAAG;IAAE,KAAK,EAAE,QAAQ,CAAC;IAAC,GAAG,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEvD,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,GAAG,MAAM,CAAC;AAE1E,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,cAAc,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,uBAAuB;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,KAAK,CAAC;CACf,CAAC;AAoCF,qBAAa,qBAAqB;IAChC,OAAO,CAAC,IAAI,CAAM;IAClB,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,UAAU,CAAkC;IACpD,OAAO,CAAC,iBAAiB,CAA0B;IAEnD;;;;OAIG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAmB1B;;;;OAIG;IACH,cAAc,IAAI,gBAAgB,EAAE;IA+BpC;;OAEG;IACH,cAAc,CAAC,GAAG,EAAE,QAAQ,GAAG,gBAAgB,EAAE;IA4CjD;;;OAGG;IACH,QAAQ,CAAC,GAAG,EAAE,QAAQ,GAAG,WAAW,GAAG,IAAI;CAqE5C"}
1
+ {"version":3,"file":"language-service.d.ts","sourceRoot":"","sources":["../src/language-service.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAW1D,MAAM,MAAM,QAAQ,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC;AAC3D,MAAM,MAAM,KAAK,GAAG;IAAE,KAAK,EAAE,QAAQ,CAAC;IAAC,GAAG,EAAE,QAAQ,CAAA;CAAE,CAAC;AAEvD,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,GAAG,MAAM,CAAC;AAE1E,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,cAAc,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,WAAW,GAAG;IACxB,uBAAuB;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,KAAK,CAAC;CACf,CAAC;AAoCF,qBAAa,qBAAqB;IAChC,OAAO,CAAC,IAAI,CAAM;IAClB,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,YAAY,CAAqB;IACzC,OAAO,CAAC,UAAU,CAAkC;IACpD,OAAO,CAAC,iBAAiB,CAA0B;IAEnD;;;;OAIG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAmB1B;;;;OAIG;IACH,cAAc,IAAI,gBAAgB,EAAE;IAmEpC;;OAEG;IACH,cAAc,CAAC,GAAG,EAAE,QAAQ,GAAG,gBAAgB,EAAE;IA4CjD;;;OAGG;IACH,QAAQ,CAAC,GAAG,EAAE,QAAQ,GAAG,WAAW,GAAG,IAAI;CAqE5C"}
@@ -13,7 +13,8 @@
13
13
  * svc.getHover({ line, character });
14
14
  */
15
15
  import { parseBridgeDiagnostics } from "./parser/index.js";
16
- import { std } from "@stackables/bridge-stdlib";
16
+ import { collectVersionedHandles } from "@stackables/bridge-core";
17
+ import { std, STD_VERSION } from "@stackables/bridge-stdlib";
17
18
  // ── Internal lookup tables (built once at module load) ─────────────────────
18
19
  const builtinToolNames = [
19
20
  ...Object.keys(std).map((k) => `std.${k}`),
@@ -63,7 +64,7 @@ export class BridgeLanguageService {
63
64
  return;
64
65
  }
65
66
  const result = parseBridgeDiagnostics(text);
66
- this.instructions = result.instructions;
67
+ this.instructions = result.document.instructions;
67
68
  this.startLines = result.startLines;
68
69
  this.parserDiagnostics = result.diagnostics;
69
70
  }
@@ -98,6 +99,42 @@ export class BridgeLanguageService {
98
99
  }
99
100
  }
100
101
  }
102
+ // Check @version tags on tool handles against the bundled std version.
103
+ // Versions exceeding the bundled std emit a warning: the tool must be
104
+ // provided at runtime via the tools map.
105
+ const versioned = collectVersionedHandles(this.instructions);
106
+ if (versioned.length > 0) {
107
+ const stdParts = STD_VERSION.split(".").map(Number);
108
+ const [stdMajor = 0, stdMinor = 0] = stdParts;
109
+ for (const { name, version } of versioned) {
110
+ if (!name.startsWith("std."))
111
+ continue;
112
+ const vParts = version.split(".").map(Number);
113
+ const [vMajor = 0, vMinor = 0] = vParts;
114
+ if (vMajor === stdMajor && stdMinor >= vMinor)
115
+ continue;
116
+ // Find the line that contains this version tag so we can report it
117
+ const versionTag = `@${version}`;
118
+ for (let i = 0; i < this.lines.length; i++) {
119
+ const col = this.lines[i].indexOf(versionTag);
120
+ if (col === -1)
121
+ continue;
122
+ // Make sure it's adjacent to the tool name
123
+ if (!this.lines[i].includes(name + versionTag))
124
+ continue;
125
+ diags.push({
126
+ message: `"${name}@${version}" exceeds bundled std ${STD_VERSION}. ` +
127
+ `Provide this tool version at runtime via the tools map.`,
128
+ severity: "warning",
129
+ range: {
130
+ start: { line: i, character: col },
131
+ end: { line: i, character: col + versionTag.length },
132
+ },
133
+ });
134
+ break;
135
+ }
136
+ }
137
+ }
101
138
  return diags;
102
139
  }
103
140
  // ── Completions ────────────────────────────────────────────────────────
@@ -217,8 +254,10 @@ function getWordAt(line, character) {
217
254
  }
218
255
  function handleBindingMarkdown(h) {
219
256
  switch (h.kind) {
220
- case "tool":
221
- return `**Tool handle** \`${h.handle}\`\n\nSource: \`${h.name}\``;
257
+ case "tool": {
258
+ const ver = h.version ? ` @${h.version}` : "";
259
+ return `**Tool handle** \`${h.handle}\`\n\nSource: \`${h.name}${ver}\``;
260
+ }
222
261
  case "input":
223
262
  return `**Input handle** \`${h.handle}\`\n\nGraphQL field arguments`;
224
263
  case "output":
@@ -237,7 +276,9 @@ function toolDepMarkdown(d) {
237
276
  return `**Context dep** \`${d.handle}\`\n\nGraphQL execution context`;
238
277
  case "const":
239
278
  return `**Const dep** \`${d.handle}\`\n\nNamed constants declared in this file`;
240
- case "tool":
241
- return `**Tool dep** \`${d.handle}\`\n\nTool: \`${d.tool}\``;
279
+ case "tool": {
280
+ const ver = d.version ? ` @${d.version}` : "";
281
+ return `**Tool dep** \`${d.handle}\`\n\nTool: \`${d.tool}${ver}\``;
282
+ }
242
283
  }
243
284
  }
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Re-exports the public parse function as well as the lexer for direct access.
5
5
  */
6
- export { parseBridgeChevrotain, parseBridgeDiagnostics } from "./parser.ts";
6
+ export { parseBridgeChevrotain, parseBridgeDiagnostics, PARSER_VERSION, } from "./parser.ts";
7
7
  export type { BridgeDiagnostic, BridgeParseResult } from "./parser.ts";
8
8
  export { BridgeLexer, allTokens } from "./lexer.ts";
9
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/parser/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAC5E,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/parser/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,cAAc,GACf,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACvE,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC"}
@@ -3,5 +3,5 @@
3
3
  *
4
4
  * Re-exports the public parse function as well as the lexer for direct access.
5
5
  */
6
- export { parseBridgeChevrotain, parseBridgeDiagnostics } from "./parser.js";
6
+ export { parseBridgeChevrotain, parseBridgeDiagnostics, PARSER_VERSION, } from "./parser.js";
7
7
  export { BridgeLexer, allTokens } from "./lexer.js";
@@ -55,6 +55,7 @@ export declare const Equals: import("chevrotain").TokenType;
55
55
  export declare const Dot: import("chevrotain").TokenType;
56
56
  export declare const Colon: import("chevrotain").TokenType;
57
57
  export declare const Comma: import("chevrotain").TokenType;
58
+ export declare const VersionTag: import("chevrotain").TokenType;
58
59
  export declare const StringLiteral: import("chevrotain").TokenType;
59
60
  export declare const NumberLiteral: import("chevrotain").TokenType;
60
61
  export declare const TrueLiteral: import("chevrotain").TokenType;
@@ -1 +1 @@
1
- {"version":3,"file":"lexer.d.ts","sourceRoot":"","sources":["../../src/parser/lexer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"lexer.d.ts","sourceRoot":"","sources":["../../src/parser/lexer.ts"],"names":[],"mappings":"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"}
@@ -27,38 +27,145 @@ export const Identifier = createToken({
27
27
  pattern: /[a-zA-Z_][\w-]*/,
28
28
  });
29
29
  // ── Keywords ───────────────────────────────────────────────────────────────
30
- export const VersionKw = createToken({ name: "VersionKw", pattern: /version/i, longer_alt: Identifier });
31
- export const ToolKw = createToken({ name: "ToolKw", pattern: /tool/i, longer_alt: Identifier });
32
- export const BridgeKw = createToken({ name: "BridgeKw", pattern: /bridge/i, longer_alt: Identifier });
33
- export const DefineKw = createToken({ name: "DefineKw", pattern: /define/i, longer_alt: Identifier });
34
- export const ConstKw = createToken({ name: "ConstKw", pattern: /const/i, longer_alt: Identifier });
35
- export const WithKw = createToken({ name: "WithKw", pattern: /with/i, longer_alt: Identifier });
36
- export const AsKw = createToken({ name: "AsKw", pattern: /as/i, longer_alt: Identifier });
37
- export const FromKw = createToken({ name: "FromKw", pattern: /from/i, longer_alt: Identifier });
38
- export const InputKw = createToken({ name: "InputKw", pattern: /input/i, longer_alt: Identifier });
39
- export const OutputKw = createToken({ name: "OutputKw", pattern: /output/i, longer_alt: Identifier });
40
- export const ContextKw = createToken({ name: "ContextKw", pattern: /context/i, longer_alt: Identifier });
41
- export const OnKw = createToken({ name: "OnKw", pattern: /on/i, longer_alt: Identifier });
42
- export const ErrorKw = createToken({ name: "ErrorKw", pattern: /error/i, longer_alt: Identifier });
43
- export const ForceKw = createToken({ name: "ForceKw", pattern: /force/i, longer_alt: Identifier });
44
- export const AliasKw = createToken({ name: "AliasKw", pattern: /alias/i, longer_alt: Identifier });
45
- export const CatchKw = createToken({ name: "CatchKw", pattern: /catch/i, longer_alt: Identifier });
46
- export const AndKw = createToken({ name: "AndKw", pattern: /and/, longer_alt: Identifier });
47
- export const OrKw = createToken({ name: "OrKw", pattern: /or/, longer_alt: Identifier });
48
- export const NotKw = createToken({ name: "NotKw", pattern: /not/, longer_alt: Identifier });
49
- export const ThrowKw = createToken({ name: "ThrowKw", pattern: /throw/, longer_alt: Identifier });
50
- export const PanicKw = createToken({ name: "PanicKw", pattern: /panic/, longer_alt: Identifier });
51
- export const ContinueKw = createToken({ name: "ContinueKw", pattern: /continue/, longer_alt: Identifier });
52
- export const BreakKw = createToken({ name: "BreakKw", pattern: /break/, longer_alt: Identifier });
30
+ export const VersionKw = createToken({
31
+ name: "VersionKw",
32
+ pattern: /version/i,
33
+ longer_alt: Identifier,
34
+ });
35
+ export const ToolKw = createToken({
36
+ name: "ToolKw",
37
+ pattern: /tool/i,
38
+ longer_alt: Identifier,
39
+ });
40
+ export const BridgeKw = createToken({
41
+ name: "BridgeKw",
42
+ pattern: /bridge/i,
43
+ longer_alt: Identifier,
44
+ });
45
+ export const DefineKw = createToken({
46
+ name: "DefineKw",
47
+ pattern: /define/i,
48
+ longer_alt: Identifier,
49
+ });
50
+ export const ConstKw = createToken({
51
+ name: "ConstKw",
52
+ pattern: /const/i,
53
+ longer_alt: Identifier,
54
+ });
55
+ export const WithKw = createToken({
56
+ name: "WithKw",
57
+ pattern: /with/i,
58
+ longer_alt: Identifier,
59
+ });
60
+ export const AsKw = createToken({
61
+ name: "AsKw",
62
+ pattern: /as/i,
63
+ longer_alt: Identifier,
64
+ });
65
+ export const FromKw = createToken({
66
+ name: "FromKw",
67
+ pattern: /from/i,
68
+ longer_alt: Identifier,
69
+ });
70
+ export const InputKw = createToken({
71
+ name: "InputKw",
72
+ pattern: /input/i,
73
+ longer_alt: Identifier,
74
+ });
75
+ export const OutputKw = createToken({
76
+ name: "OutputKw",
77
+ pattern: /output/i,
78
+ longer_alt: Identifier,
79
+ });
80
+ export const ContextKw = createToken({
81
+ name: "ContextKw",
82
+ pattern: /context/i,
83
+ longer_alt: Identifier,
84
+ });
85
+ export const OnKw = createToken({
86
+ name: "OnKw",
87
+ pattern: /on/i,
88
+ longer_alt: Identifier,
89
+ });
90
+ export const ErrorKw = createToken({
91
+ name: "ErrorKw",
92
+ pattern: /error/i,
93
+ longer_alt: Identifier,
94
+ });
95
+ export const ForceKw = createToken({
96
+ name: "ForceKw",
97
+ pattern: /force/i,
98
+ longer_alt: Identifier,
99
+ });
100
+ export const AliasKw = createToken({
101
+ name: "AliasKw",
102
+ pattern: /alias/i,
103
+ longer_alt: Identifier,
104
+ });
105
+ export const CatchKw = createToken({
106
+ name: "CatchKw",
107
+ pattern: /catch/i,
108
+ longer_alt: Identifier,
109
+ });
110
+ export const AndKw = createToken({
111
+ name: "AndKw",
112
+ pattern: /and/,
113
+ longer_alt: Identifier,
114
+ });
115
+ export const OrKw = createToken({
116
+ name: "OrKw",
117
+ pattern: /or/,
118
+ longer_alt: Identifier,
119
+ });
120
+ export const NotKw = createToken({
121
+ name: "NotKw",
122
+ pattern: /not/,
123
+ longer_alt: Identifier,
124
+ });
125
+ export const ThrowKw = createToken({
126
+ name: "ThrowKw",
127
+ pattern: /throw/,
128
+ longer_alt: Identifier,
129
+ });
130
+ export const PanicKw = createToken({
131
+ name: "PanicKw",
132
+ pattern: /panic/,
133
+ longer_alt: Identifier,
134
+ });
135
+ export const ContinueKw = createToken({
136
+ name: "ContinueKw",
137
+ pattern: /continue/,
138
+ longer_alt: Identifier,
139
+ });
140
+ export const BreakKw = createToken({
141
+ name: "BreakKw",
142
+ pattern: /break/,
143
+ longer_alt: Identifier,
144
+ });
53
145
  // ── Operators & punctuation ────────────────────────────────────────────────
54
146
  export const Arrow = createToken({ name: "Arrow", pattern: /<-/ });
55
- export const NullCoalesce = createToken({ name: "NullCoalesce", pattern: /\|\|/ });
56
- export const ErrorCoalesce = createToken({ name: "ErrorCoalesce", pattern: /\?\?/ });
147
+ export const NullCoalesce = createToken({
148
+ name: "NullCoalesce",
149
+ pattern: /\|\|/,
150
+ });
151
+ export const ErrorCoalesce = createToken({
152
+ name: "ErrorCoalesce",
153
+ pattern: /\?\?/,
154
+ });
57
155
  export const SafeNav = createToken({ name: "SafeNav", pattern: /\?\./ });
58
- export const QuestionMark = createToken({ name: "QuestionMark", pattern: /\?/ });
59
- export const GreaterEqual = createToken({ name: "GreaterEqual", pattern: />=/ });
156
+ export const QuestionMark = createToken({
157
+ name: "QuestionMark",
158
+ pattern: /\?/,
159
+ });
160
+ export const GreaterEqual = createToken({
161
+ name: "GreaterEqual",
162
+ pattern: />=/,
163
+ });
60
164
  export const LessEqual = createToken({ name: "LessEqual", pattern: /<=/ });
61
- export const DoubleEquals = createToken({ name: "DoubleEquals", pattern: /==/ });
165
+ export const DoubleEquals = createToken({
166
+ name: "DoubleEquals",
167
+ pattern: /==/,
168
+ });
62
169
  export const NotEquals = createToken({ name: "NotEquals", pattern: /!=/ });
63
170
  export const GreaterThan = createToken({ name: "GreaterThan", pattern: />/ });
64
171
  export const LessThan = createToken({ name: "LessThan", pattern: /</ });
@@ -74,6 +181,10 @@ export const Equals = createToken({ name: "Equals", pattern: /=/ });
74
181
  export const Dot = createToken({ name: "Dot", pattern: /\./ });
75
182
  export const Colon = createToken({ name: "Colon", pattern: /:/ });
76
183
  export const Comma = createToken({ name: "Comma", pattern: /,/ });
184
+ export const VersionTag = createToken({
185
+ name: "VersionTag",
186
+ pattern: /@\d[\d.]*[\dx]*/,
187
+ });
77
188
  // ── Literals ───────────────────────────────────────────────────────────────
78
189
  export const StringLiteral = createToken({
79
190
  name: "StringLiteral",
@@ -83,9 +194,21 @@ export const NumberLiteral = createToken({
83
194
  name: "NumberLiteral",
84
195
  pattern: /-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/,
85
196
  });
86
- export const TrueLiteral = createToken({ name: "TrueLiteral", pattern: /true/, longer_alt: Identifier });
87
- export const FalseLiteral = createToken({ name: "FalseLiteral", pattern: /false/, longer_alt: Identifier });
88
- export const NullLiteral = createToken({ name: "NullLiteral", pattern: /null/, longer_alt: Identifier });
197
+ export const TrueLiteral = createToken({
198
+ name: "TrueLiteral",
199
+ pattern: /true/,
200
+ longer_alt: Identifier,
201
+ });
202
+ export const FalseLiteral = createToken({
203
+ name: "FalseLiteral",
204
+ pattern: /false/,
205
+ longer_alt: Identifier,
206
+ });
207
+ export const NullLiteral = createToken({
208
+ name: "NullLiteral",
209
+ pattern: /null/,
210
+ longer_alt: Identifier,
211
+ });
89
212
  export const PathToken = createToken({
90
213
  name: "PathToken",
91
214
  pattern: /\/[\w./-]+/,
@@ -120,6 +243,7 @@ export const allTokens = [
120
243
  Dot,
121
244
  Colon,
122
245
  Comma,
246
+ VersionTag,
123
247
  StringLiteral,
124
248
  // Keywords before Identifier (longer_alt prevents prefix stealing)
125
249
  VersionKw,
@@ -1,5 +1,14 @@
1
- import type { Instruction } from "@stackables/bridge-core";
2
- export declare function parseBridgeChevrotain(text: string): Instruction[];
1
+ import type { BridgeDocument, Instruction } from "@stackables/bridge-core";
2
+ /** Exported parser version metadata for runtime use. */
3
+ export declare const PARSER_VERSION: {
4
+ /** Current bridge language version */
5
+ readonly current: "1.5";
6
+ /** Minimum supported major version (inclusive) */
7
+ readonly minMajor: 1;
8
+ /** Maximum supported major version (inclusive) */
9
+ readonly maxMajor: 1;
10
+ };
11
+ export declare function parseBridgeChevrotain(text: string): BridgeDocument;
3
12
  export type BridgeDiagnostic = {
4
13
  message: string;
5
14
  severity: "error" | "warning";
@@ -15,7 +24,7 @@ export type BridgeDiagnostic = {
15
24
  };
16
25
  };
17
26
  export type BridgeParseResult = {
18
- instructions: Instruction[];
27
+ document: BridgeDocument;
19
28
  diagnostics: BridgeDiagnostic[];
20
29
  /** 1-based start line for each top-level instruction */
21
30
  startLines: Map<Instruction, number>;
@@ -1 +1 @@
1
- {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/parser/parser.ts"],"names":[],"mappings":"AAmEA,OAAO,KAAK,EAMV,WAAW,EAMZ,MAAM,yBAAyB,CAAC;AAimCjC,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,EAAE,CAEjE;AAID,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,KAAK,EAAE;QACL,KAAK,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,MAAM,CAAA;SAAE,CAAC;QAC3C,GAAG,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,MAAM,CAAA;SAAE,CAAC;KAC1C,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,WAAW,EAAE,gBAAgB,EAAE,CAAC;IAChC,wDAAwD;IACxD,UAAU,EAAE,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;CACtC,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,CA8DtE"}
1
+ {"version":3,"file":"parser.d.ts","sourceRoot":"","sources":["../../src/parser/parser.ts"],"names":[],"mappings":"AAoEA,OAAO,KAAK,EAEV,cAAc,EAKd,WAAW,EAMZ,MAAM,yBAAyB,CAAC;AAumCjC,wDAAwD;AACxD,eAAO,MAAM,cAAc;IACzB,sCAAsC;;IAEtC,kDAAkD;;IAElD,kDAAkD;;CAE1C,CAAC;AAMX,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAElE;AAID,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,KAAK,EAAE;QACL,KAAK,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,MAAM,CAAA;SAAE,CAAC;QAC3C,GAAG,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,SAAS,EAAE,MAAM,CAAA;SAAE,CAAC;KAC1C,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,cAAc,CAAC;IACzB,WAAW,EAAE,gBAAgB,EAAE,CAAC;IAChC,wDAAwD;IACxD,UAAU,EAAE,GAAG,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;CACtC,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,CA8DtE"}
@@ -5,7 +5,7 @@
5
5
  * Produces the *exact same* AST types (`Instruction[]`).
6
6
  */
7
7
  import { CstParser } from "chevrotain";
8
- import { allTokens, Identifier, VersionKw, ToolKw, BridgeKw, DefineKw, ConstKw, WithKw, AsKw, FromKw, InputKw, OutputKw, ContextKw, OnKw, ErrorKw, Arrow, ForceKw, AliasKw, AndKw, OrKw, NotKw, ThrowKw, PanicKw, ContinueKw, BreakKw, NullCoalesce, ErrorCoalesce, SafeNav, CatchKw, LParen, RParen, LCurly, RCurly, LSquare, RSquare, Equals, Dot, Colon, Comma, StringLiteral, NumberLiteral, PathToken, TrueLiteral, FalseLiteral, NullLiteral, Star, Slash, Plus, Minus, GreaterEqual, LessEqual, DoubleEquals, NotEquals, GreaterThan, LessThan, QuestionMark, BridgeLexer, } from "./lexer.js";
8
+ import { allTokens, Identifier, VersionKw, ToolKw, BridgeKw, DefineKw, ConstKw, WithKw, AsKw, FromKw, InputKw, OutputKw, ContextKw, OnKw, ErrorKw, Arrow, ForceKw, AliasKw, AndKw, OrKw, NotKw, ThrowKw, PanicKw, ContinueKw, BreakKw, NullCoalesce, ErrorCoalesce, SafeNav, CatchKw, LParen, RParen, LCurly, RCurly, LSquare, RSquare, Equals, Dot, Colon, Comma, StringLiteral, NumberLiteral, PathToken, TrueLiteral, FalseLiteral, NullLiteral, Star, Slash, Plus, Minus, GreaterEqual, LessEqual, DoubleEquals, NotEquals, GreaterThan, LessThan, QuestionMark, VersionTag, BridgeLexer, } from "./lexer.js";
9
9
  import { SELF_MODULE } from "@stackables/bridge-core";
10
10
  // ── Reserved-word guards (mirroring the regex parser) ──────────────────────
11
11
  const RESERVED_KEYWORDS = new Set([
@@ -160,6 +160,9 @@ class BridgeParser extends CstParser {
160
160
  },
161
161
  ALT: () => {
162
162
  this.SUBRULE(this.dottedName, { LABEL: "toolName" });
163
+ this.OPTION3(() => {
164
+ this.CONSUME(VersionTag, { LABEL: "toolVersion" });
165
+ });
163
166
  this.CONSUME3(AsKw);
164
167
  this.SUBRULE3(this.nameToken, { LABEL: "toolAlias" });
165
168
  },
@@ -350,6 +353,9 @@ class BridgeParser extends CstParser {
350
353
  },
351
354
  ALT: () => {
352
355
  this.SUBRULE(this.dottedName, { LABEL: "refName" });
356
+ this.OPTION6(() => {
357
+ this.CONSUME(VersionTag, { LABEL: "refVersion" });
358
+ });
353
359
  this.OPTION5(() => {
354
360
  this.CONSUME5(AsKw);
355
361
  this.SUBRULE5(this.nameToken, { LABEL: "refAlias" });
@@ -1051,6 +1057,19 @@ const parserInstance = new BridgeParser();
1051
1057
  // Lenient instance: error recovery enabled (used by parseBridgeDiagnostics)
1052
1058
  const diagParserInstance = new BridgeParser({ recovery: true });
1053
1059
  const BRIDGE_VERSION = "1.5";
1060
+ /** Minimum major version the parser can handle (inclusive). */
1061
+ const BRIDGE_MIN_MAJOR = 1;
1062
+ /** Maximum major version the parser can handle (inclusive). */
1063
+ const BRIDGE_MAX_MAJOR = 1;
1064
+ /** Exported parser version metadata for runtime use. */
1065
+ export const PARSER_VERSION = {
1066
+ /** Current bridge language version */
1067
+ current: BRIDGE_VERSION,
1068
+ /** Minimum supported major version (inclusive) */
1069
+ minMajor: BRIDGE_MIN_MAJOR,
1070
+ /** Maximum supported major version (inclusive) */
1071
+ maxMajor: BRIDGE_MAX_MAJOR,
1072
+ };
1054
1073
  // ═══════════════════════════════════════════════════════════════════════════
1055
1074
  // Public API
1056
1075
  // ═══════════════════════════════════════════════════════════════════════════
@@ -1100,11 +1119,11 @@ export function parseBridgeDiagnostics(text) {
1100
1119
  });
1101
1120
  }
1102
1121
  // 3. Visit → AST (semantic errors thrown as "Line N: ..." messages)
1103
- let instructions = [];
1122
+ let document = { instructions: [] };
1104
1123
  let startLines = new Map();
1105
1124
  try {
1106
1125
  const result = toBridgeAst(cst, []);
1107
- instructions = result.instructions;
1126
+ document = { version: result.version, instructions: result.instructions };
1108
1127
  startLines = result.startLines;
1109
1128
  }
1110
1129
  catch (err) {
@@ -1120,7 +1139,7 @@ export function parseBridgeDiagnostics(text) {
1120
1139
  },
1121
1140
  });
1122
1141
  }
1123
- return { instructions, diagnostics, startLines };
1142
+ return { document, diagnostics, startLines };
1124
1143
  }
1125
1144
  function internalParse(text, previousInstructions) {
1126
1145
  // 1. Lex
@@ -1137,7 +1156,8 @@ function internalParse(text, previousInstructions) {
1137
1156
  throw new Error(e.message);
1138
1157
  }
1139
1158
  // 3. Visit → AST
1140
- return toBridgeAst(cst, previousInstructions).instructions;
1159
+ const result = toBridgeAst(cst, previousInstructions);
1160
+ return { version: result.version, instructions: result.instructions };
1141
1161
  }
1142
1162
  // ═══════════════════════════════════════════════════════════════════════════
1143
1163
  // CST → AST transformation (imperative visitor)
@@ -2204,9 +2224,22 @@ function toBridgeAst(cst, previousInstructions) {
2204
2224
  }
2205
2225
  const versionTok = tok(versionDecl, "ver");
2206
2226
  const versionNum = versionTok?.image;
2207
- if (versionNum !== BRIDGE_VERSION) {
2208
- throw new Error(`Unsupported bridge version "${versionNum}". This parser requires: version ${BRIDGE_VERSION}`);
2227
+ if (!versionNum) {
2228
+ throw new Error(`Missing version number. Bridge files must begin with: version ${BRIDGE_VERSION}`);
2229
+ }
2230
+ // Accept any version whose major falls within the supported range.
2231
+ // When the parser supports multiple majors (e.g. 1.x through 2.x),
2232
+ // bridge files from any of them are valid syntax.
2233
+ const vParts = versionNum.split(".");
2234
+ const vMajor = parseInt(vParts[0], 10);
2235
+ const supportedRange = BRIDGE_MIN_MAJOR === BRIDGE_MAX_MAJOR
2236
+ ? `${BRIDGE_MIN_MAJOR}.x`
2237
+ : `${BRIDGE_MIN_MAJOR}.x – ${BRIDGE_MAX_MAJOR}.x`;
2238
+ if (isNaN(vMajor) || vMajor < BRIDGE_MIN_MAJOR || vMajor > BRIDGE_MAX_MAJOR) {
2239
+ throw new Error(`Unsupported bridge major version "${versionNum}". This parser supports version ${supportedRange}`);
2209
2240
  }
2241
+ // Store the declared version (lives on BridgeDocument, not in instructions).
2242
+ const version = versionNum;
2210
2243
  const tagged = [];
2211
2244
  for (const n of subs(cst, "constDecl"))
2212
2245
  tagged.push({
@@ -2270,7 +2303,7 @@ function toBridgeAst(cst, previousInstructions) {
2270
2303
  }
2271
2304
  }
2272
2305
  }
2273
- return { instructions, startLines };
2306
+ return { version, instructions, startLines };
2274
2307
  }
2275
2308
  // ── Const ───────────────────────────────────────────────────────────────
2276
2309
  function buildConstDef(node) {
@@ -2319,7 +2352,13 @@ function buildToolDef(node, previousInstructions) {
2319
2352
  else if (wc.toolName) {
2320
2353
  const tName = extractDottedName(wc.toolName[0]);
2321
2354
  const tAlias = extractNameToken(wc.toolAlias[0]);
2322
- deps.push({ kind: "tool", handle: tAlias, tool: tName });
2355
+ const tVersion = wc.toolVersion?.[0]?.image.slice(1);
2356
+ deps.push({
2357
+ kind: "tool",
2358
+ handle: tAlias,
2359
+ tool: tName,
2360
+ ...(tVersion ? { version: tVersion } : {}),
2361
+ });
2323
2362
  }
2324
2363
  continue;
2325
2364
  }
@@ -2400,10 +2439,10 @@ function buildBridge(node, previousInstructions) {
2400
2439
  `}`,
2401
2440
  ].join("\n");
2402
2441
  const result = internalParse(expandedText, previousInstructions);
2403
- const bridgeInst = result.find((i) => i.kind === "bridge");
2442
+ const bridgeInst = result.instructions.find((i) => i.kind === "bridge");
2404
2443
  if (bridgeInst)
2405
2444
  bridgeInst.passthrough = passthroughName;
2406
- return result;
2445
+ return result.instructions;
2407
2446
  }
2408
2447
  // Full bridge block
2409
2448
  const bodyLines = subs(node, "bridgeBodyLine");
@@ -2530,6 +2569,7 @@ function buildBridgeBody(bodyLines, bridgeType, bridgeField, previousInstruction
2530
2569
  }
2531
2570
  else if (wc.refName) {
2532
2571
  const name = extractDottedName(wc.refName[0]);
2572
+ const versionTag = wc.refVersion?.[0]?.image.slice(1);
2533
2573
  const lastDot = name.lastIndexOf(".");
2534
2574
  const defaultHandle = lastDot !== -1 ? name.substring(lastDot + 1) : name;
2535
2575
  const handle = wc.refAlias
@@ -2554,7 +2594,12 @@ function buildBridgeBody(bodyLines, bridgeType, bridgeField, previousInstruction
2554
2594
  const key = `${modulePart}:${fieldPart}`;
2555
2595
  const instance = (instanceCounters.get(key) ?? 0) + 1;
2556
2596
  instanceCounters.set(key, instance);
2557
- handleBindings.push({ handle, kind: "tool", name });
2597
+ handleBindings.push({
2598
+ handle,
2599
+ kind: "tool",
2600
+ name,
2601
+ ...(versionTag ? { version: versionTag } : {}),
2602
+ });
2558
2603
  handleRes.set(handle, {
2559
2604
  module: modulePart,
2560
2605
  type: bridgeType,
@@ -2566,7 +2611,12 @@ function buildBridgeBody(bodyLines, bridgeType, bridgeField, previousInstruction
2566
2611
  const key = `Tools:${name}`;
2567
2612
  const instance = (instanceCounters.get(key) ?? 0) + 1;
2568
2613
  instanceCounters.set(key, instance);
2569
- handleBindings.push({ handle, kind: "tool", name });
2614
+ handleBindings.push({
2615
+ handle,
2616
+ kind: "tool",
2617
+ name,
2618
+ ...(versionTag ? { version: versionTag } : {}),
2619
+ });
2570
2620
  handleRes.set(handle, {
2571
2621
  module: SELF_MODULE,
2572
2622
  type: "Tools",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackables/bridge-compiler",
3
- "version": "0.0.1",
3
+ "version": "1.0.0",
4
4
  "description": "Bridge DSL parser, serializer, and language service",
5
5
  "main": "./build/index.js",
6
6
  "type": "module",
@@ -23,8 +23,8 @@
23
23
  "license": "MIT",
24
24
  "dependencies": {
25
25
  "chevrotain": "^11.1.2",
26
- "@stackables/bridge-core": "0.0.1",
27
- "@stackables/bridge-stdlib": "0.0.1"
26
+ "@stackables/bridge-core": "1.0.0",
27
+ "@stackables/bridge-stdlib": "1.5.0"
28
28
  },
29
29
  "devDependencies": {
30
30
  "@types/node": "^25.3.2",