@listen-fire/movement-lang 0.12.0-rc.6 → 0.12.0-rc.7

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.
@@ -1,4 +1,3 @@
1
- import type { LanguageVersion } from '../language_version';
2
1
  import type { EdgeCapability, EdgeSequencing, Expression, FieldCapability } from '../expression/types';
3
2
  /**
4
3
  * One argument in an adapter's construction signature. The list is the full
@@ -277,16 +276,6 @@ export interface PluginSpec {
277
276
  * goes to the extractor, not to a name.
278
277
  */
279
278
  output?: PluginOutput;
280
- /**
281
- * The shapes `output` had before it changed: each is what a plain call hands
282
- * back to a program pinned before language version `before`, earliest
283
- * first. A call is typed under its program's pin (`pluginOutputUnder`);
284
- * removing a language version removes its entries.
285
- */
286
- earlierOutputs?: ReadonlyArray<{
287
- before: LanguageVersion;
288
- output: PluginOutput;
289
- }>;
290
279
  /** The package tag it is a member of (`@lf/web`), matched exactly
291
280
  * (`packageMembers`); absent when it is in none. */
292
281
  package?: string;
@@ -313,7 +302,7 @@ export declare function pluginKey(packageTag: string, name: string): string;
313
302
  export declare function pluginProgramNameOf(key: string, spec: PluginSpec): string;
314
303
  /** What a written plugin name stands for among `plugins`: the entry keyed by
315
304
  * exactly that (a package member's key), else the one entry whose name it is
316
- * (a bare import, as versions 1 to 4 write it); several such are `ambiguous`,
305
+ * (a bare import, as the older language writes it); several such are `ambiguous`,
317
306
  * listing the packages that serve it. The Rust twin is `find_plugin`. */
