@skmtc/core 0.28.6 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/esm/context/GenerateContext.js +16 -16
  2. package/esm/context/RenderContext.d.ts +7 -7
  3. package/esm/context/RenderContext.js +17 -12
  4. package/esm/deps/jsr.io/@std/path/1.1.6/posix/is_absolute.d.ts +16 -0
  5. package/esm/deps/jsr.io/@std/path/1.1.6/posix/is_absolute.js +23 -0
  6. package/esm/deps/jsr.io/@std/path/1.1.6/windows/is_absolute.d.ts +16 -0
  7. package/esm/deps/jsr.io/@std/path/1.1.6/windows/is_absolute.js +38 -0
  8. package/esm/dsl/model/ModelDriver.js +4 -3
  9. package/esm/dsl/operation/gql/GqlOperationDriver.js +4 -3
  10. package/esm/dsl/operation/oas/OasOperationDriver.js +4 -3
  11. package/esm/dsl/webhook/WebhookDriver.js +4 -3
  12. package/esm/helpers/applyGeneratedSuffix.js +1 -1
  13. package/esm/helpers/isImported.d.ts +10 -74
  14. package/esm/helpers/isImported.js +12 -76
  15. package/esm/helpers/normalizeWorkspacePath.d.ts +64 -0
  16. package/esm/helpers/normalizeWorkspacePath.js +98 -0
  17. package/esm/helpers/toResolvedArtifactPath.d.ts +8 -5
  18. package/esm/helpers/toResolvedArtifactPath.js +11 -7
  19. package/esm/helpers/toWorkspacePath.d.ts +3 -3
  20. package/esm/helpers/toWorkspacePath.js +5 -5
  21. package/esm/mod.d.ts +1 -0
  22. package/esm/mod.js +1 -0
  23. package/esm/types/Settings.js +6 -8
  24. package/package.json +1 -1
  25. package/script/context/GenerateContext.js +16 -16
  26. package/script/context/RenderContext.d.ts +7 -7
  27. package/script/context/RenderContext.js +17 -12
  28. package/script/deps/jsr.io/@std/path/1.1.6/posix/is_absolute.d.ts +16 -0
  29. package/script/deps/jsr.io/@std/path/1.1.6/posix/is_absolute.js +26 -0
  30. package/script/deps/jsr.io/@std/path/1.1.6/windows/is_absolute.d.ts +16 -0
  31. package/script/deps/jsr.io/@std/path/1.1.6/windows/is_absolute.js +41 -0
  32. package/script/dsl/model/ModelDriver.js +4 -3
  33. package/script/dsl/operation/gql/GqlOperationDriver.js +4 -3
  34. package/script/dsl/operation/oas/OasOperationDriver.js +4 -3
  35. package/script/dsl/webhook/WebhookDriver.js +4 -3
  36. package/script/helpers/applyGeneratedSuffix.js +1 -1
  37. package/script/helpers/isImported.d.ts +10 -74
  38. package/script/helpers/isImported.js +12 -76
  39. package/script/helpers/normalizeWorkspacePath.d.ts +64 -0
  40. package/script/helpers/normalizeWorkspacePath.js +107 -0
  41. package/script/helpers/toResolvedArtifactPath.d.ts +8 -5
  42. package/script/helpers/toResolvedArtifactPath.js +11 -7
  43. package/script/helpers/toWorkspacePath.d.ts +3 -3
  44. package/script/helpers/toWorkspacePath.js +5 -5
  45. package/script/mod.d.ts +1 -0
  46. package/script/mod.js +1 -0
  47. package/script/types/Settings.js +7 -9
  48. package/esm/deps/jsr.io/@std/path/1.1.6/extname.d.ts +0 -24
  49. package/esm/deps/jsr.io/@std/path/1.1.6/extname.js +0 -31
  50. package/esm/deps/jsr.io/@std/path/1.1.6/normalize.d.ts +0 -25
  51. package/esm/deps/jsr.io/@std/path/1.1.6/normalize.js +0 -32
  52. package/esm/deps/jsr.io/@std/path/1.1.6/windows/extname.d.ts +0 -17
  53. package/esm/deps/jsr.io/@std/path/1.1.6/windows/extname.js +0 -83
  54. package/script/deps/jsr.io/@std/path/1.1.6/extname.d.ts +0 -24
  55. package/script/deps/jsr.io/@std/path/1.1.6/extname.js +0 -34
  56. package/script/deps/jsr.io/@std/path/1.1.6/normalize.d.ts +0 -25
  57. package/script/deps/jsr.io/@std/path/1.1.6/normalize.js +0 -35
  58. package/script/deps/jsr.io/@std/path/1.1.6/windows/extname.d.ts +0 -17
  59. package/script/deps/jsr.io/@std/path/1.1.6/windows/extname.js +0 -86
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Options for {@link normalizeWorkspacePath} and {@link toNormalizedWorkspacePath}.
3
+ */
4
+ export type NormalizeWorkspacePathOptions = {
5
+ /** Names the generator in the error when the path is rejected. */
6
+ generatorId?: string;
7
+ };
8
+ /**
9
+ * Whether a path contains a `..` parent-reference segment. `..` is a parent
10
+ * reference only as a whole segment — a directory name that merely contains
11
+ * dots is not flagged.
12
+ */
13
+ export declare const hasParentSegment: (path: string) => boolean;
14
+ /**
15
+ * Whether a path is absolute on either host: a POSIX root, a Windows drive
16
+ * (`C:\`, `C:/`) or a UNC share. Checked on every host, so a client.json
17
+ * written on Windows is rejected the same way on Linux.
18
+ */
19
+ export declare const isAbsolutePath: (path: string) => boolean;
20
+ /**
21
+ * Whether `path` is spelled from the workspace root — `@/`, `./`, a bare
22
+ * leading `/`, or their Windows forms. An artifact path, never a bare
23
+ * module specifier such as `zod` or `@tanstack/query`.
24
+ */
25
+ export declare const hasWorkspaceAnchor: (path: string) => boolean;
26
+ /**
27
+ * Whether `path` can name a file below `basePath`: not a Windows drive or
28
+ * UNC path, no `..` segment, and not `basePath` itself. The non-throwing
29
+ * form of {@link normalizeWorkspacePath}'s checks, for schema validation
30
+ * and for comparing a module specifier against a file path.
31
+ */
32
+ export declare const isValidWorkspacePath: (path: string) => boolean;
33
+ /**
34
+ * The path relative to `basePath`, normalized and with no anchor:
35
+ * what {@link normalizeWorkspacePath} writes after `@/`, and what
36
+ * {@link toResolvedArtifactPath} joins onto `basePath`.
37
+ *
38
+ * Throws when the path cannot name a file below `basePath`: a Windows
39
+ * drive or UNC path, a `..` segment (checked as a whole segment before
40
+ * normalization, so it is never resolved), or a path naming `basePath`
41
+ * itself (`@/`, `@`, `./`, `.`, `/`, ``).
42
+ */
43
+ export declare const toNormalizedWorkspacePath: (path: string, { generatorId }?: NormalizeWorkspacePathOptions) => string;
44
+ /**
45
+ * The one spelling of a workspace path — an export path or a destination
46
+ * path: `@/` followed by a POSIX path relative to `basePath`.
47
+ *
48
+ * A workspace path is a logical path inside the workspace, never a
49
+ * filesystem path, so it reads the same on every host. A generator may
50
+ * return one as `@/types/User.ts`, `./types/User.ts`, `/types/User.ts`,
51
+ * `types/User.ts`, or with Windows separators; the engine stores this form
52
+ * and nothing else, so file-map keys, import modules and the ejected lookup
53
+ * always agree. The result is a fixed point.
54
+ *
55
+ * Throws in the cases {@link toNormalizedWorkspacePath} throws.
56
+ *
57
+ * @example
58
+ * ```typescript
59
+ * normalizeWorkspacePath('@\\types\\User.ts') // '@/types/User.ts'
60
+ * normalizeWorkspacePath('./types/User.ts') // '@/types/User.ts'
61
+ * normalizeWorkspacePath('../User.ts') // throws
62
+ * ```
63
+ */
64
+ export declare const normalizeWorkspacePath: (path: string, options?: NormalizeWorkspacePathOptions) => string;
@@ -0,0 +1,98 @@
1
+ import { normalize } from '../deps/jsr.io/@std/path/1.1.6/posix/normalize.js';
2
+ import { isAbsolute as isPosixAbsolute } from '../deps/jsr.io/@std/path/1.1.6/posix/is_absolute.js';
3
+ import { isAbsolute as isWindowsAbsolute } from '../deps/jsr.io/@std/path/1.1.6/windows/is_absolute.js';
4
+ import { toWorkspacePath } from './toWorkspacePath.js';
5
+ /**
6
+ * Whether a path contains a `..` parent-reference segment. `..` is a parent
7
+ * reference only as a whole segment — a directory name that merely contains
8
+ * dots is not flagged.
9
+ */
10
+ export const hasParentSegment = (path) => path.split(/[/\\]/).some(segment => segment === '..');
11
+ /**
12
+ * Whether a path is absolute on either host: a POSIX root, a Windows drive
13
+ * (`C:\`, `C:/`) or a UNC share. Checked on every host, so a client.json
14
+ * written on Windows is rejected the same way on Linux.
15
+ */
16
+ export const isAbsolutePath = (path) => isPosixAbsolute(path.replaceAll('\\', '/')) || isWindowsAbsolute(path);
17
+ /**
18
+ * A Windows drive path (`C:\`, `C:/`) or a UNC path (`\\server\share`):
19
+ * the two absolute forms that can never be relative to `basePath`. A bare
20
+ * leading `/` is not one — it is an anchor spelling of the workspace root.
21
+ */
22
+ const isDriveOrUncPath = (path) => /^[A-Za-z]:[\\/]/.test(path) || path.startsWith('\\\\');
23
+ /**
24
+ * Whether `path` is spelled from the workspace root — `@/`, `./`, a bare
25
+ * leading `/`, or their Windows forms. An artifact path, never a bare
26
+ * module specifier such as `zod` or `@tanstack/query`.
27
+ */
28
+ export const hasWorkspaceAnchor = (path) => /^(@[\\/]|\.[\\/]|[\\/])/.test(path);
29
+ /**
30
+ * Whether `path` can name a file below `basePath`: not a Windows drive or
31
+ * UNC path, no `..` segment, and not `basePath` itself. The non-throwing
32
+ * form of {@link normalizeWorkspacePath}'s checks, for schema validation
33
+ * and for comparing a module specifier against a file path.
34
+ */
35
+ export const isValidWorkspacePath = (path) => !isDriveOrUncPath(path) && !hasParentSegment(path) && toBody(path) !== '';
36
+ /**
37
+ * The path relative to `basePath`, normalized and with no anchor:
38
+ * what {@link normalizeWorkspacePath} writes after `@/`, and what
39
+ * {@link toResolvedArtifactPath} joins onto `basePath`.
40
+ *
41
+ * Throws when the path cannot name a file below `basePath`: a Windows
42
+ * drive or UNC path, a `..` segment (checked as a whole segment before
43
+ * normalization, so it is never resolved), or a path naming `basePath`
44
+ * itself (`@/`, `@`, `./`, `.`, `/`, ``).
45
+ */
46
+ export const toNormalizedWorkspacePath = (path, { generatorId } = {}) => {
47
+ const reject = (reason) => {
48
+ const source = generatorId ? ` returned by generator '${generatorId}'` : '';
49
+ throw new Error(`Path '${path}'${source} ${reason}`);
50
+ };
51
+ if (isDriveOrUncPath(path)) {
52
+ return reject('is a Windows drive or UNC path; a workspace path is relative to basePath');
53
+ }
54
+ if (hasParentSegment(path)) {
55
+ return reject('contains a ".." segment; a workspace path is a forward path below basePath');
56
+ }
57
+ const body = toBody(path);
58
+ if (body === '') {
59
+ return reject('names basePath itself; a workspace path names a file below it');
60
+ }
61
+ return body;
62
+ };
63
+ /**
64
+ * The one spelling of a workspace path — an export path or a destination
65
+ * path: `@/` followed by a POSIX path relative to `basePath`.
66
+ *
67
+ * A workspace path is a logical path inside the workspace, never a
68
+ * filesystem path, so it reads the same on every host. A generator may
69
+ * return one as `@/types/User.ts`, `./types/User.ts`, `/types/User.ts`,
70
+ * `types/User.ts`, or with Windows separators; the engine stores this form
71
+ * and nothing else, so file-map keys, import modules and the ejected lookup
72
+ * always agree. The result is a fixed point.
73
+ *
74
+ * Throws in the cases {@link toNormalizedWorkspacePath} throws.
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * normalizeWorkspacePath('@\\types\\User.ts') // '@/types/User.ts'
79
+ * normalizeWorkspacePath('./types/User.ts') // '@/types/User.ts'
80
+ * normalizeWorkspacePath('../User.ts') // throws
81
+ * ```
82
+ */
83
+ export const normalizeWorkspacePath = (path, options = {}) => `@/${toNormalizedWorkspacePath(path, options)}`;
84
+ /**
85
+ * Separator swap, then every anchor spelling goes (`@/`, `./`, a leading
86
+ * `/` — {@link toWorkspacePath}), then POSIX normalize of what is left so
87
+ * `@//x` and `@/./x` collapse. The anchor goes first so normalize can
88
+ * never fold it into a name (`@/.` is the root, not a file called `@`).
89
+ * The root in any spelling is the empty string.
90
+ */
91
+ const toBody = (path) => {
92
+ const stripped = toWorkspacePath(path.replaceAll('\\', '/'));
93
+ if (stripped === '') {
94
+ return '';
95
+ }
96
+ const normalized = normalize(stripped);
97
+ return normalized === '.' ? '' : normalized;
98
+ };
@@ -2,9 +2,11 @@
2
2
  * Resolves an artifact's destination path onto `basePath`.
