@dbx-tools/core 0.9.5 → 0.9.6

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.
@@ -0,0 +1,296 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { readFileSync } from "node:fs";
3
+ import { basename, dirname, join, resolve } from "node:path";
4
+ import { json, net, stringUtils } from "@dbx-tools/shared-core";
5
+ import { statSync as fileStatSync } from "./file.js";
6
+ const ROOT_MARKERS = [
7
+ ".projenrc.ts",
8
+ ".projenrc.js",
9
+ ".projenrc.mjs",
10
+ ".projenrc.cjs",
11
+ "package.json",
12
+ ];
13
+ /** Resolve a blank, null, omitted, relative, or absolute cwd to an absolute path. */
14
+ export function resolveWorkingDirectory(cwd) {
15
+ return resolve(stringUtils.trimToNull(cwd) ?? process.cwd());
16
+ }
17
+ /**
18
+ * because this is crucial do not use exec.spawnSync
19
+ *
20
+ * Run `command args` in `cwd` and classify its stdout: `path` + `pathStats` when
21
+ * the output names something on disk, `url` (a {@link net.UrlBuilder}) when it
22
+ * parses as a real network URL. Empty {@link ProjectContext} on a non-zero exit
23
+ * or empty output.
24
+ */
25
+ function projectContextCommandOutput(command, args, cwd) {
26
+ const result = spawnSync(command, args, { cwd, stdio: ["ignore", "pipe", "ignore"] });
27
+ const output = result?.stdout?.toString()?.trim();
28
+ if (result.status === 0 && output) {
29
+ const pathStats = fileStatSync(output);
30
+ // Only an EXPLICIT `scheme://...` counts as a URL. `urlBuilder` otherwise
31
+ // synthesizes one (a bare `example.com` -> `https://…`, an absolute path ->
32
+ // `http://localhost/…`), which would mislabel directory outputs and bare
33
+ // tokens - so gate on the raw output already carrying a scheme + authority.
34
+ const url = /^[a-z][a-z0-9+.-]*:\/\//i.test(output) ? net.urlBuilder(output) : undefined;
35
+ return { output, path: pathStats ? output : undefined, pathStats, url };
36
+ }
37
+ return { output };
38
+ }
39
+ const projectCommandCache = new Map();
40
+ function projectContextCommand(command, args, cwd) {
41
+ const resolved = resolveWorkingDirectory(cwd);
42
+ const key = resolved === resolveWorkingDirectory() ? JSON.stringify([command, ...args]) : undefined;
43
+ if (key !== undefined) {
44
+ const cached = projectCommandCache.get(key);
45
+ if (cached !== undefined)
46
+ return cached;
47
+ }
48
+ const value = projectContextCommandOutput(command, args, resolved);
49
+ if (key !== undefined)
50
+ projectCommandCache.set(key, value);
51
+ return value;
52
+ }
53
+ function commandRoot(command, args, cwd) {
54
+ const parsed = projectContextCommand(command, args, cwd);
55
+ return parsed.pathStats?.isDirectory() ? parsed.path : undefined;
56
+ }
57
+ function npmRoot(cwd) {
58
+ const resolved = resolveWorkingDirectory(cwd);
59
+ return commandRoot("npm", ["prefix"], resolved);
60
+ }
61
+ function gitRoot(cwd) {
62
+ const resolved = resolveWorkingDirectory(cwd);
63
+ return commandRoot("git", ["rev-parse", "--show-toplevel"], resolved);
64
+ }
65
+ /** Resolve the nearest project root without walking above its npm or Git boundary. */
66
+ export function root(cwd) {
67
+ const resolved = resolveWorkingDirectory(cwd);
68
+ let current = resolved;
69
+ if (!fileStatSync(current)?.isDirectory()) {
70
+ current = dirname(current);
71
+ }
72
+ const boundaries = new Set([npmRoot(resolved), gitRoot(resolved)]
73
+ .filter((path) => path !== undefined)
74
+ .map((path) => resolve(path)));
75
+ const hasBoundary = boundaries.size > 0;
76
+ let best;
77
+ while (true) {
78
+ for (const [priority, marker] of ROOT_MARKERS.entries()) {
79
+ if (fileStatSync(join(current, marker))?.isFile()) {
80
+ if (best === undefined ||
81
+ priority < best.priority ||
82
+ (priority === best.priority && current.length < best.dir.length)) {
83
+ best = { dir: current, priority };
84
+ }
85
+ break;
86
+ }
87
+ }
88
+ if (!hasBoundary && best) {
89
+ return best.dir;
90
+ }
91
+ if (boundaries.has(current)) {
92
+ return best?.dir;
93
+ }
94
+ const parent = dirname(current);
95
+ if (parent === current) {
96
+ return best?.dir;
97
+ }
98
+ current = parent;
99
+ }
100
+ }
101
+ /**
102
+ * Parse a git remote URL (`https://...`, `git@host:owner/repo.git`, etc.) and
103
+ * return the repo segment, stripping any `.git` suffix. Returns `undefined` for
104
+ * empty or unparsable input.
105
+ */
106
+ export function parseGitRemote(url) {
107
+ const trimmed = url.trim();
108
+ if (!trimmed)
109
+ return undefined;
110
+ const scp = /^[^@]+@[^:]+:(.+)$/i.exec(trimmed);
111
+ if (scp)
112
+ return lastPathSegment(scp[1] ?? "");
113
+ try {
114
+ const normalized = trimmed.replace(/\.git$/i, "");
115
+ const pathname = new URL(normalized).pathname;
116
+ const segment = pathname.split("/").filter(Boolean).at(-1);
117
+ return segment ? lastPathSegment(segment) : undefined;
118
+ }
119
+ catch {
120
+ return undefined;
121
+ }
122
+ }
123
+ function lastPathSegment(path) {
124
+ const segment = path.split("/").filter(Boolean).at(-1) ?? path;
125
+ return segment.replace(/\.git$/i, "");
126
+ }
127
+ /**
128
+ * Yield candidate project-root directories for `cwd`, in priority order: the
129
+ * `npm prefix`, the git top-level, then `cwd` itself. Duplicates are skipped;
130
+ * only existing directories are yielded (except the final `cwd` fallback).
131
+ */
132
+ export function* resolveProjectRoots(cwd) {
133
+ const base = resolveWorkingDirectory(cwd);
134
+ const seen = new Set();
135
+ for (const candidate of [npmRoot(base), gitRoot(base)]) {
136
+ if (!candidate)
137
+ continue;
138
+ const dir = resolve(candidate);
139
+ if (seen.has(dir))
140
+ continue;
141
+ seen.add(dir);
142
+ if (fileStatSync(dir)?.isDirectory())
143
+ yield dir;
144
+ }
145
+ if (!seen.has(base))
146
+ yield base;
147
+ }
148
+ /** The nearest ancestor of `cwd` (from {@link resolveProjectRoots}) with a `package.json`. */
149
+ function workspaceRoot(cwd) {
150
+ let last;
151
+ for (const dir of resolveProjectRoots(cwd)) {
152
+ if (fileStatSync(resolve(dir, "package.json"))?.isFile())
153
+ return dir;
154
+ last = dir;
155
+ }
156
+ return last ?? resolveWorkingDirectory(cwd);
157
+ }
158
+ /**
159
+ * Resolve a human-friendly project name for the repo rooted at `cwd`:
160
+ * `package.json` `name`, then the git remote's repo name, then the root
161
+ * directory's basename.
162
+ */
163
+ export function name(cwd) {
164
+ const resolved = resolveWorkingDirectory(cwd);
165
+ const rootDir = workspaceRoot(resolved);
166
+ const fromPackage = readPackageName(resolve(rootDir, "package.json"));
167
+ if (fromPackage)
168
+ return fromPackage;
169
+ const remote = projectContextCommand("git", ["-C", rootDir, "remote", "get-url", "origin"], rootDir).output;
170
+ const fromGit = remote ? parseGitRemote(remote) : undefined;
171
+ if (fromGit)
172
+ return fromGit;
173
+ return basename(rootDir);
174
+ }
175
+ /**
176
+ * The GitHub CLI's canonical repo URL - the easy path. `gh` already resolves the
177
+ * true host (no ssh-alias parsing) and prints a clean `https://host/owner/repo`.
178
+ * `undefined` when `gh` is absent, unauthenticated, or the dir isn't a GH repo.
179
+ */
180
+ function repositoryUrlFromGh(cwd) {
181
+ const out = projectContextCommand("gh", ["repo", "view", "--json", "url"], cwd).output;
182
+ return stringUtils.trimToNull(json.parseRecord(out)?.url) ?? undefined;
183
+ }
184
+ /** Resolve an ssh host alias (`~/.ssh/config`) to its effective `hostname` via `ssh -G`. */
185
+ function resolveSshHostName(host, cwd) {
186
+ const line = projectContextCommand("ssh", ["-G", host], cwd)
187
+ .output?.split("\n")
188
+ .find((l) => /^hostname\s/i.test(l.trim()));
189
+ const name = line?.trim().split(/\s+/)[1];
190
+ return name && name !== host ? name : undefined;
191
+ }
192
+ /**
193
+ * Fallback: normalize `git remote get-url origin` to a plain
194
+ * `https://host/owner/repo` URL. scp-like / `ssh://` / `git://` /
195
+ * embedded-credential forms are rewritten to https, and an ssh host alias is
196
+ * followed to its real hostname.
197
+ */
198
+ function repositoryUrlFromGit(cwd) {
199
+ const raw = projectContextCommand("git", ["remote", "get-url", "origin"], cwd).output;
200
+ if (!raw)
201
+ return undefined;
202
+ // Normalize the scheme to https at the string level first: the WHATWG `URL`
203
+ // parser can't convert a non-special scheme (`ssh`/`git`) to `https` (the
204
+ // `protocol` setter no-ops), and scp-like `git@host:owner/repo` isn't a URL at
205
+ // all. Rewrite both into an `https://` string, then let {@link net.urlBuilder}
206
+ // own the structured edits (strip credentials, swap the host).
207
+ let https = raw.replace(/^git\+/, "");
208
+ const scp = /^[^@]+@([^:]+):(.+)$/.exec(https);
209
+ if (scp)
210
+ https = `https://${scp[1]}/${scp[2]}`;
211
+ https = https.replace(/^(ssh|git):\/\//, "https://");
212
+ let builder = net.urlBuilder(https);
213
+ if (!builder)
214
+ return undefined;
215
+ // Drop any embedded `user[:pass]@` credentials.
216
+ if (builder.username || builder.password) {
217
+ builder = builder.with("username", "").with("password", "");
218
+ }
219
+ // Follow an ssh host alias to the true host (so `github-reggie-db` -> `github.com`).
220
+ const realHost = resolveSshHostName(builder.hostname, cwd);
221
+ if (realHost)
222
+ builder = builder.with("hostname", realHost);
223
+ return `${builder.origin}${builder.pathname.replace(/\.git$/, "")}`;
224
+ }
225
+ /**
226
+ * The repo's canonical remote URL, or `undefined` when there is no git remote.
227
+ * Tries `gh repo view` first (host-accurate, no parsing), then normalizes
228
+ * `git remote get-url origin`. A blank, omitted, or explicitly current `cwd`
229
+ * reuses cached command probes; another resolved directory executes directly.
230
+ *
231
+ * @param cwd - directory to resolve from (defaults to `process.cwd()`).
232
+ * @param format - `"https"` (default) yields `https://host/owner/repo`;
233
+ * `"npm"` yields npm's `git+https://host/owner/repo.git` form (for a
234
+ * `package.json` `repository.url` that passes npm provenance).
235
+ */
236
+ export function repositoryUrl(cwd, format = "https") {
237
+ const resolved = resolveWorkingDirectory(cwd);
238
+ const https = repositoryUrlFromGh(resolved) ?? repositoryUrlFromGit(resolved);
239
+ if (!https)
240
+ return undefined;
241
+ return format === "npm" ? `git+${https.replace(/\.git$/, "")}.git` : https;
242
+ }
243
+ /**
244
+ * The active npm registry (`npm config get registry`) as a chainable
245
+ * {@link net.UrlBuilder}, or `undefined` when npm is absent or prints no URL.
246
+ * A blank, null, omitted, or explicitly current `cwd` reuses the cached npm
247
+ * command; another resolved directory executes it directly. Environment options
248
+ * are evaluated on every call.
249
+ */
250
+ export function npmRegistry(cwd, options) {
251
+ const resolved = resolveWorkingDirectory(cwd);
252
+ return resolveNpmRegistry(resolved, options);
253
+ }
254
+ function resolveNpmRegistry(cwd, options) {
255
+ const candidates = (function* () {
256
+ yield projectContextCommand("npm", ["config", "get", "registry"], cwd ?? undefined).output?.trim();
257
+ if (typeof process !== "undefined" && process?.env) {
258
+ const envKey = "npm_config_registry";
259
+ if (options?.envVars) {
260
+ yield process.env[envKey];
261
+ yield process.env[envKey.toUpperCase()];
262
+ }
263
+ }
264
+ })();
265
+ for (const candidate of candidates) {
266
+ if (candidate) {
267
+ const url = net.urlBuilder(candidate);
268
+ if (!url) {
269
+ continue;
270
+ }
271
+ else if (options?.overrideOnly) {
272
+ const npmjsRegistryUrl = "https://registry.npmjs.org";
273
+ const registryUrl = url.toString();
274
+ if (registryUrl === npmjsRegistryUrl || registryUrl.startsWith(npmjsRegistryUrl + "/")) {
275
+ continue;
276
+ }
277
+ }
278
+ return url;
279
+ }
280
+ }
281
+ return undefined;
282
+ }
283
+ function readPackageName(pkgPath) {
284
+ if (!fileStatSync(pkgPath)?.isFile())
285
+ return undefined;
286
+ return stringUtils.trimToNull(json.parseRecord(readFileSync(pkgPath, "utf8"))?.name) ?? undefined;
287
+ }
288
+ if (import.meta.main) {
289
+ console.log("npm root:", npmRoot());
290
+ console.log("repo root:", gitRoot());
291
+ console.log("package root:", root());
292
+ console.log("project name:", name());
293
+ console.log("repository url:", repositoryUrl());
294
+ console.log("repository url (npm):", repositoryUrl(undefined, "npm"));
295
+ }
296
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvamVjdC11dGlscy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9wcm9qZWN0LXV0aWxzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUMvQyxPQUFPLEVBQVMsWUFBWSxFQUFFLE1BQU0sU0FBUyxDQUFDO0FBQzlDLE9BQU8sRUFBRSxRQUFRLEVBQUUsT0FBTyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDN0QsT0FBTyxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsV0FBVyxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDaEUsT0FBTyxFQUFFLFFBQVEsSUFBSSxZQUFZLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFFckQsTUFBTSxZQUFZLEdBQUc7SUFDbkIsY0FBYztJQUNkLGNBQWM7SUFDZCxlQUFlO0lBQ2YsZUFBZTtJQUNmLGNBQWM7Q0FDTixDQUFDO0FBRVgscUZBQXFGO0FBQ3JGLE1BQU0sVUFBVSx1QkFBdUIsQ0FBQyxHQUFtQjtJQUN6RCxPQUFPLE9BQU8sQ0FBQyxXQUFXLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxJQUFJLE9BQU8sQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDO0FBQy9ELENBQUM7QUFpQkQ7Ozs7Ozs7R0FPRztBQUNILFNBQVMsMkJBQTJCLENBQUMsT0FBZSxFQUFFLElBQWMsRUFBRSxHQUFXO0lBQy9FLE1BQU0sTUFBTSxHQUFHLFNBQVMsQ0FBQyxPQUFPLEVBQUUsSUFBSSxFQUFFLEVBQUUsR0FBRyxFQUFFLEtBQUssRUFBRSxDQUFDLFFBQVEsRUFBRSxNQUFNLEVBQUUsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3RGLE1BQU0sTUFBTSxHQUFHLE1BQU0sRUFBRSxNQUFNLEVBQUUsUUFBUSxFQUFFLEVBQUUsSUFBSSxFQUFFLENBQUM7SUFDbEQsSUFBSSxNQUFNLENBQUMsTUFBTSxL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QWEsQ0FBQyxTQUFTLEVBQUUsS0FBSyxDQUFDLENBQUMsQ0FBQztBQUN4RSxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgc3Bhd25TeW5jIH0gZnJvbSBcIm5vZGU6Y2hpbGRfcHJvY2Vzc1wiO1xuaW1wb3J0IHsgU3RhdHMsIHJlYWRGaWxlU3luYyB9IGZyb20gXCJub2RlOmZzXCI7XG5pbXBvcnQgeyBiYXNlbmFtZSwgZGlybmFtZSwgam9pbiwgcmVzb2x2ZSB9IGZyb20gXCJub2RlOnBhdGhcIjtcbmltcG9ydCB7IGpzb24sIG5ldCwgc3RyaW5nVXRpbHMgfSBmcm9tIFwiQGRieC10b29scy9zaGFyZWQtY29yZVwiO1xuaW1wb3J0IHsgc3RhdFN5bmMgYXMgZmlsZVN0YXRTeW5jIH0gZnJvbSBcIi4vZmlsZS50c1wiO1xuXG5jb25zdCBST09UX01BUktFUlMgPSBbXG4gIFwiLnByb2plbnJjLnRzXCIsXG4gIFwiLnByb2plbnJjLmpzXCIsXG4gIFwiLnByb2plbnJjLm1qc1wiLFxuICBcIi5wcm9qZW5yYy5janNcIixcbiAgXCJwYWNrYWdlLmpzb25cIixcbl0gYXMgY29uc3Q7XG5cbi8qKiBSZXNvbHZlIGEgYmxhbmssIG51bGwsIG9taXR0ZWQsIHJlbGF0aXZlLCBvciBhYnNvbHV0ZSBjd2QgdG8gYW4gYWJzb2x1dGUgcGF0aC4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXNvbHZlV29ya2luZ0RpcmVjdG9yeShjd2Q/OiBzdHJpbmcgfCBudWxsKTogc3RyaW5nIHtcbiAgcmV0dXJuIHJlc29sdmUoc3RyaW5nVXRpbHMudHJpbVRvTnVsbChjd2QpID8/IHByb2Nlc3MuY3dkKCkpO1xufVxuXG4vKiogQSBjb21tYW5kJ3Mgc3Rkb3V0LCBjbGFzc2lmaWVkIGFzIGEgZmlsZXN5c3RlbSBwYXRoIGFuZC9vciBhIFVSTC4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUHJvamVjdENvbnRleHQge1xuICByZWFkb25seSBvdXRwdXQ6IHN0cmluZztcbiAgLyoqIGBvdXRwdXRgIHdoZW4gaXQgbmFtZXMgc29tZXRoaW5nIG9uIGRpc2suICovXG4gIHJlYWRvbmx5IHBhdGg/OiBzdHJpbmc7XG4gIC8qKiBgZmlsZS5zdGF0U3luY2Agb2Yge0BsaW5rIHBhdGh9LCB3aGVuIGl0IGV4aXN0cy4gKi9cbiAgcmVhZG9ubHkgcGF0aFN0YXRzPzogU3RhdHM7XG4gIC8qKlxuICAgKiBgb3V0cHV0YCBwYXJzZWQgaW50byBhIGNoYWluYWJsZSB7QGxpbmsgbmV0LlVybEJ1aWxkZXJ9LCB3aGVuIGl0IGlzIGEgcmVhbFxuICAgKiBuZXR3b3JrIFVSTCAtIGEgbm9uLWJsYW5rIHNjaGVtZSAobm90IGBmaWxlOmApIEFORCBhIG5vbi1ibGFuayBob3N0bmFtZS5cbiAgICogQmFyZSBwYXRocywgc2NwLWxpa2UgYGdpdEBob3N0Oi4uLmAgcmVtb3RlcywgYW5kIGBmaWxlOmAgVVJMcyBzdGF5IHVuc2V0LlxuICAgKi9cbiAgcmVhZG9ubHkgdXJsPzogbmV0LlVybEJ1aWxkZXI7XG59XG5cbi8qKlxuICogYmVjYXVzZSB0aGlzIGlzIGNydWNpYWwgZG8gbm90IHVzZSBleGVjLnNwYXduU3luY1xuICpcbiAqIFJ1biBgY29tbWFuZCBhcmdzYCBpbiBgY3dkYCBhbmQgY2xhc3NpZnkgaXRzIHN0ZG91dDogYHBhdGhgICsgYHBhdGhTdGF0c2Agd2hlblxuICogdGhlIG91dHB1dCBuYW1lcyBzb21ldGhpbmcgb24gZGlzaywgYHVybGAgKGEge0BsaW5rIG5ldC5VcmxCdWlsZGVyfSkgd2hlbiBpdFxuICogcGFyc2VzIGFzIGEgcmVhbCBuZXR3b3JrIFVSTC4gRW1wdHkge0BsaW5rIFByb2plY3RDb250ZXh0fSBvbiBhIG5vbi16ZXJvIGV4aXRcbiAqIG9yIGVtcHR5IG91dHB1dC5cbiAqL1xuZnVuY3Rpb24gcHJvamVjdENvbnRleHRDb21tYW5kT3V0cHV0KGNvbW1hbmQ6IHN0cmluZywgYXJnczogc3RyaW5nW10sIGN3ZDogc3RyaW5nKTogUHJvamVjdENvbnRleHQge1xuICBjb25zdCByZXN1bHQgPSBzcGF3blN5bmMoY29tbWFuZCwgYXJncywgeyBjd2QsIHN0ZGlvOiBbXCJpZ25vcmVcIiwgXCJwaXBlXCIsIFwiaWdub3JlXCJdIH0pO1xuICBjb25zdCBvdXRwdXQgPSByZXN1bHQ/LnN0ZG91dD8udG9TdHJpbmcoKT8udHJpbSgpO1xuICBpZiAocmVzdWx0LnN0YXR1cyA9PT0gMCAmJiBvdXRwdXQpIHtcbiAgICBjb25zdCBwYXRoU3RhdHMgPSBmaWxlU3RhdFN5bmMob3V0cHV0KTtcbiAgICAvLyBPbmx5IGFuIEVYUExJQ0lUIGBzY2hlbWU6Ly8uLi5gIGNvdW50cyBhcyBhIFVSTC4gYHVybEJ1aWxkZXJgIG90aGVyd2lzZVxuICAgIC8vIHN5bnRoZXNpemVzIG9uZSAoYSBiYXJlIGBleGFtcGxlLmNvbWAgLT4gYGh0dHBzOi8v4oCmYCwgYW4gYWJzb2x1dGUgcGF0aCAtPlxuICAgIC8vIGBodHRwOi8vbG9jYWxob3N0L+KApmApLCB3aGljaCB3b3VsZCBtaXNsYWJlbCBkaXJlY3Rvcnkgb3V0cHV0cyBhbmQgYmFyZVxuICAgIC8vIHRva2VucyAtIHNvIGdhdGUgb24gdGhlIHJhdyBvdXRwdXQgYWxyZWFkeSBjYXJyeWluZyBhIHNjaGVtZSArIGF1dGhvcml0eS5cbiAgICBjb25zdCB1cmwgPSAvXlthLXpdW2EtejAtOSsuLV0qOlxcL1xcLy9pLnRlc3Qob3V0cHV0KSA/IG5ldC51cmxCdWlsZGVyKG91dHB1dCkgOiB1bmRlZmluZWQ7XG4gICAgcmV0dXJuIHsgb3V0cHV0LCBwYXRoOiBwYXRoU3RhdHMgPyBvdXRwdXQgOiB1bmRlZmluZWQsIHBhdGhTdGF0cywgdXJsIH07XG4gIH1cbiAgcmV0dXJuIHsgb3V0cHV0IH07XG59XG5cbmNvbnN0IHByb2plY3RDb21tYW5kQ2FjaGUgPSBuZXcgTWFwPHN0cmluZywgUHJvamVjdENvbnRleHQ+KCk7XG5cbmZ1bmN0aW9uIHByb2plY3RDb250ZXh0Q29tbWFuZChjb21tYW5kOiBzdHJpbmcsIGFyZ3M6IHN0cmluZ1tdLCBjd2Q/OiBzdHJpbmcpOiBQcm9qZWN0Q29udGV4dCB7XG4gIGNvbnN0IHJlc29sdmVkID0gcmVzb2x2ZVdvcmtpbmdEaXJlY3RvcnkoY3dkKTtcbiAgY29uc3Qga2V5ID1cbiAgICByZXNvbHZlZCA9PT0gcmVzb2x2ZVdvcmtpbmdEaXJlY3RvcnkoKSA/IEpTT04uc3RyaW5naWZ5KFtjb21tYW5kLCAuLi5hcmdzXSkgOiB1bmRlZmluZWQ7XG4gIGlmIChrZXkgIT09IHVuZGVmaW5lZCkge1xuICAgIGNvbnN0IGNhY2hlZCA9IHByb2plY3RDb21tYW5kQ2FjaGUuZ2V0KGtleSk7XG4gICAgaWYgKGNhY2hlZCAhPT0gdW5kZWZpbmVkKSByZXR1cm4gY2FjaGVkO1xuICB9XG4gIGNvbnN0IHZhbHVlID0gcHJvamVjdENvbnRleHRDb21tYW5kT3V0cHV0KGNvbW1hbmQsIGFyZ3MsIHJlc29sdmVkKTtcbiAgaWYgKGtleSAhPT0gdW5kZWZpbmVkKSBwcm9qZWN0Q29tbWFuZENhY2hlLnNldChrZXksIHZhbHVlKTtcbiAgcmV0dXJuIHZhbHVlO1xufVxuXG5mdW5jdGlvbiBjb21tYW5kUm9vdChjb21tYW5kOiBzdHJpbmcsIGFyZ3M6IHN0cmluZ1tdLCBjd2Q6IHN0cmluZyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IHBhcnNlZCA9IHByb2plY3RDb250ZXh0Q29tbWFuZChjb21tYW5kLCBhcmdzLCBjd2QpO1xuICByZXR1cm4gcGFyc2VkLnBhdGhTdGF0cz8uaXNEaXJlY3RvcnkoKSA/IHBhcnNlZC5wYXRoIDogdW5kZWZpbmVkO1xufVxuXG5mdW5jdGlvbiBucG1Sb290KGN3ZD86IHN0cmluZyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IHJlc29sdmVkID0gcmVzb2x2ZVdvcmtpbmdEaXJlY3RvcnkoY3dkKTtcbiAgcmV0dXJuIGNvbW1hbmRSb290KFwibnBtXCIsIFtcInByZWZpeFwiXSwgcmVzb2x2ZWQpO1xufVxuXG5mdW5jdGlvbiBnaXRSb290KGN3ZD86IHN0cmluZyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IHJlc29sdmVkID0gcmVzb2x2ZVdvcmtpbmdEaXJlY3RvcnkoY3dkKTtcbiAgcmV0dXJuIGNvbW1hbmRSb290KFwiZ2l0XCIsIFtcInJldi1wYXJzZVwiLCBcIi0tc2hvdy10b3BsZXZlbFwiXSwgcmVzb2x2ZWQpO1xufVxuXG4vKiogUmVzb2x2ZSB0aGUgbmVhcmVzdCBwcm9qZWN0IHJvb3Qgd2l0aG91dCB3YWxraW5nIGFib3ZlIGl0cyBucG0gb3IgR2l0IGJvdW5kYXJ5LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJvb3QoY3dkPzogc3RyaW5nKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgcmVzb2x2ZWQgPSByZXNvbHZlV29ya2luZ0RpcmVjdG9yeShjd2QpO1xuICBsZXQgY3VycmVudCA9IHJlc29sdmVkO1xuXG4gIGlmICghZmlsZVN0YXRTeW5jKGN1cnJlbnQpPy5pc0RpcmVjdG9yeSgpKSB7XG4gICAgY3VycmVudCA9IGRpcm5hbWUoY3VycmVudCk7XG4gIH1cbiAgY29uc3QgYm91bmRhcmllcyA9IG5ldyBTZXQoXG4gICAgW25wbVJvb3QocmVzb2x2ZWQpLCBnaXRSb290KHJlc29sdmVkKV1cbiAgICAgIC5maWx0ZXIoKHBhdGgpOiBwYXRoIGlzIHN0cmluZyA9PiBwYXRoICE9PSB1bmRlZmluZWQpXG4gICAgICAubWFwKChwYXRoKSA9PiByZXNvbHZlKHBhdGgpKSxcbiAgKTtcbiAgY29uc3QgaGFzQm91bmRhcnkgPSBib3VuZGFyaWVzLnNpemUgPiAwO1xuICBsZXQgYmVzdDogeyBkaXI6IHN0cmluZzsgcHJpb3JpdHk6IG51bWJlciB9IHwgdW5kZWZpbmVkO1xuICB3aGlsZSAodHJ1ZSkge1xuICAgIGZvciAoY29uc3QgW3ByaW9yaXR5LCBtYXJrZXJdIG9mIFJPT1RfTUFSS0VSUy5lbnRyaWVzKCkpIHtcbiAgICAgIGlmIChmaWxlU3RhdFN5bmMoam9pbihjdXJyZW50LCBtYXJrZXIpKT8uaXNGaWxlKCkpIHtcbiAgICAgICAgaWYgKFxuICAgICAgICAgIGJlc3QgPT09IHVuZGVmaW5lZCB8fFxuICAgICAgICAgIHByaW9yaXR5IDwgYmVzdC5wcmlvcml0eSB8fFxuICAgICAgICAgIChwcmlvcml0eSA9PT0gYmVzdC5wcmlvcml0eSAmJiBjdXJyZW50Lmxlbmd0aCA8IGJlc3QuZGlyLmxlbmd0aClcbiAgICAgICAgKSB7XG4gICAgICAgICAgYmVzdCA9IHsgZGlyOiBjdXJyZW50LCBwcmlvcml0eSB9O1xuICAgICAgICB9XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAoIWhhc0JvdW5kYXJ5ICYmIGJlc3QpIHtcbiAgICAgIHJldHVybiBiZXN0LmRpcjtcbiAgICB9XG4gICAgaWYgKGJvdW5kYXJpZXMuaGFzKGN1cnJlbnQpKSB7XG4gICAgICByZXR1cm4gYmVzdD8uZGlyO1xuICAgIH1cbiAgICBjb25zdCBwYXJlbnQgPSBkaXJuYW1lKGN1cnJlbnQpO1xuICAgIGlmIChwYXJlbnQgPT09IGN1cnJlbnQpIHtcbiAgICAgIHJldHVybiBiZXN0Py5kaXI7XG4gICAgfVxuICAgIGN1cnJlbnQgPSBwYXJlbnQ7XG4gIH1cbn1cblxuLyoqXG4gKiBQYXJzZSBhIGdpdCByZW1vdGUgVVJMIChgaHR0cHM6Ly8uLi5gLCBgZ2l0QGhvc3Q6b3duZXIvcmVwby5naXRgLCBldGMuKSBhbmRcbiAqIHJldHVybiB0aGUgcmVwbyBzZWdtZW50LCBzdHJpcHBpbmcgYW55IGAuZ2l0YCBzdWZmaXguIFJldHVybnMgYHVuZGVmaW5lZGAgZm9yXG4gKiBlbXB0eSBvciB1bnBhcnNhYmxlIGlucHV0LlxuICovXG5leHBvcnQgZnVuY3Rpb24gcGFyc2VHaXRSZW1vdGUodXJsOiBzdHJpbmcpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICBjb25zdCB0cmltbWVkID0gdXJsLnRyaW0oKTtcbiAgaWYgKCF0cmltbWVkKSByZXR1cm4gdW5kZWZpbmVkO1xuXG4gIGNvbnN0IHNjcCA9IC9eW15AXStAW146XSs6KC4rKSQvaS5leGVjKHRyaW1tZWQpO1xuICBpZiAoc2NwKSByZXR1cm4gbGFzdFBhdGhTZWdtZW50KHNjcFsxXSA/PyBcIlwiKTtcblxuICB0cnkge1xuICAgIGNvbnN0IG5vcm1hbGl6ZWQgPSB0cmltbWVkLnJlcGxhY2UoL1xcLmdpdCQvaSwgXCJcIik7XG4gICAgY29uc3QgcGF0aG5hbWUgPSBuZXcgVVJMKG5vcm1hbGl6ZWQpLnBhdGhuYW1lO1xuICAgIGNvbnN0IHNlZ21lbnQgPSBwYXRobmFtZS5zcGxpdChcIi9cIikuZmlsdGVyKEJvb2xlYW4pLmF0KC0xKTtcbiAgICByZXR1cm4gc2VnbWVudCA/IGxhc3RQYXRoU2VnbWVudChzZWdtZW50KSA6IHVuZGVmaW5lZDtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxufVxuXG5mdW5jdGlvbiBsYXN0UGF0aFNlZ21lbnQocGF0aDogc3RyaW5nKTogc3RyaW5nIHtcbiAgY29uc3Qgc2VnbWVudCA9IHBhdGguc3BsaXQoXCIvXCIpLmZpbHRlcihCb29sZWFuKS5hdCgtMSkgPz8gcGF0aDtcbiAgcmV0dXJuIHNlZ21lbnQucmVwbGFjZSgvXFwuZ2l0JC9pLCBcIlwiKTtcbn1cblxuLyoqXG4gKiBZaWVsZCBjYW5kaWRhdGUgcHJvamVjdC1yb290IGRpcmVjdG9yaWVzIGZvciBgY3dkYCwgaW4gcHJpb3JpdHkgb3JkZXI6IHRoZVxuICogYG5wbSBwcmVmaXhgLCB0aGUgZ2l0IHRvcC1sZXZlbCwgdGhlbiBgY3dkYCBpdHNlbGYuIER1cGxpY2F0ZXMgYXJlIHNraXBwZWQ7XG4gKiBvbmx5IGV4aXN0aW5nIGRpcmVjdG9yaWVzIGFyZSB5aWVsZGVkIChleGNlcHQgdGhlIGZpbmFsIGBjd2RgIGZhbGxiYWNrKS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uKiByZXNvbHZlUHJvamVjdFJvb3RzKGN3ZD86IHN0cmluZyk6IEdlbmVyYXRvcjxzdHJpbmc+IHtcbiAgY29uc3QgYmFzZSA9IHJlc29sdmVXb3JraW5nRGlyZWN0b3J5KGN3ZCk7XG4gIGNvbnN0IHNlZW4gPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgZm9yIChjb25zdCBjYW5kaWRhdGUgb2YgW25wbVJvb3QoYmFzZSksIGdpdFJvb3QoYmFzZSldKSB7XG4gICAgaWYgKCFjYW5kaWRhdGUpIGNvbnRpbnVlO1xuICAgIGNvbnN0IGRpciA9IHJlc29sdmUoY2FuZGlkYXRlKTtcbiAgICBpZiAoc2Vlbi5oYXMoZGlyKSkgY29udGludWU7XG4gICAgc2Vlbi5hZGQoZGlyKTtcbiAgICBpZiAoZmlsZVN0YXRTeW5jKGRpcik/LmlzRGlyZWN0b3J5KCkpIHlpZWxkIGRpcjtcbiAgfVxuICBpZiAoIXNlZW4uaGFzKGJhc2UpKSB5aWVsZCBiYXNlO1xufVxuXG4vKiogVGhlIG5lYXJlc3QgYW5jZXN0b3Igb2YgYGN3ZGAgKGZyb20ge0BsaW5rIHJlc29sdmVQcm9qZWN0Um9vdHN9KSB3aXRoIGEgYHBhY2thZ2UuanNvbmAuICovXG5mdW5jdGlvbiB3b3Jrc3BhY2VSb290KGN3ZD86IHN0cmluZyk6IHN0cmluZyB7XG4gIGxldCBsYXN0OiBzdHJpbmcgfCB1bmRlZmluZWQ7XG4gIGZvciAoY29uc3QgZGlyIG9mIHJlc29sdmVQcm9qZWN0Um9vdHMoY3dkKSkge1xuICAgIGlmIChmaWxlU3RhdFN5bmMocmVzb2x2ZShkaXIsIFwicGFja2FnZS5qc29uXCIpKT8uaXNGaWxlKCkpIHJldHVybiBkaXI7XG4gICAgbGFzdCA9IGRpcjtcbiAgfVxuICByZXR1cm4gbGFzdCA/PyByZXNvbHZlV29ya2luZ0RpcmVjdG9yeShjd2QpO1xufVxuXG4vKipcbiAqIFJlc29sdmUgYSBodW1hbi1mcmllbmRseSBwcm9qZWN0IG5hbWUgZm9yIHRoZSByZXBvIHJvb3RlZCBhdCBgY3dkYDpcbiAqIGBwYWNrYWdlLmpzb25gIGBuYW1lYCwgdGhlbiB0aGUgZ2l0IHJlbW90ZSdzIHJlcG8gbmFtZSwgdGhlbiB0aGUgcm9vdFxuICogZGlyZWN0b3J5J3MgYmFzZW5hbWUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBuYW1lKGN3ZD86IHN0cmluZyk6IHN0cmluZyB7XG4gIGNvbnN0IHJlc29sdmVkID0gcmVzb2x2ZVdvcmtpbmdEaXJlY3RvcnkoY3dkKTtcbiAgY29uc3Qgcm9vdERpciA9IHdvcmtzcGFjZVJvb3QocmVzb2x2ZWQpO1xuXG4gIGNvbnN0IGZyb21QYWNrYWdlID0gcmVhZFBhY2thZ2VOYW1lKHJlc29sdmUocm9vdERpciwgXCJwYWNrYWdlLmpzb25cIikpO1xuICBpZiAoZnJvbVBhY2thZ2UpIHJldHVybiBmcm9tUGFja2FnZTtcblxuICBjb25zdCByZW1vdGUgPSBwcm9qZWN0Q29udGV4dENvbW1hbmQoXG4gICAgXCJnaXRcIixcbiAgICBbXCItQ1wiLCByb290RGlyLCBcInJlbW90ZVwiLCBcImdldC11cmxcIiwgXCJvcmlnaW5cIl0sXG4gICAgcm9vdERpcixcbiAgKS5vdXRwdXQ7XG4gIGNvbnN0IGZyb21HaXQgPSByZW1vdGUgPyBwYXJzZUdpdFJlbW90ZShyZW1vdGUpIDogdW5kZWZpbmVkO1xuICBpZiAoZnJvbUdpdCkgcmV0dXJuIGZyb21HaXQ7XG5cbiAgcmV0dXJuIGJhc2VuYW1lKHJvb3REaXIpO1xufVxuXG4vKipcbiAqIFRoZSBHaXRIdWIgQ0xJJ3MgY2Fub25pY2FsIHJlcG8gVVJMIC0gdGhlIGVhc3kgcGF0aC4gYGdoYCBhbHJlYWR5IHJlc29sdmVzIHRoZVxuICogdHJ1ZSBob3N0IChubyBzc2gtYWxpYXMgcGFyc2luZykgYW5kIHByaW50cyBhIGNsZWFuIGBodHRwczovL2hvc3Qvb3duZXIvcmVwb2AuXG4gKiBgdW5kZWZpbmVkYCB3aGVuIGBnaGAgaXMgYWJzZW50LCB1bmF1dGhlbnRpY2F0ZWQsIG9yIHRoZSBkaXIgaXNuJ3QgYSBHSCByZXBvLlxuICovXG5mdW5jdGlvbiByZXBvc2l0b3J5VXJsRnJvbUdoKGN3ZD86IHN0cmluZyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IG91dCA9IHByb2plY3RDb250ZXh0Q29tbWFuZChcImdoXCIsIFtcInJlcG9cIiwgXCJ2aWV3XCIsIFwiLS1qc29uXCIsIFwidXJsXCJdLCBjd2QpLm91dHB1dDtcbiAgcmV0dXJuIHN0cmluZ1V0aWxzLnRyaW1Ub051bGwoanNvbi5wYXJzZVJlY29yZChvdXQpPy51cmwpID8/IHVuZGVmaW5lZDtcbn1cblxuLyoqIFJlc29sdmUgYW4gc3NoIGhvc3QgYWxpYXMgKGB+Ly5zc2gvY29uZmlnYCkgdG8gaXRzIGVmZmVjdGl2ZSBgaG9zdG5hbWVgIHZpYSBgc3NoIC1HYC4gKi9cbmZ1bmN0aW9uIHJlc29sdmVTc2hIb3N0TmFtZShob3N0OiBzdHJpbmcsIGN3ZD86IHN0cmluZyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGNvbnN0IGxpbmUgPSBwcm9qZWN0Q29udGV4dENvbW1hbmQoXCJzc2hcIiwgW1wiLUdcIiwgaG9zdF0sIGN3ZClcbiAgICAub3V0cHV0Py5zcGxpdChcIlxcblwiKVxuICAgIC5maW5kKChsKSA9PiAvXmhvc3RuYW1lXFxzL2kudGVzdChsLnRyaW0oKSkpO1xuICBjb25zdCBuYW1lID0gbGluZT8udHJpbSgpLnNwbGl0KC9cXHMrLylbMV07XG4gIHJldHVybiBuYW1lICYmIG5hbWUgIT09IGhvc3QgPyBuYW1lIDogdW5kZWZpbmVkO1xufVxuXG4vKipcbiAqIEZhbGxiYWNrOiBub3JtYWxpemUgYGdpdCByZW1vdGUgZ2V0LXVybCBvcmlnaW5gIHRvIGEgcGxhaW5cbiAqIGBodHRwczovL2hvc3Qvb3duZXIvcmVwb2AgVVJMLiBzY3AtbGlrZSAvIGBzc2g6Ly9gIC8gYGdpdDovL2AgL1xuICogZW1iZWRkZWQtY3JlZGVudGlhbCBmb3JtcyBhcmUgcmV3cml0dGVuIHRvIGh0dHBzLCBhbmQgYW4gc3NoIGhvc3QgYWxpYXMgaXNcbiAqIGZvbGxvd2VkIHRvIGl0cyByZWFsIGhvc3RuYW1lLlxuICovXG5mdW5jdGlvbiByZXBvc2l0b3J5VXJsRnJvbUdpdChjd2Q/OiBzdHJpbmcpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICBjb25zdCByYXcgPSBwcm9qZWN0Q29udGV4dENvbW1hbmQoXCJnaXRcIiwgW1wicmVtb3RlXCIsIFwiZ2V0LXVybFwiLCBcIm9yaWdpblwiXSwgY3dkKS5vdXRwdXQ7XG4gIGlmICghcmF3KSByZXR1cm4gdW5kZWZpbmVkO1xuXG4gIC8vIE5vcm1hbGl6ZSB0aGUgc2NoZW1lIHRvIGh0dHBzIGF0IHRoZSBzdHJpbmcgbGV2ZWwgZmlyc3Q6IHRoZSBXSEFUV0cgYFVSTGBcbiAgLy8gcGFyc2VyIGNhbid0IGNvbnZlcnQgYSBub24tc3BlY2lhbCBzY2hlbWUgKGBzc2hgL2BnaXRgKSB0byBgaHR0cHNgICh0aGVcbiAgLy8gYHByb3RvY29sYCBzZXR0ZXIgbm8tb3BzKSwgYW5kIHNjcC1saWtlIGBnaXRAaG9zdDpvd25lci9yZXBvYCBpc24ndCBhIFVSTCBhdFxuICAvLyBhbGwuIFJld3JpdGUgYm90aCBpbnRvIGFuIGBodHRwczovL2Agc3RyaW5nLCB0aGVuIGxldCB7QGxpbmsgbmV0LnVybEJ1aWxkZXJ9XG4gIC8vIG93biB0aGUgc3RydWN0dXJlZCBlZGl0cyAoc3RyaXAgY3JlZGVudGlhbHMsIHN3YXAgdGhlIGhvc3QpLlxuICBsZXQgaHR0cHMgPSByYXcucmVwbGFjZSgvXmdpdFxcKy8sIFwiXCIpO1xuICBjb25zdCBzY3AgPSAvXlteQF0rQChbXjpdKyk6KC4rKSQvLmV4ZWMoaHR0cHMpO1xuICBpZiAoc2NwKSBodHRwcyA9IGBodHRwczovLyR7c2NwWzFdfS8ke3NjcFsyXX1gO1xuICBodHRwcyA9IGh0dHBzLnJlcGxhY2UoL14oc3NofGdpdCk6XFwvXFwvLywgXCJodHRwczovL1wiKTtcblxuICBsZXQgYnVpbGRlciA9IG5ldC51cmxCdWlsZGVyKGh0dHBzKTtcbiAgaWYgKCFidWlsZGVyKSByZXR1cm4gdW5kZWZpbmVkO1xuICAvLyBEcm9wIGFueSBlbWJlZGRlZCBgdXNlcls6cGFzc11AYCBjcmVkZW50aWFscy5cbiAgaWYgKGJ1aWxkZXIudXNlcm5hbWUgfHwgYnVpbGRlci5wYXNzd29yZCkge1xuICAgIGJ1aWxkZXIgPSBidWlsZGVyLndpdGgoXCJ1c2VybmFtZVwiLCBcIlwiKS53aXRoKFwicGFzc3dvcmRcIiwgXCJcIik7XG4gIH1cbiAgLy8gRm9sbG93IGFuIHNzaCBob3N0IGFsaWFzIHRvIHRoZSB0cnVlIGhvc3QgKHNvIGBnaXRodWItcmVnZ2llLWRiYCAtPiBgZ2l0aHViLmNvbWApLlxuICBjb25zdCByZWFsSG9zdCA9IHJlc29sdmVTc2hIb3N0TmFtZShidWlsZGVyLmhvc3RuYW1lLCBjd2QpO1xuICBpZiAocmVhbEhvc3QpIGJ1aWxkZXIgPSBidWlsZGVyLndpdGgoXCJob3N0bmFtZVwiLCByZWFsSG9zdCk7XG5cbiAgcmV0dXJuIGAke2J1aWxkZXIub3JpZ2lufSR7YnVpbGRlci5wYXRobmFtZS5yZXBsYWNlKC9cXC5naXQkLywgXCJcIil9YDtcbn1cblxuLyoqXG4gKiBUaGUgcmVwbydzIGNhbm9uaWNhbCByZW1vdGUgVVJMLCBvciBgdW5kZWZpbmVkYCB3aGVuIHRoZXJlIGlzIG5vIGdpdCByZW1vdGUuXG4gKiBUcmllcyBgZ2ggcmVwbyB2aWV3YCBmaXJzdCAoaG9zdC1hY2N1cmF0ZSwgbm8gcGFyc2luZyksIHRoZW4gbm9ybWFsaXplc1xuICogYGdpdCByZW1vdGUgZ2V0LXVybCBvcmlnaW5gLiBBIGJsYW5rLCBvbWl0dGVkLCBvciBleHBsaWNpdGx5IGN1cnJlbnQgYGN3ZGBcbiAqIHJldXNlcyBjYWNoZWQgY29tbWFuZCBwcm9iZXM7IGFub3RoZXIgcmVzb2x2ZWQgZGlyZWN0b3J5IGV4ZWN1dGVzIGRpcmVjdGx5LlxuICpcbiAqIEBwYXJhbSBjd2QgLSBkaXJlY3RvcnkgdG8gcmVzb2x2ZSBmcm9tIChkZWZhdWx0cyB0byBgcHJvY2Vzcy5jd2QoKWApLlxuICogQHBhcmFtIGZvcm1hdCAtIGBcImh0dHBzXCJgIChkZWZhdWx0KSB5aWVsZHMgYGh0dHBzOi8vaG9zdC9vd25lci9yZXBvYDtcbiAqICAgYFwibnBtXCJgIHlpZWxkcyBucG0ncyBgZ2l0K2h0dHBzOi8vaG9zdC9vd25lci9yZXBvLmdpdGAgZm9ybSAoZm9yIGFcbiAqICAgYHBhY2thZ2UuanNvbmAgYHJlcG9zaXRvcnkudXJsYCB0aGF0IHBhc3NlcyBucG0gcHJvdmVuYW5jZSkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXBvc2l0b3J5VXJsKGN3ZD86IHN0cmluZywgZm9ybWF0OiBcImh0dHBzXCIgfCBcIm5wbVwiID0gXCJodHRwc1wiKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgY29uc3QgcmVzb2x2ZWQgPSByZXNvbHZlV29ya2luZ0RpcmVjdG9yeShjd2QpO1xuICBjb25zdCBodHRwcyA9IHJlcG9zaXRvcnlVcmxGcm9tR2gocmVzb2x2ZWQpID8/IHJlcG9zaXRvcnlVcmxGcm9tR2l0KHJlc29sdmVkKTtcbiAgaWYgKCFodHRwcykgcmV0dXJuIHVuZGVmaW5lZDtcbiAgcmV0dXJuIGZvcm1hdCA9PT0gXCJucG1cIiA/IGBnaXQrJHtodHRwcy5yZXBsYWNlKC9cXC5naXQkLywgXCJcIil9LmdpdGAgOiBodHRwcztcbn1cblxuLyoqXG4gKiBUaGUgYWN0aXZlIG5wbSByZWdpc3RyeSAoYG5wbSBjb25maWcgZ2V0IHJlZ2lzdHJ5YCkgYXMgYSBjaGFpbmFibGVcbiAqIHtAbGluayBuZXQuVXJsQnVpbGRlcn0sIG9yIGB1bmRlZmluZWRgIHdoZW4gbnBtIGlzIGFic2VudCBvciBwcmludHMgbm8gVVJMLlxuICogQSBibGFuaywgbnVsbCwgb21pdHRlZCwgb3IgZXhwbGljaXRseSBjdXJyZW50IGBjd2RgIHJldXNlcyB0aGUgY2FjaGVkIG5wbVxuICogY29tbWFuZDsgYW5vdGhlciByZXNvbHZlZCBkaXJlY3RvcnkgZXhlY3V0ZXMgaXQgZGlyZWN0bHkuIEVudmlyb25tZW50IG9wdGlvbnNcbiAqIGFyZSBldmFsdWF0ZWQgb24gZXZlcnkgY2FsbC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG5wbVJlZ2lzdHJ5KFxuICBjd2Q/OiBzdHJpbmcgfCBudWxsLFxuICBvcHRpb25zPzogeyBvdmVycmlkZU9ubHk/OiBib29sZWFuOyBlbnZWYXJzPzogYm9vbGVhbiB9LFxuKTogbmV0LlVybEJ1aWxkZXIgfCB1bmRlZmluZWQge1xuICBjb25zdCByZXNvbHZlZCA9IHJlc29sdmVXb3JraW5nRGlyZWN0b3J5KGN3ZCk7XG4gIHJldHVybiByZXNvbHZlTnBtUmVnaXN0cnkocmVzb2x2ZWQsIG9wdGlvbnMpO1xufVxuXG5mdW5jdGlvbiByZXNvbHZlTnBtUmVnaXN0cnkoXG4gIGN3ZDogc3RyaW5nIHwgbnVsbCB8IHVuZGVmaW5lZCxcbiAgb3B0aW9uczogeyBvdmVycmlkZU9ubHk/OiBib29sZWFuOyBlbnZWYXJzPzogYm9vbGVhbiB9IHwgdW5kZWZpbmVkLFxuKTogbmV0LlVybEJ1aWxkZXIgfCB1bmRlZmluZWQge1xuICBjb25zdCBjYW5kaWRhdGVzID0gKGZ1bmN0aW9uKiAoKSB7XG4gICAgeWllbGQgcHJvamVjdENvbnRleHRDb21tYW5kKFxuICAgICAgXCJucG1cIixcbiAgICAgIFtcImNvbmZpZ1wiLCBcImdldFwiLCBcInJlZ2lzdHJ5XCJdLFxuICAgICAgY3dkID8/IHVuZGVmaW5lZCxcbiAgICApLm91dHB1dD8udHJpbSgpO1xuICAgIGlmICh0eXBlb2YgcHJvY2VzcyAhPT0gXCJ1bmRlZmluZWRcIiAmJiBwcm9jZXNzPy5lbnYpIHtcbiAgICAgIGNvbnN0IGVudktleSA9IFwibnBtX2NvbmZpZ19yZWdpc3RyeVwiO1xuICAgICAgaWYgKG9wdGlvbnM/LmVudlZhcnMpIHtcbiAgICAgICAgeWllbGQgcHJvY2Vzcy5lbnZbZW52S2V5XTtcbiAgICAgICAgeWllbGQgcHJvY2Vzcy5lbnZbZW52S2V5LnRvVXBwZXJDYXNlKCldO1xuICAgICAgfVxuICAgIH1cbiAgfSkoKTtcbiAgZm9yIChjb25zdCBjYW5kaWRhdGUgb2YgY2FuZGlkYXRlcykge1xuICAgIGlmIChjYW5kaWRhdGUpIHtcbiAgICAgIGNvbnN0IHVybCA9IG5ldC51cmxCdWlsZGVyKGNhbmRpZGF0ZSk7XG4gICAgICBpZiAoIXVybCkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH0gZWxzZSBpZiAob3B0aW9ucz8ub3ZlcnJpZGVPbmx5KSB7XG4gICAgICAgIGNvbnN0IG5wbWpzUmVnaXN0cnlVcmwgPSBcImh0dHBzOi8vcmVnaXN0cnkubnBtanMub3JnXCI7XG4gICAgICAgIGNvbnN0IHJlZ2lzdHJ5VXJsID0gdXJsLnRvU3RyaW5nKCk7XG4gICAgICAgIGlmIChyZWdpc3RyeVVybCA9PT0gbnBtanNSZWdpc3RyeVVybCB8fCByZWdpc3RyeVVybC5zdGFydHNXaXRoKG5wbWpzUmVnaXN0cnlVcmwgKyBcIi9cIikpIHtcbiAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgcmV0dXJuIHVybDtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHVuZGVmaW5lZDtcbn1cblxuZnVuY3Rpb24gcmVhZFBhY2thZ2VOYW1lKHBrZ1BhdGg6IHN0cmluZyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGlmICghZmlsZVN0YXRTeW5jKHBrZ1BhdGgpPy5pc0ZpbGUoKSkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgcmV0dXJuIHN0cmluZ1V0aWxzLnRyaW1Ub051bGwoanNvbi5wYXJzZVJlY29yZChyZWFkRmlsZVN5bmMocGtnUGF0aCwgXCJ1dGY4XCIpKT8ubmFtZSkgPz8gdW5kZWZpbmVkO1xufVxuXG5pZiAoaW1wb3J0Lm1ldGEubWFpbikge1xuICBjb25zb2xlLmxvZyhcIm5wbSByb290OlwiLCBucG1Sb290KCkpO1xuICBjb25zb2xlLmxvZyhcInJlcG8gcm9vdDpcIiwgZ2l0Um9vdCgpKTtcbiAgY29uc29sZS5sb2coXCJwYWNrYWdlIHJvb3Q6XCIsIHJvb3QoKSk7XG4gIGNvbnNvbGUubG9nKFwicHJvamVjdCBuYW1lOlwiLCBuYW1lKCkpO1xuICBjb25zb2xlLmxvZyhcInJlcG9zaXRvcnkgdXJsOlwiLCByZXBvc2l0b3J5VXJsKCkpO1xuICBjb25zb2xlLmxvZyhcInJlcG9zaXRvcnkgdXJsIChucG0pOlwiLCByZXBvc2l0b3J5VXJsKHVuZGVmaW5lZCwgXCJucG1cIikpO1xufVxuIl19
@@ -1 +1 @@
1
- {"root":["../src/bin.ts","../src/brand.ts","../src/bundle.ts","../src/config.ts","../src/exec.ts","../src/file-lock.ts","../src/file.ts","../src/process-lock.ts","../src/project.ts","../index.ts"],"version":"5.9.3"}
1
+ {"root":["../src/bin.ts","../src/brand-files.ts","../src/bundle.ts","../src/config-utils.ts","../src/exec.ts","../src/file-lock.ts","../src/file.ts","../src/process-lock.ts","../src/project-utils.ts","../index.ts"],"version":"5.9.3"}
package/package.json CHANGED
@@ -25,7 +25,8 @@
25
25
  "typescript": "^5.9.3"
26
26
  },
