@beehexa/hexasync-template-model 2608.20.18 → 2608.20.31

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 (41) hide show
  1. package/dist/componentKey.d.ts +26 -0
  2. package/dist/componentKey.d.ts.map +1 -0
  3. package/dist/componentKey.js +32 -0
  4. package/dist/componentKey.js.map +1 -0
  5. package/dist/connectorSupport.d.ts +123 -0
  6. package/dist/connectorSupport.d.ts.map +1 -0
  7. package/dist/connectorSupport.js +116 -0
  8. package/dist/connectorSupport.js.map +1 -0
  9. package/dist/contract.d.ts +57 -0
  10. package/dist/contract.d.ts.map +1 -0
  11. package/dist/contract.js +68 -0
  12. package/dist/contract.js.map +1 -0
  13. package/dist/flowRender.d.ts +89 -0
  14. package/dist/flowRender.d.ts.map +1 -0
  15. package/dist/flowRender.js +316 -0
  16. package/dist/flowRender.js.map +1 -0
  17. package/dist/index.d.ts +30 -0
  18. package/dist/index.d.ts.map +1 -0
  19. package/dist/index.js +28 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/nodeAddress.d.ts +105 -0
  22. package/dist/nodeAddress.d.ts.map +1 -0
  23. package/dist/nodeAddress.js +195 -0
  24. package/dist/nodeAddress.js.map +1 -0
  25. package/dist/references.d.ts +200 -0
  26. package/dist/references.d.ts.map +1 -0
  27. package/dist/references.js +368 -0
  28. package/dist/references.js.map +1 -0
  29. package/dist/stepGlyph.d.ts +67 -0
  30. package/dist/stepGlyph.d.ts.map +1 -0
  31. package/dist/stepGlyph.js +155 -0
  32. package/dist/stepGlyph.js.map +1 -0
  33. package/dist/templating.d.ts +88 -0
  34. package/dist/templating.d.ts.map +1 -0
  35. package/dist/templating.js +103 -0
  36. package/dist/templating.js.map +1 -0
  37. package/dist/uriPath.d.ts +43 -0
  38. package/dist/uriPath.d.ts.map +1 -0
  39. package/dist/uriPath.js +151 -0
  40. package/dist/uriPath.js.map +1 -0
  41. package/package.json +1 -1