3
3
  *
4
4
  * `destinationPath` is a workspace path in any spelling
5
- * ({@link toWorkspacePath}) — `@/models/User.ts` as a generator wrote it,
6
- * or `./models/User.ts` — and is always joined onto `basePath`; there is no
7
- * absolute-path escape.
5
+ * ({@link toNormalizedWorkspacePath}) — `@/models/User.ts` as a generator
6
+ * wrote it, `./models/User.ts`, or with Windows separators — and is always
7
+ * joined onto `basePath` with forward slashes, so the artifact key reads
8
+ * the same on every host. A `..` segment or an absolute path is refused:
9
+ * every artifact lands below `basePath`, whoever writes it.
8
10
  *
9
11
  * @module toResolvedArtifactPath
10
12
  */
@@ -22,8 +24,9 @@ type ToResolvedArtifactPathArgs = {
22
24
  destinationPath: string;
23
25
  };
24
26
  /**
25
- * Joins `destinationPath` (canonicalized) onto `basePath`, or onto `./` when
26
- * `basePath` is undefined.
27
+ * Joins `destinationPath` (canonicalized) onto `basePath`, or onto the
28
+ * workspace root when `basePath` is undefined. Throws when
29
+ * `destinationPath` cannot name a file below `basePath`.
27
30
  *
28
31
  * @example
29
32
  * ```typescript
@@ -2,18 +2,22 @@
2
2
  * Resolves an artifact's destination path onto `basePath`.
3
3
  *
4
4
  * `destinationPath` is a workspace path in any spelling
5
- * ({@link toWorkspacePath}) — `@/models/User.ts` as a generator wrote it,
6
- * or `./models/User.ts` — and is always joined onto `basePath`; there is no
7
- * absolute-path escape.
5
+ * ({@link toNormalizedWorkspacePath}) — `@/models/User.ts` as a generator
6
+ * wrote it, `./models/User.ts`, or with Windows separators — and is always
7
+ * joined onto `basePath` with forward slashes, so the artifact key reads
8
+ * the same on every host. A `..` segment or an absolute path is refused:
9
+ * every artifact lands below `basePath`, whoever writes it.
8
10
  *
9
11
  * @module toResolvedArtifactPath
10
12
  */