27
27
  "dependencies": {
28
- "@dbx-tools/shared-core": "^0.9.5",
28
+ "@dbx-tools/core-rs": "^0.9.6",
29
+ "@dbx-tools/shared-core": "^0.9.6",
29
30
  "extract-zip": "^2.0.1",
30
31
  "proper-lockfile": "^4.1.2",
31
32
  "tar": "^7.5.22",
@@ -43,10 +44,22 @@
43
44
  "types": "./lib/index.d.ts",
44
45
  "default": "./lib/index.js"
45
46
  },
47
+ "./bin": {
48
+ "types": "./lib/src/bin.d.ts",
49
+ "default": "./lib/src/bin.js"
50
+ },
51
+ "./exec": {
52
+ "types": "./lib/src/exec.d.ts",
53
+ "default": "./lib/src/exec.js"
54
+ },
55
+ "./project-utils": {
56
+ "types": "./lib/src/project-utils.d.ts",
57
+ "default": "./lib/src/project-utils.js"
58
+ },
46
59
  "./package.json": "./package.json"
47
60
  }
48
61
  },
49
- "version": "0.9.5",
62
+ "version": "0.9.6",
50
63
  "types": "./lib/index.d.ts",
51
64
  "type": "module",
52
65
  "exports": {
@@ -54,6 +67,18 @@
54
67
  "types": "./lib/index.d.ts",
55
68
  "default": "./lib/index.js"
56
69
  },