318
307
  export declare function findPlugin(plugins: Readonly<Record<string, PluginSpec>>, name: string): {
319
308
  found: {
@@ -519,7 +508,7 @@ export interface EdgeSchema {
519
508
  * The edge is the one the system declared as its records' resources (the
520
509
  * describe's reserved `_resources` reference — the knowledge graph's
521
510
  * `Resources`). An ordinary edge, walked by its name like any other; what
522
- * the flag records is that a pre-version-5 `x-[f:_resources]->` on this
511
+ * the flag records is that an older `x-[f:_resources]->` on this
523
512
  * system read it, so MOV_RESOURCES_NOT_EXTRACTED can name it. Diagnostics
524
513
  * only: nothing resolves `_resources` to it.
525
514
  */
@@ -662,8 +651,7 @@ export interface PositionSchema {
662
651
  /**
663
652
  * A record of this type can be DELETED — the system's own promise, declared
664
653
  * per type in its describe (`deletable: true`) where its `deleteRecord`
665
- * removes one. Absent ⇒ it makes no such promise, and since language
666
- * version 5 `delete x` of this type is MOV_DELETE_NOT_DECLARED (an
654
+ * removes one. Absent ⇒ it makes no such promise, and `delete x` of this type is MOV_DELETE_NOT_DECLARED (an
667
655
  * undescribed or pending position says nothing, so nothing is refused).
668
656
  */
669
657
  deletable?: boolean;
@@ -76,15 +76,15 @@ function unquoteConstructionArg(raw) {
76
76
  }
77
77
  return trimmed;
78
78
  }
79
- // ── A plugin's arguments by position (language version 5, design §2.7) ──
79
+ // ── A plugin's arguments by position (design §2.7) ──
80
80
  //
81
81
  // Its required inputs in the manifest's declared order, then one optional
82
82
  // settings record `{ name: value }` for the rest. Binding turns that call into
83
- // the named arguments versions 1–4 write, so every check and the wire to the
83
+ // the named arguments the older language writes, so every check and the wire to the
84
84
  // plugin read one form. The Rust twin is `PluginSpec::bind_args`
85
85
  // (crates/movement-parser/src/catalog/plugin_args.rs); both checkers and both
86
86
  // engines bind through these two and nothing else.
87
- // ── A plugin package (language version 5, design §2.10, §4.3) ──
87
+ // ── A plugin package (design §2.10, §4.3) ──
88
88
  //
89
89
  // A tag a plugin's spec declares as its `package`, matched exactly and never
90
90
  // parsed. ``import { `@lf/web` as web } from plugins`` binds each member under
@@ -102,7 +102,7 @@ function pluginProgramNameOf(key, spec) {
102
102
  }
103
103
  /** What a written plugin name stands for among `plugins`: the entry keyed by
104
104
  * exactly that (a package member's key), else the one entry whose name it is
105
- * (a bare import, as versions 1 to 4 write it); several such are `ambiguous`,
105
+ * (a bare import, as the older language writes it); several such are `ambiguous`,
106
106
  * listing the packages that serve it. The Rust twin is `find_plugin`. */
107
107
  function findPlugin(plugins, name) {
108
108
  const exact = Object.hasOwn(plugins, name) ? plugins[name] : undefined;
@@ -148,7 +148,7 @@ function refinementKey(input) {
148
148
  }
149
149
  /**
150
150
  * The filter with its field reads' `fieldOnly` marks dropped. The mark says
151
- * how a read was SPELLED — through the hop's alias from version 5
151
+ * how a read was SPELLED — through the hop's alias
152
152
  * (`e.action`), bare before (`action`) — and both spellings name the same
153
153
  * field, so the key must not tell them apart: a host registers its narrowing
154
154
  * once, from its own filter, and every version's program must find it.
@@ -1,9 +1,11 @@
1
- import type { LanguageVersion } from '../language_version';
1
+ import { type LanguageVersion, type LanguageVersionStanding } from '../language_version';
2
2
  import type { CatalogSnapshot } from '../service/snapshot';
3
3
  import type { Diagnostic } from './diagnostic';
4
4
  export interface RustCheckOptions {
5
+ /** The movement's pin, held to the rule before the artifact is asked: the
6
+ * artifact checks in its own release's language. */
5
7
  languageVersion: LanguageVersion;
6
- /** Checking for a move up from this version (`CheckOptions.upgradingFrom`). */
8
+ /** Checking for a move up from this release (`CheckOptions.upgradingFrom`). */
7
9
  upgradingFrom?: LanguageVersion;
8
10
  }
9
11
  /** A source the Rust checker could not check: it does not parse, or the
@@ -11,8 +13,18 @@ export interface RustCheckOptions {
11
13
  export declare class RustCheckRefused extends Error {
12
14
  constructor(message: string);
13
15
  }
16
+ /** The language the artifact reads: its release's version. */
17
+ export declare function languageVersion(): LanguageVersion;
18
+ /** How `pin` stands against the artifact's release, and the refusal's text
19
+ * when it does not read it (the rule in Rust: the drift test holds it equal
20
+ * to `languageVersionStanding`). */
21
+ export declare function languageStanding(pin: string): {
22
+ standing: LanguageVersionStanding;
23
+ message: string | null;
24
+ };
14
25
  /** Every diagnostic the Rust checker reports for `source` against
15
- * `snapshot`, warnings and info included. */
26
+ * `snapshot`, warnings and info included. A pin this release does not read
27
+ * is its standing diagnostic alone, the artifact not asked. */
16
28
  export declare function checkSourceInRust(source: string, snapshot: CatalogSnapshot, options: RustCheckOptions): Diagnostic[];
17
29
  /** A checker fact about one node, keyed by its AST path (a JSON Pointer from
18
30
  * the Program, `file` naming a library's): a write spread's field list, a
@@ -66,7 +78,6 @@ export declare function checkAnswerInRust(source: string, snapshot: CatalogSnaps
66
78
  * when the schema enumerates nothing at the record type. */
67
79
  export declare function compatibleInRust(request: {
68
80
  source: string;
69
- languageVersion: LanguageVersion;
70
81
  declaration: string;
71
82
  schema: unknown;
72
83
  recordType: string;
@@ -10,10 +10,13 @@
10
10
  // editor's live diagnostics stay on the TypeScript checker.
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.RustCheckRefused = void 0;
13
+ exports.languageVersion = languageVersion;
14
+ exports.languageStanding = languageStanding;
13
15
  exports.checkSourceInRust = checkSourceInRust;
14
16
  exports.checkAnswerInRust = checkAnswerInRust;
15
17
  exports.compatibleInRust = compatibleInRust;
16
18
  const loader_1 = require("../wasm/loader");
19
+ const language_version_1 = require("../language_version");
17
20
  /** A source the Rust checker could not check: it does not parse, or the
18
21
  * snapshot does not load. */
19
22
  class RustCheckRefused extends Error {
@@ -23,10 +26,35 @@ class RustCheckRefused extends Error {
23
26
  }
24
27
  }
25
28
  exports.RustCheckRefused = RustCheckRefused;
29
+ /** The language the artifact reads: its release's version. */
30
+ function languageVersion() {
31
+ const reply = (0, loader_1.callLanguageVersion)();
32
+ if (!reply.ok || typeof reply.json !== 'string')
33
+ throw new Error(`language_version: ${JSON.stringify(reply.json)}`);
34
+ return reply.json;
35
+ }
36
+ /** How `pin` stands against the artifact's release, and the refusal's text
37
+ * when it does not read it (the rule in Rust: the drift test holds it equal
38
+ * to `languageVersionStanding`). */
39
+ function languageStanding(pin) {
40
+ const reply = (0, loader_1.callLanguageStanding)(pin);
41
+ const json = reply.json;
42
+ if (!reply.ok || !isRecord(json) || !isStanding(json.standing) || (json.message !== null && typeof json.message !== 'string')) {
43
+ throw new Error(`language_standing: ${JSON.stringify(json)}`);
44
+ }
45
+ return { standing: json.standing, message: json.message };
46
+ }
47
+ function isStanding(value) {
48
+ return value === 'compatible' || value === 'newer' || value === 'olderKey' || value === 'malformed';
49
+ }
26
50
  /** Every diagnostic the Rust checker reports for `source` against
27
- * `snapshot`, warnings and info included. */
51
+ * `snapshot`, warnings and info included. A pin this release does not read
52
+ * is its standing diagnostic alone, the artifact not asked. */
28
53
  function checkSourceInRust(source, snapshot, options) {
29
- const reply = (0, loader_1.callCheckProgram)(source, JSON.stringify(snapshot), options.languageVersion, options.upgradingFrom ?? 0);
54
+ const refusal = (0, language_version_1.languageVersionDiagnostic)(options.languageVersion);
55
+ if (refusal !== undefined)
56
+ return [refusal];
57
+ const reply = (0, loader_1.callCheckProgram)(source, JSON.stringify(snapshot), callOptions(options));
30
58
  const json = reply.json;
31
59
  if (!reply.ok)
32
60
  throw refused(json);
@@ -37,7 +65,10 @@ function checkSourceInRust(source, snapshot, options) {
37
65
  }
38
66
  /** `checkSourceInRust` as data (crates/movement-checker/src/answer.rs). */
39
67
  function checkAnswerInRust(source, snapshot, options) {
40
- const reply = (0, loader_1.callCheckAnswer)(source, JSON.stringify(snapshot), options.languageVersion, options.upgradingFrom ?? 0);
68
+ const refusal = (0, language_version_1.languageVersionDiagnostic)(options.languageVersion);
69
+ if (refusal !== undefined)
70
+ return { diagnostics: [refusal], stamps: [] };
71
+ const reply = (0, loader_1.callCheckAnswer)(source, JSON.stringify(snapshot), callOptions(options));
41
72
  const json = reply.json;
42
73
  if (!reply.ok)
43
74
  throw refused(json);
@@ -65,6 +96,9 @@ function compatibleInRust(request) {
65
96
  return { fits: json.fits };
66
97
  throw new Error(`the Rust checker answered check.compatible with ${JSON.stringify(json)}`);
67
98
  }
99
+ function callOptions(options) {
100
+ return options.upgradingFrom === undefined ? {} : { upgradingFrom: options.upgradingFrom };
101
+ }
68
102
  function refused(json) {
69
103
  const error = isRecord(json) && isRecord(json.error) ? json.error : undefined;
70
104
  return new RustCheckRefused(typeof error?.message === 'string' ? error.message : 'the Rust checker refused the check');
@@ -1,15 +1,16 @@
1
1
  import type { Expression } from './types';
2
2
  import type { ExprSlot } from '../parser/ast';
3
+ import type { LanguageVersion } from '../language_version';
3
4
  import { type MovementCondition } from '../parser/expression/lower';
4
5
  import type { MExpr } from '../parser/expression/tree';
5
6
  export { BridgeError } from './error';
6
7
  export { POSITION_SENTINEL, type MovementCondition } from '../parser/expression/lower';
7
- export declare function parseMovementExpression(raw: string, languageVersion?: number): Expression;
8
- export declare function parseMovementCondition(raw: string, languageVersion?: number): MovementCondition;
8
+ export declare function parseMovementExpression(raw: string, languageVersion?: LanguageVersion): Expression;
9
+ export declare function parseMovementCondition(raw: string, languageVersion?: LanguageVersion): MovementCondition;
9
10
  /** The slot's tree as the grammar read it, before lowering decides what any
10
11
  * name in it means — what call resolution walks. Throws the slot's syntax
11
12
  * error, as the lowerings below do. */
12
- export declare function treeOfSlot(slot: ExprSlot, languageVersion?: number): MExpr;
13
+ export declare function treeOfSlot(slot: ExprSlot, languageVersion?: LanguageVersion): MExpr;
13
14
  /**
14
15
  * A slot whose tree is `tree` — a rewriting of `slot`'s own tree (a nested
15
16
  * call replaced by the name it is bound to), or one of its sub-expressions.
@@ -23,9 +24,9 @@ export declare function slotOfTree(slot: ExprSlot, tree: MExpr): ExprSlot;
23
24
  * original's offsets, so a place in one is the same place in the other. */
24
25
  export declare function originalSlot(slot: ExprSlot): ExprSlot;
25
26
  /** The slot as a value expression. */
26
- export declare function expressionOfSlot(slot: ExprSlot, languageVersion?: number): Expression;
27
+ export declare function expressionOfSlot(slot: ExprSlot, languageVersion?: LanguageVersion): Expression;
27
28
  /** The slot as an `if` condition. */
28
- export declare function conditionOfSlot(slot: ExprSlot, languageVersion?: number): MovementCondition;
29
+ export declare function conditionOfSlot(slot: ExprSlot, languageVersion?: LanguageVersion): MovementCondition;
29
30
  /**
30
31
  * A string slot's text for a READER — the story, a diagnostic, a listing.
31
32
  * A literal that interpolates has no text until it is evaluated in a firing
@@ -299,10 +299,10 @@ export declare function objectMemberExpression(member: ObjectMember): Expression
299
299
  /** An object member rebuilt with `rewrite` applied to its expression. */
300
300
  export declare function mapObjectMember(member: ObjectMember, rewrite: (expr: Expression) => Expression): ObjectMember;
301
301
  export type Expression =
302
- /** `fieldOnly`: a hop's alias read from language version 5 (`m.email`),
302
+ /** `fieldOnly`: a hop's alias read (`m.email`),
303
303
  * always the field of the record the hop lands on. Without it a name in a
304
304
  * hop's WHERE is a variable when one is in scope, else the field (the
305
- * reading versions 1–4 keep). A source given the filter reads both as the
305
+ * reading the older language keeps). A source given the filter reads both as the
306
306
  * field, as it always has. */
307
307
  {
308
308
  type: 'property';
@@ -1,58 +1,28 @@
1
1
  import type { Diagnostic } from './checker/diagnostic';
2
- /** A language version's identity. */
3
- export type LanguageVersion = number;
4
- export interface LanguageVersionInfo {
5
- version: LanguageVersion;
6
- /** Display only. */
7
- name: string;
8
- /** What the version is, for release notes and people. */
9
- is: string;
10
- }
11
- export declare const LANGUAGE_VERSIONS: readonly LanguageVersionInfo[];
12
- /** What a movement saved today is pinned to, and what an entry point given no
13
- * version compiles and runs under. */
14
- export declare const CURRENT_LANGUAGE_VERSION: LanguageVersion;
15
- /** The versions this release parses, checks and runs. */
16
- export declare const SUPPORTED_LANGUAGE_VERSIONS: ReadonlySet<LanguageVersion>;
17
- /** Supported versions that will be removed: they still run, with a warning. */
18
- export declare const DEPRECATED_LANGUAGE_VERSIONS: ReadonlySet<LanguageVersion>;
19
- /** What a release declares about versions. The standing of a pin is a question
20
- * asked of a release, so a deploy check can ask it of the next one. */
21
- export interface LanguageRelease {
22
- current: LanguageVersion;
23
- supported: ReadonlySet<LanguageVersion>;
24
- deprecated: ReadonlySet<LanguageVersion>;
25
- }
26
- export declare const THIS_RELEASE: LanguageRelease;
27
- export declare function languageVersionInfo(version: LanguageVersion): LanguageVersionInfo | undefined;
28
- /** `"Quiet Heron" (1)` — or `version 7` for an integer this release has never
29
- * heard of (a movement saved by a newer release). */
30
- export declare function describeLanguageVersion(version: LanguageVersion): string;
31
- /** How a version is shown to a person or an agent: the integer that identifies
32
- * it, and its name. */
33
- export interface LanguageVersionView {
34
- version: LanguageVersion;
35
- name: string;
36
- }
37
- export declare function languageVersionView(version: LanguageVersion): LanguageVersionView;
38
- export type LanguageVersionStanding = 'supported' | 'deprecated' | 'unsupported';
39
- export declare function languageVersionStanding(version: LanguageVersion, release?: LanguageRelease): LanguageVersionStanding;
2
+ /** A pin: the release a movement was written against, `MAJOR.MINOR.PATCH[-pre]`. */
3
+ export type LanguageVersion = string;
4
+ /** This release's version, and so the language it reads. */
5
+ export declare const LANGUAGE_VERSION: LanguageVersion;
6
+ export type LanguageVersionStanding = 'compatible' | 'newer' | 'olderKey' | 'malformed';
7
+ /** The part of a version a pin must share with a release; undefined for a
8
+ * text that is not a version. */
9
+ export declare function compatibilityKey(version: string): string | undefined;
10
+ /** How `pin` stands against the release `own`. */
11
+ export declare function languageVersionStanding(pin: string, own?: LanguageVersion): LanguageVersionStanding;
12
+ /** Whether the release `own` reads a movement pinned to `pin`. */
13
+ export declare function compatible(pin: string, own?: LanguageVersion): boolean;
40
14
  export declare const LanguageVersionDiagnosticCodes: {
41
15
  readonly UNSUPPORTED: "MOV_LANGUAGE_VERSION_UNSUPPORTED";
42
- readonly DEPRECATED: "MOV_LANGUAGE_VERSION_DEPRECATED";
43
16
  };
44
17
  /**
45
- * What a movement pinned to `version` must be told before anything else: an
46
- * error when this release cannot run it (never a silent fallback to the current
47
- * version), a warning when it runs but will stop doing so, nothing otherwise.
48
- * The message names the version and the fix.
18
+ * What a movement pinned to `pin` must be told before anything else: an error
19
+ * when this release does not read it (never a silent fallback to the current
20
+ * version), naming the pin and the remedy; nothing when it does.
49
21
  */
50
- export declare function languageVersionDiagnostic(version: LanguageVersion, release?: LanguageRelease): Diagnostic | undefined;
51
- /** The run host's units (Henry 2026-10-16): from version 5 every file has
52
- * these names in scope, each already connected — `listen to manual fire
53
- * hello`, `listen to cron { schedule: "0 9 * * 1" } fire digest` — with no
54
- * import and no `connect`. A file's own binding of the name replaces it.
22
+ export declare function languageVersionDiagnostic(pin: string, own?: LanguageVersion): Diagnostic | undefined;
23
+ /** The run host's units (Henry 2026-10-16): every file has these names in
24
+ * scope, each already connected — `listen to manual fire hello`,
25
+ * `listen to cron { schedule: "0 9 * * 1" } fire digest` — with no import
26
+ * and no `connect`. A file's own binding of the name replaces it.
55
27
  * (`RUN_HOST_UNITS` in crates/movement-parser/src/version.rs.) */
56
28
  export declare const RUN_HOST_UNITS: readonly string[];
57
- /** The units a file pinned to `version` has in scope. */
58
- export declare function runHostUnits(version: LanguageVersion): readonly string[];
@@ -1,123 +1,83 @@
1
1
  "use strict";
2
- // Language versions — the one table.
2
+ // The language version is the toolchain release: the one semver every crate
3
+ // and package carries. A movement's pin is the release it was written
4
+ // against, and a release reads a pin whose compatibility key is its own: the
5
+ // minor under 0.x (`0.12`), the major from 1.0 (`1`). Any other pin is refused
6
+ // by name, with the remedy (docs/contracts/language-versions.md).
3
7
  //
4
- // A saved movement is pinned to the language version it was written against,
5
- // and every layer (parser, checker, engine, plugins, adapters) honours that pin
6
- // by a conditional at the point of difference:
7
- //
8
- // if (ctx.languageVersion < 2) { …the old behaviour… }
9
- //
10
- // The integer is the identity — code compares it and never parses the name.
11
- // The name is display only: it is what a person sees.
12
- //
13
- // A version keeps its row here after it leaves SUPPORTED, so a movement pinned
14
- // to it can still be refused by name.
15
- //
16
- // See plans/language-versioning-2026-09-29/.
8
+ // The same rule is crates/movement-parser/src/version.rs; a test holds the two
9
+ // equal (packages/engine-contracts/__test__/contracts.unit.test.ts).
17
10
  Object.defineProperty(exports, "__esModule", { value: true });
18
- exports.RUN_HOST_UNITS = exports.LanguageVersionDiagnosticCodes = exports.THIS_RELEASE = exports.DEPRECATED_LANGUAGE_VERSIONS = exports.SUPPORTED_LANGUAGE_VERSIONS = exports.CURRENT_LANGUAGE_VERSION = exports.LANGUAGE_VERSIONS = void 0;
19
- exports.languageVersionInfo = languageVersionInfo;
20
- exports.describeLanguageVersion = describeLanguageVersion;
21
- exports.languageVersionView = languageVersionView;
11
+ exports.RUN_HOST_UNITS = exports.LanguageVersionDiagnosticCodes = exports.LANGUAGE_VERSION = void 0;
12
+ exports.compatibilityKey = compatibilityKey;
22
13
  exports.languageVersionStanding = languageVersionStanding;
14
+ exports.compatible = compatible;
23
15
  exports.languageVersionDiagnostic = languageVersionDiagnostic;
24
- exports.runHostUnits = runHostUnits;
16
+ const language_version_value_1 = require("./language_version_value");
25
17
  const never_1 = require("./never");
26
- exports.LANGUAGE_VERSIONS = [
27
- { version: 1, name: 'Quiet Heron', is: 'the language as of tag v0.6.0' },
28
- { version: 2, name: 'Bright Otter', is: 'the language from v0.7.0 through v0.9.1' },
29
- {
30
- version: 3,
31
- name: 'Steady Lynx',
32
- is: 'the language from v0.10.0: a list literal is a tuple — exact at a literal index, a list of its members\' union elsewhere',
33
- },
34
- {
35
- version: 4,
36
- name: 'Luminous Owl',
37
- is: 'the language from v0.11.0: a match yields absent on a miss, a write handle reaches its pre-write record through @old',
38
- },
39
- {
40
- version: 5,
41
- name: 'Dancing Wren',
42
- is: 'the language after v0.11.0: no engine-side store and no meta edges — no `write … bind` (a link lives in the system that holds it), no `#` hops (a plugin is a function you call), `delete` only where the system declares a type deletable, `_resources` only on an extraction\'s result (a record walks its system\'s file edge: `Attachments`, `Files`, `Resources`), a file is never joined into text (its text is `READ(f)`), a closure is a value (a list may hold closures, and a value that is one is called), and `parallel` is retired (`MAP` over the functions, calling each, is the join)',
43
- },
44
- ];
45
- /** What a movement saved today is pinned to, and what an entry point given no
46
- * version compiles and runs under. */
47
- exports.CURRENT_LANGUAGE_VERSION = 5;
48
- /** The versions this release parses, checks and runs. */
49
- exports.SUPPORTED_LANGUAGE_VERSIONS = new Set([5]);
50
- /** Supported versions that will be removed: they still run, with a warning. */
51
- exports.DEPRECATED_LANGUAGE_VERSIONS = new Set();
52
- exports.THIS_RELEASE = {
53
- current: exports.CURRENT_LANGUAGE_VERSION,
54
- supported: exports.SUPPORTED_LANGUAGE_VERSIONS,
55
- deprecated: exports.DEPRECATED_LANGUAGE_VERSIONS,
56
- };
57
- function languageVersionInfo(version) {
58
- return exports.LANGUAGE_VERSIONS.find((info) => info.version === version);
18
+ /** This release's version, and so the language it reads. */
19
+ exports.LANGUAGE_VERSION = language_version_value_1.PACKAGE_VERSION;
20
+ const SEMVER = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
21
+ function parse(version) {
22
+ const match = SEMVER.exec(version);
23
+ return match === null ? undefined : { major: Number(match[1]), minor: Number(match[2]) };
59
24
  }
60
- /** `"Quiet Heron" (1)` — or `version 7` for an integer this release has never
61
- * heard of (a movement saved by a newer release). */
62
- function describeLanguageVersion(version) {
63
- const info = languageVersionInfo(version);
64
- return info ? `"${info.name}" (${info.version})` : `version ${version}`;
25
+ /** The part of a version a pin must share with a release; undefined for a
26
+ * text that is not a version. */
27
+ function compatibilityKey(version) {
28
+ const parsed = parse(version);
29
+ if (parsed === undefined)
30
+ return undefined;
31
+ return parsed.major === 0 ? `0.${parsed.minor}` : String(parsed.major);
65
32
  }
66
- function languageVersionView(version) {
67
- return { version, name: languageVersionInfo(version)?.name ?? `version ${version}` };
33
+ /** How `pin` stands against the release `own`. */
34
+ function languageVersionStanding(pin, own = exports.LANGUAGE_VERSION) {
35
+ const pinned = parse(pin);
36
+ const release = parse(own);
37
+ if (pinned === undefined || release === undefined)
38
+ return 'malformed';
39
+ if (compatibilityKey(pin) === compatibilityKey(own))
40
+ return 'compatible';
41
+ const newer = pinned.major !== release.major ? pinned.major > release.major : pinned.minor > release.minor;
42
+ return newer ? 'newer' : 'olderKey';
68
43
  }
69
- function languageVersionStanding(version, release = exports.THIS_RELEASE) {
70
- if (!release.supported.has(version))
71
- return 'unsupported';
72
- if (release.deprecated.has(version))
73
- return 'deprecated';
74
- return 'supported';
44
+ /** Whether the release `own` reads a movement pinned to `pin`. */
45
+ function compatible(pin, own = exports.LANGUAGE_VERSION) {
46
+ return languageVersionStanding(pin, own) === 'compatible';
75
47
  }
76
48
  exports.LanguageVersionDiagnosticCodes = {
77
49
  UNSUPPORTED: 'MOV_LANGUAGE_VERSION_UNSUPPORTED',
78
- DEPRECATED: 'MOV_LANGUAGE_VERSION_DEPRECATED',
79
50
  };
80
- /**
81
- * What a movement pinned to `version` must be told before anything else: an
82
- * error when this release cannot run it (never a silent fallback to the current
83
- * version), a warning when it runs but will stop doing so, nothing otherwise.
84
- * The message names the version and the fix.
85
- */
86
- function languageVersionDiagnostic(version, release = exports.THIS_RELEASE) {
87
- const span = { start: { line: 1, col: 1 }, end: { line: 1, col: 1 } };
88
- const current = describeLanguageVersion(release.current);
89
- const standing = languageVersionStanding(version, release);
51
+ function refusalMessage(pin, own, standing) {
90
52
  switch (standing) {
91
- case 'supported':
92
- return undefined;
93
- case 'unsupported':
94
- return {
95
- code: exports.LanguageVersionDiagnosticCodes.UNSUPPORTED,
96
- message: `this automation is written in language version ${describeLanguageVersion(version)}, ` +
97
- `which this release does not support, so it will not validate or run. ` +
98
- `To fix: validate it under ${current}, repair what that reports, and upgrade it to ${current}.`,
99
- span,
100
- };
101
- case 'deprecated':
102
- return {
103
- code: exports.LanguageVersionDiagnosticCodes.DEPRECATED,
104
- message: `this automation is written in language version ${describeLanguageVersion(version)}, ` +
105
- `which is deprecated and will be removed in a future release. ` +
106
- `Validate it under ${current}, repair what that reports, and upgrade it to ${current} before then.`,
107
- span,
108
- severity: 'warning',
109
- };
53
+ case 'newer':
54
+ return `this automation pins language ${pin}, newer than this release (${own}); upgrade the engine`;
55
+ case 'olderKey':
56
+ return `this automation pins language ${pin}, which this release (${own}) does not read; validate it under ${own} and upgrade it`;
57
+ case 'malformed':
58
+ return `this automation pins language ${pin}, which is not a version; a pin is a release's version, such as ${own}`;
110
59
  default:
111
60
  return (0, never_1.neverAsAny)(standing);
112
61
  }
113
62
  }
114
- /** The run host's units (Henry 2026-10-16): from version 5 every file has
115
- * these names in scope, each already connected — `listen to manual fire
116
- * hello`, `listen to cron { schedule: "0 9 * * 1" } fire digest` — with no
117
- * import and no `connect`. A file's own binding of the name replaces it.
63
+ /**
64
+ * What a movement pinned to `pin` must be told before anything else: an error
65
+ * when this release does not read it (never a silent fallback to the current
66
+ * version), naming the pin and the remedy; nothing when it does.
67
+ */
68
+ function languageVersionDiagnostic(pin, own = exports.LANGUAGE_VERSION) {
69
+ const standing = languageVersionStanding(pin, own);
70
+ if (standing === 'compatible')
71
+ return undefined;
72
+ return {
73
+ code: exports.LanguageVersionDiagnosticCodes.UNSUPPORTED,
74
+ message: refusalMessage(pin, own, standing),
75
+ span: { start: { line: 1, col: 1 }, end: { line: 1, col: 1 } },
76
+ };
77
+ }
78
+ /** The run host's units (Henry 2026-10-16): every file has these names in
79
+ * scope, each already connected — `listen to manual fire hello`,
80
+ * `listen to cron { schedule: "0 9 * * 1" } fire digest` — with no import
81
+ * and no `connect`. A file's own binding of the name replaces it.
118
82
  * (`RUN_HOST_UNITS` in crates/movement-parser/src/version.rs.) */
119
83
  exports.RUN_HOST_UNITS = ['cron', 'manual'];
120
- /** The units a file pinned to `version` has in scope. */
121
- function runHostUnits(version) {
122
- return version >= 5 ? exports.RUN_HOST_UNITS : [];
123
- }
@@ -0,0 +1 @@
1
+ export declare const PACKAGE_VERSION = "0.12.0-rc.7";
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PACKAGE_VERSION = void 0;
4
+ // The package's version, written here from package.json by
5
+ // scripts/build-packages.cjs (a source and its build sit at different depths
6
+ // beside package.json, so neither can require it by one relative path).
7
+ // __test__/language_version.unit.test.ts holds it equal to package.json.
8
+ exports.PACKAGE_VERSION = '0.12.0-rc.7';