11
13
  import "../_dnt.polyfills.js";
12
- import { join } from '../deps/jsr.io/@std/path/1.1.6/join.js';
14
+ import { join } from '../deps/jsr.io/@std/path/1.1.6/posix/join.js';
15
+ import { toNormalizedWorkspacePath } from './normalizeWorkspacePath.js';
13
16
  import { toWorkspacePath } from './toWorkspacePath.js';
14
17
  /**
15
- * Joins `destinationPath` (canonicalized) onto `basePath`, or onto `./` when
16
- * `basePath` is undefined.
18
+ * Joins `destinationPath` (canonicalized) onto `basePath`, or onto the
19
+ * workspace root when `basePath` is undefined. Throws when
20
+ * `destinationPath` cannot name a file below `basePath`.
17
21
  *
18
22
  * @example
19
23
  * ```typescript
@@ -24,5 +28,5 @@ import { toWorkspacePath } from './toWorkspacePath.js';
24
28
  * ```
25
29
  */
26
30
  export const toResolvedArtifactPath = ({ basePath, destinationPath }) => {
27
- return join(basePath ?? './', toWorkspacePath(destinationPath));
31
+ return join(toWorkspacePath(basePath ?? ''), toNormalizedWorkspacePath(destinationPath));
28
32
  };