70
+ "./bin": {
71
+ "types": "./lib/src/bin.d.ts",
72
+ "default": "./lib/src/bin.js"
73
+ },
74
+ "./exec": {
75
+ "types": "./lib/src/exec.d.ts",
76
+ "default": "./lib/src/exec.js"
77
+ },
78
+ "./project-utils": {
79
+ "types": "./lib/src/project-utils.d.ts",
80
+ "default": "./lib/src/project-utils.js"
81
+ },
57
82
  "./package.json": "./package.json"
58
83
  },
59
84
  "files": [
package/src/bin.ts CHANGED
@@ -20,7 +20,7 @@ import { homedir, tmpdir } from "node:os";
20
20
  import { basename, join } from "node:path";
21
21
  import { promisify } from "node:util";
22
22
 
23
- import { error, log } from "@dbx-tools/shared-core";
23
+ import { errorUtils, log } from "@dbx-tools/shared-core";
24
24
  import extractZip from "extract-zip";
25
25
  import { x as extractTar } from "tar";
26
26
 
@@ -193,7 +193,7 @@ async function isValidBin(path: string, options: BinOptions): Promise<boolean> {
193
193
  } catch (cause) {
194
194
  logger.debug("binary version command failed", {
195
195
  path,
196
- error: error.errorMessage(cause),
196
+ error: errorUtils.errorMessage(cause),
197
197
  });
198
198
  return false;
199
199
  }
@@ -1,9 +1,9 @@
1
1
  /** Node-only discovery and file loading for the shared brand context. */
2
2
  import { readFile } from "node:fs/promises";
3
3
  import { dirname, extname, isAbsolute, resolve } from "node:path";
4
- import { brand as sharedBrand } from "@dbx-tools/shared-core";
4
+ import { brandUtils } from "@dbx-tools/shared-core";
5
5
  import { statSync } from "./file.ts";
6
- import { resolveProjectRoots } from "./project.ts";
6
+ import { resolveProjectRoots } from "./project-utils.ts";
7
7
 
8
8
  const BRAND_CONTEXT_FILES = [
9
9
  "branding/brand.yaml",
@@ -14,13 +14,13 @@ const BRAND_CONTEXT_FILES = [
14
14
  "brand.json",
15
15
  ] as const;
16
16
 
17
- export type BrandContext = sharedBrand.BrandContext;
18
- export type BrandContextInput = sharedBrand.BrandContextInput;
19
- export const BrandContextSchema = sharedBrand.BrandContextSchema;
20
- export const defaultBrandContext = sharedBrand.defaultBrandContext;
21
- export const parseBrandContext = sharedBrand.parseBrandContext;
22
- export const brandContextJsonSchema = sharedBrand.brandContextJsonSchema;
23
- export const brandContextPrompt = sharedBrand.brandContextPrompt;
17
+ export type BrandContext = brandUtils.BrandContext;
18
+ export type BrandContextInput = brandUtils.BrandContextInput;
19
+ export const BrandContextSchema = brandUtils.BrandContextSchema;
20
+ export const defaultBrandContext = brandUtils.defaultBrandContext;
21
+ export const parseBrandContext = brandUtils.parseBrandContext;
22
+ export const brandContextJsonSchema = brandUtils.brandContextJsonSchema;
23
+ export const brandContextPrompt = brandUtils.brandContextPrompt;
24
24
 
25
25
  /** Find a conventional YAML or JSON brand file from known project roots. */
26
26
  export function findBrandContextFile(cwd: string = process.cwd()): string | undefined {
@@ -48,7 +48,7 @@ export async function loadBrandContextFile(path: string): Promise<BrandContext>
48
48
  throw new Error(`Unsupported brand context format: ${extension || "no extension"}`);
49
49
  }
50
50
 
51
- return sharedBrand.parseBrandContext(input);
51
+ return brandUtils.parseBrandContext(input);
52
52
  }
53
53
 
54
54
  /**
@@ -57,7 +57,7 @@ export async function loadBrandContextFile(path: string): Promise<BrandContext>
57
57
  */
58
58
  export async function loadBrandContext(cwd: string = process.cwd()): Promise<BrandContext> {
59
59
  const path = findBrandContextFile(cwd);
60
- return path ? loadBrandContextFile(path) : sharedBrand.defaultBrandContext;
60
+ return path ? loadBrandContextFile(path) : brandUtils.defaultBrandContext;
61
61
  }
62
62
 
63
63
  /** Resolve a relative asset reference against the brand file that declared it. */
package/src/bundle.ts CHANGED
@@ -11,10 +11,10 @@
11
11
 
12
12
  import { opendir, realpath, stat } from "node:fs/promises";
13
13
  import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
14
- import { json, object, string } from "@dbx-tools/shared-core";
14
+ import { json, object, stringUtils } from "@dbx-tools/shared-core";
15
15
  import { spawn } from "./exec.ts";
16
- import { resolveWorkingDirectory } from "./project.ts";
17
- import { project } from "../index.ts";
16
+ import { resolveWorkingDirectory } from "./project-utils.ts";
17
+ import { projectUtils } from "../index.ts";
18
18
 
19
19
  const BUNDLE_FILE_NAMES = new Set(["databricks.yml", "databricks.yaml"]);
20
20
  const IGNORED_DIRECTORIES = [
@@ -166,7 +166,7 @@ async function validateBundle(
166
166
  stdout: "capture",
167
167
  stderr: "capture",
168
168
  });
169
- const detail = string.trimToNull(result.stderr) ?? string.trimToNull(result.stdout);
169
+ const detail = stringUtils.trimToNull(result.stderr) ?? stringUtils.trimToNull(result.stdout);
170
170
  const bundleFailure =
171
171
  result.exitCode === 0
172
172
  ? undefined
@@ -205,7 +205,7 @@ function isWithinOrEqual(candidate: string, parent: string): boolean {
205
205
  if (import.meta.main) {
206
206
  const path = process.argv[2];
207
207
  if (!path) throw new Error("Usage: bun bundle.ts <path>");
208
- for await (const resource of appResources(project.root()!, path)) {
208
+ for await (const resource of appResources(projectUtils.root()!, path)) {
209
209
  console.dir(resource, { depth: null });
210
210
  }
211
211
  }