@vibe-agent-toolkit/utils 0.1.35 → 0.1.37
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/dist/asset-reference.d.ts +35 -0
- package/dist/asset-reference.d.ts.map +1 -0
- package/dist/asset-reference.js +138 -0
- package/dist/asset-reference.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve a VAT "asset reference" to an absolute filesystem path.
|
|
3
|
+
*
|
|
4
|
+
* An asset reference is either:
|
|
5
|
+
* - A filesystem path (relative to baseDir, or absolute), OR
|
|
6
|
+
* - An npm bare specifier (`@scope/pkg/subpath` or `pkg/subpath`),
|
|
7
|
+
* resolved via Node module resolution from baseDir, honoring the
|
|
8
|
+
* target package's `exports` map.
|
|
9
|
+
*
|
|
10
|
+
* Bare specifiers let VAT consumers reference schemas (and future
|
|
11
|
+
* config-supplied files) published as npm packages without hardcoding
|
|
12
|
+
* the package's internal layout. The publisher's `exports` field owns
|
|
13
|
+
* the layout; consumers stay portable.
|
|
14
|
+
*
|
|
15
|
+
* NOTE: this is a VAT-internal abstraction for locating files. It is NOT
|
|
16
|
+
* an RFC 3986 URI reference and is intentionally NOT used by markdown link
|
|
17
|
+
* walkers (including the `format: "uri-reference"` frontmatter checker) —
|
|
18
|
+
* bare specifiers are not valid URIs and would not resolve in a renderer.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* resolveAssetReference('@scope/pkg/schemas/foo.json', '/proj')
|
|
22
|
+
* // -> '/proj/node_modules/@scope/pkg/dist/schemas/foo.json' (per the
|
|
23
|
+
* // package's exports map)
|
|
24
|
+
* resolveAssetReference('./schemas/foo.json', '/proj')
|
|
25
|
+
* // -> '/proj/schemas/foo.json'
|
|
26
|
+
* resolveAssetReference('/abs/foo.json', '/proj')
|
|
27
|
+
* // -> '/abs/foo.json'
|
|
28
|
+
*
|
|
29
|
+
* @param specifier - The asset reference (path or bare npm specifier)
|
|
30
|
+
* @param baseDir - Absolute directory used as the resolution anchor
|
|
31
|
+
* @returns Absolute filesystem path to the asset
|
|
32
|
+
* @throws Error with actionable message and `cause` on resolution failure
|
|
33
|
+
*/
|
|
34
|
+
export declare function resolveAssetReference(specifier: string, baseDir: string): string;
|
|
35
|
+
//# sourceMappingURL=asset-reference.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asset-reference.d.ts","sourceRoot":"","sources":["../src/asset-reference.ts"],"names":[],"mappings":"AAYA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAmBhF"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { existsSync } from 'node:fs';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { pathToFileURL } from 'node:url';
|
|
4
|
+
import { isAbsolutePath, safePath } from './path-utils.js';
|
|
5
|
+
// First segment must be a valid npm package name (scoped or unscoped),
|
|
6
|
+
// followed by `/` and at least one subpath segment. Paths starting with
|
|
7
|
+
// `.`, `/`, or a Windows drive letter are filesystem paths, never bare
|
|
8
|
+
// specifiers.
|
|
9
|
+
const BARE_SPECIFIER_RE = /^(?:@[^/]+\/[^/]+|[a-z0-9][a-z0-9._-]*)\/.+/i;
|
|
10
|
+
/**
|
|
11
|
+
* Resolve a VAT "asset reference" to an absolute filesystem path.
|
|
12
|
+
*
|
|
13
|
+
* An asset reference is either:
|
|
14
|
+
* - A filesystem path (relative to baseDir, or absolute), OR
|
|
15
|
+
* - An npm bare specifier (`@scope/pkg/subpath` or `pkg/subpath`),
|
|
16
|
+
* resolved via Node module resolution from baseDir, honoring the
|
|
17
|
+
* target package's `exports` map.
|
|
18
|
+
*
|
|
19
|
+
* Bare specifiers let VAT consumers reference schemas (and future
|
|
20
|
+
* config-supplied files) published as npm packages without hardcoding
|
|
21
|
+
* the package's internal layout. The publisher's `exports` field owns
|
|
22
|
+
* the layout; consumers stay portable.
|
|
23
|
+
*
|
|
24
|
+
* NOTE: this is a VAT-internal abstraction for locating files. It is NOT
|
|
25
|
+
* an RFC 3986 URI reference and is intentionally NOT used by markdown link
|
|
26
|
+
* walkers (including the `format: "uri-reference"` frontmatter checker) —
|
|
27
|
+
* bare specifiers are not valid URIs and would not resolve in a renderer.
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* resolveAssetReference('@scope/pkg/schemas/foo.json', '/proj')
|
|
31
|
+
* // -> '/proj/node_modules/@scope/pkg/dist/schemas/foo.json' (per the
|
|
32
|
+
* // package's exports map)
|
|
33
|
+
* resolveAssetReference('./schemas/foo.json', '/proj')
|
|
34
|
+
* // -> '/proj/schemas/foo.json'
|
|
35
|
+
* resolveAssetReference('/abs/foo.json', '/proj')
|
|
36
|
+
* // -> '/abs/foo.json'
|
|
37
|
+
*
|
|
38
|
+
* @param specifier - The asset reference (path or bare npm specifier)
|
|
39
|
+
* @param baseDir - Absolute directory used as the resolution anchor
|
|
40
|
+
* @returns Absolute filesystem path to the asset
|
|
41
|
+
* @throws Error with actionable message and `cause` on resolution failure
|
|
42
|
+
*/
|
|
43
|
+
export function resolveAssetReference(specifier, baseDir) {
|
|
44
|
+
if (!isBareSpecifier(specifier)) {
|
|
45
|
+
return safePath.resolve(baseDir, specifier);
|
|
46
|
+
}
|
|
47
|
+
const requireFn = createRequire(pathToFileURL(safePath.join(baseDir, 'package.json')).href);
|
|
48
|
+
try {
|
|
49
|
+
return requireFn.resolve(specifier);
|
|
50
|
+
}
|
|
51
|
+
catch (cause) {
|
|
52
|
+
// Unscoped bare specifiers can also be interpreted as relative paths
|
|
53
|
+
// (e.g., `dir/file.json` with no installed package "dir"). Fall back
|
|
54
|
+
// to path resolution. Scoped (`@scope/...`) has no such ambiguity —
|
|
55
|
+
// surface the error.
|
|
56
|
+
if (!specifier.startsWith('@') && isModuleNotFound(cause)) {
|
|
57
|
+
return safePath.resolve(baseDir, specifier);
|
|
58
|
+
}
|
|
59
|
+
throw new Error(formatActionableError(specifier, baseDir, cause), { cause: cause });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Build a message that distinguishes the three common failure modes so callers
|
|
64
|
+
* know where to look. Node's raw error often points at the resolved on-disk
|
|
65
|
+
* path, which adopters easily misread as a VAT path-handling bug.
|
|
66
|
+
*/
|
|
67
|
+
function formatActionableError(specifier, baseDir, cause) {
|
|
68
|
+
const headline = formatResolutionError(cause);
|
|
69
|
+
const code = cause?.code;
|
|
70
|
+
const missingPath = extractMissingModulePath(cause);
|
|
71
|
+
// Mode 1: Node walked the package's `exports` map, computed an absolute
|
|
72
|
+
// target path, and that file is not on disk. This is the most confusing
|
|
73
|
+
// case for adopters: the package IS installed, the exports map IS correct,
|
|
74
|
+
// but a build step in the target package didn't run (or produced different
|
|
75
|
+
// output). Name the missing file explicitly and point at the publisher.
|
|
76
|
+
if (code === 'MODULE_NOT_FOUND' && missingPath && missingPath !== specifier && isAbsolutePath(missingPath)) {
|
|
77
|
+
const fileExists = safeExistsSync(missingPath);
|
|
78
|
+
if (!fileExists) {
|
|
79
|
+
return (`Failed to resolve asset reference '${specifier}': ` +
|
|
80
|
+
`the package's "exports" map points to '${missingPath}', but that file does not exist on disk.\n` +
|
|
81
|
+
`Hint: the target package was found, but a build step did not produce this file. ` +
|
|
82
|
+
`Rebuild the publishing package (e.g., \`pnpm --filter <package> build\`) to generate the missing artifact, ` +
|
|
83
|
+
`or verify the package's "exports" subpath pattern matches what its build emits.\n` +
|
|
84
|
+
`Node error: ${headline}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// Mode 2: Exports map didn't expose the requested subpath at all.
|
|
88
|
+
if (code === 'ERR_PACKAGE_PATH_NOT_EXPORTED') {
|
|
89
|
+
return (`Failed to resolve asset reference '${specifier}': ` +
|
|
90
|
+
`the target package does not expose this subpath in its "exports" map.\n` +
|
|
91
|
+
`Hint: check the package's package.json "exports" field — only paths declared there are reachable via bare specifier.\n` +
|
|
92
|
+
`Node error: ${headline}`);
|
|
93
|
+
}
|
|
94
|
+
// Mode 3: Package itself not installed / not reachable from baseDir.
|
|
95
|
+
return (`Failed to resolve asset reference '${specifier}': ${headline}\n` +
|
|
96
|
+
`Check the package's "exports" field, or run install in ${baseDir}.`);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Node's MODULE_NOT_FOUND message has the form: `Cannot find module 'X'`.
|
|
100
|
+
* Pull `X` out so we can decide whether the error refers to the original
|
|
101
|
+
* specifier (package not installed) or to a resolved on-disk path (file
|
|
102
|
+
* missing at exports target).
|
|
103
|
+
*/
|
|
104
|
+
const CANNOT_FIND_MODULE_RE = /Cannot find module '([^']+)'/;
|
|
105
|
+
function extractMissingModulePath(cause) {
|
|
106
|
+
if (!(cause instanceof Error))
|
|
107
|
+
return undefined;
|
|
108
|
+
const match = CANNOT_FIND_MODULE_RE.exec(cause.message);
|
|
109
|
+
return match?.[1];
|
|
110
|
+
}
|
|
111
|
+
function safeExistsSync(filePath) {
|
|
112
|
+
try {
|
|
113
|
+
// eslint-disable-next-line security/detect-non-literal-fs-filename -- filePath is a Node-resolved exports target, used only to refine the error message
|
|
114
|
+
return existsSync(filePath);
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function isBareSpecifier(value) {
|
|
121
|
+
return BARE_SPECIFIER_RE.test(value);
|
|
122
|
+
}
|
|
123
|
+
function isModuleNotFound(err) {
|
|
124
|
+
return (typeof err === 'object' &&
|
|
125
|
+
err !== null &&
|
|
126
|
+
'code' in err &&
|
|
127
|
+
err.code === 'MODULE_NOT_FOUND');
|
|
128
|
+
}
|
|
129
|
+
function formatResolutionError(err) {
|
|
130
|
+
if (err instanceof Error) {
|
|
131
|
+
// Node's MODULE_NOT_FOUND / ERR_PACKAGE_PATH_NOT_EXPORTED messages are
|
|
132
|
+
// long and noisy; first line is the actionable summary.
|
|
133
|
+
const firstLine = err.message.split('\n', 1)[0];
|
|
134
|
+
return firstLine ?? err.message;
|
|
135
|
+
}
|
|
136
|
+
return String(err);
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=asset-reference.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"asset-reference.js","sourceRoot":"","sources":["../src/asset-reference.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,gBAAgB,CAAC;AAG/B,cAAc,iBAAiB,CAAC;AAGhC,cAAc,eAAe,CAAC;AAG9B,cAAc,mBAAmB,CAAC;AAGlC,cAAc,wBAAwB,CAAC;AAGvC,cAAc,gBAAgB,CAAC;AAG/B,cAAc,oBAAoB,CAAC;AAGnC,cAAc,kBAAkB,CAAC;AAGjC,cAAc,mBAAmB,CAAC;AAGlC,cAAc,wBAAwB,CAAC;AAGvC,cAAc,eAAe,CAAC;AAG9B,cAAc,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,gBAAgB,CAAC;AAG/B,cAAc,iBAAiB,CAAC;AAGhC,cAAc,sBAAsB,CAAC;AAGrC,cAAc,eAAe,CAAC;AAG9B,cAAc,mBAAmB,CAAC;AAGlC,cAAc,wBAAwB,CAAC;AAGvC,cAAc,gBAAgB,CAAC;AAG/B,cAAc,oBAAoB,CAAC;AAGnC,cAAc,kBAAkB,CAAC;AAGjC,cAAc,mBAAmB,CAAC;AAGlC,cAAc,wBAAwB,CAAC;AAGvC,cAAc,eAAe,CAAC;AAG9B,cAAc,oBAAoB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
export * from './safe-exec.js';
|
|
9
9
|
// Cross-platform path utilities
|
|
10
10
|
export * from './path-utils.js';
|
|
11
|
+
// Asset reference resolution (paths + npm bare specifiers)
|
|
12
|
+
export * from './asset-reference.js';
|
|
11
13
|
// Filesystem utilities
|
|
12
14
|
export * from './fs-utils.js';
|
|
13
15
|
// Directory crawling with glob patterns
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,8DAA8D;AAC9D,cAAc,gBAAgB,CAAC;AAE/B,gCAAgC;AAChC,cAAc,iBAAiB,CAAC;AAEhC,uBAAuB;AACvB,cAAc,eAAe,CAAC;AAE9B,wCAAwC;AACxC,cAAc,mBAAmB,CAAC;AAElC,sBAAsB;AACtB,cAAc,wBAAwB,CAAC;AAEvC,8CAA8C;AAC9C,cAAc,gBAAgB,CAAC;AAE/B,kEAAkE;AAClE,cAAc,oBAAoB,CAAC;AAEnC,yDAAyD;AACzD,cAAc,kBAAkB,CAAC;AAEjC,oDAAoD;AACpD,cAAc,mBAAmB,CAAC;AAElC,4CAA4C;AAC5C,cAAc,wBAAwB,CAAC;AAEvC,2DAA2D;AAC3D,cAAc,eAAe,CAAC;AAE9B,oEAAoE;AACpE,cAAc,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,8DAA8D;AAC9D,cAAc,gBAAgB,CAAC;AAE/B,gCAAgC;AAChC,cAAc,iBAAiB,CAAC;AAEhC,2DAA2D;AAC3D,cAAc,sBAAsB,CAAC;AAErC,uBAAuB;AACvB,cAAc,eAAe,CAAC;AAE9B,wCAAwC;AACxC,cAAc,mBAAmB,CAAC;AAElC,sBAAsB;AACtB,cAAc,wBAAwB,CAAC;AAEvC,8CAA8C;AAC9C,cAAc,gBAAgB,CAAC;AAE/B,kEAAkE;AAClE,cAAc,oBAAoB,CAAC;AAEnC,yDAAyD;AACzD,cAAc,kBAAkB,CAAC;AAEjC,oDAAoD;AACpD,cAAc,mBAAmB,CAAC;AAElC,4CAA4C;AAC5C,cAAc,wBAAwB,CAAC;AAEvC,2DAA2D;AAC3D,cAAc,eAAe,CAAC;AAE9B,oEAAoE;AACpE,cAAc,oBAAoB,CAAC"}
|