@@ -7,9 +7,9 @@
7
7
  * config and examples write it as `./`, and std `normalize` — applied to
8
8
  * `File.path` by the drivers — strips `./` but leaves `@/` alone. Anything
9
9
  * that compares paths from more than one of those sources (package matching,
10
- * on-disk resolution) must see all spellings as equal: every leading `@/` or
11
- * `./` goes, a trailing `/` goes, a Windows `\` is a `/`, and the workspace
12
- * root itself (`@/`, `./`, `.`, ``) is the empty string. The result is a fixed
10
+ * on-disk resolution) must see all spellings as equal: every leading `@/`,
11
+ * `./` or bare `/` goes, a trailing `/` goes, a Windows `\` is a `/`, and the
12
+ * workspace root itself (`@/`, `@`, `./`, `.`, `/`, ``) is the empty string. The result is a fixed
13
13
  * point: canonicalizing it again changes nothing.
14
14
  *
15
15
  * The `@/` stripped here is Skmtc's **workspace root** — the prefix
@@ -7,9 +7,9 @@
7
7
  * config and examples write it as `./`, and std `normalize` — applied to
8
8
  * `File.path` by the drivers — strips `./` but leaves `@/` alone. Anything
9
9
  * that compares paths from more than one of those sources (package matching,
10
- * on-disk resolution) must see all spellings as equal: every leading `@/` or
11
- * `./` goes, a trailing `/` goes, a Windows `\` is a `/`, and the workspace
12
- * root itself (`@/`, `./`, `.`, ``) is the empty string. The result is a fixed
10
+ * on-disk resolution) must see all spellings as equal: every leading `@/`,
11
+ * `./` or bare `/` goes, a trailing `/` goes, a Windows `\` is a `/`, and the
12
+ * workspace root itself (`@/`, `@`, `./`, `.`, `/`, ``) is the empty string. The result is a fixed
13
13
  * point: canonicalizing it again changes nothing.
14
14
  *
15
15
  * The `@/` stripped here is Skmtc's **workspace root** — the prefix
@@ -29,9 +29,9 @@
29
29
  export const toWorkspacePath = (path) => {
30
30
  const withoutAnchor = path
31
31
  .replaceAll('\\', '/')
32
- .replace(/^(?:@\/|\.\/)+/, '')
32
+ .replace(/^(?:@\/|\.\/|\/)+/, '')
33
33
  .replace(/\/+$/, '');
34
- return withoutAnchor === '.' ? '' : withoutAnchor;
34
+ return withoutAnchor === '.' || withoutAnchor === '@' ? '' : withoutAnchor;
35
35
  };
36
36
  /**
37
37
  * `path` is `rootPath` itself or a file or folder below it. A root is a
package/esm/mod.d.ts CHANGED
@@ -118,6 +118,7 @@ export * from './helpers/strings.js';
118
118
  export * from './helpers/parseModuleName.js';
119
119
  export * from './helpers/toResolvedArtifactPath.js';
120
120
  export * from './helpers/toWorkspacePath.js';
121
+ export * from './helpers/normalizeWorkspacePath.js';
121
122
  export * from './helpers/matchPackage.js';
122
123
  export * from './helpers/withVariant.js';
123
124
  export * from './helpers/toVariantList.js';
package/esm/mod.js CHANGED
@@ -118,6 +118,7 @@ export * from './helpers/strings.js';
118
118
  export * from './helpers/parseModuleName.js';
119
119
  export * from './helpers/toResolvedArtifactPath.js';
120
120
  export * from './helpers/toWorkspacePath.js';
121
+ export * from './helpers/normalizeWorkspacePath.js';
121
122
  export * from './helpers/matchPackage.js';
122
123
  export * from './helpers/withVariant.js';
123
124
  export * from './helpers/toVariantList.js';
@@ -52,13 +52,8 @@ import "../_dnt.polyfills.js";
52
52
  import { generatorEnrichments } from './Enrichments.js';
53
53
  import * as v from 'valibot';
54
54
  import { method } from './Method.js';
55
+ import { hasParentSegment, isAbsolutePath, isValidWorkspacePath } from '../helpers/normalizeWorkspacePath.js';
55
56
  import { toWorkspacePath } from '../helpers/toWorkspacePath.js';
56
- /**
57
- * Whether a relative path contains a `..` parent-reference segment.
58
- * `..` is a parent reference only as a whole path segment — a
59
- * directory name that merely contains dots is not flagged.
60
- */
61
- const hasParentSegment = (path) => path.split(/[/\\]/).some(segment => segment === '..');
62
57
  /**
63
58
  * Valibot schema for {@link ModulePackage}.
64
59
  *
@@ -175,7 +170,9 @@ export const anchorsSettings = v.object({
175
170
  out: v.optional(v.string())
176
171
  });
177
172
  export const clientSettings = v.object({
178
- basePath: v.optional(v.string()),
173
+ basePath: v.optional(v.pipe(v.string(), v.check(basePath => !isAbsolutePath(basePath), 'basePath must be relative to the SKMTC root (the directory containing .skmtc/); ' +
174
+ 'absolute paths are not supported because generated output is always written under it'), v.check(basePath => !hasParentSegment(basePath), 'basePath must be a forward path with no ".." segments — it is the on-disk anchor ' +
175
+ 'every generated file sits below'))),
179
176
  schemaSource: v.optional(v.string()),
180
177
  packages: v.optional(modulePackages),
181
178
  enrichments: v.optional(generatorEnrichments),
@@ -185,7 +182,8 @@ export const clientSettings = v.object({
185
182
  inputDirs: v.optional(v.array(v.string())),
186
183
  formatter: v.optional(v.string()),
187
184
  generatedSuffix: v.optional(v.string()),
188
- ejected: v.optional(v.array(v.string()))
185
+ ejected: v.optional(v.array(v.pipe(v.string(), v.check(isValidWorkspacePath, 'settings.ejected entries are export paths: a forward path below basePath, ' +
186
+ 'with no ".." segment and not a Windows drive or UNC path'))))
189
187
  });
190
188
  /**
191
189
  * Valibot schema for validating SKMTC client configuration.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skmtc/core",
3
- "version": "0.28.6",
3
+ "version": "0.29.0",
4
4
  "description": "Skmtc is a declarative code generation framework",
5
5
  "keywords": [
6
6
  "openapi",
@@ -16,7 +16,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
16
16
  var _GenerateContext_instances, _GenerateContext_files, _GenerateContext_previews, _GenerateContext_captureChannel, _GenerateContext_enrichmentAudit, _GenerateContext_reportSkippedEnrichment, _GenerateContext_schemaRefNames, _GenerateContext_subjectDefaults, _GenerateContext_runOasOperationGenerator, _GenerateContext_runWebhookGenerator, _GenerateContext_runGqlOperationGenerator, _GenerateContext_runModelGenerator, _GenerateContext_addPreview, _GenerateContext_toContentSettingsExportPath, _GenerateContext_ejectedBySuffixedPath_get, _GenerateContext_ejectedBySuffixedPathCache, _GenerateContext_findContainer, _GenerateContext_toContainer;
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.toModelSource = exports.toGqlOperationSource = exports.toWebhookSource = exports.toOasOperationSource = exports.GenerateContext = void 0;
19
- const normalize_js_1 = require("../deps/jsr.io/@std/path/1.1.6/normalize.js");
19
+ const normalizeWorkspacePath_js_1 = require("../helpers/normalizeWorkspacePath.js");
20
20
  const applyGeneratedSuffix_js_1 = require("../helpers/applyGeneratedSuffix.js");
21
21
  const OasOperationDriver_js_1 = require("../dsl/operation/oas/OasOperationDriver.js");
22
22
  const WebhookDriver_js_1 = require("../dsl/webhook/WebhookDriver.js");
@@ -449,7 +449,7 @@ class GenerateContext {
449
449
  * language-constructed file, use {@link addFile}.
450
450
  */
451
451
  getFile(filePath) {
452
- return __classPrivateFieldGet(this, _GenerateContext_files, "f").get((0, normalize_js_1.normalize)(filePath));
452
+ return __classPrivateFieldGet(this, _GenerateContext_files, "f").get((0, normalizeWorkspacePath_js_1.normalizeWorkspacePath)(filePath));
453
453
  }
454
454
  /**
455
455
  * Read-only view of every file generated so far, keyed by (normalized)
@@ -473,7 +473,7 @@ class GenerateContext {
473
473
  * (`context.getFile(path) ?? context.addFile(new KtFile({ … }))`).
474
474
  */
475
475
  addFile(file) {
476
- const normalizedPath = (0, normalize_js_1.normalize)(file.path);
476
+ const normalizedPath = (0, normalizeWorkspacePath_js_1.normalizeWorkspacePath)(file.path);
477
477
  if (__classPrivateFieldGet(this, _GenerateContext_files, "f").has(normalizedPath)) {
478
478
  throw new Error(`File already exists: ${normalizedPath}`);
479
479
  }
@@ -487,7 +487,7 @@ class GenerateContext {
487
487
  * @param args - Registration arguments with destination path and JSON content
488
488
  */
489
489
  registerJson({ destinationPath, json }) {
490
- const normalizedPath = (0, normalize_js_1.normalize)(destinationPath);
490
+ const normalizedPath = (0, normalizeWorkspacePath_js_1.normalizeWorkspacePath)(destinationPath);
491
491
  let currentFile = this.getFile(normalizedPath);
492
492
  if (!currentFile) {
493
493
  currentFile = new JsonFile_js_1.JsonFile({ path: normalizedPath, content: {} });
@@ -506,7 +506,7 @@ class GenerateContext {
506
506
  * @experimental This method is experimental and may change in future versions
507
507
  */
508
508
  registerMarkdown({ destinationPath, markdown }) {
509
- const normalizedPath = (0, normalize_js_1.normalize)(destinationPath);
509
+ const normalizedPath = (0, normalizeWorkspacePath_js_1.normalizeWorkspacePath)(destinationPath);
510
510
  let currentFile = this.getFile(normalizedPath);
511
511
  if (!currentFile) {
512
512
  currentFile = new MarkdownFile_js_1.MarkdownFile({ path: normalizedPath, content: '' });
@@ -527,7 +527,7 @@ class GenerateContext {
527
527
  * @mutates this.files
528
528
  */
529
529
  register({ imports = [], reExports = [], definitions, custom, destinationPath, into }) {
530
- const normalizedPath = (0, normalize_js_1.normalize)(destinationPath);
530
+ const normalizedPath = (0, normalizeWorkspacePath_js_1.normalizeWorkspacePath)(destinationPath);
531
531
  const currentFile = this.getFile(normalizedPath);
532
532
  // `register` never creates files — it speaks pure data and the engine
533
533
  // never names a file class. Callers pre-create the destination file
@@ -635,7 +635,7 @@ class GenerateContext {
635
635
  // the use site (same ephemeral read the Drivers make) — pre-creates
636
636
  // the destination file caller-side, and stores via the pure-data
637
637
  // `register`.
638
- const normalizedPath = (0, normalize_js_1.normalize)(destinationPath);
638
+ const normalizedPath = (0, normalizeWorkspacePath_js_1.normalizeWorkspacePath)(destinationPath);
639
639
  if (!this.getFile(normalizedPath)) {
640
640
  this.addFile(projection.lang.createFile({ path: normalizedPath, settings: this.settings }));
641
641
  }
@@ -702,7 +702,7 @@ class GenerateContext {
702
702
  enrichments,
703
703
  variant,
704
704
  options
705
- })),
705
+ }), args.projection.id),
706
706
  enrichments,
707
707
  variant
708
708
  });
@@ -730,7 +730,7 @@ class GenerateContext {
730
730
  enrichments,
731
731
  variant,
732
732
  options
733
- })),
733
+ }), args.projection.id),
734
734
  enrichments,
735
735
  variant
736
736
  });
@@ -763,7 +763,7 @@ class GenerateContext {
763
763
  enrichments,
764
764
  variant,
765
765
  options
766
- })),
766
+ }), args.projection.id),
767
767
  enrichments,
768
768
  variant
769
769
  });
@@ -785,7 +785,7 @@ class GenerateContext {
785
785
  name: projection.toIdentifierName({ refName, enrichments, variant, options }),
786
786
  ...projection.toIdentifierType(refName, this)
787
787
  }),
788
- exportPath: __classPrivateFieldGet(this, _GenerateContext_instances, "m", _GenerateContext_toContentSettingsExportPath).call(this, projection.toExportPath({ refName, enrichments, variant, options })),
788
+ exportPath: __classPrivateFieldGet(this, _GenerateContext_instances, "m", _GenerateContext_toContentSettingsExportPath).call(this, projection.toExportPath({ refName, enrichments, variant, options }), projection.id),
789
789
  enrichments,
790
790
  variant
791
791
  });
@@ -1172,15 +1172,15 @@ _GenerateContext_files = new WeakMap(), _GenerateContext_previews = new WeakMap(
1172
1172
  module: { ...module, exportPath: __classPrivateFieldGet(this, _GenerateContext_instances, "m", _GenerateContext_toContentSettingsExportPath).call(this, module.exportPath) },
1173
1173
  source
1174
1174
  };
1175
- }, _GenerateContext_toContentSettingsExportPath = function _GenerateContext_toContentSettingsExportPath(exportPath) {
1176
- const suffixed = (0, applyGeneratedSuffix_js_1.applyGeneratedSuffix)(exportPath, this.settings?.generatedSuffix ?? applyGeneratedSuffix_js_1.DEFAULT_GENERATED_SUFFIX);
1177
- return __classPrivateFieldGet(this, _GenerateContext_instances, "a", _GenerateContext_ejectedBySuffixedPath_get).get((0, normalize_js_1.normalize)(suffixed)) ?? suffixed;
1175
+ }, _GenerateContext_toContentSettingsExportPath = function _GenerateContext_toContentSettingsExportPath(exportPath, generatorId) {
1176
+ const suffixed = (0, applyGeneratedSuffix_js_1.applyGeneratedSuffix)((0, normalizeWorkspacePath_js_1.normalizeWorkspacePath)(exportPath, { generatorId }), this.settings?.generatedSuffix ?? applyGeneratedSuffix_js_1.DEFAULT_GENERATED_SUFFIX);
1177
+ return __classPrivateFieldGet(this, _GenerateContext_instances, "a", _GenerateContext_ejectedBySuffixedPath_get).get(suffixed) ?? suffixed;
1178
1178
  }, _GenerateContext_ejectedBySuffixedPath_get = function _GenerateContext_ejectedBySuffixedPath_get() {
1179
1179
  if (__classPrivateFieldGet(this, _GenerateContext_ejectedBySuffixedPathCache, "f") === undefined) {
1180
1180
  const suffix = this.settings?.generatedSuffix ?? applyGeneratedSuffix_js_1.DEFAULT_GENERATED_SUFFIX;
1181
1181
  __classPrivateFieldSet(this, _GenerateContext_ejectedBySuffixedPathCache, new Map((this.settings?.ejected ?? []).map(ejectedPath => {
1182
- const normalized = (0, normalize_js_1.normalize)(ejectedPath);
1183
- return [(0, normalize_js_1.normalize)((0, applyGeneratedSuffix_js_1.applyGeneratedSuffix)(normalized, suffix)), normalized];
1182
+ const normalized = (0, normalizeWorkspacePath_js_1.normalizeWorkspacePath)(ejectedPath);
1183
+ return [(0, applyGeneratedSuffix_js_1.applyGeneratedSuffix)(normalized, suffix), normalized];
1184
1184
  })), "f");
1185
1185
  }
1186
1186
  return __classPrivateFieldGet(this, _GenerateContext_ejectedBySuffixedPathCache, "f");
@@ -130,13 +130,13 @@ export declare class RenderContext {
130
130
  */
131
131
  collate(stackTrail: StackTrail): FilesRenderResult;
132
132
  /**
133
- * Retrieves a file from the context by its normalized path.
133
+ * Retrieves a file from the context by its export path.
134
134
  *
135
- * This method looks up a file in the context's file map using path normalization
136
- * to ensure consistent path resolution. It validates that the requested file
137
- * exists and throws an error if not found.
135
+ * The path is canonicalized first ({@link normalizeWorkspacePath}), so any
136
+ * spelling of the same export path finds the same file. Throws when no
137
+ * file exists at that path.
138
138
  *
139
- * @param filePath - The file path to retrieve (will be normalized)
139
+ * @param filePath - The export path to retrieve, in any spelling
140
140
  * @returns The File or JsonFile instance
141
141
  * @throws {Error} When the file is not found in the context
142
142
  *
@@ -145,9 +145,9 @@ export declare class RenderContext {
145
145
  * const file = renderContext.getFile('./src/models/User.ts');
146
146
  * console.log(file.toString()); // Access file content
147
147
  *
148
- * // Works with various path formats
148
+ * // Every spelling of the same export path finds the same file
149
149
  * const sameFile = renderContext.getFile('src/models/User.ts');
150
- * const alsoSameFile = renderContext.getFile('/absolute/path/src/models/User.ts');
150
+ * const alsoSameFile = renderContext.getFile('@/src/models/User.ts');
151
151
  * ```
