@elaraai/e3-cli 0.0.2-beta.9 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +4 -0
- package/README.md +169 -46
- package/dist/src/cli.js +197 -73
- package/dist/src/cli.js.map +1 -1
- package/dist/src/commands/auth.d.ts +23 -0
- package/dist/src/commands/auth.d.ts.map +1 -0
- package/dist/src/commands/auth.js +200 -0
- package/dist/src/commands/auth.js.map +1 -0
- package/dist/src/commands/complete.d.ts +14 -0
- package/dist/src/commands/complete.d.ts.map +1 -0
- package/dist/src/commands/complete.js +166 -0
- package/dist/src/commands/complete.js.map +1 -0
- package/dist/src/commands/complete.spec.d.ts +6 -0
- package/dist/src/commands/complete.spec.d.ts.map +1 -0
- package/dist/src/commands/complete.spec.js +63 -0
- package/dist/src/commands/complete.spec.js.map +1 -0
- package/dist/src/commands/completion-install.d.ts +47 -0
- package/dist/src/commands/completion-install.d.ts.map +1 -0
- package/dist/src/commands/completion-install.js +141 -0
- package/dist/src/commands/completion-install.js.map +1 -0
- package/dist/src/commands/completion-install.spec.d.ts +6 -0
- package/dist/src/commands/completion-install.spec.d.ts.map +1 -0
- package/dist/src/commands/completion-install.spec.js +136 -0
- package/dist/src/commands/completion-install.spec.js.map +1 -0
- package/dist/src/commands/completion.d.ts +12 -0
- package/dist/src/commands/completion.d.ts.map +1 -0
- package/dist/src/commands/completion.js +75 -0
- package/dist/src/commands/completion.js.map +1 -0
- package/dist/src/commands/completion.spec.d.ts +6 -0
- package/dist/src/commands/completion.spec.d.ts.map +1 -0
- package/dist/src/commands/completion.spec.js +48 -0
- package/dist/src/commands/completion.spec.js.map +1 -0
- package/dist/src/commands/convert.impl.spec.d.ts +6 -0
- package/dist/src/commands/convert.impl.spec.d.ts.map +1 -0
- package/dist/src/commands/convert.impl.spec.js +245 -0
- package/dist/src/commands/convert.impl.spec.js.map +1 -0
- package/dist/src/commands/dataset-status.d.ts +9 -0
- package/dist/src/commands/dataset-status.d.ts.map +1 -0
- package/dist/src/commands/dataset-status.js +77 -0
- package/dist/src/commands/dataset-status.js.map +1 -0
- package/dist/src/commands/find.d.ts +17 -0
- package/dist/src/commands/find.d.ts.map +1 -0
- package/dist/src/commands/find.js +59 -0
- package/dist/src/commands/find.js.map +1 -0
- package/dist/src/commands/find.spec.d.ts +6 -0
- package/dist/src/commands/find.spec.d.ts.map +1 -0
- package/dist/src/commands/find.spec.js +43 -0
- package/dist/src/commands/find.spec.js.map +1 -0
- package/dist/src/commands/get.d.ts +3 -0
- package/dist/src/commands/get.d.ts.map +1 -1
- package/dist/src/commands/get.js +43 -20
- package/dist/src/commands/get.js.map +1 -1
- package/dist/src/commands/get.spec.d.ts +6 -0
- package/dist/src/commands/get.spec.d.ts.map +1 -0
- package/dist/src/commands/get.spec.js +28 -0
- package/dist/src/commands/get.spec.js.map +1 -0
- package/dist/src/commands/list.d.ts +6 -2
- package/dist/src/commands/list.d.ts.map +1 -1
- package/dist/src/commands/list.js +189 -30
- package/dist/src/commands/list.js.map +1 -1
- package/dist/src/commands/logs.d.ts.map +1 -1
- package/dist/src/commands/logs.js +96 -70
- package/dist/src/commands/logs.js.map +1 -1
- package/dist/src/commands/package.d.ts.map +1 -1
- package/dist/src/commands/package.js +78 -18
- package/dist/src/commands/package.js.map +1 -1
- package/dist/src/commands/repo.d.ts +44 -0
- package/dist/src/commands/repo.d.ts.map +1 -0
- package/dist/src/commands/repo.js +278 -0
- package/dist/src/commands/repo.js.map +1 -0
- package/dist/src/commands/run.d.ts +12 -0
- package/dist/src/commands/run.d.ts.map +1 -1
- package/dist/src/commands/run.js +21 -13
- package/dist/src/commands/run.js.map +1 -1
- package/dist/src/commands/run.spec.d.ts +6 -0
- package/dist/src/commands/run.spec.d.ts.map +1 -0
- package/dist/src/commands/run.spec.js +39 -0
- package/dist/src/commands/run.spec.js.map +1 -0
- package/dist/src/commands/set.d.ts +1 -0
- package/dist/src/commands/set.d.ts.map +1 -1
- package/dist/src/commands/set.js +33 -32
- package/dist/src/commands/set.js.map +1 -1
- package/dist/src/commands/start.d.ts.map +1 -1
- package/dist/src/commands/start.js +270 -52
- package/dist/src/commands/start.js.map +1 -1
- package/dist/src/commands/watch.d.ts +5 -2
- package/dist/src/commands/watch.d.ts.map +1 -1
- package/dist/src/commands/watch.js +32 -26
- package/dist/src/commands/watch.js.map +1 -1
- package/dist/src/commands/workspace.d.ts +12 -1
- package/dist/src/commands/workspace.d.ts.map +1 -1
- package/dist/src/commands/workspace.js +332 -38
- package/dist/src/commands/workspace.js.map +1 -1
- package/dist/src/credentials.d.ts +123 -0
- package/dist/src/credentials.d.ts.map +1 -0
- package/dist/src/credentials.js +213 -0
- package/dist/src/credentials.js.map +1 -0
- package/dist/src/format.d.ts +18 -0
- package/dist/src/format.d.ts.map +1 -0
- package/dist/src/format.js +43 -0
- package/dist/src/format.js.map +1 -0
- package/dist/src/path-resolver.d.ts +86 -0
- package/dist/src/path-resolver.d.ts.map +1 -0
- package/dist/src/path-resolver.js +241 -0
- package/dist/src/path-resolver.js.map +1 -0
- package/dist/src/path-resolver.spec.d.ts +6 -0
- package/dist/src/path-resolver.spec.d.ts.map +1 -0
- package/dist/src/path-resolver.spec.js +247 -0
- package/dist/src/path-resolver.spec.js.map +1 -0
- package/dist/src/utils.d.ts +76 -1
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/src/utils.js +104 -1
- package/dist/src/utils.js.map +1 -1
- package/dist/src/utils.spec.d.ts +6 -0
- package/dist/src/utils.spec.d.ts.map +1 -0
- package/dist/src/utils.spec.js +199 -0
- package/dist/src/utils.spec.js.map +1 -0
- package/package.json +22 -18
- package/scripts/postinstall.cjs +26 -0
- package/dist/src/commands/gc.d.ts +0 -12
- package/dist/src/commands/gc.d.ts.map +0 -1
- package/dist/src/commands/gc.js +0 -44
- package/dist/src/commands/gc.js.map +0 -1
- package/dist/src/commands/init.d.ts +0 -9
- package/dist/src/commands/init.d.ts.map +0 -1
- package/dist/src/commands/init.js +0 -33
- package/dist/src/commands/init.js.map +0 -1
- package/dist/src/commands/status.d.ts +0 -9
- package/dist/src/commands/status.d.ts.map +0 -1
- package/dist/src/commands/status.js +0 -157
- package/dist/src/commands/status.js.map +0 -1
- package/dist/src/commands/tree.d.ts +0 -14
- package/dist/src/commands/tree.d.ts.map +0 -1
- package/dist/src/commands/tree.js +0 -77
- package/dist/src/commands/tree.js.map +0 -1
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Credential storage for e3 CLI.
|
|
7
|
+
*
|
|
8
|
+
* Stores access and refresh tokens for authenticated servers
|
|
9
|
+
* in ~/.e3/credentials.json.
|
|
10
|
+
*/
|
|
11
|
+
import * as fs from 'node:fs';
|
|
12
|
+
import * as path from 'node:path';
|
|
13
|
+
import * as os from 'node:os';
|
|
14
|
+
/**
|
|
15
|
+
* Get path to credentials file.
|
|
16
|
+
* Uses E3_CREDENTIALS_PATH env var if set, otherwise ~/.e3/credentials.json.
|
|
17
|
+
*/
|
|
18
|
+
function getCredentialsPath() {
|
|
19
|
+
return process.env.E3_CREDENTIALS_PATH ?? path.join(os.homedir(), '.e3', 'credentials.json');
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Normalize server URL (remove trailing slash).
|
|
23
|
+
*/
|
|
24
|
+
export function normalizeServerUrl(url) {
|
|
25
|
+
return url.replace(/\/+$/, '');
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Load credentials file.
|
|
29
|
+
*/
|
|
30
|
+
export function loadCredentials() {
|
|
31
|
+
try {
|
|
32
|
+
const content = fs.readFileSync(getCredentialsPath(), 'utf8');
|
|
33
|
+
return JSON.parse(content);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return { version: 1, credentials: {} };
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Save credentials file.
|
|
41
|
+
*/
|
|
42
|
+
export function saveCredentials(file) {
|
|
43
|
+
const credPath = getCredentialsPath();
|
|
44
|
+
const dir = path.dirname(credPath);
|
|
45
|
+
if (!fs.existsSync(dir)) {
|
|
46
|
+
fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
47
|
+
}
|
|
48
|
+
fs.writeFileSync(credPath, JSON.stringify(file, null, 2), { mode: 0o600 });
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Get credential for a server.
|
|
52
|
+
*/
|
|
53
|
+
export function getCredential(serverUrl) {
|
|
54
|
+
const file = loadCredentials();
|
|
55
|
+
return file.credentials[normalizeServerUrl(serverUrl)] ?? null;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Set credential for a server.
|
|
59
|
+
*/
|
|
60
|
+
export function setCredential(serverUrl, entry) {
|
|
61
|
+
const file = loadCredentials();
|
|
62
|
+
file.credentials[normalizeServerUrl(serverUrl)] = entry;
|
|
63
|
+
saveCredentials(file);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Remove credential for a server.
|
|
67
|
+
*/
|
|
68
|
+
export function removeCredential(serverUrl) {
|
|
69
|
+
const file = loadCredentials();
|
|
70
|
+
const key = normalizeServerUrl(serverUrl);
|
|
71
|
+
if (key in file.credentials) {
|
|
72
|
+
delete file.credentials[key];
|
|
73
|
+
saveCredentials(file);
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* List all saved credentials.
|
|
80
|
+
*/
|
|
81
|
+
export function listCredentials() {
|
|
82
|
+
const file = loadCredentials();
|
|
83
|
+
return Object.entries(file.credentials).map(([server, entry]) => ({
|
|
84
|
+
server,
|
|
85
|
+
expiresAt: entry.expiresAt,
|
|
86
|
+
}));
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Check if a token expiration time has passed.
|
|
90
|
+
*/
|
|
91
|
+
export function isExpired(expiresAt) {
|
|
92
|
+
return new Date(expiresAt).getTime() < Date.now();
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Fetch OIDC discovery document.
|
|
96
|
+
*/
|
|
97
|
+
export async function fetchDiscovery(serverUrl) {
|
|
98
|
+
const url = `${normalizeServerUrl(serverUrl)}/.well-known/openid-configuration`;
|
|
99
|
+
const response = await fetch(url);
|
|
100
|
+
if (!response.ok) {
|
|
101
|
+
throw new Error(`Failed to fetch OIDC discovery: ${response.status}`);
|
|
102
|
+
}
|
|
103
|
+
return response.json();
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Start device authorization flow.
|
|
107
|
+
*/
|
|
108
|
+
export async function startDeviceAuth(discovery) {
|
|
109
|
+
const response = await fetch(discovery.device_authorization_endpoint, {
|
|
110
|
+
method: 'POST',
|
|
111
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
112
|
+
body: new URLSearchParams({ client_id: 'e3-cli' }),
|
|
113
|
+
});
|
|
114
|
+
if (!response.ok) {
|
|
115
|
+
throw new Error(`Failed to start device authorization: ${response.status}`);
|
|
116
|
+
}
|
|
117
|
+
return response.json();
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Poll for device code approval.
|
|
121
|
+
*/
|
|
122
|
+
export async function pollForTokens(discovery, deviceCode, interval, expiresIn) {
|
|
123
|
+
const deadline = Date.now() + expiresIn * 1000;
|
|
124
|
+
while (Date.now() < deadline) {
|
|
125
|
+
await new Promise((resolve) => setTimeout(resolve, interval * 1000));
|
|
126
|
+
const response = await fetch(discovery.token_endpoint, {
|
|
127
|
+
method: 'POST',
|
|
128
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
129
|
+
body: new URLSearchParams({
|
|
130
|
+
grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
|
|
131
|
+
device_code: deviceCode,
|
|
132
|
+
client_id: 'e3-cli',
|
|
133
|
+
}),
|
|
134
|
+
});
|
|
135
|
+
if (response.ok) {
|
|
136
|
+
return response.json();
|
|
137
|
+
}
|
|
138
|
+
const error = await response.json();
|
|
139
|
+
if (error.error === 'authorization_pending') {
|
|
140
|
+
continue; // Keep polling
|
|
141
|
+
}
|
|
142
|
+
if (error.error === 'slow_down') {
|
|
143
|
+
interval += 1; // Slow down as requested
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
throw new Error(`Token exchange failed: ${error.error} - ${error.error_description ?? ''}`);
|
|
147
|
+
}
|
|
148
|
+
throw new Error('Device authorization timed out');
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Refresh an access token using a refresh token.
|
|
152
|
+
*/
|
|
153
|
+
export async function refreshAccessToken(serverUrl, refreshToken) {
|
|
154
|
+
const discovery = await fetchDiscovery(serverUrl);
|
|
155
|
+
const response = await fetch(discovery.token_endpoint, {
|
|
156
|
+
method: 'POST',
|
|
157
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
158
|
+
body: new URLSearchParams({
|
|
159
|
+
grant_type: 'refresh_token',
|
|
160
|
+
refresh_token: refreshToken,
|
|
161
|
+
client_id: 'e3-cli',
|
|
162
|
+
}),
|
|
163
|
+
});
|
|
164
|
+
if (!response.ok) {
|
|
165
|
+
const error = await response.json();
|
|
166
|
+
throw new Error(`Token refresh failed: ${error.error} - ${error.error_description ?? ''}`);
|
|
167
|
+
}
|
|
168
|
+
return response.json();
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Get a valid access token for a server.
|
|
172
|
+
*
|
|
173
|
+
* If the current token is expired, attempts to refresh it.
|
|
174
|
+
* Throws if not logged in or refresh fails.
|
|
175
|
+
*/
|
|
176
|
+
export async function getValidToken(serverUrl) {
|
|
177
|
+
const creds = getCredential(serverUrl);
|
|
178
|
+
if (!creds) {
|
|
179
|
+
throw new Error(`Not logged in to ${serverUrl}. Run: e3 login ${serverUrl}`);
|
|
180
|
+
}
|
|
181
|
+
// Return existing token if not expired
|
|
182
|
+
if (!isExpired(creds.expiresAt)) {
|
|
183
|
+
return creds.accessToken;
|
|
184
|
+
}
|
|
185
|
+
// Attempt to refresh
|
|
186
|
+
try {
|
|
187
|
+
const tokens = await refreshAccessToken(serverUrl, creds.refreshToken);
|
|
188
|
+
const newEntry = {
|
|
189
|
+
accessToken: tokens.access_token,
|
|
190
|
+
refreshToken: tokens.refresh_token,
|
|
191
|
+
expiresAt: new Date(Date.now() + tokens.expires_in * 1000).toISOString(),
|
|
192
|
+
};
|
|
193
|
+
setCredential(serverUrl, newEntry);
|
|
194
|
+
return tokens.access_token;
|
|
195
|
+
}
|
|
196
|
+
catch (err) {
|
|
197
|
+
// Refresh failed, need to re-login
|
|
198
|
+
removeCredential(serverUrl);
|
|
199
|
+
const message = err instanceof Error ? err.message : 'unknown error';
|
|
200
|
+
throw new Error(`Session expired and refresh failed: ${message}. Run: e3 login ${serverUrl}`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Decode JWT payload without verification (for display purposes only).
|
|
205
|
+
*/
|
|
206
|
+
export function decodeJwtPayload(token) {
|
|
207
|
+
const parts = token.split('.');
|
|
208
|
+
if (parts.length !== 3) {
|
|
209
|
+
throw new Error('Invalid JWT format');
|
|
210
|
+
}
|
|
211
|
+
return JSON.parse(Buffer.from(parts[1], 'base64url').toString());
|
|
212
|
+
}
|
|
213
|
+
//# sourceMappingURL=credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../../src/credentials.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
import type { PackageExportProgress } from '@elaraai/e3-types';
|
|
6
|
+
/**
|
|
7
|
+
* Shared formatting utilities for CLI commands.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Format a byte count as a human-readable string.
|
|
11
|
+
*
|
|
12
|
+
* @param bytes - Size in bytes
|
|
13
|
+
* @returns Formatted string like "42 B", "1.5 KB", "1 MB"
|
|
14
|
+
*/
|
|
15
|
+
export declare function formatSize(bytes: number): string;
|
|
16
|
+
export declare function writeExportProgress(progress: PackageExportProgress): void;
|
|
17
|
+
export declare function clearProgress(): void;
|
|
18
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../src/format.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAE/D;;GAEG;AAEH;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAahD;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,qBAAqB,GAAG,IAAI,CAQzE;AAED,wBAAgB,aAAa,IAAI,IAAI,CAEpC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Shared formatting utilities for CLI commands.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Format a byte count as a human-readable string.
|
|
10
|
+
*
|
|
11
|
+
* @param bytes - Size in bytes
|
|
12
|
+
* @returns Formatted string like "42 B", "1.5 KB", "1 MB"
|
|
13
|
+
*/
|
|
14
|
+
export function formatSize(bytes) {
|
|
15
|
+
if (bytes < 1024)
|
|
16
|
+
return `${bytes} B`;
|
|
17
|
+
const units = ['KB', 'MB', 'GB', 'TB'];
|
|
18
|
+
let value = bytes;
|
|
19
|
+
for (const unit of units) {
|
|
20
|
+
value /= 1024;
|
|
21
|
+
if (value < 1024 || unit === 'TB') {
|
|
22
|
+
const formatted = value % 1 === 0 ? value.toFixed(0) : value.toFixed(1);
|
|
23
|
+
return `${formatted} ${unit}`;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
// unreachable, but TypeScript needs it
|
|
27
|
+
return `${bytes} B`;
|
|
28
|
+
}
|
|
29
|
+
export function writeExportProgress(progress) {
|
|
30
|
+
if (progress.type === 'pending') {
|
|
31
|
+
process.stdout.write(`\rPending...\x1b[K`);
|
|
32
|
+
}
|
|
33
|
+
else if (progress.type === 'exporting') {
|
|
34
|
+
process.stdout.write(`\rExporting... ${progress.value.objectsProcessed} objects\x1b[K`);
|
|
35
|
+
}
|
|
36
|
+
else if (progress.type === 'uploading') {
|
|
37
|
+
process.stdout.write(`\rUploading...\x1b[K`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export function clearProgress() {
|
|
41
|
+
process.stdout.write('\r\x1b[K');
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/format.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH;;GAEG;AAEH;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,IAAI,KAAK,GAAG,IAAI;QAAE,OAAO,GAAG,KAAK,IAAI,CAAC;IACtC,MAAM,KAAK,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IACvC,IAAI,KAAK,GAAG,KAAK,CAAC;IAClB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,KAAK,IAAI,IAAI,CAAC;QACd,IAAI,KAAK,GAAG,IAAI,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;YAClC,MAAM,SAAS,GAAG,KAAK,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;YACxE,OAAO,GAAG,SAAS,IAAI,IAAI,EAAE,CAAC;QAChC,CAAC;IACH,CAAC;IACD,uCAAuC;IACvC,OAAO,GAAG,KAAK,IAAI,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,QAA+B;IACjE,IAAI,QAAQ,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAChC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC;IAC7C,CAAC;SAAM,IAAI,QAAQ,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;QACzC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,kBAAkB,QAAQ,CAAC,KAAK,CAAC,gBAAgB,gBAAgB,CAAC,CAAC;IAC1F,CAAC;SAAM,IAAI,QAAQ,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;QACzC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC/C,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;AACnC,CAAC"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Dataset path resolver.
|
|
7
|
+
*
|
|
8
|
+
* Users address datasets with the flat form `<ws>.<name>`. The on-disk storage
|
|
9
|
+
* uses `<ws>/inputs/<name>` for inputs and `<ws>/tasks/<name>/output` for task
|
|
10
|
+
* outputs. The resolver maps between them, consulting the workspace tree to
|
|
11
|
+
* discover which kind a name refers to.
|
|
12
|
+
*
|
|
13
|
+
* The async wrappers (`buildWorkspaceIndex`, `resolveDatasetPath`) fetch the
|
|
14
|
+
* workspace tree once per call. The pure helpers (`indexFromTree`,
|
|
15
|
+
* `indexFromRemoteEntries`, `resolveDatasetPathFromIndex`) take the index
|
|
16
|
+
* directly and are used by unit tests.
|
|
17
|
+
*/
|
|
18
|
+
import { type TreeNode } from '@elaraai/e3-core';
|
|
19
|
+
import { type ListEntry } from '@elaraai/e3-api-client';
|
|
20
|
+
import type { TreePath } from '@elaraai/e3-types';
|
|
21
|
+
import type { RepoLocation } from './utils.js';
|
|
22
|
+
/** Kind of a resolved dataset. */
|
|
23
|
+
export type DatasetKind = 'input' | 'task-output' | 'other';
|
|
24
|
+
/** A resolved dataset entry from the workspace. */
|
|
25
|
+
export interface ResolvedEntry {
|
|
26
|
+
/** The short name a user types (e.g. `greet`). */
|
|
27
|
+
name: string;
|
|
28
|
+
/** Storage TreePath (e.g. `[tasks, greet, output]`). */
|
|
29
|
+
storage: TreePath;
|
|
30
|
+
/** Whether this is an input, task output, or something else. */
|
|
31
|
+
kind: DatasetKind;
|
|
32
|
+
}
|
|
33
|
+
/** Result of a successful path resolution. */
|
|
34
|
+
export interface ResolvedPath {
|
|
35
|
+
ws: string;
|
|
36
|
+
/** Storage TreePath (always the canonical on-disk path). */
|
|
37
|
+
path: TreePath;
|
|
38
|
+
/** The kind of dataset resolved. */
|
|
39
|
+
kind: DatasetKind;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Build an index from a workspace tree as returned by `workspaceGetTree`.
|
|
43
|
+
*
|
|
44
|
+
* Pure. Leaf nodes under `inputs/` become `kind: 'input'`. Leaf nodes under
|
|
45
|
+
* `tasks/` become `kind: 'task-output'` and the storage path gains the
|
|
46
|
+
* `output` suffix (because `workspaceGetTree` collapses task subtrees).
|
|
47
|
+
* Leaves elsewhere get `kind: 'other'` with a dotted name.
|
|
48
|
+
*/
|
|
49
|
+
export declare function indexFromTree(tree: TreeNode[]): ResolvedEntry[];
|
|
50
|
+
/**
|
|
51
|
+
* Build an index from remote `datasetListRecursive` entries.
|
|
52
|
+
*
|
|
53
|
+
* Pure. Each entry's path is a dot-separated string; same partitioning rules
|
|
54
|
+
* as `indexFromTree`.
|
|
55
|
+
*/
|
|
56
|
+
export declare function indexFromRemoteEntries(items: ListEntry[]): ResolvedEntry[];
|
|
57
|
+
/**
|
|
58
|
+
* Resolve a flat dataset path against a pre-built index.
|
|
59
|
+
*
|
|
60
|
+
* Pure. Implements the same rules as `resolveDatasetPath` but takes the
|
|
61
|
+
* index as a parameter so unit tests don't need a repo.
|
|
62
|
+
*
|
|
63
|
+
* @throws Error with suggestions when the name is unknown or ambiguous.
|
|
64
|
+
*/
|
|
65
|
+
export declare function resolveDatasetPathFromIndex(pathSpec: string, index: ResolvedEntry[]): ResolvedPath;
|
|
66
|
+
/**
|
|
67
|
+
* Fetch the workspace tree and build an index of every dataset reachable
|
|
68
|
+
* by its short name.
|
|
69
|
+
*/
|
|
70
|
+
export declare function buildWorkspaceIndex(location: RepoLocation, ws: string): Promise<ResolvedEntry[]>;
|
|
71
|
+
/**
|
|
72
|
+
* Resolve a flat dataset path (`<ws>.<name>`) to a canonical storage path,
|
|
73
|
+
* fetching the workspace index as needed.
|
|
74
|
+
*/
|
|
75
|
+
export declare function resolveDatasetPath(location: RepoLocation, pathSpec: string): Promise<ResolvedPath>;
|
|
76
|
+
/**
|
|
77
|
+
* Return the candidates most similar to `target`, sorted best-first.
|
|
78
|
+
*
|
|
79
|
+
* Uses Levenshtein distance with a relative threshold so short typos near
|
|
80
|
+
* short names still match (e.g. `gret` → `greet`). Candidates with distance
|
|
81
|
+
* exceeding the threshold are filtered out.
|
|
82
|
+
*/
|
|
83
|
+
export declare function suggestSimilar(target: string, candidates: string[], max: number): string[];
|
|
84
|
+
/** Standard Levenshtein edit distance. Exported for testing. */
|
|
85
|
+
export declare function levenshtein(a: string, b: string): number;
|
|
86
|
+
//# sourceMappingURL=path-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-resolver.d.ts","sourceRoot":"","sources":["../../src/path-resolver.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;;;;;;;;;GAYG;AAEH,OAAO,EAGL,KAAK,QAAQ,EACd,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAEL,KAAK,SAAS,EACf,MAAM,wBAAwB,CAAC;AAGhC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,kCAAkC;AAClC,MAAM,MAAM,WAAW,GAAG,OAAO,GAAG,aAAa,GAAG,OAAO,CAAC;AAE5D,mDAAmD;AACnD,MAAM,WAAW,aAAa;IAC5B,kDAAkD;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,wDAAwD;IACxD,OAAO,EAAE,QAAQ,CAAC;IAClB,gEAAgE;IAChE,IAAI,EAAE,WAAW,CAAC;CACnB;AAED,8CAA8C;AAC9C,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,4DAA4D;IAC5D,IAAI,EAAE,QAAQ,CAAC;IACf,oCAAoC;IACpC,IAAI,EAAE,WAAW,CAAC;CACnB;AAMD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,aAAa,EAAE,CAE/D;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,aAAa,EAAE,CAW1E;AAED;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,aAAa,EAAE,GACrB,YAAY,CAqDd;AAMD;;;GAGG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,YAAY,EACtB,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,aAAa,EAAE,CAAC,CAe1B;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,YAAY,EACtB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,YAAY,CAAC,CAIvB;AAiFD;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAAE,EACpB,GAAG,EAAE,MAAM,GACV,MAAM,EAAE,CAWV;AAED,gEAAgE;AAChE,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAsBxD"}
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2025 Elara AI Pty Ltd
|
|
3
|
+
* Licensed under BSL 1.1. See LICENSE for details.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Dataset path resolver.
|
|
7
|
+
*
|
|
8
|
+
* Users address datasets with the flat form `<ws>.<name>`. The on-disk storage
|
|
9
|
+
* uses `<ws>/inputs/<name>` for inputs and `<ws>/tasks/<name>/output` for task
|
|
10
|
+
* outputs. The resolver maps between them, consulting the workspace tree to
|
|
11
|
+
* discover which kind a name refers to.
|
|
12
|
+
*
|
|
13
|
+
* The async wrappers (`buildWorkspaceIndex`, `resolveDatasetPath`) fetch the
|
|
14
|
+
* workspace tree once per call. The pure helpers (`indexFromTree`,
|
|
15
|
+
* `indexFromRemoteEntries`, `resolveDatasetPathFromIndex`) take the index
|
|
16
|
+
* directly and are used by unit tests.
|
|
17
|
+
*/
|
|
18
|
+
import { workspaceGetTree, LocalStorage, } from '@elaraai/e3-core';
|
|
19
|
+
import { datasetListRecursive, } from '@elaraai/e3-api-client';
|
|
20
|
+
import { variant } from '@elaraai/east';
|
|
21
|
+
import { parseDatasetPath } from '@elaraai/e3-types';
|
|
22
|
+
// =============================================================================
|
|
23
|
+
// Pure helpers (unit-testable without a repo)
|
|
24
|
+
// =============================================================================
|
|
25
|
+
/**
|
|
26
|
+
* Build an index from a workspace tree as returned by `workspaceGetTree`.
|
|
27
|
+
*
|
|
28
|
+
* Pure. Leaf nodes under `inputs/` become `kind: 'input'`. Leaf nodes under
|
|
29
|
+
* `tasks/` become `kind: 'task-output'` and the storage path gains the
|
|
30
|
+
* `output` suffix (because `workspaceGetTree` collapses task subtrees).
|
|
31
|
+
* Leaves elsewhere get `kind: 'other'` with a dotted name.
|
|
32
|
+
*/
|
|
33
|
+
export function indexFromTree(tree) {
|
|
34
|
+
return collectEntries(tree, []);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Build an index from remote `datasetListRecursive` entries.
|
|
38
|
+
*
|
|
39
|
+
* Pure. Each entry's path is a dot-separated string; same partitioning rules
|
|
40
|
+
* as `indexFromTree`.
|
|
41
|
+
*/
|
|
42
|
+
export function indexFromRemoteEntries(items) {
|
|
43
|
+
const out = [];
|
|
44
|
+
for (const item of items) {
|
|
45
|
+
if (item.type !== 'dataset')
|
|
46
|
+
continue;
|
|
47
|
+
const segments = item.value.path.split('.').filter((s) => s.length > 0);
|
|
48
|
+
if (segments.length === 0)
|
|
49
|
+
continue;
|
|
50
|
+
const name = segments[segments.length - 1];
|
|
51
|
+
const prefix = segments.slice(0, -1);
|
|
52
|
+
out.push(entryForLeaf(name, prefix));
|
|
53
|
+
}
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Resolve a flat dataset path against a pre-built index.
|
|
58
|
+
*
|
|
59
|
+
* Pure. Implements the same rules as `resolveDatasetPath` but takes the
|
|
60
|
+
* index as a parameter so unit tests don't need a repo.
|
|
61
|
+
*
|
|
62
|
+
* @throws Error with suggestions when the name is unknown or ambiguous.
|
|
63
|
+
*/
|
|
64
|
+
export function resolveDatasetPathFromIndex(pathSpec, index) {
|
|
65
|
+
const { ws, path: parsed } = parseDatasetPath(pathSpec);
|
|
66
|
+
if (parsed.length === 0) {
|
|
67
|
+
throw new Error(`Path must include a name (e.g. '${ws}.<name>')`);
|
|
68
|
+
}
|
|
69
|
+
const head = String(parsed[0].value);
|
|
70
|
+
const rest = parsed.slice(1).map((s) => String(s.value));
|
|
71
|
+
// Detect tree paths (no sub-name given).
|
|
72
|
+
if ((head === 'inputs' || head === 'tasks') && rest.length === 0) {
|
|
73
|
+
throw new Error(`'${ws}.${head}' is a tree, not a dataset. Use '${ws}.<name>' to address a specific dataset.`);
|
|
74
|
+
}
|
|
75
|
+
// Detect legacy forms and reject with a friendly message.
|
|
76
|
+
if (head === 'inputs' && rest.length === 1) {
|
|
77
|
+
throw new Error(`Use the short form: '${ws}.${rest[0]}' instead of '${ws}.inputs.${rest[0]}'.`);
|
|
78
|
+
}
|
|
79
|
+
if (head === 'tasks' && rest.length === 2 && rest[1] === 'output') {
|
|
80
|
+
throw new Error(`Use the short form: '${ws}.${rest[0]}' instead of '${ws}.tasks.${rest[0]}.output'.`);
|
|
81
|
+
}
|
|
82
|
+
// Detect access to internal task datasets (e.g. tasks.double.function_ir) — not writable.
|
|
83
|
+
if (head === 'tasks' && rest.length >= 2 && rest[rest.length - 1] !== 'output') {
|
|
84
|
+
throw new Error(`'${ws}.tasks.${rest.join('.')}' is not writable. Only inputs and task outputs can be read or written.`);
|
|
85
|
+
}
|
|
86
|
+
const matches = index.filter((e) => e.name === head);
|
|
87
|
+
if (matches.length === 0) {
|
|
88
|
+
throw notFoundError(ws, head, index);
|
|
89
|
+
}
|
|
90
|
+
if (matches.length > 1) {
|
|
91
|
+
throw ambiguousError(ws, head, matches);
|
|
92
|
+
}
|
|
93
|
+
const match = matches[0];
|
|
94
|
+
if (rest.length > 0) {
|
|
95
|
+
throw new Error(`Nested field access ('${pathSpec}') is not supported; ` +
|
|
96
|
+
`read the full value with 'e3 dataset get ${ws}.${head}' and select the field.`);
|
|
97
|
+
}
|
|
98
|
+
return { ws, path: match.storage, kind: match.kind };
|
|
99
|
+
}
|
|
100
|
+
// =============================================================================
|
|
101
|
+
// Async wrappers (fetch the tree, then delegate to pure helpers)
|
|
102
|
+
// =============================================================================
|
|
103
|
+
/**
|
|
104
|
+
* Fetch the workspace tree and build an index of every dataset reachable
|
|
105
|
+
* by its short name.
|
|
106
|
+
*/
|
|
107
|
+
export async function buildWorkspaceIndex(location, ws) {
|
|
108
|
+
if (location.type === 'local') {
|
|
109
|
+
const storage = new LocalStorage();
|
|
110
|
+
const tree = await workspaceGetTree(storage, location.path, ws, []);
|
|
111
|
+
return indexFromTree(tree);
|
|
112
|
+
}
|
|
113
|
+
const items = await datasetListRecursive(location.baseUrl, location.repo, ws, [], { token: location.token });
|
|
114
|
+
return indexFromRemoteEntries(items);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Resolve a flat dataset path (`<ws>.<name>`) to a canonical storage path,
|
|
118
|
+
* fetching the workspace index as needed.
|
|
119
|
+
*/
|
|
120
|
+
export async function resolveDatasetPath(location, pathSpec) {
|
|
121
|
+
const { ws } = parseDatasetPath(pathSpec);
|
|
122
|
+
const index = await buildWorkspaceIndex(location, ws);
|
|
123
|
+
return resolveDatasetPathFromIndex(pathSpec, index);
|
|
124
|
+
}
|
|
125
|
+
// =============================================================================
|
|
126
|
+
// Internal helpers
|
|
127
|
+
// =============================================================================
|
|
128
|
+
function collectEntries(nodes, prefix) {
|
|
129
|
+
const out = [];
|
|
130
|
+
for (const node of nodes) {
|
|
131
|
+
if (node.kind === 'dataset') {
|
|
132
|
+
out.push(entryForLeaf(node.name, prefix));
|
|
133
|
+
}
|
|
134
|
+
else if (node.kind === 'tree') {
|
|
135
|
+
out.push(...collectEntries(node.children, [...prefix, node.name]));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return out;
|
|
139
|
+
}
|
|
140
|
+
function entryForLeaf(name, prefix) {
|
|
141
|
+
if (prefix.length === 1 && prefix[0] === 'tasks') {
|
|
142
|
+
return {
|
|
143
|
+
name,
|
|
144
|
+
kind: 'task-output',
|
|
145
|
+
storage: toTreePath(['tasks', name, 'output']),
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
// customTask outputs are stored as tasks/<taskName>/output (one level deeper)
|
|
149
|
+
if (prefix.length === 2 && prefix[0] === 'tasks' && name === 'output') {
|
|
150
|
+
const taskName = prefix[1];
|
|
151
|
+
return {
|
|
152
|
+
name: taskName,
|
|
153
|
+
kind: 'task-output',
|
|
154
|
+
storage: toTreePath(['tasks', taskName, 'output']),
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
if (prefix.length === 1 && prefix[0] === 'inputs') {
|
|
158
|
+
return {
|
|
159
|
+
name,
|
|
160
|
+
kind: 'input',
|
|
161
|
+
storage: toTreePath(['inputs', name]),
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
return {
|
|
165
|
+
name: [...prefix, name].join('.'),
|
|
166
|
+
kind: 'other',
|
|
167
|
+
storage: toTreePath([...prefix, name]),
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
function toTreePath(segments) {
|
|
171
|
+
return segments.map((s) => variant('field', s));
|
|
172
|
+
}
|
|
173
|
+
function notFoundError(ws, name, index) {
|
|
174
|
+
const suggestions = suggestSimilar(name, index.map((e) => e.name), 5);
|
|
175
|
+
let msg = `'${ws}.${name}' not found in workspace '${ws}'.`;
|
|
176
|
+
if (suggestions.length > 0) {
|
|
177
|
+
msg += ` Did you mean:\n`;
|
|
178
|
+
for (const s of suggestions) {
|
|
179
|
+
const entry = index.find((e) => e.name === s);
|
|
180
|
+
msg += ` ${ws}.${s} (${entry.kind})\n`;
|
|
181
|
+
}
|
|
182
|
+
msg = msg.replace(/\n$/, '');
|
|
183
|
+
}
|
|
184
|
+
else if (index.length > 0) {
|
|
185
|
+
msg += ` Available names:\n`;
|
|
186
|
+
for (const e of index.slice(0, 10)) {
|
|
187
|
+
msg += ` ${ws}.${e.name} (${e.kind})\n`;
|
|
188
|
+
}
|
|
189
|
+
if (index.length > 10)
|
|
190
|
+
msg += ` ... and ${index.length - 10} more`;
|
|
191
|
+
msg = msg.replace(/\n$/, '');
|
|
192
|
+
}
|
|
193
|
+
return new Error(msg);
|
|
194
|
+
}
|
|
195
|
+
function ambiguousError(ws, name, matches) {
|
|
196
|
+
const lines = matches.map((m) => ` ${ws}.${name} (${m.kind})`);
|
|
197
|
+
return new Error(`'${ws}.${name}' is ambiguous. Multiple datasets share this name:\n${lines.join('\n')}`);
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Return the candidates most similar to `target`, sorted best-first.
|
|
201
|
+
*
|
|
202
|
+
* Uses Levenshtein distance with a relative threshold so short typos near
|
|
203
|
+
* short names still match (e.g. `gret` → `greet`). Candidates with distance
|
|
204
|
+
* exceeding the threshold are filtered out.
|
|
205
|
+
*/
|
|
206
|
+
export function suggestSimilar(target, candidates, max) {
|
|
207
|
+
if (candidates.length === 0)
|
|
208
|
+
return [];
|
|
209
|
+
const scored = candidates
|
|
210
|
+
.map((c) => ({ c, d: levenshtein(target, c) }))
|
|
211
|
+
.sort((a, b) => a.d - b.d);
|
|
212
|
+
const threshold = Math.max(2, Math.floor(target.length / 2));
|
|
213
|
+
return scored
|
|
214
|
+
.filter((s) => s.d <= threshold)
|
|
215
|
+
.slice(0, max)
|
|
216
|
+
.map((s) => s.c);
|
|
217
|
+
}
|
|
218
|
+
/** Standard Levenshtein edit distance. Exported for testing. */
|
|
219
|
+
export function levenshtein(a, b) {
|
|
220
|
+
if (a === b)
|
|
221
|
+
return 0;
|
|
222
|
+
if (a.length === 0)
|
|
223
|
+
return b.length;
|
|
224
|
+
if (b.length === 0)
|
|
225
|
+
return a.length;
|
|
226
|
+
const prev = new Array(b.length + 1);
|
|
227
|
+
const curr = new Array(b.length + 1);
|
|
228
|
+
for (let j = 0; j <= b.length; j++)
|
|
229
|
+
prev[j] = j;
|
|
230
|
+
for (let i = 1; i <= a.length; i++) {
|
|
231
|
+
curr[0] = i;
|
|
232
|
+
for (let j = 1; j <= b.length; j++) {
|
|
233
|
+
const cost = a[i - 1] === b[j - 1] ? 0 : 1;
|
|
234
|
+
curr[j] = Math.min(prev[j] + 1, curr[j - 1] + 1, prev[j - 1] + cost);
|
|
235
|
+
}
|
|
236
|
+
for (let j = 0; j <= b.length; j++)
|
|
237
|
+
prev[j] = curr[j];
|
|
238
|
+
}
|
|
239
|
+
return prev[b.length];
|
|
240
|
+
}
|
|
241
|
+
//# sourceMappingURL=path-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-resolver.js","sourceRoot":"","sources":["../../src/path-resolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-resolver.spec.d.ts","sourceRoot":"","sources":["../../src/path-resolver.spec.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|