@@ -0,0 +1,88 @@
1
+ /**
2
+ * The two templating layers, told apart (FR-50, Phase 1 Story 3.8).
3
+ *
4
+ * A value can carry substitution that happens when you BUILD and substitution that happens when
5
+ * it RUNS, and the difference decides who finds out about a mistake:
6
+ *
7
+ * `**VariableKey**` COMPOSE-TIME. The composer substitutes it from the project's variable
8
+ * pool. A missing one is caught at compose, by the person composing.
9
+ * `{{ … }}` RUNTIME. The worker evaluates it (Scriban) against live data. A missing
10
+ * one is caught in production, by whoever is on call.
11
+ *
12
+ * Conflating them is how a `{{env.__HSS_X}}` gets reported as an unresolved compose-time
13
+ * variable — noise on something that is working exactly as designed — and, worse, how a genuinely
14
+ * missing environment key gets the same severity as a typo'd variable name.
15
+ *
16
+ * ALL `{{ … }}` IS SCRIBAN — including inside a JSONata expression. A JSONata value may embed
17
+ * Scriban so the JSONata itself can be built dynamically, and the worker evaluates Scriban FIRST,
18
+ * then treats the result as JSONata. So there is no nested-language boundary to reason about
19
+ * here: a `{{ … }}` occurrence is runtime Scriban wherever it appears, and the surrounding
20
+ * expression language does not change that.
21
+ *
22
+ * RUNTIME IS SCRIBAN, NOT JUST `env`. The corpus holds ~30,000 `{{ … }}` occurrences: control
23
+ * flow (`{{end}}`), pipes (`{{ '' | uuid }}`), runtime data (`{{puller.before.X}}`) and 377
24
+ * distinct `env.__HSS_*` keys. The AC names the `env` case because that is the one with an
25
+ * external dependency, so it is classified separately rather than being the whole definition of
26
+ * "runtime" — a narrower model would have mislabelled the other 29,000.
27
+ */
28
+ /** When the substitution happens, and therefore who discovers a mistake. */
29
+ export type TemplatingLayer = 'compose-time' | 'runtime';
30
+ /**
31
+ * What a runtime expression reaches for.
32
+ *
33
+ * `environment` is singled out because it depends on something outside the template entirely —
34
+ * a key that must exist in the deployment — so a later diagnostic can treat it differently from
35
+ * an expression over data the worker already holds.
36
+ */
37
+ export type RuntimeReference = 'environment' | 'expression';
38
+ export interface TemplateOccurrence {
39
+ readonly layer: TemplatingLayer;
40
+ /** Only meaningful for `runtime`. */
41
+ readonly runtimeReference?: RuntimeReference;
42
+ /** The full matched text, e.g. `**Foo**` or `{{ env.__HSS_X }}`. */
43
+ readonly raw: string;
44
+ /**
45
+ * What the occurrence names: the variable key for compose-time, the environment key for a
46
+ * runtime `env` reference, and the trimmed expression otherwise.
47
+ */
48
+ readonly key: string;
49
+ /**
50
+ * Every environment key this occurrence reads, for a `runtime` occurrence that reads any.
51
+ *
52
+ * `key` carries only the FIRST, because it is one string. `{{ env.A + env.B }}` is one expression
53
+ * reading two keys, and the whole reason `environment` is a distinct `runtimeReference` is so a
54
+ * later rule can ask "does this deployment define them" — which it cannot do for `env.B` if only
55
+ * `env.A` was ever recorded.
56
+ */
57
+ readonly environmentKeys?: readonly string[];
58
+ /**
59
+ * Offsets into the VALUE as parsed, not into the source text.
60
+ *
61
+ * Named precisely because the difference bites: a caller receives `scalar.value`, which for a
62
+ * quoted scalar has had escapes expanded and for a block scalar has been folded and dedented, so
63
+ * these offsets are not source positions and cannot be turned into one without the scalar's own
64
+ * range. An earlier comment promised "so a caller can map back to a source range", which is not
65
+ * something these offsets alone can do.
66
+ */
67
+ readonly start: number;
68
+ readonly end: number;
69
+ }
70
+ /**
71
+ * Every templating occurrence in a value, each classified independently.
72
+ *
73
+ * Independently matters: one value can mix layers — a URL built from a compose-time variable
74
+ * followed by a runtime expression is both — and a classifier returning a single verdict per
75
+ * value would have to be wrong about one of them.
76
+ */
77
+ export declare function classifyTemplating(value: string): TemplateOccurrence[];
78
+ /** Does this value carry any compose-time substitution? */
79
+ export declare function hasComposeTimeTemplating(value: string): boolean;
80
+ /**
81
+ * Compose-time keys in a value — what a resolver needs.
82
+ *
83
+ * Runtime occurrences are deliberately absent: asking the variable pool about `{{ item.id }}`
84
+ * would always fail, and reporting that failure would be reporting on something the composer
85
+ * was never responsible for.
86
+ */
87
+ export declare function composeTimeKeys(value: string): string[];
88
+ //# sourceMappingURL=templating.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templating.d.ts","sourceRoot":"","sources":["../src/templating.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,4EAA4E;AAC5E,MAAM,MAAM,eAAe,GAAG,cAAc,GAAG,SAAS,CAAC;AAEzD;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GAAG,aAAa,GAAG,YAAY,CAAC;AAE5D,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;IAChC,qCAAqC;IACrC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IAC7C,oEAAoE;IACpE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7C;;;;;;;;OAQG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAwBD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,kBAAkB,EAAE,CAgCtE;AAED,2DAA2D;AAC3D,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE/D;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAQvD"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * The two templating layers, told apart (FR-50, Phase 1 Story 3.8).
3
+ *
4
+ * A value can carry substitution that happens when you BUILD and substitution that happens when
5
+ * it RUNS, and the difference decides who finds out about a mistake:
6
+ *
7
+ * `**VariableKey**` COMPOSE-TIME. The composer substitutes it from the project's variable
8
+ * pool. A missing one is caught at compose, by the person composing.
9
+ * `{{ … }}` RUNTIME. The worker evaluates it (Scriban) against live data. A missing
10
+ * one is caught in production, by whoever is on call.
11
+ *
12
+ * Conflating them is how a `{{env.__HSS_X}}` gets reported as an unresolved compose-time
13
+ * variable — noise on something that is working exactly as designed — and, worse, how a genuinely
14
+ * missing environment key gets the same severity as a typo'd variable name.
15
+ *
16
+ * ALL `{{ … }}` IS SCRIBAN — including inside a JSONata expression. A JSONata value may embed
17
+ * Scriban so the JSONata itself can be built dynamically, and the worker evaluates Scriban FIRST,
18
+ * then treats the result as JSONata. So there is no nested-language boundary to reason about
19
+ * here: a `{{ … }}` occurrence is runtime Scriban wherever it appears, and the surrounding
20
+ * expression language does not change that.
21
+ *
22
+ * RUNTIME IS SCRIBAN, NOT JUST `env`. The corpus holds ~30,000 `{{ … }}` occurrences: control
23
+ * flow (`{{end}}`), pipes (`{{ '' | uuid }}`), runtime data (`{{puller.before.X}}`) and 377
24
+ * distinct `env.__HSS_*` keys. The AC names the `env` case because that is the one with an
25
+ * external dependency, so it is classified separately rather than being the whole definition of
26
+ * "runtime" — a narrower model would have mislabelled the other 29,000.
27
+ */
28
+ /**
29
+ * Identifier-shaped, matching the composer's own residual-token rule.
30
+ *
31
+ * Deliberately not `\*\*.+\*\*`: markdown bold is indistinguishable from a variable token by
32
+ * shape alone, and a looser pattern would classify every bold phrase in a `description` as an
33
+ * unresolved variable. The composer already draws the line here; drawing it differently would
34
+ * mean two answers to one question.
35
+ */
36
+ const COMPOSE_TIME_RE = /\*\*[A-Za-z0-9_]+\*\*/g;
37
+ /** Scriban, non-greedy so adjacent expressions do not merge into one. */
38
+ const RUNTIME_RE = /\{\{[\s\S]*?\}\}/g;
39
+ /**
40
+ * A runtime expression that reads an environment key. GLOBAL — an expression can read several.
41
+ *
42
+ * The leading guard excludes `myenv.X`, but a QUOTE satisfies `[^A-Za-z0-9_.]` too, so
43
+ * `{{ "env.LITERAL" }}` was reported as a deployment dependency on a key that is a string literal.
44
+ * Quotes are now excluded explicitly.
45
+ */
46
+ const ENV_REF_RE = /(?:^|[^A-Za-z0-9_.'"`])env\.([A-Za-z0-9_]+)/g;
47
+ /**
48
+ * Every templating occurrence in a value, each classified independently.
49
+ *
50
+ * Independently matters: one value can mix layers — a URL built from a compose-time variable
51
+ * followed by a runtime expression is both — and a classifier returning a single verdict per
52
+ * value would have to be wrong about one of them.
53
+ */
54
+ export function classifyTemplating(value) {
55
+ if (typeof value !== 'string' || value.length === 0)
56
+ return [];
57
+ const found = [];
58
+ for (const m of value.matchAll(COMPOSE_TIME_RE)) {
59
+ found.push({
60
+ layer: 'compose-time',
61
+ raw: m[0],
62
+ key: m[0].slice(2, -2),
63
+ start: m.index,
64
+ end: m.index + m[0].length,
65
+ });
66
+ }
67
+ for (const m of value.matchAll(RUNTIME_RE)) {
68
+ const inner = m[0].slice(2, -2).trim();
69
+ // ALL of them. `ENV_REF_RE` was non-global and used with a single `.exec`, so a compound
70
+ // expression reported only its first key and every later one was invisible.
71
+ const envKeys = [...inner.matchAll(ENV_REF_RE)].map((e) => e[1]);
72
+ found.push({
73
+ layer: 'runtime',
74
+ runtimeReference: envKeys.length > 0 ? 'environment' : 'expression',
75
+ raw: m[0],
76
+ key: envKeys.length > 0 ? envKeys[0] : inner,
77
+ ...(envKeys.length > 0 ? { environmentKeys: envKeys } : {}),
78
+ start: m.index,
79
+ end: m.index + m[0].length,
80
+ });
81
+ }
82
+ // Source order, so a caller reporting occurrences reads them the way the author wrote them.
83
+ return found.sort((a, b) => a.start - b.start);
84
+ }
85
+ /** Does this value carry any compose-time substitution? */
86
+ export function hasComposeTimeTemplating(value) {
87
+ return classifyTemplating(value).some((t) => t.layer === 'compose-time');
88
+ }
89
+ /**
90
+ * Compose-time keys in a value — what a resolver needs.
91
+ *
92
+ * Runtime occurrences are deliberately absent: asking the variable pool about `{{ item.id }}`
93
+ * would always fail, and reporting that failure would be reporting on something the composer
94
+ * was never responsible for.
95
+ */
96
+ export function composeTimeKeys(value) {
97
+ return [
98
+ ...new Set(classifyTemplating(value)
99
+ .filter((t) => t.layer === 'compose-time')
100
+ .map((t) => t.key)),
101
+ ];
102
+ }
103
+ //# sourceMappingURL=templating.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templating.js","sourceRoot":"","sources":["../src/templating.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * URI path algebra — the AD-18 corollary.
3
+ *
4
+ * Core may not use `node:path` (AD-3, amended 2026-08-01): the VS Code web
5
+ * extension host does not provide it, and a bundler polyfill is exactly how
6
+ * desktop and web end up disagreeing about file identity. So core does its own
7
+ * path arithmetic over **normalized URI strings**: POSIX `/` only, with `.` and
8
+ * `..` collapsed explicitly.
9
+ *
10
+ * Pure string work. No IO, no Node builtins, no platform behaviour.
11
+ */
12
+ export declare function normalizeUri(uri: string): string;
13
+ export declare function joinUri(base: string, ...segments: readonly string[]): string;
14
+ export declare function dirnameUri(uri: string): string;
15
+ export declare function basenameUri(uri: string): string;
16
+ /**
17
+ * True when `target` is absolute in its own right — rooted, drive-rooted, or schemed.
18
+ *
19
+ * Exported because `node:path`'s `isAbsolute` cannot answer this question for the web host: it
20
+ * knows nothing of `vscode-vfs://`, and on Windows it would reject a rooted POSIX path that is
21
+ * perfectly absolute in URI terms. This was the last of Story 1.5's 37 `path.*` call sites, and
22
+ * it had to move before `resolveMdIncludes` could follow the rest of the compose logic into core.
23
+ *
24
+ * ### The drive letter (reported 2026-08-08)
25
+ *
26
+ * It answered FALSE for `C:\docs\notes.md`, which is as absolute as a path gets. `merge.ts` asks
27
+ * this question at both `!md[…]` resolution sites — `isAbsoluteUri(ref) ? ref : resolveUri(base,
28
+ * ref)` — so an author on Windows writing an absolute include had it joined onto the project's base
29
+ * directory instead, producing `D:/project/C:/docs/notes.md` and an `ENOENT` naming a path nobody
30
+ * wrote. On Linux the same include starts with `/` and was always answered correctly, which is why
31
+ * only a Windows test run found it.
32
+ */
33
+ export declare function isAbsoluteUri(target: string): boolean;
34
+ export declare function resolveUri(base: string, target: string): string;
35
+ export declare function relativeUri(from: string, to: string): string;
36
+ /**
37
+ * The escape guard (AC 5). True only when `child` is strictly inside `parent`.
38
+ *
39
+ * Segment-aware on purpose: a `startsWith` check would accept `rootsibling/x`
40
+ * for parent `root` and happily write outside the install target.
41
+ */
42
+ export declare function isInsideUri(parent: string, child: string): boolean;
43
+ //# sourceMappingURL=uriPath.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uriPath.d.ts","sourceRoot":"","sources":["../src/uriPath.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAkDH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAWhD;AAED,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAM5E;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAM9C;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAK/C;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAOrD;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAa5D;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAUlE"}
@@ -0,0 +1,151 @@
1
+ /**
2
+ * URI path algebra — the AD-18 corollary.
3
+ *
4
+ * Core may not use `node:path` (AD-3, amended 2026-08-01): the VS Code web
5
+ * extension host does not provide it, and a bundler polyfill is exactly how
6
+ * desktop and web end up disagreeing about file identity. So core does its own
7
+ * path arithmetic over **normalized URI strings**: POSIX `/` only, with `.` and
8
+ * `..` collapsed explicitly.
9
+ *
10
+ * Pure string work. No IO, no Node builtins, no platform behaviour.
11
+ */
12
+ /**
13
+ * `c:/…` — a Windows absolute path, which is ROOTED WITHOUT a leading slash.
14
+ *
15
+ * The one shape this file's "POSIX `/` only" model does not otherwise describe. Every caller has
16
+ * already folded backslashes to `/` before this is tested, so only the forward form appears here.
17
+ *
18
+ * A single letter followed by `:/` cannot be a URI scheme in this codebase's terms — `splitPrefix`
19
+ * and `isAbsoluteUri` both test the `scheme://` form FIRST, so `c://host/x` is still read as a
20
+ * scheme with an authority rather than as a drive.
21
+ */
22
+ const DRIVE_ROOT = /^[a-zA-Z]:\//;
23
+ /** Splits `scheme://authority`, or a Windows drive root (if any), from the path remainder. */
24
+ function splitPrefix(uri) {
25
+ const m = /^([a-zA-Z][a-zA-Z0-9+.-]*:\/\/[^/]*\/?)/.exec(uri);
26
+ if (m)
27
+ return { prefix: m[1], rest: uri.slice(m[1].length) };
28
+ // A DRIVE is a root. Left as an ordinary segment it was one — so `..` could climb PAST `c:` and
29
+ // out of the volume, and `relativeUri` saw two different drives as sharing a root and produced a
30
+ // traversal between them. `c:/` is three characters, always.
31
+ if (DRIVE_ROOT.test(uri))
32
+ return { prefix: uri.slice(0, 3), rest: uri.slice(3) };
33
+ if (uri.startsWith('/'))
34
+ return { prefix: '/', rest: uri.slice(1) };
35
+ return { prefix: '', rest: uri };
36
+ }
37
+ function collapse(segments, keepLeadingDotDot) {
38
+ const out = [];
39
+ for (const seg of segments) {
40
+ if (seg === '' || seg === '.')
41
+ continue;
42
+ if (seg === '..') {
43
+ const last = out[out.length - 1];
44
+ if (out.length > 0 && last !== '..') {
45
+ out.pop();
46
+ }
47
+ else if (keepLeadingDotDot) {
48
+ out.push('..');
49
+ }
50
+ // When traversal cannot be kept (rooted path), it is dropped —
51
+ // a rooted path can never escape its own root.
52
+ continue;
53
+ }
54
+ out.push(seg);
55
+ }
56
+ return out;
57
+ }
58
+ export function normalizeUri(uri) {
59
+ const forwardOnly = String(uri).replace(/\\/g, '/');
60
+ const { prefix, rest } = splitPrefix(forwardOnly);
61
+ const rooted = prefix !== '';
62
+ const segments = collapse(rest.split('/'), !rooted);
63
+ const joined = segments.join('/');
64
+ if (prefix === '')
65
+ return joined;
66
+ if (prefix === '/')
67
+ return `/${joined}`;
68
+ return joined === ''
69
+ ? prefix
70
+ : `${prefix.endsWith('/') ? prefix : `${prefix}/`}${joined}`;
71
+ }
72
+ export function joinUri(base, ...segments) {
73
+ const tail = segments.filter((s) => s !== undefined && s !== null && String(s) !== '');
74
+ const combined = [String(base), ...tail.map(String)].join('/');
75
+ return normalizeUri(combined);
76
+ }
77
+ export function dirnameUri(uri) {
78
+ const normalized = normalizeUri(uri);
79
+ const { prefix, rest } = splitPrefix(normalized);
80
+ const idx = rest.lastIndexOf('/');
81
+ if (idx === -1)
82
+ return prefix === '' ? '' : prefix;
83
+ return normalizeUri(`${prefix}${rest.slice(0, idx)}`);
84
+ }
85
+ export function basenameUri(uri) {
86
+ const normalized = normalizeUri(uri);
87
+ const { rest } = splitPrefix(normalized);
88
+ const idx = rest.lastIndexOf('/');
89
+ return idx === -1 ? rest : rest.slice(idx + 1);
90
+ }
91
+ /**
92
+ * True when `target` is absolute in its own right — rooted, drive-rooted, or schemed.
93
+ *
94
+ * Exported because `node:path`'s `isAbsolute` cannot answer this question for the web host: it
95
+ * knows nothing of `vscode-vfs://`, and on Windows it would reject a rooted POSIX path that is
96
+ * perfectly absolute in URI terms. This was the last of Story 1.5's 37 `path.*` call sites, and
97
+ * it had to move before `resolveMdIncludes` could follow the rest of the compose logic into core.
98
+ *
99
+ * ### The drive letter (reported 2026-08-08)
100
+ *
101
+ * It answered FALSE for `C:\docs\notes.md`, which is as absolute as a path gets. `merge.ts` asks
102
+ * this question at both `!md[…]` resolution sites — `isAbsoluteUri(ref) ? ref : resolveUri(base,
103
+ * ref)` — so an author on Windows writing an absolute include had it joined onto the project's base
104
+ * directory instead, producing `D:/project/C:/docs/notes.md` and an `ENOENT` naming a path nobody
105
+ * wrote. On Linux the same include starts with `/` and was always answered correctly, which is why
106
+ * only a Windows test run found it.
107
+ */
108
+ export function isAbsoluteUri(target) {
109
+ const t = String(target).replace(/\\/g, '/');
110
+ return (t.startsWith('/') ||
111
+ /^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(t) ||
112
+ DRIVE_ROOT.test(t));
113
+ }
114
+ export function resolveUri(base, target) {
115
+ return isAbsoluteUri(target) ? normalizeUri(target) : joinUri(base, target);
116
+ }
117
+ export function relativeUri(from, to) {
118
+ const a = normalizeUri(from);
119
+ const b = normalizeUri(to);
120
+ const pa = splitPrefix(a);
121
+ const pb = splitPrefix(b);
122
+ if (pa.prefix !== pb.prefix)
123
+ return b; // different roots — no relative path exists
124
+ const fromSeg = pa.rest.split('/').filter((s) => s !== '');
125
+ const toSeg = pb.rest.split('/').filter((s) => s !== '');
126
+ let i = 0;
127
+ while (i < fromSeg.length && i < toSeg.length && fromSeg[i] === toSeg[i])
128
+ i += 1;
129
+ const up = Array.from({ length: fromSeg.length - i }, () => '..');
130
+ return [...up, ...toSeg.slice(i)].join('/');
131
+ }
132
+ /**
133
+ * The escape guard (AC 5). True only when `child` is strictly inside `parent`.
134
+ *
135
+ * Segment-aware on purpose: a `startsWith` check would accept `rootsibling/x`
136
+ * for parent `root` and happily write outside the install target.
137
+ */
138
+ export function isInsideUri(parent, child) {
139
+ const p = normalizeUri(parent);
140
+ const c = normalizeUri(child);
141
+ const pp = splitPrefix(p);
142
+ const pc = splitPrefix(c);
143
+ if (pp.prefix !== pc.prefix)
144
+ return false;
145
+ const pSeg = pp.rest.split('/').filter((s) => s !== '');
146
+ const cSeg = pc.rest.split('/').filter((s) => s !== '');
147
+ if (cSeg.length <= pSeg.length)
148
+ return false;
149
+ return pSeg.every((seg, i) => cSeg[i] === seg);
150
+ }
151
+ //# sourceMappingURL=uriPath.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uriPath.js","sourceRoot":"","sources":["../src/uriPath.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@beehexa/hexasync-template-model",
3
- "version": "2608.20.18",
3
+ "version": "2608.20.31",
4
4
  "description": "Domain types for HexaSync templates. No behaviour.",
5
5
  "license": "SEE LICENSE IN ../../LICENSE",
6
6
  "type": "module",