152
152
  */
153
153
  getFile(filePath: string): FileBase;
@@ -17,7 +17,7 @@ var _RenderContext_captureChannel, _RenderContext_sink, _RenderContext_captures;
17
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
18
  exports.RenderContext = void 0;
19
19
  const tiny_invariant_1 = __importDefault(require("tiny-invariant"));
20
- const normalize_js_1 = require("../deps/jsr.io/@std/path/1.1.6/normalize.js");
20
+ const normalizeWorkspacePath_js_1 = require("../helpers/normalizeWorkspacePath.js");
21
21
  const toResolvedArtifactPath_js_1 = require("../helpers/toResolvedArtifactPath.js");
22
22
  const CodeFileBase_js_1 = require("../dsl/CodeFileBase.js");
23
23
  const CaptureSink_js_1 = require("../anchors/CaptureSink.js");
@@ -174,8 +174,9 @@ class RenderContext {
174
174
  __classPrivateFieldSet(this, _RenderContext_sink, undefined, "f");
175
175
  }
176
176
  // Build one sidecar per captured File from the spans the sink
177
- // resolved (no re-render, no `toString`). Keyed by destination path,
178
- // matching the file map. Accumulate the flat generation map.
177
+ // resolved (no re-render, no `toString`). Keyed by the resolved artifact
178
+ // path, matching `artifacts` and the manifest, so a sidecar sits at
179
+ // `<outDir>/<artifact key>.skm.json` where doctor looks for it.
179
180
  const { parser, schemaSrc, generatorMeta } = postPassConfig;
