@jointhedots/gear 1.1.13 → 1.1.15

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.
@@ -66,7 +66,8 @@ export class BuildTarget {
66
66
  const start = Date.now();
67
67
  await task.execute();
68
68
  const elapsed = (Date.now() - start) / 1000;
69
- this.log.info(`⏱ ${name} completed in ${elapsed.toFixed(2)}s`);
69
+ if (elapsed > 1.0)
70
+ this.log.info(`⏱ ${name} completed in ${elapsed.toFixed(2)}s`);
70
71
  }
71
72
  async build() {
72
73
  const buildStartTime = Date.now();
@@ -9,7 +9,7 @@ import { PackageRootDir, resolve_normalized_suffixed_path } from "../../utils/fi
9
9
  import { Library } from "../../model/workspace.js";
10
10
  import { computeNameHashID } from "../../utils/normalized-name.js";
11
11
  import { BuildTask } from "./task.js";
12
- const VirtualOutDir = Path.normalize('X:/');
12
+ const VirtualOutDir = process.platform === 'win32' ? 'X:\\' : '/_/';
13
13
  function getEsbuildLogLevel(mode) {
14
14
  switch (mode) {
15
15
  case "verbose":
@@ -1,7 +1,9 @@
1
- import * as Glob from 'glob';
1
+ import Fs from 'fs';
2
2
  import Os from 'os';
3
3
  import Path from 'path';
4
4
  import Ts from 'typescript';
5
+ import { execFile } from 'child_process';
6
+ import { promisify } from 'util';
5
7
  import { BuildTask } from "./task.js";
6
8
  import { BuildTarget } from "../build-target.js";
7
9
  import { Library } from "../../model/workspace.js";
@@ -33,15 +35,6 @@ function getError(diagnostics) {
33
35
  error.name = 'EmitterError';
34
36
  return error;
35
37
  }
36
- function getFilenames(baseDir, files) {
37
- return files.map(function (filename) {
38
- const resolvedFilename = Path.resolve(filename);
39
- if (resolvedFilename.indexOf(baseDir) === 0) {
40
- return resolvedFilename;
41
- }
42
- return Path.resolve(baseDir, filename);
43
- });
44
- }
45
38
  function processTree(sourceFile, replacer) {
46
39
  let code = '';
47
40
  let cursorPosition = 0;
@@ -67,19 +60,6 @@ function processTree(sourceFile, replacer) {
67
60
  code += sourceFile.text.slice(cursorPosition);
68
61
  return code;
69
62
  }
70
- function getTSConfig(baseDir, tsconfig) {
71
- const { config, error } = Ts.parseConfigFileTextToJson("tsconfig.json", tsconfig);
72
- if (error)
73
- throw getError([error]);
74
- const configParsed = Ts.parseJsonConfigFileContent(config, Ts.sys, baseDir);
75
- if (configParsed.errors && configParsed.errors.length) {
76
- throw getError(configParsed.errors);
77
- }
78
- return [
79
- configParsed.fileNames,
80
- configParsed.options
81
- ];
82
- }
83
63
  function isNodeKindImportType(value) {
84
64
  return value && value.kind === Ts.SyntaxKind.ImportType;
85
65
  }
@@ -97,212 +77,144 @@ function isNodeKindExportDeclaration(value) {
97
77
  }
98
78
  class TypescriptProject {
99
79
  baseDir;
100
- files;
101
80
  compilerOptions;
102
- host;
103
- program;
104
- filenames;
81
+ dtsDir;
105
82
  constructor(baseDir, tsconfig, outDir) {
106
83
  this.baseDir = Path.resolve(baseDir);
107
- const [files, compilerOptions] = getTSConfig(baseDir, tsconfig);
108
- compilerOptions.declaration = true;
109
- compilerOptions.emitDeclarationOnly = true;
110
- compilerOptions.noEmit = false;
111
- compilerOptions.target = compilerOptions.target || Ts.ScriptTarget.Latest;
112
- compilerOptions.moduleResolution = compilerOptions.moduleResolution || Ts.ModuleResolutionKind.Bundler;
84
+ const { config, error } = Ts.parseConfigFileTextToJson("tsconfig.json", tsconfig);
85
+ if (error)
86
+ throw getError([error]);
87
+ const configParsed = Ts.parseJsonConfigFileContent(config, Ts.sys, baseDir);
88
+ if (configParsed.errors?.length)
89
+ throw getError(configParsed.errors);
90
+ const compilerOptions = configParsed.options;
113
91
  compilerOptions.outDir = compilerOptions.outDir || outDir;
114
- this.files = files;
115
92
  this.compilerOptions = compilerOptions;
116
- this.filenames = getFilenames(this.baseDir, files);
117
- this.host = Ts.createCompilerHost(compilerOptions);
118
- this.program = Ts.createProgram(this.filenames, compilerOptions, this.host);
93
+ // Create a temp directory for tsgo to emit .d.ts into
94
+ this.dtsDir = Fs.mkdtempSync(Path.join(Os.tmpdir(), 'gear-dts-'));
119
95
  }
120
- getSourceFiles() {
121
- return this.program.getSourceFiles();
122
- }
123
- emit(sourceFile, writeFile) {
124
- return this.program.emit(sourceFile, writeFile);
125
- }
126
- getSemanticDiagnostics(sourceFile) {
127
- return this.program.getSemanticDiagnostics(sourceFile);
96
+ /** Run tsgo to emit .d.ts files into dtsDir. Returns stderr output. */
97
+ async emitWithTsgo() {
98
+ const tsgoPath = Path.resolve('node_modules/.bin/tsgo');
99
+ const args = [
100
+ '-p', Path.join(this.baseDir, 'tsconfig.json'),
101
+ '--declaration',
102
+ '--emitDeclarationOnly',
103
+ '--skipLibCheck',
104
+ '--outDir', this.dtsDir,
105
+ ];
106
+ try {
107
+ await promisify(execFile)(tsgoPath, args, {
108
+ cwd: this.baseDir,
109
+ timeout: 120_000,
110
+ shell: true,
111
+ });
112
+ }
113
+ catch (e) {
114
+ // tsgo may exit non-zero on type errors but still emit .d.ts files
115
+ }
128
116
  }
129
- getSyntacticDiagnostics(sourceFile) {
130
- return this.program.getSyntacticDiagnostics(sourceFile);
117
+ /** Recursively collect all .d.ts files emitted by tsgo */
118
+ getEmittedDtsFiles() {
119
+ const results = [];
120
+ function walk(dir) {
121
+ for (const entry of Fs.readdirSync(dir, { withFileTypes: true })) {
122
+ const full = Path.join(dir, entry.name);
123
+ if (entry.isDirectory())
124
+ walk(full);
125
+ else if (isDtsFilename(entry.name))
126
+ results.push(full);
127
+ }
128
+ }
129
+ if (Fs.existsSync(this.dtsDir))
130
+ walk(this.dtsDir);
131
+ return results;
131
132
  }
132
- getDeclarationDiagnostics(sourceFile) {
133
- return this.program.getDeclarationDiagnostics(sourceFile);
133
+ /** Clean up temp directory */
134
+ cleanup() {
135
+ try {
136
+ Fs.rmSync(this.dtsDir, { recursive: true, force: true });
137
+ }
138
+ catch { }
134
139
  }
135
140
  }
136
141
  export function createTypescriptProject(baseDir, tsconfig, outDir) {
137
142
  return new TypescriptProject(baseDir, tsconfig, outDir);
138
143
  }
139
144
  export function generateTypescriptDefinition(options) {
140
- const project = options.project;
141
- const diagnostics = [];
145
+ const { project, prefix } = options;
142
146
  const baseDir = project.baseDir;
143
- const outDir = project.compilerOptions.outDir;
144
- const excludesMap = {};
145
- options.exclude = options.exclude || ['node_modules/**/*'];
146
- options.exclude.forEach(function (filename) {
147
- Glob.sync(filename, { cwd: baseDir }).forEach(function (globFileName) {
148
- excludesMap[normalizeFileName(Path.resolve(baseDir, globFileName))] = true;
149
- });
150
- });
151
- // Compute baseUrl prefix to strip from module paths
152
147
  const normalizedBaseDir = normalizeFileName(Path.resolve(baseDir)) + "/";
153
- let baseUrlPrefix = '';
154
- if (project.compilerOptions.baseUrl) {
155
- const absoluteBaseUrl = Path.resolve(baseDir, project.compilerOptions.baseUrl);
156
- const normalizedBaseUrl = normalizeFileName(absoluteBaseUrl);
157
- baseUrlPrefix = normalizedBaseUrl.slice(normalizedBaseDir.length);
158
- if (baseUrlPrefix && !baseUrlPrefix.endsWith('/')) {
159
- baseUrlPrefix += '/';
160
- }
161
- }
162
- function stripBaseUrlPrefix(modulePath) {
163
- if (baseUrlPrefix && modulePath.startsWith(baseUrlPrefix)) {
164
- return modulePath.slice(baseUrlPrefix.length);
165
- }
166
- return modulePath;
167
- }
168
- let outputContent = '';
148
+ const normalizedDtsDir = normalizeFileName(Path.resolve(project.dtsDir)) + "/";
149
+ const resolveCache = new Map();
150
+ const outputParts = [];
169
151
  if (options.externs) {
170
152
  options.externs.forEach(function (path) {
171
- outputContent += `/// <reference path="${path}" />` + eol;
153
+ outputParts.push(`/// <reference path="${path}" />` + eol);
172
154
  });
173
155
  }
174
156
  if (options.types) {
175
157
  options.types.forEach(function (type) {
176
- outputContent += `/// <reference types="${type}" />` + eol;
158
+ outputParts.push(`/// <reference types="${type}" />` + eol);
177
159
  });
178
160
  }
179
- // Filter source files
180
- const sourcesMap = {};
181
- const internalsMap = {};
182
- project.getSourceFiles().some(function (sourceFile) {
183
- const { fileName } = sourceFile;
184
- if (fileName.indexOf(normalizedBaseDir) !== 0)
185
- return;
186
- if (excludesMap[fileName])
187
- return;
188
- const shortName = fileName.slice(normalizedBaseDir.length);
189
- const shortNameNoExt = shortName.slice(0, -Path.extname(fileName).length);
190
- const strippedShortName = stripBaseUrlPrefix(shortName);
191
- const strippedShortNameNoExt = stripBaseUrlPrefix(shortNameNoExt);
192
- const moduleId = `${options.prefix}/${strippedShortNameNoExt}`;
193
- internalsMap[shortName] = moduleId;
194
- internalsMap[shortNameNoExt] = moduleId;
195
- internalsMap[strippedShortName] = moduleId;
196
- internalsMap[strippedShortNameNoExt] = moduleId;
197
- sourcesMap[fileName] = true;
198
- });
199
- // Build reverse map from internal paths to export names
200
- // e.g., "src/Inputs" -> "./Inputs" means internal path "src/Inputs" exports as "prefix/Inputs"
201
- // Store as [internalPrefix, exportName] pairs for prefix matching
161
+ // Process each emitted .d.ts file as internal: module
162
+ const dtsFiles = project.getEmittedDtsFiles();
163
+ for (const dtsPath of dtsFiles) {
164
+ const normalizedDts = normalizeFileName(Path.resolve(dtsPath));
165
+ if (!normalizedDts.startsWith(normalizedDtsDir))
166
+ continue;
167
+ const relativeDts = normalizedDts.slice(normalizedDtsDir.length);
168
+ const relativeSource = relativeDts.replace(/\.d\.ts$/, '');
169
+ const data = Fs.readFileSync(dtsPath, 'utf-8');
170
+ const declFile = Ts.createSourceFile(dtsPath, data, Ts.ScriptTarget.Latest, true);
171
+ writeDeclaration(declFile, relativeSource);
172
+ }
173
+ // Emit public re-export modules
202
174
  if (options.exports) {
203
175
  for (const entry of Object.values(options.exports)) {
204
- const fileName = entry.source;
205
- if (fileName.indexOf(normalizedBaseDir) !== 0)
206
- continue;
207
- if (excludesMap[fileName])
208
- continue;
209
- const shortName = fileName.slice(normalizedBaseDir.length);
210
- const shortNameNoExt = shortName.slice(0, -Path.extname(fileName).length);
211
- const strippedShortName = stripBaseUrlPrefix(shortName);
212
- const strippedShortNameNoExt = stripBaseUrlPrefix(shortNameNoExt);
213
- const moduleId = entry.id;
214
- internalsMap[shortName] = moduleId;
215
- internalsMap[shortNameNoExt] = moduleId;
216
- internalsMap[strippedShortName] = moduleId;
217
- internalsMap[strippedShortNameNoExt] = moduleId;
218
- sourcesMap[fileName] = true;
176
+ const internalId = resolveInternalModuleImport(entry.source);
177
+ if (internalId) {
178
+ outputParts.push(`declare module '${entry.id}' {${eol}`);
179
+ outputParts.push(`${indent}export * from '${internalId}';${eol}`);
180
+ outputParts.push(`}${eol}${eol}`);
181
+ }
219
182
  }
220
183
  }
221
- // Unified module ID normalization: strip extensions, baseUrl prefix, and remap to exports
222
- function normalizeModuleId(moduleId) {
223
- // Strip .ts, .tsx, .js, .jsx, .d.ts extensions
224
- moduleId = moduleId.replace(/\.(d\.ts|ts|tsx|js|jsx)$/, '');
225
- // Strip baseUrl prefix
226
- moduleId = stripBaseUrlPrefix(moduleId);
227
- // Apply resolved prefix
228
- const remapped = internalsMap[moduleId] ||
229
- internalsMap[moduleId + "/index"] ||
230
- internalsMap[moduleId + "/index.ts"];
231
- return remapped || moduleId;
232
- }
233
- // Generate source files
234
- project.getSourceFiles().some(function (sourceFile) {
235
- if (!sourcesMap[sourceFile.fileName])
236
- return;
237
- // Source file is already a declaration file so should does not need to be pre-processed by the emitter
238
- if (isDtsFilename(sourceFile.fileName)) {
239
- writeDeclaration(sourceFile, sourceFile.fileName);
240
- return;
241
- }
242
- const emitOutput = project.emit(sourceFile, (filename, data) => writeFile(filename, data, sourceFile.fileName));
243
- if (emitOutput.emitSkipped || emitOutput.diagnostics.length > 0) {
244
- diagnostics.push(...emitOutput.diagnostics);
245
- diagnostics.push(...project.getSemanticDiagnostics(sourceFile));
246
- diagnostics.push(...project.getSyntacticDiagnostics(sourceFile));
247
- diagnostics.push(...project.getDeclarationDiagnostics(sourceFile));
184
+ function resolveInternalModuleImport(moduleId, importDir = "") {
185
+ if (moduleId.charAt(0) === '.') {
186
+ return prefix + normalizeFileName(Path.join(importDir, moduleId));
248
187
  }
249
- });
250
- function isExternalModule(moduleId) {
251
- if (!internalsMap[moduleId]) {
252
- return true;
188
+ if (resolveCache.has(moduleId))
189
+ return resolveCache.get(moduleId);
190
+ const containingFile = Path.resolve(baseDir, importDir, '__resolve.ts');
191
+ const result = Ts.resolveModuleName(moduleId, containingFile, project.compilerOptions, Ts.sys);
192
+ if (result.resolvedModule && !result.resolvedModule.isExternalLibraryImport) {
193
+ const resolved = normalizeFileName(result.resolvedModule.resolvedFileName);
194
+ if (resolved.startsWith(normalizedBaseDir)) {
195
+ const value = prefix + resolved.slice(normalizedBaseDir.length).replace(/\.(d\.ts|tsx?|jsx?)$/, '');
196
+ resolveCache.set(moduleId, value);
197
+ return value;
198
+ }
253
199
  }
254
- return false;
255
- }
256
- function writeFile(filename, data, sourceFilePath) {
257
- if (isDtsFilename(filename)) {
258
- const declFile = Ts.createSourceFile(filename, data, project.compilerOptions.target, true);
259
- writeDeclaration(declFile, sourceFilePath);
200
+ // Check if moduleId is already an internal path relative to baseDir
201
+ const absolute = normalizeFileName(Path.resolve(baseDir, importDir, moduleId));
202
+ if (absolute.startsWith(normalizedBaseDir)) {
203
+ const value = prefix + absolute.slice(normalizedBaseDir.length);
204
+ resolveCache.set(moduleId, value);
205
+ return value;
260
206
  }
207
+ resolveCache.set(moduleId, null);
208
+ return null;
261
209
  }
262
- function writeDeclaration(declarationFile, sourceFilePath) {
263
- // Compute rawSourceModuleId based on the source file path that produced the declaration
264
- const resolvedSourcePath = Path.resolve(sourceFilePath);
265
- const sourceExt = Path.extname(resolvedSourcePath);
266
- const rawSourceModuleId = normalizeFileName(resolvedSourcePath.slice(baseDir.length + 1, -sourceExt.length));
267
- // Normalize and remap the module ID
268
- const moduleDeclId = normalizeModuleId(rawSourceModuleId);
269
- outputContent += `declare module '${moduleDeclId}' {${eol}${indent}`;
270
- function resolveModuleImport(moduleId) {
271
- // Resolve module id
272
- let resolved;
273
- if (moduleId.charAt(0) === '.') {
274
- resolved = normalizeFileName(Path.join(Path.dirname(rawSourceModuleId), moduleId));
275
- }
276
- else {
277
- // Try to resolve using TypeScript's module resolution (handles tsconfig paths)
278
- const resolveResult = Ts.resolveModuleName(moduleId, declarationFile.fileName, project.compilerOptions, project.host);
279
- if (resolveResult.resolvedModule) {
280
- const resolvedFileName = normalizeFileName(resolveResult.resolvedModule.resolvedFileName);
281
- if (excludesMap[resolvedFileName])
282
- return moduleId;
283
- // Check if resolved file is within our project (internal module)
284
- if (resolvedFileName.startsWith(normalizedBaseDir)) {
285
- // Convert absolute path to relative module id
286
- resolved = resolvedFileName.slice(normalizedBaseDir.length);
287
- }
288
- else {
289
- // External module - return as-is
290
- return moduleId;
291
- }
292
- }
293
- else {
294
- resolved = moduleId;
295
- if (isExternalModule(resolved))
296
- return resolved;
297
- }
298
- }
299
- // Normalize: strip extensions, baseUrl prefix, and remap to exports
300
- return normalizeModuleId(resolved);
301
- }
210
+ function writeDeclaration(declarationFile, rawSourceModuleId) {
211
+ const moduleDeclId = resolveInternalModuleImport(rawSourceModuleId);
212
+ const moduleDir = Path.dirname(rawSourceModuleId);
213
+ outputParts.push(`declare module '${moduleDeclId}' {${eol}${indent}`);
302
214
  const content = processTree(declarationFile, function (node) {
303
215
  if (isNodeKindExternalModuleReference(node)) {
304
216
  const expression = node.expression;
305
- const resolved = resolveModuleImport(expression.text);
217
+ const resolved = resolveInternalModuleImport(expression.text, moduleDir) ?? expression.text;
306
218
  return ` require('${resolved}')`;
307
219
  }
308
220
  else if (isNodeKindImportDeclaration(node) && !node.importClause) {
@@ -313,8 +225,8 @@ export function generateTypescriptDefinition(options) {
313
225
  }
314
226
  else if (isNodeKindStringLiteral(node) && node.parent &&
315
227
  (isNodeKindExportDeclaration(node.parent) || isNodeKindImportDeclaration(node.parent) || isNodeKindImportType(node.parent?.parent))) {
316
- const resolved = resolveModuleImport(node.text);
317
- if (resolved) {
228
+ const resolved = resolveInternalModuleImport(node.text, moduleDir);
229
+ if (resolved != null) {
318
230
  return ` '${resolved}'`;
319
231
  }
320
232
  }
@@ -322,38 +234,13 @@ export function generateTypescriptDefinition(options) {
322
234
  const chunks = content.replaceAll("\r", "").split("\n").map(c => c.trimEnd());
323
235
  while (chunks.length > 0 && chunks[chunks.length - 1] === "")
324
236
  chunks.pop();
325
- outputContent += chunks.join(eol + indent) + eol;
326
- outputContent += '}' + eol + eol;
237
+ outputParts.push(chunks.join(eol + indent) + eol);
238
+ outputParts.push('}' + eol + eol);
327
239
  }
328
240
  return {
329
- dts: outputContent,
330
- diagnostics,
241
+ dts: outputParts.join(''),
331
242
  };
332
243
  }
333
- export function logDiagnostics(log, diagnostics) {
334
- if (diagnostics && diagnostics.length > 0) {
335
- for (const diagnostic of diagnostics) {
336
- const text = typeof diagnostic.messageText === 'string'
337
- ? diagnostic.messageText
338
- : diagnostic.messageText.messageText;
339
- const message = {
340
- id: `TS${diagnostic.code}`,
341
- text,
342
- detail: diagnostic,
343
- };
344
- if (diagnostic.file && diagnostic.start !== undefined) {
345
- const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
346
- message.location = {
347
- file: diagnostic.file.fileName,
348
- line: line + 1,
349
- column: character,
350
- length: diagnostic.length ?? 0,
351
- };
352
- }
353
- log.put('error', message);
354
- }
355
- }
356
- }
357
244
  export class TypescriptDefinitionTask extends BuildTask {
358
245
  library;
359
246
  constructor(target, library) {
@@ -367,14 +254,15 @@ export class TypescriptDefinitionTask extends BuildTask {
367
254
  const configText = file.read.text(Path.join(lib.path, "./tsconfig.json"))
368
255
  || file.read.text("./tsconfig.json");
369
256
  const project = createTypescriptProject(lib.path, configText, storage.getBaseDirFS());
370
- const { dts, diagnostics } = generateTypescriptDefinition({
257
+ await project.emitWithTsgo();
258
+ const { dts } = generateTypescriptDefinition({
371
259
  project,
372
- prefix: lib.name,
260
+ prefix: lib.name + ":",
373
261
  exclude: ["node_modules/**/*"],
374
262
  exports: create_export_map(lib, lib.bundle),
375
263
  });
376
264
  file.write.text(storage.getBaseDirFS() + "/types.d.ts", dts);
377
- logDiagnostics(this.log, diagnostics);
265
+ project.cleanup();
378
266
  }
379
267
  catch (e) {
380
268
  this.log.error("no 'type.d.ts' will be generated for the package:" + e.message);
@@ -7,6 +7,7 @@ import { create_bundle_manifest } from "./create-manifests.js";
7
7
  import { Bundle, Library, Workspace } from "../workspace.js";
8
8
  import { file, make_canonical_path, make_normalized_dirname, make_normalized_path, make_relative_path } from "../../utils/file.js";
9
9
  import { findConfigFile, is_config_filename, readConfigFile, readSingletonConfigFile } from "./config-loader.js";
10
+ import { read_lockfile } from "./lockfile.js";
10
11
  const exclude_dirs = ["node_modules", ".git"];
11
12
  function is_ignored_dir(ws, path) {
12
13
  const normalized_path = make_normalized_path(path);
@@ -252,7 +253,7 @@ function show_constants(ws) {
252
253
  }
253
254
  }
254
255
  export async function discover_workspace(ws) {
255
- let package_lock = null;
256
+ let lockfile = null;
256
257
  for (let path = ws.path;;) {
257
258
  const package_json = await readJsonFile(path + "/package.json");
258
259
  if (package_json) {
@@ -267,30 +268,20 @@ export async function discover_workspace(ws) {
267
268
  };
268
269
  }
269
270
  }
270
- const package_lock_path = path + "/package-lock.json";
271
- if (!package_lock && Fs.existsSync(package_lock_path)) {
272
- package_lock = await readJsonFile(package_lock_path);
271
+ if (!lockfile) {
272
+ lockfile = await read_lockfile(path);
273
273
  }
274
274
  const next_path = make_normalized_dirname(path);
275
275
  if (next_path === path)
276
276
  break;
277
277
  path = next_path;
278
278
  }
279
- if (!package_lock) {
280
- throw new Error(`Package lock not found for '${ws.name}'`);
281
- }
282
- for (const location in package_lock.packages) {
283
- let pkg = package_lock.packages[location];
284
- if (location.startsWith("node_modules/")) {
285
- if (pkg.link) {
286
- pkg = package_lock.packages[pkg.resolved];
287
- }
288
- const name = location.replace(/^.*node_modules\//, "");
289
- ws.resolved_versions[name] = pkg.version;
290
- }
279
+ if (!lockfile) {
280
+ throw new Error(`Lock file not found for '${ws.name}'`);
291
281
  }
282
+ ws.resolved_versions = lockfile.resolved_versions;
292
283
  await discover_workspace_libraries(ws);
293
- for (const location in package_lock.packages) {
284
+ for (const location of lockfile.installed_locations) {
294
285
  await discover_library(ws, location, true);
295
286
  }
296
287
  for (const bun of ws.bundles) {
@@ -0,0 +1,108 @@
1
+ import Fs from "node:fs";
2
+ import Fsp from "node:fs/promises";
3
+ import YAML from "yaml";
4
+ import { readJsonFile } from "../storage.js";
5
+ export async function read_lockfile(dir) {
6
+ const npm_path = dir + "/package-lock.json";
7
+ if (Fs.existsSync(npm_path)) {
8
+ return parse_npm_lockfile(await readJsonFile(npm_path));
9
+ }
10
+ const pnpm_path = dir + "/pnpm-lock.yaml";
11
+ if (Fs.existsSync(pnpm_path)) {
12
+ return parse_pnpm_lockfile(YAML.parse(await Fsp.readFile(pnpm_path, "utf-8")));
13
+ }
14
+ const yarn_path = dir + "/yarn.lock";
15
+ if (Fs.existsSync(yarn_path)) {
16
+ return parse_yarn_lockfile(await Fsp.readFile(yarn_path, "utf-8"));
17
+ }
18
+ return null;
19
+ }
20
+ function parse_npm_lockfile(lock) {
21
+ const resolved_versions = {};
22
+ const installed_locations = [];
23
+ for (const location in lock.packages) {
24
+ if (!location)
25
+ continue;
26
+ installed_locations.push(location);
27
+ if (location.startsWith("node_modules/")) {
28
+ let pkg = lock.packages[location];
29
+ if (pkg.link) {
30
+ pkg = lock.packages[pkg.resolved];
31
+ }
32
+ const name = location.replace(/^.*node_modules\//, "");
33
+ if (pkg?.version) {
34
+ resolved_versions[name] = pkg.version;
35
+ }
36
+ }
37
+ }
38
+ return { resolved_versions, installed_locations };
39
+ }
40
+ function parse_pnpm_lockfile(lock) {
41
+ const resolved_versions = {};
42
+ const locations = new Set();
43
+ if (lock.packages) {
44
+ for (const key in lock.packages) {
45
+ const clean = key.startsWith("/") ? key.slice(1) : key;
46
+ const atIdx = clean.lastIndexOf("@");
47
+ if (atIdx > 0) {
48
+ const name = clean.slice(0, atIdx);
49
+ const version = clean.slice(atIdx + 1).split("(")[0];
50
+ if (name && version) {
51
+ resolved_versions[name] = version;
52
+ locations.add("node_modules/" + name);
53
+ }
54
+ }
55
+ }
56
+ }
57
+ if (lock.importers) {
58
+ for (const key in lock.importers) {
59
+ if (key !== ".")
60
+ locations.add(key);
61
+ }
62
+ }
63
+ return { resolved_versions, installed_locations: [...locations] };
64
+ }
65
+ function parse_yarn_lockfile(text) {
66
+ const resolved_versions = {};
67
+ const locations = new Set();
68
+ if (text.includes("__metadata:")) {
69
+ const lock = YAML.parse(text);
70
+ for (const key in lock) {
71
+ if (key === "__metadata")
72
+ continue;
73
+ if (lock[key]?.version) {
74
+ const name = extract_package_name(key.split(",")[0].trim());
75
+ if (name) {
76
+ resolved_versions[name] = lock[key].version;
77
+ locations.add("node_modules/" + name);
78
+ }
79
+ }
80
+ }
81
+ }
82
+ else {
83
+ parse_yarn_classic(text, resolved_versions, locations);
84
+ }
85
+ return { resolved_versions, installed_locations: [...locations] };
86
+ }
87
+ function extract_package_name(entry) {
88
+ entry = entry.replace(/^"|"$/g, "");
89
+ // @scope/name@version or name@version
90
+ const at = entry.startsWith("@") ? entry.indexOf("@", 1) : entry.indexOf("@");
91
+ return at > 0 ? entry.slice(0, at) : null;
92
+ }
93
+ function parse_yarn_classic(text, resolved_versions, locations) {
94
+ let current_name = null;
95
+ for (const line of text.split("\n")) {
96
+ const trimmed = line.trim();
97
+ if (!line.startsWith(" ") && !line.startsWith("#") && trimmed.endsWith(":")) {
98
+ current_name = extract_package_name(trimmed.slice(0, -1).split(",")[0].trim());
99
+ }
100
+ else if (current_name && trimmed.startsWith("version ")) {
101
+ const version = trimmed.slice(8).replace(/^"|"$/g, "");
102
+ resolved_versions[current_name] = version;
103
+ locations.add("node_modules/" + current_name);
104
+ current_name = null;
105
+ }
106
+ }
107
+ }
108
+ //# sourceMappingURL=lockfile.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jointhedots/gear",
3
- "version": "1.1.13",
3
+ "version": "1.1.15",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "jointhedots-gear": "esm/cli.js"
@@ -33,19 +33,17 @@
33
33
  "@aws-sdk/client-s3": "^3.968.0",
34
34
  "@jspm/core": "^2.1.0",
35
35
  "@tailwindcss/postcss": "~4.1.3",
36
- "@types/semver": "~7.7.1",
36
+ "@typescript/native-preview": "^7.0.0-dev.20260310.1",
37
37
  "dotenv": "~17.2.3",
38
38
  "esbuild": "~0.27.2",
39
39
  "esbuild-sass-plugin": "~3.6.0",
40
40
  "express": "~5.2.1",
41
- "glob": "~13.0.0",
42
41
  "mime": "~4.1.0",
43
42
  "node-watch": "~0.7.4",
44
43
  "postcss": "~8.5.6",
45
44
  "sass": "~1.97.2",
46
45
  "semver": "~7.7.3",
47
46
  "sharp": "~0.34.5",
48
- "source-map-support": "~0.5.21",
49
47
  "toml": "^3.0.0",
50
48
  "typescript": "~5.9.3",
51
49
  "yaml": "^2.8.2",
@@ -55,6 +53,7 @@
55
53
  "@polycuber/script.cli": "~1.0.5",
56
54
  "@types/chrome": "~0.1.33",
57
55
  "@types/node": "~22.7.4",
56
+ "@types/semver": "~7.7.1",
58
57
  "@types/web-app-manifest": "~1.0.9",
59
58
  "@types/yargs": "~17.0.35"
60
59
  },