180
181
  const sidecars = {};
181
182
  const generationMap = [];
@@ -188,7 +189,11 @@ class RenderContext {
188
189
  parser,
189
190
  generatorMeta
190
191
  });
191
- sidecars[capture.destinationPath] = sidecar;
192
+ const artifactPath = (0, toResolvedArtifactPath_js_1.toResolvedArtifactPath)({
193
+ basePath: this.basePath,
194
+ destinationPath: capture.destinationPath
195
+ });
196
+ sidecars[artifactPath] = sidecar;
192
197
  generationMap.push(...(0, generationMap_js_1.entriesForSidecar)(sidecar));
193
198
  }
194
199
  __classPrivateFieldSet(this, _RenderContext_captures, [], "f");
@@ -276,13 +281,13 @@ class RenderContext {
276
281
  return output;
277
282
  }
278
283
  /**
279
- * Retrieves a file from the context by its normalized path.
284
+ * Retrieves a file from the context by its export path.
280
285
  *
281
- * This method looks up a file in the context's file map using path normalization
282
- * to ensure consistent path resolution. It validates that the requested file
283
- * exists and throws an error if not found.
286
+ * The path is canonicalized first ({@link normalizeWorkspacePath}), so any
287
+ * spelling of the same export path finds the same file. Throws when no
288
+ * file exists at that path.
284
289
  *
285
- * @param filePath - The file path to retrieve (will be normalized)
290
+ * @param filePath - The export path to retrieve, in any spelling
286
291
  * @returns The File or JsonFile instance
287
292
  * @throws {Error} When the file is not found in the context
288
293
  *
@@ -291,13 +296,13 @@ class RenderContext {
291
296
  * const file = renderContext.getFile('./src/models/User.ts');
292
297
  * console.log(file.toString()); // Access file content
293
298
  *
294
- * // Works with various path formats
299
+ * // Every spelling of the same export path finds the same file
295
300
  * const sameFile = renderContext.getFile('src/models/User.ts');
296
- * const alsoSameFile = renderContext.getFile('/absolute/path/src/models/User.ts');
301
+ * const alsoSameFile = renderContext.getFile('@/src/models/User.ts');
297
302
  * ```
298
303
  */
299
304
  getFile(filePath) {
300
- const normalizedPath = (0, normalize_js_1.normalize)(filePath);
305
+ const normalizedPath = (0, normalizeWorkspacePath_js_1.normalizeWorkspacePath)(filePath);
301
306
  const currentFile = this.files.get(normalizedPath);
302
307
  (0, tiny_invariant_1.default)(currentFile, `File not found during render phase: ${normalizedPath}`);
303
308
  return currentFile;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Verifies whether provided path is absolute.
3
+ *
4
+ * @example Usage
5
+ * ```ts
6
+ * import { isAbsolute } from "@std/path/posix/is-absolute";
7
+ * import { assert, assertFalse } from "@std/assert";
8
+ *
9
+ * assert(isAbsolute("/home/user/Documents/"));
10
+ * assertFalse(isAbsolute("home/user/Documents/"));
11
+ * ```
12
+ *
13
+ * @param path The path to verify.
14
+ * @returns Whether the path is absolute.
15
+ */
16
+ export declare function isAbsolute(path: string): boolean;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ // Copyright 2018-2026 the Deno authors. MIT license.
3
+ // This module is browser compatible.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.isAbsolute = isAbsolute;
6
+ const assert_path_js_1 = require("../_common/assert_path.js");
7
+ const _util_js_1 = require("./_util.js");
8
+ /**
9
+ * Verifies whether provided path is absolute.
10
+ *
11
+ * @example Usage
12
+ * ```ts
13
+ * import { isAbsolute } from "@std/path/posix/is-absolute";
14
+ * import { assert, assertFalse } from "@std/assert";
15
+ *
16
+ * assert(isAbsolute("/home/user/Documents/"));
17
+ * assertFalse(isAbsolute("home/user/Documents/"));
18
+ * ```
19
+ *
20
+ * @param path The path to verify.
21
+ * @returns Whether the path is absolute.
22
+ */
23
+ function isAbsolute(path) {
24
+ (0, assert_path_js_1.assertPath)(path);
25
+ return path.length > 0 && (0, _util_js_1.isPosixPathSeparator)(path.charCodeAt(0));
26
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Verifies whether provided path is absolute.
3
+ *
4
+ * @example Usage
5
+ * ```ts
6
+ * import { isAbsolute } from "@std/path/windows/is-absolute";
7
+ * import { assert, assertFalse } from "@std/assert";
8
+ *
9
+ * assert(isAbsolute("C:\\foo\\bar"));
10
+ * assertFalse(isAbsolute("..\\baz"));
11
+ * ```
12
+ *
13
+ * @param path The path to verify.
14
+ * @returns `true` if the path is absolute, `false` otherwise.
15
+ */
16
+ export declare function isAbsolute(path: string): boolean;