codarch 0.1.3 → 0.1.4
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/index.js +1161 -452
- package/package.json +1 -1
- package/web/assets/index-BLE7eQgu.js +9 -0
- package/web/assets/index-Bnq20GR3.css +1 -0
- package/web/assets/tree-sitter-B8lY9Ae0.wasm +0 -0
- package/web/assets/tree-sitter-tsx-DFihddBo.wasm +0 -0
- package/web/assets/tree-sitter-typescript-BQpamM5l.wasm +0 -0
- package/web/assets/worker-BWIy7NG8.js +461 -0
- package/web/index.html +2 -2
- package/web/assets/index-DhLrsTc_.js +0 -9
- package/web/assets/index-Dmmkr41i.css +0 -1
package/index.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// apps/cli/src/commands/analyze.ts
|
|
4
|
-
import
|
|
5
|
-
import
|
|
4
|
+
import fs4 from "node:fs";
|
|
5
|
+
import path3 from "node:path";
|
|
6
6
|
|
|
7
7
|
// packages/parsers/src/ts/parser.ts
|
|
8
8
|
import Parser from "tree-sitter";
|
|
9
9
|
import TypeScript from "tree-sitter-typescript";
|
|
10
|
-
|
|
10
|
+
|
|
11
|
+
// packages/parsers/src/ts/measure.ts
|
|
11
12
|
var FUNCTION_TYPES = /* @__PURE__ */ new Set([
|
|
12
13
|
"function_declaration",
|
|
13
14
|
"function_expression",
|
|
@@ -28,30 +29,13 @@ var DECISION_TYPES = /* @__PURE__ */ new Set([
|
|
|
28
29
|
"conditional_expression"
|
|
29
30
|
]);
|
|
30
31
|
var LOGICAL_OPERATORS = /* @__PURE__ */ new Set(["&&", "||", "??"]);
|
|
31
|
-
var TypeScriptParser = class {
|
|
32
|
-
name = "typescript";
|
|
33
|
-
extensions = EXTENSIONS;
|
|
34
|
-
tsParser = new Parser();
|
|
35
|
-
tsxParser = new Parser();
|
|
36
|
-
constructor() {
|
|
37
|
-
this.tsParser.setLanguage(TypeScript.typescript);
|
|
38
|
-
this.tsxParser.setLanguage(TypeScript.tsx);
|
|
39
|
-
}
|
|
40
|
-
parse(source, filePath) {
|
|
41
|
-
const parser = usesTsxGrammar(filePath) ? this.tsxParser : this.tsParser;
|
|
42
|
-
const root = parser.parse(source, void 0, {
|
|
43
|
-
bufferSize: Math.max(64 * 1024, Buffer.byteLength(source, "utf8") + 1)
|
|
44
|
-
}).rootNode;
|
|
45
|
-
return {
|
|
46
|
-
metrics: measureSource(source, root),
|
|
47
|
-
imports: collectImports(root)
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
};
|
|
51
32
|
function usesTsxGrammar(filePath) {
|
|
52
33
|
const lower = filePath.toLowerCase();
|
|
53
34
|
return lower.endsWith(".tsx") || lower.endsWith(".jsx") || lower.endsWith(".js") || lower.endsWith(".mjs") || lower.endsWith(".cjs");
|
|
54
35
|
}
|
|
36
|
+
function isComment(text) {
|
|
37
|
+
return text.startsWith("//") || text.startsWith("/*") || text.startsWith("#!");
|
|
38
|
+
}
|
|
55
39
|
function measureSource(source, root) {
|
|
56
40
|
const codeLines = /* @__PURE__ */ new Set();
|
|
57
41
|
const stack = [root];
|
|
@@ -60,8 +44,8 @@ function measureSource(source, root) {
|
|
|
60
44
|
let maxFunctionLength = 0;
|
|
61
45
|
while (stack.length > 0) {
|
|
62
46
|
const node = stack.pop();
|
|
63
|
-
if (node.type === "comment" || node.type === "hash_bang_line") continue;
|
|
64
47
|
if (node.childCount === 0) {
|
|
48
|
+
if (isComment(node.text)) continue;
|
|
65
49
|
if (node.text.trim() !== "") {
|
|
66
50
|
for (let row = node.startPosition.row; row <= node.endPosition.row; row++) {
|
|
67
51
|
codeLines.add(row);
|
|
@@ -225,11 +209,175 @@ function decodeStringBody(body) {
|
|
|
225
209
|
);
|
|
226
210
|
}
|
|
227
211
|
|
|
212
|
+
// packages/parsers/src/ts/parser.ts
|
|
213
|
+
var EXTENSIONS = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"];
|
|
214
|
+
var TypeScriptParser = class {
|
|
215
|
+
name = "typescript";
|
|
216
|
+
extensions = EXTENSIONS;
|
|
217
|
+
tsParser = new Parser();
|
|
218
|
+
tsxParser = new Parser();
|
|
219
|
+
constructor() {
|
|
220
|
+
this.tsParser.setLanguage(TypeScript.typescript);
|
|
221
|
+
this.tsxParser.setLanguage(TypeScript.tsx);
|
|
222
|
+
}
|
|
223
|
+
parse(source, filePath) {
|
|
224
|
+
const parser = usesTsxGrammar(filePath) ? this.tsxParser : this.tsParser;
|
|
225
|
+
const root = parser.parse(source, void 0, {
|
|
226
|
+
bufferSize: Math.max(64 * 1024, Buffer.byteLength(source, "utf8") + 1)
|
|
227
|
+
}).rootNode;
|
|
228
|
+
const node = root;
|
|
229
|
+
return {
|
|
230
|
+
metrics: measureSource(source, node),
|
|
231
|
+
imports: collectImports(node)
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
};
|
|
235
|
+
|
|
228
236
|
// packages/parsers/src/resolve.ts
|
|
229
|
-
import fs from "node:fs";
|
|
230
|
-
import path from "node:path";
|
|
231
|
-
import { builtinModules } from "node:module";
|
|
232
237
|
import ts from "typescript";
|
|
238
|
+
|
|
239
|
+
// packages/parsers/src/builtins.ts
|
|
240
|
+
var NODE_BUILTINS = [
|
|
241
|
+
"_http_agent",
|
|
242
|
+
"_http_client",
|
|
243
|
+
"_http_common",
|
|
244
|
+
"_http_incoming",
|
|
245
|
+
"_http_outgoing",
|
|
246
|
+
"_http_server",
|
|
247
|
+
"_stream_duplex",
|
|
248
|
+
"_stream_passthrough",
|
|
249
|
+
"_stream_readable",
|
|
250
|
+
"_stream_transform",
|
|
251
|
+
"_stream_wrap",
|
|
252
|
+
"_stream_writable",
|
|
253
|
+
"_tls_common",
|
|
254
|
+
"_tls_wrap",
|
|
255
|
+
"assert",
|
|
256
|
+
"assert/strict",
|
|
257
|
+
"async_hooks",
|
|
258
|
+
"buffer",
|
|
259
|
+
"child_process",
|
|
260
|
+
"cluster",
|
|
261
|
+
"console",
|
|
262
|
+
"constants",
|
|
263
|
+
"crypto",
|
|
264
|
+
"dgram",
|
|
265
|
+
"diagnostics_channel",
|
|
266
|
+
"dns",
|
|
267
|
+
"dns/promises",
|
|
268
|
+
"domain",
|
|
269
|
+
"events",
|
|
270
|
+
"fs",
|
|
271
|
+
"fs/promises",
|
|
272
|
+
"http",
|
|
273
|
+
"http2",
|
|
274
|
+
"https",
|
|
275
|
+
"inspector",
|
|
276
|
+
"inspector/promises",
|
|
277
|
+
"module",
|
|
278
|
+
"net",
|
|
279
|
+
"os",
|
|
280
|
+
"path",
|
|
281
|
+
"path/posix",
|
|
282
|
+
"path/win32",
|
|
283
|
+
"perf_hooks",
|
|
284
|
+
"process",
|
|
285
|
+
"punycode",
|
|
286
|
+
"querystring",
|
|
287
|
+
"readline",
|
|
288
|
+
"readline/promises",
|
|
289
|
+
"repl",
|
|
290
|
+
"stream",
|
|
291
|
+
"stream/consumers",
|
|
292
|
+
"stream/promises",
|
|
293
|
+
"stream/web",
|
|
294
|
+
"string_decoder",
|
|
295
|
+
"sys",
|
|
296
|
+
"timers",
|
|
297
|
+
"timers/promises",
|
|
298
|
+
"tls",
|
|
299
|
+
"trace_events",
|
|
300
|
+
"tty",
|
|
301
|
+
"url",
|
|
302
|
+
"util",
|
|
303
|
+
"util/types",
|
|
304
|
+
"v8",
|
|
305
|
+
"vm",
|
|
306
|
+
"wasi",
|
|
307
|
+
"worker_threads",
|
|
308
|
+
"zlib",
|
|
309
|
+
"node:sea",
|
|
310
|
+
"node:sqlite",
|
|
311
|
+
"node:test",
|
|
312
|
+
"node:test/reporters"
|
|
313
|
+
];
|
|
314
|
+
function isNodeBuiltin(specifier) {
|
|
315
|
+
if (specifier.startsWith("node:")) return true;
|
|
316
|
+
return NODE_BUILTINS.includes(specifier);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// packages/parsers/src/path.ts
|
|
320
|
+
function join(...segments) {
|
|
321
|
+
const parts = [];
|
|
322
|
+
for (const segment of segments) {
|
|
323
|
+
if (!segment) continue;
|
|
324
|
+
for (const piece of segment.split("/")) {
|
|
325
|
+
if (piece === "" || piece === ".") continue;
|
|
326
|
+
if (piece === "..") {
|
|
327
|
+
parts.pop();
|
|
328
|
+
continue;
|
|
329
|
+
}
|
|
330
|
+
parts.push(piece);
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
return `/${parts.join("/")}`;
|
|
334
|
+
}
|
|
335
|
+
function resolve(...segments) {
|
|
336
|
+
let resolved = "";
|
|
337
|
+
let absolute = false;
|
|
338
|
+
for (let index = segments.length - 1; index >= 0 && !absolute; index -= 1) {
|
|
339
|
+
const segment = segments[index];
|
|
340
|
+
if (!segment) continue;
|
|
341
|
+
resolved = resolved === "" ? segment : `${segment}/${resolved}`;
|
|
342
|
+
absolute = segment.startsWith("/");
|
|
343
|
+
}
|
|
344
|
+
if (!absolute) resolved = `/${resolved}`;
|
|
345
|
+
return join(resolved);
|
|
346
|
+
}
|
|
347
|
+
function dirname(target) {
|
|
348
|
+
const normalized = target.replace(/\/+$/, "");
|
|
349
|
+
const index = normalized.lastIndexOf("/");
|
|
350
|
+
if (index <= 0) return "/";
|
|
351
|
+
return normalized.slice(0, index);
|
|
352
|
+
}
|
|
353
|
+
function basename(target) {
|
|
354
|
+
const normalized = target.replace(/\/+$/, "");
|
|
355
|
+
const index = normalized.lastIndexOf("/");
|
|
356
|
+
return index === -1 ? normalized : normalized.slice(index + 1);
|
|
357
|
+
}
|
|
358
|
+
function extname(target) {
|
|
359
|
+
const name = basename(target);
|
|
360
|
+
const index = name.lastIndexOf(".");
|
|
361
|
+
if (index <= 0) return "";
|
|
362
|
+
return name.slice(index);
|
|
363
|
+
}
|
|
364
|
+
function relative(from, target) {
|
|
365
|
+
const fromParts = from.split("/").filter(Boolean);
|
|
366
|
+
const targetParts = target.split("/").filter(Boolean);
|
|
367
|
+
let common = 0;
|
|
368
|
+
while (common < fromParts.length && common < targetParts.length && fromParts[common] === targetParts[common]) {
|
|
369
|
+
common += 1;
|
|
370
|
+
}
|
|
371
|
+
const up = fromParts.length - common;
|
|
372
|
+
const down = targetParts.slice(common);
|
|
373
|
+
const parts = [...Array.from({ length: up }, () => ".."), ...down];
|
|
374
|
+
return parts.join("/");
|
|
375
|
+
}
|
|
376
|
+
function isAbsolute(target) {
|
|
377
|
+
return target.startsWith("/");
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// packages/parsers/src/resolve.ts
|
|
233
381
|
var SOURCE_EXTENSIONS = [
|
|
234
382
|
".ts",
|
|
235
383
|
".tsx",
|
|
@@ -255,9 +403,6 @@ var WORKSPACE_SKIP_DIRS = /* @__PURE__ */ new Set([
|
|
|
255
403
|
]);
|
|
256
404
|
var MAX_WORKSPACE_DEPTH = 8;
|
|
257
405
|
var MAX_RESOLVE_DEPTH = 8;
|
|
258
|
-
var BUILTINS = new Set(
|
|
259
|
-
builtinModules.flatMap((name) => [name, `node:${name}`])
|
|
260
|
-
);
|
|
261
406
|
var ASSET_EXTENSIONS = [
|
|
262
407
|
".css",
|
|
263
408
|
".scss",
|
|
@@ -283,31 +428,33 @@ var ASSET_EXTENSIONS = [
|
|
|
283
428
|
".pdf"
|
|
284
429
|
];
|
|
285
430
|
function isAssetSpecifier(specifier) {
|
|
286
|
-
const
|
|
287
|
-
return ASSET_EXTENSIONS.some((extension) =>
|
|
431
|
+
const clean2 = specifier.split(/[?#]/, 1)[0]?.toLowerCase() ?? "";
|
|
432
|
+
return ASSET_EXTENSIONS.some((extension) => clean2.endsWith(extension));
|
|
288
433
|
}
|
|
289
434
|
var ImportResolver = class {
|
|
290
435
|
warnings = [];
|
|
291
436
|
root;
|
|
437
|
+
fileSystem;
|
|
292
438
|
byPath = /* @__PURE__ */ new Map();
|
|
293
439
|
packageJsonCache = /* @__PURE__ */ new Map();
|
|
294
440
|
configCache = /* @__PURE__ */ new Map();
|
|
295
441
|
workspaces;
|
|
296
|
-
constructor(rootInput, files) {
|
|
297
|
-
this.root =
|
|
298
|
-
|
|
299
|
-
this.
|
|
442
|
+
constructor(rootInput, files, fileSystem) {
|
|
443
|
+
this.root = resolve(rootInput);
|
|
444
|
+
this.fileSystem = fileSystem;
|
|
445
|
+
for (const file of files) this.byPath.set(this.pathKey(file.absolutePath), file);
|
|
446
|
+
this.workspaces = discoverWorkspaces(this.root, this.fileSystem, this.warnings);
|
|
300
447
|
}
|
|
301
448
|
resolve(importerPath, specifier) {
|
|
302
|
-
if (
|
|
449
|
+
if (isNodeBuiltin(specifier)) {
|
|
303
450
|
return { kind: "external", specifier, builtin: true };
|
|
304
451
|
}
|
|
305
452
|
if (specifier.startsWith(".") || specifier.startsWith("/")) {
|
|
306
|
-
const base = specifier.startsWith("/") ?
|
|
453
|
+
const base = specifier.startsWith("/") ? resolve(this.root, `.${specifier}`) : resolve(dirname(resolve(importerPath)), specifier);
|
|
307
454
|
const file = this.resolveAsFileOrDirectory(base);
|
|
308
455
|
return file ? { kind: "internal", file } : { kind: "unresolved", specifier, reason: "no se encontr\xF3 el fichero" };
|
|
309
456
|
}
|
|
310
|
-
const config = this.configFor(
|
|
457
|
+
const config = this.configFor(dirname(resolve(importerPath)));
|
|
311
458
|
if (config) {
|
|
312
459
|
const alias = matchAlias(config.aliases, specifier);
|
|
313
460
|
if (alias) {
|
|
@@ -345,7 +492,7 @@ var ImportResolver = class {
|
|
|
345
492
|
const subpath = specifier === workspace.name ? "." : `./${specifier.slice(workspace.name.length + 1)}`;
|
|
346
493
|
for (const target of packageExportTargets(workspace.json.exports, subpath)) {
|
|
347
494
|
const file = this.resolveAsFileOrDirectory(
|
|
348
|
-
|
|
495
|
+
resolve(workspace.dir, target)
|
|
349
496
|
);
|
|
350
497
|
if (file) return file;
|
|
351
498
|
}
|
|
@@ -354,7 +501,7 @@ var ImportResolver = class {
|
|
|
354
501
|
const value = workspace.json[field5];
|
|
355
502
|
if (typeof value !== "string") continue;
|
|
356
503
|
const file = this.resolveAsFileOrDirectory(
|
|
357
|
-
|
|
504
|
+
resolve(workspace.dir, value)
|
|
358
505
|
);
|
|
359
506
|
if (file) return file;
|
|
360
507
|
}
|
|
@@ -365,13 +512,13 @@ var ImportResolver = class {
|
|
|
365
512
|
"index.tsx"
|
|
366
513
|
]) {
|
|
367
514
|
const file = this.resolveAsFileOrDirectory(
|
|
368
|
-
|
|
515
|
+
resolve(workspace.dir, fallback)
|
|
369
516
|
);
|
|
370
517
|
if (file) return file;
|
|
371
518
|
}
|
|
372
519
|
} else {
|
|
373
520
|
const file = this.resolveAsFileOrDirectory(
|
|
374
|
-
|
|
521
|
+
resolve(workspace.dir, subpath.slice(2))
|
|
375
522
|
);
|
|
376
523
|
if (file) return file;
|
|
377
524
|
}
|
|
@@ -380,7 +527,7 @@ var ImportResolver = class {
|
|
|
380
527
|
resolveAsFileOrDirectory(base, depth = 0) {
|
|
381
528
|
if (depth > MAX_RESOLVE_DEPTH) return null;
|
|
382
529
|
for (const candidate of fileCandidates(base)) {
|
|
383
|
-
const file = this.byPath.get(pathKey(candidate));
|
|
530
|
+
const file = this.byPath.get(this.pathKey(candidate));
|
|
384
531
|
if (file) return file;
|
|
385
532
|
}
|
|
386
533
|
const pkg = this.readPackageJson(base);
|
|
@@ -389,67 +536,77 @@ var ImportResolver = class {
|
|
|
389
536
|
const value = pkg[field5];
|
|
390
537
|
if (typeof value !== "string") continue;
|
|
391
538
|
const file = this.resolveAsFileOrDirectory(
|
|
392
|
-
|
|
539
|
+
resolve(base, value),
|
|
393
540
|
depth + 1
|
|
394
541
|
);
|
|
395
542
|
if (file) return file;
|
|
396
543
|
}
|
|
397
544
|
for (const target of packageExportTargets(pkg.exports, ".")) {
|
|
398
545
|
const file = this.resolveAsFileOrDirectory(
|
|
399
|
-
|
|
546
|
+
resolve(base, target),
|
|
400
547
|
depth + 1
|
|
401
548
|
);
|
|
402
549
|
if (file) return file;
|
|
403
550
|
}
|
|
404
551
|
}
|
|
405
552
|
for (const candidate of indexCandidates(base)) {
|
|
406
|
-
const file = this.byPath.get(pathKey(candidate));
|
|
553
|
+
const file = this.byPath.get(this.pathKey(candidate));
|
|
407
554
|
if (file) return file;
|
|
408
555
|
}
|
|
409
556
|
return null;
|
|
410
557
|
}
|
|
411
558
|
readPackageJson(directory) {
|
|
412
|
-
const key = pathKey(directory);
|
|
559
|
+
const key = this.pathKey(directory);
|
|
413
560
|
if (this.packageJsonCache.has(key)) {
|
|
414
561
|
return this.packageJsonCache.get(key) ?? null;
|
|
415
562
|
}
|
|
416
|
-
const json = readJsonFile(
|
|
563
|
+
const json = readJsonFile(
|
|
564
|
+
this.fileSystem,
|
|
565
|
+
join(directory, "package.json"),
|
|
566
|
+
this.warnings
|
|
567
|
+
);
|
|
417
568
|
this.packageJsonCache.set(key, json);
|
|
418
569
|
return json;
|
|
419
570
|
}
|
|
420
571
|
configFor(startDirectory) {
|
|
421
572
|
const visited = [];
|
|
422
|
-
let directory =
|
|
573
|
+
let directory = resolve(startDirectory);
|
|
423
574
|
while (true) {
|
|
424
|
-
const key = pathKey(directory);
|
|
575
|
+
const key = this.pathKey(directory);
|
|
425
576
|
const cached = this.configCache.get(key);
|
|
426
577
|
if (cached !== void 0) {
|
|
427
578
|
for (const visitedKey of visited) this.configCache.set(visitedKey, cached);
|
|
428
579
|
return cached;
|
|
429
580
|
}
|
|
430
581
|
visited.push(key);
|
|
431
|
-
const configPath = findTsConfig(directory);
|
|
582
|
+
const configPath = findTsConfig(this.fileSystem, directory);
|
|
432
583
|
if (configPath) {
|
|
433
|
-
const loaded = loadTsConfig(configPath, this.warnings);
|
|
584
|
+
const loaded = loadTsConfig(this.fileSystem, configPath, this.warnings);
|
|
434
585
|
for (const visitedKey of visited) this.configCache.set(visitedKey, loaded);
|
|
435
586
|
return loaded;
|
|
436
587
|
}
|
|
437
|
-
if (key === pathKey(this.root)) break;
|
|
438
|
-
const parent =
|
|
588
|
+
if (key === this.pathKey(this.root)) break;
|
|
589
|
+
const parent = dirname(directory);
|
|
439
590
|
if (parent === directory || !isWithin(this.root, parent)) break;
|
|
440
591
|
directory = parent;
|
|
441
592
|
}
|
|
442
593
|
for (const visitedKey of visited) this.configCache.set(visitedKey, null);
|
|
443
594
|
return null;
|
|
444
595
|
}
|
|
596
|
+
/**
|
|
597
|
+
* Clave de una ruta para las tablas internas.
|
|
598
|
+
*
|
|
599
|
+
* En sistemas que no distinguen mayúsculas, la clave se normaliza para que
|
|
600
|
+
* `./Foo` encuentre `foo.ts`.
|
|
601
|
+
*/
|
|
602
|
+
pathKey(value) {
|
|
603
|
+
const resolved = resolve(value);
|
|
604
|
+
return this.fileSystem.caseSensitive ? resolved : resolved.toLowerCase();
|
|
605
|
+
}
|
|
445
606
|
};
|
|
446
|
-
function pathKey(value) {
|
|
447
|
-
const resolved = path.resolve(value);
|
|
448
|
-
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
449
|
-
}
|
|
450
607
|
function isWithin(root, candidate) {
|
|
451
|
-
const
|
|
452
|
-
return
|
|
608
|
+
const relative2 = relative(root, candidate);
|
|
609
|
+
return relative2 === "" || !relative2.startsWith("..") && !isAbsolute(relative2);
|
|
453
610
|
}
|
|
454
611
|
function fileCandidates(base) {
|
|
455
612
|
const lower = base.toLowerCase();
|
|
@@ -467,7 +624,7 @@ function fileCandidates(base) {
|
|
|
467
624
|
if (lower.endsWith(".cjs")) {
|
|
468
625
|
return [`${base.slice(0, -4)}.cts`, base];
|
|
469
626
|
}
|
|
470
|
-
if (
|
|
627
|
+
if (extname(base) !== "") return [base];
|
|
471
628
|
return [
|
|
472
629
|
base,
|
|
473
630
|
...SOURCE_EXTENSIONS.map((extension) => `${base}${extension}`)
|
|
@@ -475,18 +632,29 @@ function fileCandidates(base) {
|
|
|
475
632
|
}
|
|
476
633
|
function indexCandidates(directory) {
|
|
477
634
|
return SOURCE_EXTENSIONS.map(
|
|
478
|
-
(extension) =>
|
|
635
|
+
(extension) => join(directory, `index${extension}`)
|
|
479
636
|
);
|
|
480
637
|
}
|
|
481
|
-
function findTsConfig(directory) {
|
|
638
|
+
function findTsConfig(fileSystem, directory) {
|
|
482
639
|
for (const name of ["tsconfig.json", "jsconfig.json"]) {
|
|
483
|
-
const candidate =
|
|
484
|
-
if (
|
|
640
|
+
const candidate = join(directory, name);
|
|
641
|
+
if (fileSystem.exists(candidate)) return candidate;
|
|
485
642
|
}
|
|
486
643
|
return null;
|
|
487
644
|
}
|
|
488
|
-
function loadTsConfig(configPath, warnings) {
|
|
489
|
-
const
|
|
645
|
+
function loadTsConfig(fileSystem, configPath, warnings) {
|
|
646
|
+
const host = {
|
|
647
|
+
useCaseSensitiveFileNames: fileSystem.caseSensitive,
|
|
648
|
+
readDirectory: () => [],
|
|
649
|
+
fileExists: (candidate) => fileSystem.exists(candidate),
|
|
650
|
+
readFile: (candidate) => fileSystem.tryReadFile(candidate) ?? void 0,
|
|
651
|
+
getCurrentDirectory: () => "/",
|
|
652
|
+
onUnRecoverableConfigFileDiagnostic: () => void 0
|
|
653
|
+
};
|
|
654
|
+
const read = ts.readConfigFile(
|
|
655
|
+
configPath,
|
|
656
|
+
(candidate) => fileSystem.tryReadFile(candidate) ?? void 0
|
|
657
|
+
);
|
|
490
658
|
if (read.error || read.config === void 0) {
|
|
491
659
|
warnings.push(
|
|
492
660
|
`no se pudo leer ${configPath}: ${read.error?.messageText ?? "configuraci\xF3n vac\xEDa"}`
|
|
@@ -495,13 +663,13 @@ function loadTsConfig(configPath, warnings) {
|
|
|
495
663
|
}
|
|
496
664
|
const parsed = ts.parseJsonConfigFileContent(
|
|
497
665
|
read.config,
|
|
498
|
-
|
|
499
|
-
|
|
666
|
+
host,
|
|
667
|
+
dirname(configPath),
|
|
500
668
|
void 0,
|
|
501
669
|
configPath
|
|
502
670
|
);
|
|
503
|
-
const configDirectory =
|
|
504
|
-
const baseUrl =
|
|
671
|
+
const configDirectory = dirname(configPath);
|
|
672
|
+
const baseUrl = resolve(configDirectory, parsed.options.baseUrl ?? ".");
|
|
505
673
|
const paths = parsed.options.paths ?? {};
|
|
506
674
|
const aliases = [];
|
|
507
675
|
for (const [pattern, targets] of Object.entries(paths)) {
|
|
@@ -509,7 +677,7 @@ function loadTsConfig(configPath, warnings) {
|
|
|
509
677
|
const star = pattern.indexOf("*");
|
|
510
678
|
const prefix = star === -1 ? pattern : pattern.slice(0, star);
|
|
511
679
|
const suffix = star === -1 ? "" : pattern.slice(star + 1);
|
|
512
|
-
const resolvedTargets = targets.filter((target) => typeof target === "string").map((target) =>
|
|
680
|
+
const resolvedTargets = targets.filter((target) => typeof target === "string").map((target) => resolve(baseUrl, target));
|
|
513
681
|
if (resolvedTargets.length > 0) {
|
|
514
682
|
aliases.push({
|
|
515
683
|
prefix,
|
|
@@ -602,8 +770,12 @@ function matchWildcardKey(pattern, subpath) {
|
|
|
602
770
|
}
|
|
603
771
|
return subpath.slice(prefix.length, subpath.length - suffix.length);
|
|
604
772
|
}
|
|
605
|
-
function discoverWorkspaces(root, warnings) {
|
|
606
|
-
const rootJson = readJsonFile(
|
|
773
|
+
function discoverWorkspaces(root, fileSystem, warnings) {
|
|
774
|
+
const rootJson = readJsonFile(
|
|
775
|
+
fileSystem,
|
|
776
|
+
join(root, "package.json"),
|
|
777
|
+
warnings
|
|
778
|
+
);
|
|
607
779
|
if (!rootJson) return [];
|
|
608
780
|
const patterns = workspacePatterns(rootJson.workspaces);
|
|
609
781
|
if (patterns.length === 0) return [];
|
|
@@ -615,14 +787,15 @@ function discoverWorkspaces(root, warnings) {
|
|
|
615
787
|
const current = stack.pop();
|
|
616
788
|
if (current.relative !== "" && patterns.some((pattern) => pattern.test(current.relative))) {
|
|
617
789
|
const json = readJsonFile(
|
|
618
|
-
|
|
790
|
+
fileSystem,
|
|
791
|
+
join(current.directory, "package.json"),
|
|
619
792
|
warnings
|
|
620
793
|
);
|
|
621
794
|
if (json && typeof json.name === "string") {
|
|
622
795
|
const existing = byName.get(json.name);
|
|
623
796
|
if (existing) {
|
|
624
797
|
warnings.push(
|
|
625
|
-
`workspace duplicado "${json.name}": ${
|
|
798
|
+
`workspace duplicado "${json.name}": ${relative(root, existing.dir)} y ${relative(root, current.directory)}`
|
|
626
799
|
);
|
|
627
800
|
} else {
|
|
628
801
|
byName.set(json.name, {
|
|
@@ -636,7 +809,7 @@ function discoverWorkspaces(root, warnings) {
|
|
|
636
809
|
if (current.depth >= MAX_WORKSPACE_DEPTH) continue;
|
|
637
810
|
let entries;
|
|
638
811
|
try {
|
|
639
|
-
entries =
|
|
812
|
+
entries = fileSystem.readDirectory(current.directory);
|
|
640
813
|
} catch (error) {
|
|
641
814
|
warnings.push(
|
|
642
815
|
`no se pudo leer ${current.relative || "."}: ${error.message}`
|
|
@@ -644,10 +817,10 @@ function discoverWorkspaces(root, warnings) {
|
|
|
644
817
|
continue;
|
|
645
818
|
}
|
|
646
819
|
for (const entry of entries) {
|
|
647
|
-
if (!entry.isDirectory
|
|
820
|
+
if (!entry.isDirectory) continue;
|
|
648
821
|
if (WORKSPACE_SKIP_DIRS.has(entry.name)) continue;
|
|
649
822
|
stack.push({
|
|
650
|
-
directory:
|
|
823
|
+
directory: join(current.directory, entry.name),
|
|
651
824
|
relative: current.relative ? `${current.relative}/${entry.name}` : entry.name,
|
|
652
825
|
depth: current.depth + 1
|
|
653
826
|
});
|
|
@@ -693,16 +866,15 @@ function globToRegExp(glob) {
|
|
|
693
866
|
function escapeRegExp(value) {
|
|
694
867
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
695
868
|
}
|
|
696
|
-
function readJsonFile(file, warnings) {
|
|
869
|
+
function readJsonFile(fileSystem, file, warnings) {
|
|
697
870
|
let text;
|
|
698
871
|
try {
|
|
699
|
-
text =
|
|
872
|
+
text = fileSystem.tryReadFile(file);
|
|
700
873
|
} catch (error) {
|
|
701
|
-
|
|
702
|
-
warnings.push(`no se pudo leer ${file}: ${error.message}`);
|
|
703
|
-
}
|
|
874
|
+
warnings.push(`no se pudo leer ${file}: ${error.message}`);
|
|
704
875
|
return null;
|
|
705
876
|
}
|
|
877
|
+
if (text === null) return null;
|
|
706
878
|
try {
|
|
707
879
|
const parsed = JSON.parse(text.replace(/^\uFEFF/, ""));
|
|
708
880
|
return isRecord(parsed) ? parsed : null;
|
|
@@ -881,41 +1053,516 @@ function compareStrings(left, right) {
|
|
|
881
1053
|
}
|
|
882
1054
|
|
|
883
1055
|
// packages/parsers/src/analyze.ts
|
|
884
|
-
import
|
|
885
|
-
import path4 from "node:path";
|
|
1056
|
+
import { basename as basename2 } from "node:path";
|
|
886
1057
|
|
|
887
1058
|
// packages/schema/src/errors.ts
|
|
888
1059
|
var CcJsonError = class extends Error {
|
|
889
1060
|
path;
|
|
890
|
-
constructor(message,
|
|
891
|
-
super(`${message} (en ${
|
|
1061
|
+
constructor(message, path7) {
|
|
1062
|
+
super(`${message} (en ${path7})`);
|
|
892
1063
|
this.name = "CcJsonError";
|
|
893
|
-
this.path =
|
|
1064
|
+
this.path = path7;
|
|
894
1065
|
}
|
|
895
1066
|
};
|
|
896
1067
|
function isRecord2(value) {
|
|
897
1068
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
898
1069
|
}
|
|
899
|
-
function requireRecord(value,
|
|
900
|
-
if (!isRecord2(value)) throw new CcJsonError("se esperaba un objeto",
|
|
1070
|
+
function requireRecord(value, path7) {
|
|
1071
|
+
if (!isRecord2(value)) throw new CcJsonError("se esperaba un objeto", path7);
|
|
901
1072
|
return value;
|
|
902
1073
|
}
|
|
903
|
-
function requireString(value,
|
|
1074
|
+
function requireString(value, path7, field5) {
|
|
904
1075
|
if (typeof value !== "string" || value.length === 0) {
|
|
905
|
-
throw new CcJsonError(`"${field5}" debe ser una cadena no vac\xEDa`,
|
|
1076
|
+
throw new CcJsonError(`"${field5}" debe ser una cadena no vac\xEDa`, path7);
|
|
906
1077
|
}
|
|
907
1078
|
return value;
|
|
908
1079
|
}
|
|
909
1080
|
|
|
1081
|
+
// node_modules/@noble/hashes/_u64.js
|
|
1082
|
+
var fromNumH = (n) => n / 2 ** 32 | 0;
|
|
1083
|
+
var fromNumL = (n) => n >>> 0;
|
|
1084
|
+
function setU64FromNum(view, byteOffset, n, isLE) {
|
|
1085
|
+
const h = fromNumH(n);
|
|
1086
|
+
const l = fromNumL(n);
|
|
1087
|
+
view.setUint32(byteOffset, isLE ? l : h, isLE);
|
|
1088
|
+
view.setUint32(byteOffset + 4, isLE ? h : l, isLE);
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
// node_modules/@noble/hashes/utils.js
|
|
1092
|
+
function isBytes(a) {
|
|
1093
|
+
return a instanceof Uint8Array || ArrayBuffer.isView(a) && a.constructor.name === "Uint8Array" && "BYTES_PER_ELEMENT" in a && a.BYTES_PER_ELEMENT === 1;
|
|
1094
|
+
}
|
|
1095
|
+
var atitle = (title) => title ? `"${title}" ` : "";
|
|
1096
|
+
function anumber(n, title = "") {
|
|
1097
|
+
if (typeof n !== "number")
|
|
1098
|
+
throw new TypeError(atitle(title) + "expected number, got " + typeof n);
|
|
1099
|
+
if (!Number.isSafeInteger(n) || n < 0)
|
|
1100
|
+
throw new RangeError(atitle(title) + "expected integer >= 0, got " + n);
|
|
1101
|
+
return n;
|
|
1102
|
+
}
|
|
1103
|
+
function abytes(value, length, title = "") {
|
|
1104
|
+
if (isBytes(value) && (length === void 0 || value.length === length))
|
|
1105
|
+
return value;
|
|
1106
|
+
if (length !== void 0)
|
|
1107
|
+
anumber(length, "length");
|
|
1108
|
+
const bytes = isBytes(value);
|
|
1109
|
+
const ofLen = length !== void 0 ? ` of length ${length}` : "";
|
|
1110
|
+
const got = bytes ? `length=${value.length}` : `type=${typeof value}`;
|
|
1111
|
+
const message = atitle(title) + "expected Uint8Array" + ofLen + ", got " + got;
|
|
1112
|
+
if (!bytes)
|
|
1113
|
+
throw new TypeError(message);
|
|
1114
|
+
throw new RangeError(message);
|
|
1115
|
+
}
|
|
1116
|
+
var aobject = (value, label) => {
|
|
1117
|
+
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
1118
|
+
throw new TypeError((label === "object" ? "" : `"${label}" `) + "expected object, got type=" + typeof value);
|
|
1119
|
+
};
|
|
1120
|
+
var aopts = (value, label) => {
|
|
1121
|
+
aobject(value, label);
|
|
1122
|
+
const proto = Object.getPrototypeOf(value);
|
|
1123
|
+
if (proto !== Object.prototype && proto !== null)
|
|
1124
|
+
throw new TypeError(`"${label}" expected plain object`);
|
|
1125
|
+
if (Object.hasOwn(value, "__proto__"))
|
|
1126
|
+
throw new TypeError(`"${label}.__proto__" is not allowed`);
|
|
1127
|
+
};
|
|
1128
|
+
function aexists(instance, checkFinished = true) {
|
|
1129
|
+
if (instance.destroyed)
|
|
1130
|
+
throw new Error("hash was destroyed");
|
|
1131
|
+
if (checkFinished && instance.finished)
|
|
1132
|
+
throw new Error("digest() was already called");
|
|
1133
|
+
}
|
|
1134
|
+
function aoutput(out, instance) {
|
|
1135
|
+
abytes(out, void 0, "output");
|
|
1136
|
+
const min = instance.outputLen;
|
|
1137
|
+
if (!(out.length >= min)) {
|
|
1138
|
+
throw new RangeError('"output" expected length >= ' + min);
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1141
|
+
function clean(...arrays) {
|
|
1142
|
+
for (let i = 0; i < arrays.length; i++) {
|
|
1143
|
+
arrays[i].fill(0);
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1146
|
+
function createView(arr) {
|
|
1147
|
+
return new DataView(arr.buffer, arr.byteOffset, arr.byteLength);
|
|
1148
|
+
}
|
|
1149
|
+
function rotr(word, shift) {
|
|
1150
|
+
return word << 32 - shift | word >>> shift;
|
|
1151
|
+
}
|
|
1152
|
+
function rotl(word, shift) {
|
|
1153
|
+
return word << shift | word >>> 32 - shift >>> 0;
|
|
1154
|
+
}
|
|
1155
|
+
function checkOpts(defaults, opts, title = "opts") {
|
|
1156
|
+
aopts(defaults, "defaults");
|
|
1157
|
+
if (opts !== void 0)
|
|
1158
|
+
aopts(opts, title);
|
|
1159
|
+
const merged = Object.assign(/* @__PURE__ */ Object.create(null), defaults, opts);
|
|
1160
|
+
return merged;
|
|
1161
|
+
}
|
|
1162
|
+
function createHasher(hashCons, info = {}) {
|
|
1163
|
+
if (typeof hashCons !== "function")
|
|
1164
|
+
throw new TypeError('"hashCons" expected function, got type=' + typeof hashCons);
|
|
1165
|
+
info = checkOpts({}, info, "info");
|
|
1166
|
+
const hashC = (msg, opts) => hashCons(opts).update(msg).digest();
|
|
1167
|
+
const tmp = hashCons(void 0);
|
|
1168
|
+
hashC.outputLen = tmp.outputLen;
|
|
1169
|
+
hashC.blockLen = tmp.blockLen;
|
|
1170
|
+
hashC.canXOF = tmp.canXOF;
|
|
1171
|
+
hashC.create = (opts) => hashCons(opts);
|
|
1172
|
+
Object.assign(hashC, info);
|
|
1173
|
+
return Object.freeze(hashC);
|
|
1174
|
+
}
|
|
1175
|
+
var oidNist = (suffix) => ({
|
|
1176
|
+
// Current NIST hashAlgs suffixes used here fit in one DER subidentifier octet.
|
|
1177
|
+
// Larger suffix values would need base-128 OID encoding and a different length byte.
|
|
1178
|
+
oid: Uint8Array.from([6, 9, 96, 134, 72, 1, 101, 3, 4, 2, suffix])
|
|
1179
|
+
});
|
|
1180
|
+
|
|
1181
|
+
// node_modules/@noble/hashes/_md.js
|
|
1182
|
+
function Chi(a, b, c) {
|
|
1183
|
+
return a & b ^ ~a & c;
|
|
1184
|
+
}
|
|
1185
|
+
function Maj(a, b, c) {
|
|
1186
|
+
return a & b ^ a & c ^ b & c;
|
|
1187
|
+
}
|
|
1188
|
+
var HashMD = class {
|
|
1189
|
+
blockLen;
|
|
1190
|
+
outputLen;
|
|
1191
|
+
canXOF = false;
|
|
1192
|
+
padOffset;
|
|
1193
|
+
isLE;
|
|
1194
|
+
// For partial updates less than block size
|
|
1195
|
+
buffer;
|
|
1196
|
+
view;
|
|
1197
|
+
finished = false;
|
|
1198
|
+
length = 0;
|
|
1199
|
+
pos = 0;
|
|
1200
|
+
destroyed = false;
|
|
1201
|
+
constructor(blockLen, outputLen, padOffset, isLE) {
|
|
1202
|
+
this.blockLen = blockLen;
|
|
1203
|
+
this.outputLen = outputLen;
|
|
1204
|
+
this.padOffset = padOffset;
|
|
1205
|
+
this.isLE = isLE;
|
|
1206
|
+
this.buffer = new Uint8Array(blockLen);
|
|
1207
|
+
this.view = createView(this.buffer);
|
|
1208
|
+
}
|
|
1209
|
+
update(data) {
|
|
1210
|
+
aexists(this);
|
|
1211
|
+
abytes(data);
|
|
1212
|
+
const { view, buffer, blockLen } = this;
|
|
1213
|
+
const len = data.length;
|
|
1214
|
+
let processed = false;
|
|
1215
|
+
for (let pos = 0; pos < len; ) {
|
|
1216
|
+
const take = Math.min(blockLen - this.pos, len - pos);
|
|
1217
|
+
if (take === blockLen) {
|
|
1218
|
+
const dataView = createView(data);
|
|
1219
|
+
for (; blockLen <= len - pos; pos += blockLen)
|
|
1220
|
+
this.process(dataView, pos);
|
|
1221
|
+
processed = true;
|
|
1222
|
+
continue;
|
|
1223
|
+
}
|
|
1224
|
+
buffer.set(pos === 0 && take === len ? data : data.subarray(pos, pos + take), this.pos);
|
|
1225
|
+
this.pos += take;
|
|
1226
|
+
pos += take;
|
|
1227
|
+
if (this.pos === blockLen) {
|
|
1228
|
+
this.process(view, 0);
|
|
1229
|
+
this.pos = 0;
|
|
1230
|
+
processed = true;
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
this.length += data.length;
|
|
1234
|
+
if (processed)
|
|
1235
|
+
this.roundClean();
|
|
1236
|
+
return this;
|
|
1237
|
+
}
|
|
1238
|
+
digestInto(out) {
|
|
1239
|
+
aexists(this);
|
|
1240
|
+
aoutput(out, this);
|
|
1241
|
+
this.finished = true;
|
|
1242
|
+
const { buffer, view, blockLen, isLE } = this;
|
|
1243
|
+
let { pos } = this;
|
|
1244
|
+
buffer[pos++] = 128;
|
|
1245
|
+
buffer.fill(0, pos);
|
|
1246
|
+
if (this.padOffset > blockLen - pos) {
|
|
1247
|
+
this.process(view, 0);
|
|
1248
|
+
buffer.fill(0);
|
|
1249
|
+
}
|
|
1250
|
+
setU64FromNum(view, blockLen - 8, this.length * 8, isLE);
|
|
1251
|
+
this.process(view, 0);
|
|
1252
|
+
this.roundClean();
|
|
1253
|
+
const oview = out === buffer ? view : createView(out);
|
|
1254
|
+
const len = this.outputLen;
|
|
1255
|
+
const outLen = len / 4;
|
|
1256
|
+
const state = this.get();
|
|
1257
|
+
if (len % 4 || outLen > state.length)
|
|
1258
|
+
throw new Error("invalid outputLen");
|
|
1259
|
+
for (let i = 0; i < outLen; i++)
|
|
1260
|
+
oview.setUint32(4 * i, state[i], isLE);
|
|
1261
|
+
}
|
|
1262
|
+
digest() {
|
|
1263
|
+
const { buffer, outputLen } = this;
|
|
1264
|
+
this.digestInto(buffer);
|
|
1265
|
+
const res = buffer.slice(0, outputLen);
|
|
1266
|
+
this.destroy();
|
|
1267
|
+
return res;
|
|
1268
|
+
}
|
|
1269
|
+
_cloneIntoMeta(to) {
|
|
1270
|
+
const { buffer, length, finished, destroyed, pos } = this;
|
|
1271
|
+
to.destroyed = destroyed;
|
|
1272
|
+
to.finished = finished;
|
|
1273
|
+
to.length = length;
|
|
1274
|
+
to.pos = pos;
|
|
1275
|
+
if (pos)
|
|
1276
|
+
to.buffer.set(buffer);
|
|
1277
|
+
return to;
|
|
1278
|
+
}
|
|
1279
|
+
clone() {
|
|
1280
|
+
return this._cloneInto();
|
|
1281
|
+
}
|
|
1282
|
+
};
|
|
1283
|
+
var SHA256_IV = /* @__PURE__ */ Uint32Array.from([
|
|
1284
|
+
1779033703,
|
|
1285
|
+
3144134277,
|
|
1286
|
+
1013904242,
|
|
1287
|
+
2773480762,
|
|
1288
|
+
1359893119,
|
|
1289
|
+
2600822924,
|
|
1290
|
+
528734635,
|
|
1291
|
+
1541459225
|
|
1292
|
+
]);
|
|
1293
|
+
|
|
1294
|
+
// node_modules/@noble/hashes/legacy.js
|
|
1295
|
+
var SHA1_IV = /* @__PURE__ */ Uint32Array.from([
|
|
1296
|
+
1732584193,
|
|
1297
|
+
4023233417,
|
|
1298
|
+
2562383102,
|
|
1299
|
+
271733878,
|
|
1300
|
+
3285377520
|
|
1301
|
+
]);
|
|
1302
|
+
var p32 = /* @__PURE__ */ Math.pow(2, 32);
|
|
1303
|
+
var K = /* @__PURE__ */ Array.from({ length: 64 }, (_, i) => Math.floor(p32 * Math.abs(Math.sin(i + 1))));
|
|
1304
|
+
var MD5_IV = /* @__PURE__ */ SHA1_IV.slice(0, 4);
|
|
1305
|
+
var MD5_W = /* @__PURE__ */ new Uint32Array(16);
|
|
1306
|
+
var MD5_SHIFTS = /* @__PURE__ */ (() => {
|
|
1307
|
+
const S = [
|
|
1308
|
+
[7, 12, 17, 22],
|
|
1309
|
+
[5, 9, 14, 20],
|
|
1310
|
+
[4, 11, 16, 23],
|
|
1311
|
+
[6, 10, 15, 21]
|
|
1312
|
+
];
|
|
1313
|
+
return Uint8Array.from({ length: 64 }, (_, i) => S[Math.floor(i / 16)][i % 4]);
|
|
1314
|
+
})();
|
|
1315
|
+
var _MD5 = class extends HashMD {
|
|
1316
|
+
A = MD5_IV[0] | 0;
|
|
1317
|
+
B = MD5_IV[1] | 0;
|
|
1318
|
+
C = MD5_IV[2] | 0;
|
|
1319
|
+
D = MD5_IV[3] | 0;
|
|
1320
|
+
constructor() {
|
|
1321
|
+
super(64, 16, 8, true);
|
|
1322
|
+
}
|
|
1323
|
+
get() {
|
|
1324
|
+
const { A, B, C, D } = this;
|
|
1325
|
+
return [A, B, C, D];
|
|
1326
|
+
}
|
|
1327
|
+
set(A, B, C, D) {
|
|
1328
|
+
this.A = A | 0;
|
|
1329
|
+
this.B = B | 0;
|
|
1330
|
+
this.C = C | 0;
|
|
1331
|
+
this.D = D | 0;
|
|
1332
|
+
}
|
|
1333
|
+
_cloneInto(to) {
|
|
1334
|
+
(to ||= new this.constructor()).set(...this.get());
|
|
1335
|
+
return this._cloneIntoMeta(to);
|
|
1336
|
+
}
|
|
1337
|
+
process(view, offset) {
|
|
1338
|
+
for (let i = 0; i < 16; i++, offset += 4)
|
|
1339
|
+
MD5_W[i] = view.getUint32(offset, true);
|
|
1340
|
+
let { A, B, C, D } = this;
|
|
1341
|
+
for (let i = 0; i < 64; i++) {
|
|
1342
|
+
let F, g;
|
|
1343
|
+
if (i < 16) {
|
|
1344
|
+
F = Chi(B, C, D);
|
|
1345
|
+
g = i;
|
|
1346
|
+
} else if (i < 32) {
|
|
1347
|
+
F = Chi(D, B, C);
|
|
1348
|
+
g = (5 * i + 1) % 16;
|
|
1349
|
+
} else if (i < 48) {
|
|
1350
|
+
F = B ^ C ^ D;
|
|
1351
|
+
g = (3 * i + 5) % 16;
|
|
1352
|
+
} else {
|
|
1353
|
+
F = C ^ (B | ~D);
|
|
1354
|
+
g = 7 * i % 16;
|
|
1355
|
+
}
|
|
1356
|
+
F = F + A + K[i] + MD5_W[g];
|
|
1357
|
+
A = D;
|
|
1358
|
+
D = C;
|
|
1359
|
+
C = B;
|
|
1360
|
+
B = B + rotl(F, MD5_SHIFTS[i]);
|
|
1361
|
+
}
|
|
1362
|
+
A = A + this.A | 0;
|
|
1363
|
+
B = B + this.B | 0;
|
|
1364
|
+
C = C + this.C | 0;
|
|
1365
|
+
D = D + this.D | 0;
|
|
1366
|
+
this.set(A, B, C, D);
|
|
1367
|
+
}
|
|
1368
|
+
roundClean() {
|
|
1369
|
+
clean(MD5_W);
|
|
1370
|
+
}
|
|
1371
|
+
destroy() {
|
|
1372
|
+
this.destroyed = true;
|
|
1373
|
+
this.set(0, 0, 0, 0);
|
|
1374
|
+
clean(this.buffer);
|
|
1375
|
+
}
|
|
1376
|
+
};
|
|
1377
|
+
var md5 = /* @__PURE__ */ createHasher(() => new _MD5());
|
|
1378
|
+
|
|
1379
|
+
// node_modules/@noble/hashes/sha2.js
|
|
1380
|
+
var SHA256_K = /* @__PURE__ */ Uint32Array.from([
|
|
1381
|
+
1116352408,
|
|
1382
|
+
1899447441,
|
|
1383
|
+
3049323471,
|
|
1384
|
+
3921009573,
|
|
1385
|
+
961987163,
|
|
1386
|
+
1508970993,
|
|
1387
|
+
2453635748,
|
|
1388
|
+
2870763221,
|
|
1389
|
+
3624381080,
|
|
1390
|
+
310598401,
|
|
1391
|
+
607225278,
|
|
1392
|
+
1426881987,
|
|
1393
|
+
1925078388,
|
|
1394
|
+
2162078206,
|
|
1395
|
+
2614888103,
|
|
1396
|
+
3248222580,
|
|
1397
|
+
3835390401,
|
|
1398
|
+
4022224774,
|
|
1399
|
+
264347078,
|
|
1400
|
+
604807628,
|
|
1401
|
+
770255983,
|
|
1402
|
+
1249150122,
|
|
1403
|
+
1555081692,
|
|
1404
|
+
1996064986,
|
|
1405
|
+
2554220882,
|
|
1406
|
+
2821834349,
|
|
1407
|
+
2952996808,
|
|
1408
|
+
3210313671,
|
|
1409
|
+
3336571891,
|
|
1410
|
+
3584528711,
|
|
1411
|
+
113926993,
|
|
1412
|
+
338241895,
|
|
1413
|
+
666307205,
|
|
1414
|
+
773529912,
|
|
1415
|
+
1294757372,
|
|
1416
|
+
1396182291,
|
|
1417
|
+
1695183700,
|
|
1418
|
+
1986661051,
|
|
1419
|
+
2177026350,
|
|
1420
|
+
2456956037,
|
|
1421
|
+
2730485921,
|
|
1422
|
+
2820302411,
|
|
1423
|
+
3259730800,
|
|
1424
|
+
3345764771,
|
|
1425
|
+
3516065817,
|
|
1426
|
+
3600352804,
|
|
1427
|
+
4094571909,
|
|
1428
|
+
275423344,
|
|
1429
|
+
430227734,
|
|
1430
|
+
506948616,
|
|
1431
|
+
659060556,
|
|
1432
|
+
883997877,
|
|
1433
|
+
958139571,
|
|
1434
|
+
1322822218,
|
|
1435
|
+
1537002063,
|
|
1436
|
+
1747873779,
|
|
1437
|
+
1955562222,
|
|
1438
|
+
2024104815,
|
|
1439
|
+
2227730452,
|
|
1440
|
+
2361852424,
|
|
1441
|
+
2428436474,
|
|
1442
|
+
2756734187,
|
|
1443
|
+
3204031479,
|
|
1444
|
+
3329325298
|
|
1445
|
+
]);
|
|
1446
|
+
var SHA256_W = /* @__PURE__ */ new Uint32Array(64);
|
|
1447
|
+
var SHA2_32B = class extends HashMD {
|
|
1448
|
+
// We cannot use array here since array allows indexing by variable
|
|
1449
|
+
// which means optimizer/compiler cannot use registers.
|
|
1450
|
+
// Numeric initializers matter: starting the fields as `undefined` changes
|
|
1451
|
+
// V8's field representation and makes sha256 3x slower (measured).
|
|
1452
|
+
A = 0;
|
|
1453
|
+
B = 0;
|
|
1454
|
+
C = 0;
|
|
1455
|
+
D = 0;
|
|
1456
|
+
E = 0;
|
|
1457
|
+
F = 0;
|
|
1458
|
+
G = 0;
|
|
1459
|
+
H = 0;
|
|
1460
|
+
constructor(outputLen, IV) {
|
|
1461
|
+
super(64, outputLen, 8, false);
|
|
1462
|
+
this.A = IV[0] | 0;
|
|
1463
|
+
this.B = IV[1] | 0;
|
|
1464
|
+
this.C = IV[2] | 0;
|
|
1465
|
+
this.D = IV[3] | 0;
|
|
1466
|
+
this.E = IV[4] | 0;
|
|
1467
|
+
this.F = IV[5] | 0;
|
|
1468
|
+
this.G = IV[6] | 0;
|
|
1469
|
+
this.H = IV[7] | 0;
|
|
1470
|
+
}
|
|
1471
|
+
get() {
|
|
1472
|
+
const { A, B, C, D, E, F, G, H } = this;
|
|
1473
|
+
return [A, B, C, D, E, F, G, H];
|
|
1474
|
+
}
|
|
1475
|
+
// prettier-ignore
|
|
1476
|
+
set(A, B, C, D, E, F, G, H) {
|
|
1477
|
+
this.A = A | 0;
|
|
1478
|
+
this.B = B | 0;
|
|
1479
|
+
this.C = C | 0;
|
|
1480
|
+
this.D = D | 0;
|
|
1481
|
+
this.E = E | 0;
|
|
1482
|
+
this.F = F | 0;
|
|
1483
|
+
this.G = G | 0;
|
|
1484
|
+
this.H = H | 0;
|
|
1485
|
+
}
|
|
1486
|
+
_cloneInto(to) {
|
|
1487
|
+
(to ||= new this.constructor()).set(...this.get());
|
|
1488
|
+
return this._cloneIntoMeta(to);
|
|
1489
|
+
}
|
|
1490
|
+
process(view, offset) {
|
|
1491
|
+
for (let i = 0; i < 16; i++, offset += 4)
|
|
1492
|
+
SHA256_W[i] = view.getUint32(offset, false);
|
|
1493
|
+
for (let i = 16; i < 64; i++) {
|
|
1494
|
+
const W15 = SHA256_W[i - 15];
|
|
1495
|
+
const W2 = SHA256_W[i - 2];
|
|
1496
|
+
const s0 = rotr(W15, 7) ^ rotr(W15, 18) ^ W15 >>> 3;
|
|
1497
|
+
const s1 = rotr(W2, 17) ^ rotr(W2, 19) ^ W2 >>> 10;
|
|
1498
|
+
SHA256_W[i] = s1 + SHA256_W[i - 7] + s0 + SHA256_W[i - 16] | 0;
|
|
1499
|
+
}
|
|
1500
|
+
let { A, B, C, D, E, F, G, H } = this;
|
|
1501
|
+
for (let i = 0; i < 64; i++) {
|
|
1502
|
+
const sigma1 = rotr(E, 6) ^ rotr(E, 11) ^ rotr(E, 25);
|
|
1503
|
+
const T1 = H + sigma1 + Chi(E, F, G) + SHA256_K[i] + SHA256_W[i] | 0;
|
|
1504
|
+
const sigma0 = rotr(A, 2) ^ rotr(A, 13) ^ rotr(A, 22);
|
|
1505
|
+
const T2 = sigma0 + Maj(A, B, C) | 0;
|
|
1506
|
+
H = G;
|
|
1507
|
+
G = F;
|
|
1508
|
+
F = E;
|
|
1509
|
+
E = D + T1 | 0;
|
|
1510
|
+
D = C;
|
|
1511
|
+
C = B;
|
|
1512
|
+
B = A;
|
|
1513
|
+
A = T1 + T2 | 0;
|
|
1514
|
+
}
|
|
1515
|
+
A = A + this.A | 0;
|
|
1516
|
+
B = B + this.B | 0;
|
|
1517
|
+
C = C + this.C | 0;
|
|
1518
|
+
D = D + this.D | 0;
|
|
1519
|
+
E = E + this.E | 0;
|
|
1520
|
+
F = F + this.F | 0;
|
|
1521
|
+
G = G + this.G | 0;
|
|
1522
|
+
H = H + this.H | 0;
|
|
1523
|
+
this.set(A, B, C, D, E, F, G, H);
|
|
1524
|
+
}
|
|
1525
|
+
roundClean() {
|
|
1526
|
+
clean(SHA256_W);
|
|
1527
|
+
}
|
|
1528
|
+
destroy() {
|
|
1529
|
+
this.destroyed = true;
|
|
1530
|
+
this.set(0, 0, 0, 0, 0, 0, 0, 0);
|
|
1531
|
+
clean(this.buffer);
|
|
1532
|
+
}
|
|
1533
|
+
};
|
|
1534
|
+
var _SHA256 = class extends SHA2_32B {
|
|
1535
|
+
constructor() {
|
|
1536
|
+
super(32, SHA256_IV);
|
|
1537
|
+
}
|
|
1538
|
+
};
|
|
1539
|
+
var sha256 = /* @__PURE__ */ createHasher(
|
|
1540
|
+
() => new _SHA256(),
|
|
1541
|
+
/* @__PURE__ */ oidNist(1)
|
|
1542
|
+
);
|
|
1543
|
+
|
|
1544
|
+
// packages/schema/src/hash.ts
|
|
1545
|
+
var encoder = new TextEncoder();
|
|
1546
|
+
function sha256Hex(input) {
|
|
1547
|
+
return toHex(sha256(encoder.encode(input)));
|
|
1548
|
+
}
|
|
1549
|
+
function md5Hex(input) {
|
|
1550
|
+
return toHex(md5(encoder.encode(input)));
|
|
1551
|
+
}
|
|
1552
|
+
function toHex(bytes) {
|
|
1553
|
+
let hex = "";
|
|
1554
|
+
for (const byte of bytes) hex += byte.toString(16).padStart(2, "0");
|
|
1555
|
+
return hex;
|
|
1556
|
+
}
|
|
1557
|
+
|
|
910
1558
|
// packages/schema/src/identity.ts
|
|
911
|
-
import { createHash } from "node:crypto";
|
|
912
1559
|
var ID_LENGTH = 16;
|
|
913
1560
|
function normalizeName(name) {
|
|
914
1561
|
return name.normalize("NFC");
|
|
915
1562
|
}
|
|
916
|
-
function pathSegments(
|
|
1563
|
+
function pathSegments(path7) {
|
|
917
1564
|
const segments = [];
|
|
918
|
-
for (const raw of
|
|
1565
|
+
for (const raw of path7.replace(/\\/g, "/").split("/")) {
|
|
919
1566
|
const segment = normalizeName(raw);
|
|
920
1567
|
if (segment === "" || segment === ".") continue;
|
|
921
1568
|
if (segment === "..") {
|
|
@@ -929,18 +1576,18 @@ function pathSegments(path9) {
|
|
|
929
1576
|
function canonicalPath(segments) {
|
|
930
1577
|
return `/${segments.map(normalizeName).join("/")}`;
|
|
931
1578
|
}
|
|
932
|
-
function idFromCanonicalPath(
|
|
933
|
-
const canonical =
|
|
934
|
-
return
|
|
1579
|
+
function idFromCanonicalPath(path7, type = "File") {
|
|
1580
|
+
const canonical = path7.startsWith("/") ? path7 : `/${path7}`;
|
|
1581
|
+
return sha256Hex(type + canonical).slice(0, ID_LENGTH);
|
|
935
1582
|
}
|
|
936
1583
|
function nodeId(type, segments) {
|
|
937
1584
|
return idFromCanonicalPath(canonicalPath(segments), type);
|
|
938
1585
|
}
|
|
939
|
-
function fileId(
|
|
940
|
-
return nodeId("File", pathSegments(
|
|
1586
|
+
function fileId(path7) {
|
|
1587
|
+
return nodeId("File", pathSegments(path7));
|
|
941
1588
|
}
|
|
942
|
-
function folderId(
|
|
943
|
-
return nodeId("Folder", pathSegments(
|
|
1589
|
+
function folderId(path7) {
|
|
1590
|
+
return nodeId("Folder", pathSegments(path7));
|
|
944
1591
|
}
|
|
945
1592
|
|
|
946
1593
|
// packages/schema/src/legacy.ts
|
|
@@ -996,15 +1643,15 @@ function normalizeLegacyCcJson(input) {
|
|
|
996
1643
|
const metrics = {};
|
|
997
1644
|
const built = [];
|
|
998
1645
|
const ids = /* @__PURE__ */ new Map();
|
|
999
|
-
const buildNode = (value, parentPath,
|
|
1646
|
+
const buildNode = (value, parentPath, path7, depth) => {
|
|
1000
1647
|
if (depth > MAX_DEPTH) {
|
|
1001
|
-
throw new CcJsonError(`profundidad m\xE1xima ${MAX_DEPTH} superada`,
|
|
1648
|
+
throw new CcJsonError(`profundidad m\xE1xima ${MAX_DEPTH} superada`, path7);
|
|
1002
1649
|
}
|
|
1003
|
-
const raw = requireRecord(value,
|
|
1004
|
-
const name = readNodeName(raw.name, `${
|
|
1650
|
+
const raw = requireRecord(value, path7);
|
|
1651
|
+
const name = readNodeName(raw.name, `${path7}.name`);
|
|
1005
1652
|
const type = raw.type;
|
|
1006
1653
|
if (type !== "File" && type !== "Folder") {
|
|
1007
|
-
throw new CcJsonError('"type" debe ser "File" o "Folder"', `${
|
|
1654
|
+
throw new CcJsonError('"type" debe ser "File" o "Folder"', `${path7}.type`);
|
|
1008
1655
|
}
|
|
1009
1656
|
const fullPath = [...parentPath, name];
|
|
1010
1657
|
const id = nodeId(type, fullPath.slice(1));
|
|
@@ -1012,13 +1659,13 @@ function normalizeLegacyCcJson(input) {
|
|
|
1012
1659
|
if (previous !== void 0) {
|
|
1013
1660
|
throw new CcJsonError(
|
|
1014
1661
|
`id duplicado "${id}" para "${previous}" y "${fullPath.join("/")}"`,
|
|
1015
|
-
`${
|
|
1662
|
+
`${path7}.name`
|
|
1016
1663
|
);
|
|
1017
1664
|
}
|
|
1018
1665
|
ids.set(id, fullPath.join("/"));
|
|
1019
1666
|
built.push({ id, name, fullPath: fullPath.join("/") });
|
|
1020
1667
|
const node = { id, name, type };
|
|
1021
|
-
const attributes = readMetrics(raw.attributes, `${
|
|
1668
|
+
const attributes = readMetrics(raw.attributes, `${path7}.attributes`);
|
|
1022
1669
|
if (attributes) metrics[id] = attributes;
|
|
1023
1670
|
const contentHash = readOptionalString(raw.checksum) ?? readOptionalString(raw.contentHash);
|
|
1024
1671
|
if (contentHash) node.contentHash = contentHash;
|
|
@@ -1026,14 +1673,14 @@ function normalizeLegacyCcJson(input) {
|
|
|
1026
1673
|
if (link) node.link = link;
|
|
1027
1674
|
if (raw.children !== void 0) {
|
|
1028
1675
|
if (!Array.isArray(raw.children)) {
|
|
1029
|
-
throw new CcJsonError('"children" debe ser un array', `${
|
|
1676
|
+
throw new CcJsonError('"children" debe ser un array', `${path7}.children`);
|
|
1030
1677
|
}
|
|
1031
1678
|
if (type === "File" && raw.children.length > 0) {
|
|
1032
|
-
throw new CcJsonError("un fichero no puede tener hijos", `${
|
|
1679
|
+
throw new CcJsonError("un fichero no puede tener hijos", `${path7}.children`);
|
|
1033
1680
|
}
|
|
1034
1681
|
if (type === "Folder" && raw.children.length > 0) {
|
|
1035
1682
|
node.children = raw.children.map(
|
|
1036
|
-
(child, index) => buildNode(child, fullPath, `${
|
|
1683
|
+
(child, index) => buildNode(child, fullPath, `${path7}.children[${index}]`, depth + 1)
|
|
1037
1684
|
);
|
|
1038
1685
|
}
|
|
1039
1686
|
}
|
|
@@ -1050,15 +1697,15 @@ function normalizeLegacyCcJson(input) {
|
|
|
1050
1697
|
throw new CcJsonError('"edges" debe ser un array', `${base}.edges`);
|
|
1051
1698
|
}
|
|
1052
1699
|
edgesRaw.forEach((edge, index) => {
|
|
1053
|
-
const
|
|
1054
|
-
const raw = requireRecord(edge,
|
|
1055
|
-
const fromName = requireString(raw.fromNodeName, `${
|
|
1056
|
-
const toName = requireString(raw.toNodeName, `${
|
|
1700
|
+
const path7 = `${base}.edges[${index}]`;
|
|
1701
|
+
const raw = requireRecord(edge, path7);
|
|
1702
|
+
const fromName = requireString(raw.fromNodeName, `${path7}.fromNodeName`, "fromNodeName");
|
|
1703
|
+
const toName = requireString(raw.toNodeName, `${path7}.toNodeName`, "toNodeName");
|
|
1057
1704
|
const normalized = {
|
|
1058
|
-
fromId: resolveEndpoint(fromName, pathIndex, stripNames, `${
|
|
1059
|
-
toId: resolveEndpoint(toName, pathIndex, stripNames, `${
|
|
1705
|
+
fromId: resolveEndpoint(fromName, pathIndex, stripNames, `${path7}.fromNodeName`),
|
|
1706
|
+
toId: resolveEndpoint(toName, pathIndex, stripNames, `${path7}.toNodeName`)
|
|
1060
1707
|
};
|
|
1061
|
-
const attributes = readMetrics(raw.attributes, `${
|
|
1708
|
+
const attributes = readMetrics(raw.attributes, `${path7}.attributes`);
|
|
1062
1709
|
if (attributes) normalized.attributes = attributes;
|
|
1063
1710
|
if (typeof raw.isCyclic === "boolean") normalized.isCyclic = raw.isCyclic;
|
|
1064
1711
|
if (typeof raw.isPointingUpwards === "boolean") {
|
|
@@ -1128,10 +1775,10 @@ function buildPathIndex(built, multipleRoots) {
|
|
|
1128
1775
|
for (const node of built) {
|
|
1129
1776
|
const segments = node.fullPath.split("/");
|
|
1130
1777
|
if (segments.length > 1) add(segments.slice(1).join("/"), node.id);
|
|
1131
|
-
const
|
|
1132
|
-
if (
|
|
1133
|
-
add(
|
|
1134
|
-
add(`root/${
|
|
1778
|
+
const relative2 = segments.slice(multipleRoots ? 2 : 1).join("/");
|
|
1779
|
+
if (relative2 !== "") {
|
|
1780
|
+
add(relative2, node.id);
|
|
1781
|
+
add(`root/${relative2}`, node.id);
|
|
1135
1782
|
} else if (segments.length === 1) {
|
|
1136
1783
|
add("root", node.id);
|
|
1137
1784
|
}
|
|
@@ -1143,10 +1790,10 @@ function buildPathIndex(built, multipleRoots) {
|
|
|
1143
1790
|
}
|
|
1144
1791
|
return index;
|
|
1145
1792
|
}
|
|
1146
|
-
function resolveEndpoint(endpoint, index, stripNames,
|
|
1793
|
+
function resolveEndpoint(endpoint, index, stripNames, path7) {
|
|
1147
1794
|
const segments = canonicalSegments(endpoint);
|
|
1148
1795
|
if (segments.length === 0) {
|
|
1149
|
-
throw new CcJsonError("extremo de arista vac\xEDo",
|
|
1796
|
+
throw new CcJsonError("extremo de arista vac\xEDo", path7);
|
|
1150
1797
|
}
|
|
1151
1798
|
const candidates = [segments.join("/")];
|
|
1152
1799
|
if (segments.length > 1 && stripNames.has(segments[0])) {
|
|
@@ -1158,7 +1805,7 @@ function resolveEndpoint(endpoint, index, stripNames, path9) {
|
|
|
1158
1805
|
}
|
|
1159
1806
|
const bare = index.get(segments[segments.length - 1]);
|
|
1160
1807
|
if (bare) return bare;
|
|
1161
|
-
throw new CcJsonError(`no se pudo resolver el nodo "${endpoint}"`,
|
|
1808
|
+
throw new CcJsonError(`no se pudo resolver el nodo "${endpoint}"`, path7);
|
|
1162
1809
|
}
|
|
1163
1810
|
function canonicalSegments(value) {
|
|
1164
1811
|
const result = [];
|
|
@@ -1173,85 +1820,85 @@ function canonicalSegments(value) {
|
|
|
1173
1820
|
}
|
|
1174
1821
|
return result;
|
|
1175
1822
|
}
|
|
1176
|
-
function readNodeName(value,
|
|
1177
|
-
const name = normalizeName(requireString(value,
|
|
1823
|
+
function readNodeName(value, path7) {
|
|
1824
|
+
const name = normalizeName(requireString(value, path7, "name"));
|
|
1178
1825
|
if (name === "." || name === "..") {
|
|
1179
|
-
throw new CcJsonError('el nombre no puede ser "." ni ".."',
|
|
1826
|
+
throw new CcJsonError('el nombre no puede ser "." ni ".."', path7);
|
|
1180
1827
|
}
|
|
1181
1828
|
if (name.includes("/")) {
|
|
1182
|
-
throw new CcJsonError('el nombre no puede contener "/"',
|
|
1829
|
+
throw new CcJsonError('el nombre no puede contener "/"', path7);
|
|
1183
1830
|
}
|
|
1184
1831
|
return name;
|
|
1185
1832
|
}
|
|
1186
1833
|
function readOptionalString(value) {
|
|
1187
1834
|
return typeof value === "string" && value.length > 0 ? value : void 0;
|
|
1188
1835
|
}
|
|
1189
|
-
function readMetrics(value,
|
|
1836
|
+
function readMetrics(value, path7) {
|
|
1190
1837
|
if (value === void 0) return void 0;
|
|
1191
|
-
const raw = requireRecord(value,
|
|
1838
|
+
const raw = requireRecord(value, path7);
|
|
1192
1839
|
const out = {};
|
|
1193
1840
|
for (const [metric, metricValue] of Object.entries(raw)) {
|
|
1194
1841
|
if (typeof metricValue !== "number" || !Number.isFinite(metricValue)) {
|
|
1195
1842
|
throw new CcJsonError(
|
|
1196
1843
|
`la m\xE9trica "${metric}" debe ser un n\xFAmero finito`,
|
|
1197
|
-
`${
|
|
1844
|
+
`${path7}["${metric}"]`
|
|
1198
1845
|
);
|
|
1199
1846
|
}
|
|
1200
1847
|
out[metric] = metricValue;
|
|
1201
1848
|
}
|
|
1202
1849
|
return Object.keys(out).length > 0 ? out : void 0;
|
|
1203
1850
|
}
|
|
1204
|
-
function readAttributeTypes(value,
|
|
1851
|
+
function readAttributeTypes(value, path7) {
|
|
1205
1852
|
if (value === void 0) return {};
|
|
1206
|
-
const raw = requireRecord(value,
|
|
1853
|
+
const raw = requireRecord(value, path7);
|
|
1207
1854
|
if ("nodes" in raw || "edges" in raw) {
|
|
1208
|
-
const nodes2 = raw.nodes === void 0 ? void 0 : readTypeMap(raw.nodes, `${
|
|
1209
|
-
const edges = raw.edges === void 0 ? void 0 : readTypeMap(raw.edges, `${
|
|
1855
|
+
const nodes2 = raw.nodes === void 0 ? void 0 : readTypeMap(raw.nodes, `${path7}.nodes`);
|
|
1856
|
+
const edges = raw.edges === void 0 ? void 0 : readTypeMap(raw.edges, `${path7}.edges`);
|
|
1210
1857
|
return {
|
|
1211
1858
|
...nodes2 && Object.keys(nodes2).length > 0 ? { nodes: nodes2 } : {},
|
|
1212
1859
|
...edges && Object.keys(edges).length > 0 ? { edges } : {}
|
|
1213
1860
|
};
|
|
1214
1861
|
}
|
|
1215
|
-
const nodes = readTypeMap(raw,
|
|
1862
|
+
const nodes = readTypeMap(raw, path7);
|
|
1216
1863
|
return Object.keys(nodes).length > 0 ? { nodes } : {};
|
|
1217
1864
|
}
|
|
1218
|
-
function readTypeMap(value,
|
|
1219
|
-
const raw = requireRecord(value,
|
|
1865
|
+
function readTypeMap(value, path7) {
|
|
1866
|
+
const raw = requireRecord(value, path7);
|
|
1220
1867
|
const out = {};
|
|
1221
1868
|
for (const [metric, type] of Object.entries(raw)) {
|
|
1222
1869
|
if (type !== "absolute" && type !== "relative") {
|
|
1223
1870
|
throw new CcJsonError(
|
|
1224
1871
|
`el tipo de "${metric}" debe ser "absolute" o "relative"`,
|
|
1225
|
-
`${
|
|
1872
|
+
`${path7}["${metric}"]`
|
|
1226
1873
|
);
|
|
1227
1874
|
}
|
|
1228
1875
|
out[metric] = type;
|
|
1229
1876
|
}
|
|
1230
1877
|
return out;
|
|
1231
1878
|
}
|
|
1232
|
-
function readDescriptors(value,
|
|
1879
|
+
function readDescriptors(value, path7) {
|
|
1233
1880
|
if (value === void 0) return {};
|
|
1234
|
-
const raw = requireRecord(value,
|
|
1881
|
+
const raw = requireRecord(value, path7);
|
|
1235
1882
|
if ("nodes" in raw || "edges" in raw) {
|
|
1236
|
-
const nodes = raw.nodes === void 0 ? void 0 : readDescriptorMap(raw.nodes, `${
|
|
1237
|
-
const edges = raw.edges === void 0 ? void 0 : readDescriptorMap(raw.edges, `${
|
|
1883
|
+
const nodes = raw.nodes === void 0 ? void 0 : readDescriptorMap(raw.nodes, `${path7}.nodes`);
|
|
1884
|
+
const edges = raw.edges === void 0 ? void 0 : readDescriptorMap(raw.edges, `${path7}.edges`);
|
|
1238
1885
|
return {
|
|
1239
1886
|
...nodes && Object.keys(nodes).length > 0 ? { nodes } : {},
|
|
1240
1887
|
...edges && Object.keys(edges).length > 0 ? { edges } : {}
|
|
1241
1888
|
};
|
|
1242
1889
|
}
|
|
1243
|
-
const flat = readDescriptorMap(raw,
|
|
1890
|
+
const flat = readDescriptorMap(raw, path7);
|
|
1244
1891
|
return Object.keys(flat).length > 0 ? { flat } : {};
|
|
1245
1892
|
}
|
|
1246
|
-
function readDescriptorMap(value,
|
|
1247
|
-
const raw = requireRecord(value,
|
|
1893
|
+
function readDescriptorMap(value, path7) {
|
|
1894
|
+
const raw = requireRecord(value, path7);
|
|
1248
1895
|
const out = {};
|
|
1249
1896
|
for (const [metric, descriptor] of Object.entries(raw)) {
|
|
1250
|
-
const record = requireRecord(descriptor, `${
|
|
1897
|
+
const record = requireRecord(descriptor, `${path7}["${metric}"]`);
|
|
1251
1898
|
if (record.direction !== void 0 && typeof record.direction !== "number") {
|
|
1252
1899
|
throw new CcJsonError(
|
|
1253
1900
|
`"direction" de "${metric}" debe ser un n\xFAmero`,
|
|
1254
|
-
`${
|
|
1901
|
+
`${path7}["${metric}"].direction`
|
|
1255
1902
|
);
|
|
1256
1903
|
}
|
|
1257
1904
|
out[metric] = record;
|
|
@@ -1276,26 +1923,26 @@ function parseCcJson2(input) {
|
|
|
1276
1923
|
const roots = Array.isArray(filesRaw) ? filesRaw : [filesRaw];
|
|
1277
1924
|
if (roots.length === 0) throw new CcJsonError("el \xE1rbol est\xE1 vac\xEDo", "$.files");
|
|
1278
1925
|
const ids = /* @__PURE__ */ new Set();
|
|
1279
|
-
const validateNode = (value,
|
|
1280
|
-
if (depth > MAX_DEPTH2) throw new CcJsonError(`profundidad m\xE1xima ${MAX_DEPTH2} superada`,
|
|
1281
|
-
const raw = requireRecord(value,
|
|
1282
|
-
const id = requireString(raw.id, `${
|
|
1283
|
-
if (ids.has(id)) throw new CcJsonError(`id duplicado "${id}"`, `${
|
|
1926
|
+
const validateNode = (value, path7, depth) => {
|
|
1927
|
+
if (depth > MAX_DEPTH2) throw new CcJsonError(`profundidad m\xE1xima ${MAX_DEPTH2} superada`, path7);
|
|
1928
|
+
const raw = requireRecord(value, path7);
|
|
1929
|
+
const id = requireString(raw.id, `${path7}.id`, "id");
|
|
1930
|
+
if (ids.has(id)) throw new CcJsonError(`id duplicado "${id}"`, `${path7}.id`);
|
|
1284
1931
|
ids.add(id);
|
|
1285
|
-
const name = requireString(raw.name, `${
|
|
1932
|
+
const name = requireString(raw.name, `${path7}.name`, "name");
|
|
1286
1933
|
const type = raw.type;
|
|
1287
1934
|
if (type !== "File" && type !== "Folder") {
|
|
1288
|
-
throw new CcJsonError('"type" debe ser "File" o "Folder"', `${
|
|
1935
|
+
throw new CcJsonError('"type" debe ser "File" o "Folder"', `${path7}.type`);
|
|
1289
1936
|
}
|
|
1290
1937
|
const node = { id, name, type };
|
|
1291
1938
|
if (typeof raw.contentHash === "string") node.contentHash = raw.contentHash;
|
|
1292
1939
|
if (typeof raw.link === "string") node.link = raw.link;
|
|
1293
1940
|
if (raw.children !== void 0) {
|
|
1294
1941
|
if (!Array.isArray(raw.children)) {
|
|
1295
|
-
throw new CcJsonError('"children" debe ser un array', `${
|
|
1942
|
+
throw new CcJsonError('"children" debe ser un array', `${path7}.children`);
|
|
1296
1943
|
}
|
|
1297
1944
|
node.children = raw.children.map(
|
|
1298
|
-
(child, index) => validateNode(child, `${
|
|
1945
|
+
(child, index) => validateNode(child, `${path7}.children[${index}]`, depth + 1)
|
|
1299
1946
|
);
|
|
1300
1947
|
}
|
|
1301
1948
|
return node;
|
|
@@ -1326,10 +1973,10 @@ function parseCcJson2(input) {
|
|
|
1326
1973
|
throw new CcJsonError('"edges" debe ser un array', "$.lenses.dependency.edges");
|
|
1327
1974
|
}
|
|
1328
1975
|
dependency.edges.forEach((edge, index) => {
|
|
1329
|
-
const
|
|
1330
|
-
const raw = requireRecord(edge,
|
|
1331
|
-
requireString(raw.fromId, `${
|
|
1332
|
-
requireString(raw.toId, `${
|
|
1976
|
+
const path7 = `$.lenses.dependency.edges[${index}]`;
|
|
1977
|
+
const raw = requireRecord(edge, path7);
|
|
1978
|
+
requireString(raw.fromId, `${path7}.fromId`, "fromId");
|
|
1979
|
+
requireString(raw.toId, `${path7}.toId`, "toId");
|
|
1333
1980
|
});
|
|
1334
1981
|
}
|
|
1335
1982
|
}
|
|
@@ -1418,9 +2065,9 @@ function topByMetric(cc, metric, limit = 10) {
|
|
|
1418
2065
|
const ranked = [];
|
|
1419
2066
|
for (const [id, values] of Object.entries(attributes)) {
|
|
1420
2067
|
const value = values[metric];
|
|
1421
|
-
const
|
|
1422
|
-
if (value === void 0 ||
|
|
1423
|
-
ranked.push({ id, path:
|
|
2068
|
+
const path7 = paths.get(id);
|
|
2069
|
+
if (value === void 0 || path7 === void 0) continue;
|
|
2070
|
+
ranked.push({ id, path: path7, value });
|
|
1424
2071
|
}
|
|
1425
2072
|
ranked.sort((a, b) => b.value - a.value || a.path.localeCompare(b.path));
|
|
1426
2073
|
return ranked.slice(0, limit);
|
|
@@ -1430,155 +2077,6 @@ function defaultMetric(stats) {
|
|
|
1430
2077
|
return stats.metricCoverage[0]?.name;
|
|
1431
2078
|
}
|
|
1432
2079
|
|
|
1433
|
-
// packages/parsers/src/git.ts
|
|
1434
|
-
import { spawnSync } from "node:child_process";
|
|
1435
|
-
import fs2 from "node:fs";
|
|
1436
|
-
import path2 from "node:path";
|
|
1437
|
-
var COMMIT_PREFIX = "__CODARCH_COMMIT__";
|
|
1438
|
-
var DEFAULT_MAX_BUFFER = 128 * 1024 * 1024;
|
|
1439
|
-
var EMPTY = {
|
|
1440
|
-
metrics: /* @__PURE__ */ new Map(),
|
|
1441
|
-
commits: 0,
|
|
1442
|
-
authors: 0,
|
|
1443
|
-
shallow: false,
|
|
1444
|
-
enabled: false,
|
|
1445
|
-
warnings: []
|
|
1446
|
-
};
|
|
1447
|
-
function collectGitChurn(rootInput, files, options = {}) {
|
|
1448
|
-
if (options.enabled === false || files.length === 0) {
|
|
1449
|
-
return { ...EMPTY, metrics: /* @__PURE__ */ new Map() };
|
|
1450
|
-
}
|
|
1451
|
-
const root = realPath(rootInput);
|
|
1452
|
-
const maxBuffer = options.maxBuffer ?? DEFAULT_MAX_BUFFER;
|
|
1453
|
-
const warnings = [];
|
|
1454
|
-
const topLevel = runGit(root, ["rev-parse", "--show-toplevel"], maxBuffer);
|
|
1455
|
-
if (!topLevel.ok) {
|
|
1456
|
-
return {
|
|
1457
|
-
...EMPTY,
|
|
1458
|
-
metrics: /* @__PURE__ */ new Map(),
|
|
1459
|
-
warnings: [`no hay historial git utilizable: ${topLevel.error}`]
|
|
1460
|
-
};
|
|
1461
|
-
}
|
|
1462
|
-
const repoRoot = realPath(topLevel.stdout.trim());
|
|
1463
|
-
const shallowResult = runGit(
|
|
1464
|
-
repoRoot,
|
|
1465
|
-
["rev-parse", "--is-shallow-repository"],
|
|
1466
|
-
maxBuffer
|
|
1467
|
-
);
|
|
1468
|
-
const shallow = shallowResult.ok && shallowResult.stdout.trim().toLowerCase() === "true";
|
|
1469
|
-
if (shallow) {
|
|
1470
|
-
warnings.push(
|
|
1471
|
-
"el repositorio es shallow: el churn puede estar incompleto"
|
|
1472
|
-
);
|
|
1473
|
-
}
|
|
1474
|
-
const log = runGit(
|
|
1475
|
-
repoRoot,
|
|
1476
|
-
[
|
|
1477
|
-
"-c",
|
|
1478
|
-
"core.quotePath=false",
|
|
1479
|
-
"log",
|
|
1480
|
-
"--no-merges",
|
|
1481
|
-
"--numstat",
|
|
1482
|
-
`--format=${COMMIT_PREFIX}%H%x09%ae`
|
|
1483
|
-
],
|
|
1484
|
-
maxBuffer
|
|
1485
|
-
);
|
|
1486
|
-
if (!log.ok) {
|
|
1487
|
-
return {
|
|
1488
|
-
...EMPTY,
|
|
1489
|
-
shallow,
|
|
1490
|
-
warnings: [...warnings, `no se pudo leer git log: ${log.error}`]
|
|
1491
|
-
};
|
|
1492
|
-
}
|
|
1493
|
-
const wanted = new Set(files);
|
|
1494
|
-
const commitsByFile = /* @__PURE__ */ new Map();
|
|
1495
|
-
const authorsByFile = /* @__PURE__ */ new Map();
|
|
1496
|
-
const authors = /* @__PURE__ */ new Set();
|
|
1497
|
-
let commits = 0;
|
|
1498
|
-
let currentAuthor = "";
|
|
1499
|
-
let touched = /* @__PURE__ */ new Set();
|
|
1500
|
-
const flushCommit = () => {
|
|
1501
|
-
if (!currentAuthor || touched.size === 0) return;
|
|
1502
|
-
commits++;
|
|
1503
|
-
authors.add(currentAuthor);
|
|
1504
|
-
for (const file of touched) {
|
|
1505
|
-
commitsByFile.set(file, (commitsByFile.get(file) ?? 0) + 1);
|
|
1506
|
-
let fileAuthors = authorsByFile.get(file);
|
|
1507
|
-
if (!fileAuthors) {
|
|
1508
|
-
fileAuthors = /* @__PURE__ */ new Set();
|
|
1509
|
-
authorsByFile.set(file, fileAuthors);
|
|
1510
|
-
}
|
|
1511
|
-
fileAuthors.add(currentAuthor);
|
|
1512
|
-
}
|
|
1513
|
-
touched = /* @__PURE__ */ new Set();
|
|
1514
|
-
currentAuthor = "";
|
|
1515
|
-
};
|
|
1516
|
-
for (const rawLine of log.stdout.split(/\r?\n/)) {
|
|
1517
|
-
if (rawLine.startsWith(COMMIT_PREFIX)) {
|
|
1518
|
-
flushCommit();
|
|
1519
|
-
const fields2 = rawLine.slice(COMMIT_PREFIX.length).split(" ");
|
|
1520
|
-
const author = fields2[1]?.trim() ?? "";
|
|
1521
|
-
currentAuthor = author || "(sin autor)";
|
|
1522
|
-
continue;
|
|
1523
|
-
}
|
|
1524
|
-
if (!currentAuthor || rawLine === "") continue;
|
|
1525
|
-
const fields = rawLine.split(" ");
|
|
1526
|
-
if (fields.length < 3) continue;
|
|
1527
|
-
const gitPath = fields.slice(2).join(" ");
|
|
1528
|
-
if (!gitPath) continue;
|
|
1529
|
-
const relative = path2.relative(root, path2.resolve(repoRoot, gitPath));
|
|
1530
|
-
if (relative === "" || relative === ".." || relative.startsWith(`..${path2.sep}`) || path2.isAbsolute(relative)) {
|
|
1531
|
-
continue;
|
|
1532
|
-
}
|
|
1533
|
-
const normalized = relative.split(path2.sep).join("/");
|
|
1534
|
-
if (!wanted.has(normalized)) continue;
|
|
1535
|
-
touched.add(normalized);
|
|
1536
|
-
}
|
|
1537
|
-
flushCommit();
|
|
1538
|
-
const metrics = /* @__PURE__ */ new Map();
|
|
1539
|
-
for (const file of files) {
|
|
1540
|
-
metrics.set(file, {
|
|
1541
|
-
commits: commitsByFile.get(file) ?? 0,
|
|
1542
|
-
authors: authorsByFile.get(file)?.size ?? 0
|
|
1543
|
-
});
|
|
1544
|
-
}
|
|
1545
|
-
return {
|
|
1546
|
-
metrics,
|
|
1547
|
-
commits,
|
|
1548
|
-
authors: authors.size,
|
|
1549
|
-
shallow,
|
|
1550
|
-
enabled: true,
|
|
1551
|
-
warnings
|
|
1552
|
-
};
|
|
1553
|
-
}
|
|
1554
|
-
function realPath(input) {
|
|
1555
|
-
const resolved = path2.resolve(input);
|
|
1556
|
-
try {
|
|
1557
|
-
return fs2.realpathSync.native(resolved);
|
|
1558
|
-
} catch {
|
|
1559
|
-
return resolved;
|
|
1560
|
-
}
|
|
1561
|
-
}
|
|
1562
|
-
function runGit(cwd, args, maxBuffer) {
|
|
1563
|
-
const result = spawnSync("git", args, {
|
|
1564
|
-
cwd,
|
|
1565
|
-
encoding: "utf8",
|
|
1566
|
-
maxBuffer,
|
|
1567
|
-
windowsHide: true
|
|
1568
|
-
});
|
|
1569
|
-
if (result.error) {
|
|
1570
|
-
return { ok: false, stdout: "", error: result.error.message };
|
|
1571
|
-
}
|
|
1572
|
-
if (result.status !== 0) {
|
|
1573
|
-
return {
|
|
1574
|
-
ok: false,
|
|
1575
|
-
stdout: result.stdout ?? "",
|
|
1576
|
-
error: (result.stderr ?? "").trim() || `git exited with ${result.status}`
|
|
1577
|
-
};
|
|
1578
|
-
}
|
|
1579
|
-
return { ok: true, stdout: result.stdout ?? "", error: "" };
|
|
1580
|
-
}
|
|
1581
|
-
|
|
1582
2080
|
// packages/parsers/src/migration.ts
|
|
1583
2081
|
var EXTENSION_LANGUAGE = {
|
|
1584
2082
|
".ts": "ts",
|
|
@@ -1722,9 +2220,9 @@ function jsIsBridge(source, specifiers) {
|
|
|
1722
2220
|
return specifiers.some((specifier) => ffiKindForSpecifier(specifier) !== null) || JS_FFI.test(source);
|
|
1723
2221
|
}
|
|
1724
2222
|
function ffiKindForSpecifier(specifier) {
|
|
1725
|
-
const
|
|
1726
|
-
if (
|
|
1727
|
-
if (
|
|
2223
|
+
const clean2 = specifier.split(/[?#]/, 1)[0]?.toLowerCase() ?? "";
|
|
2224
|
+
if (clean2.endsWith(".wasm")) return "wasm";
|
|
2225
|
+
if (clean2.endsWith(".node")) return "native";
|
|
1728
2226
|
return null;
|
|
1729
2227
|
}
|
|
1730
2228
|
function buildMigration(files, links) {
|
|
@@ -1814,7 +2312,6 @@ function compareStrings2(left, right) {
|
|
|
1814
2312
|
}
|
|
1815
2313
|
|
|
1816
2314
|
// packages/parsers/src/snapshot.ts
|
|
1817
|
-
import { createHash as createHash2 } from "node:crypto";
|
|
1818
2315
|
var METRIC_DESCRIPTORS = {
|
|
1819
2316
|
loc: {
|
|
1820
2317
|
title: "L\xEDneas",
|
|
@@ -1989,8 +2486,8 @@ function buildSnapshot(input) {
|
|
|
1989
2486
|
isCyclic: edge.isCyclic
|
|
1990
2487
|
}));
|
|
1991
2488
|
const dependencyNodes = {};
|
|
1992
|
-
for (const [
|
|
1993
|
-
dependencyNodes[fileId(
|
|
2489
|
+
for (const [path7, metrics] of input.graph.metrics) {
|
|
2490
|
+
dependencyNodes[fileId(path7)] = { level: metrics.dependencyLevel };
|
|
1994
2491
|
}
|
|
1995
2492
|
const migrationLens = input.migration ? migrationLensFrom(input.migration) : void 0;
|
|
1996
2493
|
const lenses = {
|
|
@@ -2039,7 +2536,7 @@ function migrationLensFrom(migration) {
|
|
|
2039
2536
|
};
|
|
2040
2537
|
}
|
|
2041
2538
|
function checksumFor(files, lenses) {
|
|
2042
|
-
return
|
|
2539
|
+
return md5Hex(stableStringify({ files, lenses }));
|
|
2043
2540
|
}
|
|
2044
2541
|
function stableStringify(value) {
|
|
2045
2542
|
if (value === null || value === void 0) return "null";
|
|
@@ -2076,9 +2573,9 @@ function compareStrings3(left, right) {
|
|
|
2076
2573
|
}
|
|
2077
2574
|
|
|
2078
2575
|
// packages/parsers/src/walk.ts
|
|
2079
|
-
import fs3 from "node:fs";
|
|
2080
|
-
import path3 from "node:path";
|
|
2081
2576
|
import ignore from "ignore";
|
|
2577
|
+
|
|
2578
|
+
// packages/parsers/src/extensions.ts
|
|
2082
2579
|
var DEFAULT_EXTENSIONS = [
|
|
2083
2580
|
".ts",
|
|
2084
2581
|
".tsx",
|
|
@@ -2089,29 +2586,26 @@ var DEFAULT_EXTENSIONS = [
|
|
|
2089
2586
|
".mjs",
|
|
2090
2587
|
".cjs"
|
|
2091
2588
|
];
|
|
2589
|
+
|
|
2590
|
+
// packages/parsers/src/walk.ts
|
|
2092
2591
|
var ALWAYS_IGNORED = [".git", "node_modules", ".codarch"];
|
|
2093
|
-
function walkSourceFiles(
|
|
2094
|
-
const root = path3.resolve(rootInput);
|
|
2095
|
-
const stat = fs3.statSync(root);
|
|
2096
|
-
if (!stat.isDirectory()) {
|
|
2097
|
-
throw new Error(`no es un directorio: ${rootInput}`);
|
|
2098
|
-
}
|
|
2592
|
+
function walkSourceFiles(fileSystem, options = {}) {
|
|
2099
2593
|
const extensions = options.extensions ?? DEFAULT_EXTENSIONS;
|
|
2100
2594
|
const warnings = [];
|
|
2101
2595
|
const files = [];
|
|
2102
2596
|
const rootMatcher = ignore().add(ALWAYS_IGNORED);
|
|
2103
2597
|
for (const pattern of options.ignore ?? []) rootMatcher.add(pattern);
|
|
2104
|
-
const rootGitignore = readGitignore(
|
|
2598
|
+
const rootGitignore = readGitignore(fileSystem, "/", "", warnings);
|
|
2105
2599
|
if (rootGitignore) rootMatcher.add(rootGitignore);
|
|
2106
2600
|
const initialLayers = [{ base: "", matcher: rootMatcher }];
|
|
2107
2601
|
const stack = [
|
|
2108
|
-
{ absolutePath:
|
|
2602
|
+
{ absolutePath: "/", relativePath: "", layers: initialLayers }
|
|
2109
2603
|
];
|
|
2110
2604
|
while (stack.length > 0) {
|
|
2111
2605
|
const directory = stack.pop();
|
|
2112
2606
|
let entries;
|
|
2113
2607
|
try {
|
|
2114
|
-
entries =
|
|
2608
|
+
entries = fileSystem.readDirectory(directory.absolutePath);
|
|
2115
2609
|
} catch (error) {
|
|
2116
2610
|
warnings.push(
|
|
2117
2611
|
`no se pudo leer ${directory.relativePath || "."}: ${error.message}`
|
|
@@ -2122,15 +2616,14 @@ function walkSourceFiles(rootInput, options = {}) {
|
|
|
2122
2616
|
(left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0
|
|
2123
2617
|
);
|
|
2124
2618
|
for (const entry of entries) {
|
|
2125
|
-
if (entry.isSymbolicLink()) continue;
|
|
2126
2619
|
const relativePath2 = directory.relativePath ? `${directory.relativePath}/${entry.name}` : entry.name;
|
|
2127
|
-
const absolutePath =
|
|
2128
|
-
if (entry.isDirectory
|
|
2620
|
+
const absolutePath = directory.absolutePath === "/" ? `/${entry.name}` : `${directory.absolutePath}/${entry.name}`;
|
|
2621
|
+
if (entry.isDirectory) {
|
|
2129
2622
|
if (isIgnored(directory.layers, relativePath2, true)) continue;
|
|
2130
|
-
const nested = readGitignore(absolutePath, relativePath2, warnings);
|
|
2623
|
+
const nested = readGitignore(fileSystem, absolutePath, relativePath2, warnings);
|
|
2131
2624
|
const layers = nested ? [...directory.layers, { base: relativePath2, matcher: ignore().add(nested) }] : directory.layers;
|
|
2132
2625
|
stack.push({ absolutePath, relativePath: relativePath2, layers });
|
|
2133
|
-
} else if (entry.isFile
|
|
2626
|
+
} else if (entry.isFile) {
|
|
2134
2627
|
if (isIgnored(directory.layers, relativePath2, false)) continue;
|
|
2135
2628
|
if (!matchesExtension(entry.name, extensions)) continue;
|
|
2136
2629
|
files.push({ absolutePath, relativePath: relativePath2 });
|
|
@@ -2143,16 +2636,14 @@ function walkSourceFiles(rootInput, options = {}) {
|
|
|
2143
2636
|
warnings.sort();
|
|
2144
2637
|
return { files, warnings };
|
|
2145
2638
|
}
|
|
2146
|
-
function readGitignore(
|
|
2147
|
-
const file =
|
|
2639
|
+
function readGitignore(fileSystem, absoluteDirectory, relativeBase, warnings) {
|
|
2640
|
+
const file = absoluteDirectory === "/" ? "/.gitignore" : `${absoluteDirectory}/.gitignore`;
|
|
2148
2641
|
try {
|
|
2149
|
-
return
|
|
2642
|
+
return fileSystem.tryReadFile(file);
|
|
2150
2643
|
} catch (error) {
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
);
|
|
2155
|
-
}
|
|
2644
|
+
warnings.push(
|
|
2645
|
+
`no se pudo leer ${relativeBase ? `${relativeBase}/` : ""}.gitignore: ${error.message}`
|
|
2646
|
+
);
|
|
2156
2647
|
return null;
|
|
2157
2648
|
}
|
|
2158
2649
|
}
|
|
@@ -2173,19 +2664,20 @@ function matchesExtension(name, extensions) {
|
|
|
2173
2664
|
return extensions.some((extension) => lower.endsWith(extension));
|
|
2174
2665
|
}
|
|
2175
2666
|
|
|
2176
|
-
// packages/parsers/src/analyze.ts
|
|
2177
|
-
function
|
|
2667
|
+
// packages/parsers/src/analyze-core.ts
|
|
2668
|
+
function analyzeFiles(options) {
|
|
2178
2669
|
const started = Date.now();
|
|
2179
|
-
const
|
|
2180
|
-
const
|
|
2181
|
-
const
|
|
2670
|
+
const fileSystem = options.fileSystem;
|
|
2671
|
+
const root = options.root ?? "/";
|
|
2672
|
+
const projectName = options.projectName ?? readProjectName(fileSystem, root, options.fallbackName);
|
|
2673
|
+
const walked = walkSourceFiles(fileSystem, {
|
|
2182
2674
|
ignore: options.ignore,
|
|
2183
2675
|
extensions: options.extensions ?? MIGRATION_EXTENSIONS
|
|
2184
2676
|
});
|
|
2185
2677
|
const warnings = [...walked.warnings];
|
|
2186
|
-
const resolver = new ImportResolver(root, walked.files);
|
|
2678
|
+
const resolver = new ImportResolver(root, walked.files, fileSystem);
|
|
2187
2679
|
warnings.push(...resolver.warnings);
|
|
2188
|
-
const parser =
|
|
2680
|
+
const parser = options.parser;
|
|
2189
2681
|
const parsedFiles = [];
|
|
2190
2682
|
const migrationFiles = [];
|
|
2191
2683
|
const migrationLinks = [];
|
|
@@ -2215,7 +2707,7 @@ function analyzeRepository(rootInput, options = {}) {
|
|
|
2215
2707
|
}
|
|
2216
2708
|
let source;
|
|
2217
2709
|
try {
|
|
2218
|
-
source =
|
|
2710
|
+
source = fileSystem.readFile(file.absolutePath);
|
|
2219
2711
|
} catch (error) {
|
|
2220
2712
|
warnings.push(
|
|
2221
2713
|
`no se pudo leer ${file.relativePath}: ${error.message}`
|
|
@@ -2311,18 +2803,15 @@ function analyzeRepository(rootInput, options = {}) {
|
|
|
2311
2803
|
)
|
|
2312
2804
|
});
|
|
2313
2805
|
}
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
parsedFiles.map((file) => file.relativePath)
|
|
2317
|
-
|
|
2318
|
-
);
|
|
2319
|
-
warnings.push(...git.warnings);
|
|
2320
|
-
if (git.enabled) {
|
|
2806
|
+
let churnResult = null;
|
|
2807
|
+
if (options.churn) {
|
|
2808
|
+
churnResult = options.churn(parsedFiles.map((file) => file.relativePath));
|
|
2809
|
+
warnings.push(...churnResult.warnings);
|
|
2321
2810
|
for (const file of parsedFiles) {
|
|
2322
|
-
const
|
|
2323
|
-
if (!
|
|
2324
|
-
file.metrics.number_of_commits =
|
|
2325
|
-
file.metrics.number_of_authors =
|
|
2811
|
+
const metrics = churnResult.metrics.get(file.relativePath);
|
|
2812
|
+
if (!metrics) continue;
|
|
2813
|
+
file.metrics.number_of_commits = metrics.commits;
|
|
2814
|
+
file.metrics.number_of_authors = metrics.authors;
|
|
2326
2815
|
}
|
|
2327
2816
|
}
|
|
2328
2817
|
const graph = buildGraph(
|
|
@@ -2382,19 +2871,14 @@ function analyzeRepository(rootInput, options = {}) {
|
|
|
2382
2871
|
builtinImports,
|
|
2383
2872
|
typeOnlyImports,
|
|
2384
2873
|
unresolvedImports: unresolved.length,
|
|
2385
|
-
git: {
|
|
2386
|
-
enabled: git.enabled,
|
|
2387
|
-
commits: git.commits,
|
|
2388
|
-
authors: git.authors,
|
|
2389
|
-
shallow: git.shallow
|
|
2390
|
-
},
|
|
2391
2874
|
migration: migration.summary,
|
|
2875
|
+
churn: churnResult,
|
|
2392
2876
|
durationMs: Date.now() - started
|
|
2393
2877
|
};
|
|
2394
2878
|
}
|
|
2395
|
-
function readProjectName(root) {
|
|
2879
|
+
function readProjectName(fileSystem, root, fallbackName) {
|
|
2396
2880
|
try {
|
|
2397
|
-
const text =
|
|
2881
|
+
const text = fileSystem.readFile(join(root, "package.json"));
|
|
2398
2882
|
const parsed = JSON.parse(text.replace(/^\uFEFF/, ""));
|
|
2399
2883
|
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) && typeof parsed.name === "string") {
|
|
2400
2884
|
const name = parsed.name.trim();
|
|
@@ -2402,7 +2886,232 @@ function readProjectName(root) {
|
|
|
2402
2886
|
}
|
|
2403
2887
|
} catch {
|
|
2404
2888
|
}
|
|
2405
|
-
return
|
|
2889
|
+
return fallbackName ?? basename(root) ?? "Proyecto";
|
|
2890
|
+
}
|
|
2891
|
+
|
|
2892
|
+
// packages/parsers/src/git.ts
|
|
2893
|
+
import { spawnSync } from "node:child_process";
|
|
2894
|
+
import fs from "node:fs";
|
|
2895
|
+
import path from "node:path";
|
|
2896
|
+
var COMMIT_PREFIX = "__CODARCH_COMMIT__";
|
|
2897
|
+
var DEFAULT_MAX_BUFFER = 128 * 1024 * 1024;
|
|
2898
|
+
var EMPTY = {
|
|
2899
|
+
metrics: /* @__PURE__ */ new Map(),
|
|
2900
|
+
commits: 0,
|
|
2901
|
+
authors: 0,
|
|
2902
|
+
shallow: false,
|
|
2903
|
+
enabled: false,
|
|
2904
|
+
warnings: []
|
|
2905
|
+
};
|
|
2906
|
+
function collectGitChurn(rootInput, files, options = {}) {
|
|
2907
|
+
if (options.enabled === false || files.length === 0) {
|
|
2908
|
+
return { ...EMPTY, metrics: /* @__PURE__ */ new Map() };
|
|
2909
|
+
}
|
|
2910
|
+
const root = realPath(rootInput);
|
|
2911
|
+
const maxBuffer = options.maxBuffer ?? DEFAULT_MAX_BUFFER;
|
|
2912
|
+
const warnings = [];
|
|
2913
|
+
const topLevel = runGit(root, ["rev-parse", "--show-toplevel"], maxBuffer);
|
|
2914
|
+
if (!topLevel.ok) {
|
|
2915
|
+
return {
|
|
2916
|
+
...EMPTY,
|
|
2917
|
+
metrics: /* @__PURE__ */ new Map(),
|
|
2918
|
+
warnings: [`no hay historial git utilizable: ${topLevel.error}`]
|
|
2919
|
+
};
|
|
2920
|
+
}
|
|
2921
|
+
const repoRoot = realPath(topLevel.stdout.trim());
|
|
2922
|
+
const shallowResult = runGit(
|
|
2923
|
+
repoRoot,
|
|
2924
|
+
["rev-parse", "--is-shallow-repository"],
|
|
2925
|
+
maxBuffer
|
|
2926
|
+
);
|
|
2927
|
+
const shallow = shallowResult.ok && shallowResult.stdout.trim().toLowerCase() === "true";
|
|
2928
|
+
if (shallow) {
|
|
2929
|
+
warnings.push(
|
|
2930
|
+
"el repositorio es shallow: el churn puede estar incompleto"
|
|
2931
|
+
);
|
|
2932
|
+
}
|
|
2933
|
+
const log = runGit(
|
|
2934
|
+
repoRoot,
|
|
2935
|
+
[
|
|
2936
|
+
"-c",
|
|
2937
|
+
"core.quotePath=false",
|
|
2938
|
+
"log",
|
|
2939
|
+
"--no-merges",
|
|
2940
|
+
"--numstat",
|
|
2941
|
+
`--format=${COMMIT_PREFIX}%H%x09%ae`
|
|
2942
|
+
],
|
|
2943
|
+
maxBuffer
|
|
2944
|
+
);
|
|
2945
|
+
if (!log.ok) {
|
|
2946
|
+
return {
|
|
2947
|
+
...EMPTY,
|
|
2948
|
+
shallow,
|
|
2949
|
+
warnings: [...warnings, `no se pudo leer git log: ${log.error}`]
|
|
2950
|
+
};
|
|
2951
|
+
}
|
|
2952
|
+
const wanted = new Set(files);
|
|
2953
|
+
const commitsByFile = /* @__PURE__ */ new Map();
|
|
2954
|
+
const authorsByFile = /* @__PURE__ */ new Map();
|
|
2955
|
+
const authors = /* @__PURE__ */ new Set();
|
|
2956
|
+
let commits = 0;
|
|
2957
|
+
let currentAuthor = "";
|
|
2958
|
+
let touched = /* @__PURE__ */ new Set();
|
|
2959
|
+
const flushCommit = () => {
|
|
2960
|
+
if (!currentAuthor || touched.size === 0) return;
|
|
2961
|
+
commits++;
|
|
2962
|
+
authors.add(currentAuthor);
|
|
2963
|
+
for (const file of touched) {
|
|
2964
|
+
commitsByFile.set(file, (commitsByFile.get(file) ?? 0) + 1);
|
|
2965
|
+
let fileAuthors = authorsByFile.get(file);
|
|
2966
|
+
if (!fileAuthors) {
|
|
2967
|
+
fileAuthors = /* @__PURE__ */ new Set();
|
|
2968
|
+
authorsByFile.set(file, fileAuthors);
|
|
2969
|
+
}
|
|
2970
|
+
fileAuthors.add(currentAuthor);
|
|
2971
|
+
}
|
|
2972
|
+
touched = /* @__PURE__ */ new Set();
|
|
2973
|
+
currentAuthor = "";
|
|
2974
|
+
};
|
|
2975
|
+
for (const rawLine of log.stdout.split(/\r?\n/)) {
|
|
2976
|
+
if (rawLine.startsWith(COMMIT_PREFIX)) {
|
|
2977
|
+
flushCommit();
|
|
2978
|
+
const fields2 = rawLine.slice(COMMIT_PREFIX.length).split(" ");
|
|
2979
|
+
const author = fields2[1]?.trim() ?? "";
|
|
2980
|
+
currentAuthor = author || "(sin autor)";
|
|
2981
|
+
continue;
|
|
2982
|
+
}
|
|
2983
|
+
if (!currentAuthor || rawLine === "") continue;
|
|
2984
|
+
const fields = rawLine.split(" ");
|
|
2985
|
+
if (fields.length < 3) continue;
|
|
2986
|
+
const gitPath = fields.slice(2).join(" ");
|
|
2987
|
+
if (!gitPath) continue;
|
|
2988
|
+
const relative2 = path.relative(root, path.resolve(repoRoot, gitPath));
|
|
2989
|
+
if (relative2 === "" || relative2 === ".." || relative2.startsWith(`..${path.sep}`) || path.isAbsolute(relative2)) {
|
|
2990
|
+
continue;
|
|
2991
|
+
}
|
|
2992
|
+
const normalized = relative2.split(path.sep).join("/");
|
|
2993
|
+
if (!wanted.has(normalized)) continue;
|
|
2994
|
+
touched.add(normalized);
|
|
2995
|
+
}
|
|
2996
|
+
flushCommit();
|
|
2997
|
+
const metrics = /* @__PURE__ */ new Map();
|
|
2998
|
+
for (const file of files) {
|
|
2999
|
+
metrics.set(file, {
|
|
3000
|
+
commits: commitsByFile.get(file) ?? 0,
|
|
3001
|
+
authors: authorsByFile.get(file)?.size ?? 0
|
|
3002
|
+
});
|
|
3003
|
+
}
|
|
3004
|
+
return {
|
|
3005
|
+
metrics,
|
|
3006
|
+
commits,
|
|
3007
|
+
authors: authors.size,
|
|
3008
|
+
shallow,
|
|
3009
|
+
enabled: true,
|
|
3010
|
+
warnings
|
|
3011
|
+
};
|
|
3012
|
+
}
|
|
3013
|
+
function realPath(input) {
|
|
3014
|
+
const resolved = path.resolve(input);
|
|
3015
|
+
try {
|
|
3016
|
+
return fs.realpathSync.native(resolved);
|
|
3017
|
+
} catch {
|
|
3018
|
+
return resolved;
|
|
3019
|
+
}
|
|
3020
|
+
}
|
|
3021
|
+
function runGit(cwd, args, maxBuffer) {
|
|
3022
|
+
const result = spawnSync("git", args, {
|
|
3023
|
+
cwd,
|
|
3024
|
+
encoding: "utf8",
|
|
3025
|
+
maxBuffer,
|
|
3026
|
+
windowsHide: true
|
|
3027
|
+
});
|
|
3028
|
+
if (result.error) {
|
|
3029
|
+
return { ok: false, stdout: "", error: result.error.message };
|
|
3030
|
+
}
|
|
3031
|
+
if (result.status !== 0) {
|
|
3032
|
+
return {
|
|
3033
|
+
ok: false,
|
|
3034
|
+
stdout: result.stdout ?? "",
|
|
3035
|
+
error: (result.stderr ?? "").trim() || `git exited with ${result.status}`
|
|
3036
|
+
};
|
|
3037
|
+
}
|
|
3038
|
+
return { ok: true, stdout: result.stdout ?? "", error: "" };
|
|
3039
|
+
}
|
|
3040
|
+
|
|
3041
|
+
// packages/parsers/src/node-fs.ts
|
|
3042
|
+
import fs2 from "node:fs";
|
|
3043
|
+
import path2 from "node:path";
|
|
3044
|
+
var NodeFileSystem = class {
|
|
3045
|
+
caseSensitive = process.platform !== "win32";
|
|
3046
|
+
root;
|
|
3047
|
+
constructor(root) {
|
|
3048
|
+
this.root = path2.resolve(root);
|
|
3049
|
+
}
|
|
3050
|
+
readFile(target) {
|
|
3051
|
+
return fs2.readFileSync(this.native(target), "utf8");
|
|
3052
|
+
}
|
|
3053
|
+
tryReadFile(target) {
|
|
3054
|
+
try {
|
|
3055
|
+
return fs2.readFileSync(this.native(target), "utf8");
|
|
3056
|
+
} catch (error) {
|
|
3057
|
+
if (error.code !== "ENOENT") {
|
|
3058
|
+
throw error;
|
|
3059
|
+
}
|
|
3060
|
+
return null;
|
|
3061
|
+
}
|
|
3062
|
+
}
|
|
3063
|
+
readDirectory(target) {
|
|
3064
|
+
const entries = fs2.readdirSync(this.native(target), { withFileTypes: true });
|
|
3065
|
+
return entries.map((entry) => ({
|
|
3066
|
+
name: entry.name,
|
|
3067
|
+
isDirectory: entry.isDirectory(),
|
|
3068
|
+
isFile: entry.isFile()
|
|
3069
|
+
}));
|
|
3070
|
+
}
|
|
3071
|
+
exists(target) {
|
|
3072
|
+
return fs2.existsSync(this.native(target));
|
|
3073
|
+
}
|
|
3074
|
+
/** Ruta real en disco de una ruta virtual. */
|
|
3075
|
+
native(target) {
|
|
3076
|
+
const relative2 = target.replace(/^\/+/, "");
|
|
3077
|
+
return relative2 === "" ? this.root : path2.join(this.root, relative2);
|
|
3078
|
+
}
|
|
3079
|
+
};
|
|
3080
|
+
|
|
3081
|
+
// packages/parsers/src/analyze.ts
|
|
3082
|
+
function analyzeRepository(rootInput, options = {}) {
|
|
3083
|
+
const fileSystem = options.fileSystem ?? new NodeFileSystem(rootInput);
|
|
3084
|
+
const useGit = options.git !== false;
|
|
3085
|
+
const result = analyzeFiles({
|
|
3086
|
+
fileSystem,
|
|
3087
|
+
root: options.root ?? "/",
|
|
3088
|
+
projectName: options.projectName,
|
|
3089
|
+
fallbackName: basename2(rootInput),
|
|
3090
|
+
ignore: options.ignore,
|
|
3091
|
+
extensions: options.extensions,
|
|
3092
|
+
parser: new TypeScriptParser(),
|
|
3093
|
+
churn: (relativePaths) => {
|
|
3094
|
+
const git = collectGitChurn(rootInput, relativePaths, { enabled: useGit });
|
|
3095
|
+
return {
|
|
3096
|
+
metrics: git.metrics,
|
|
3097
|
+
warnings: git.warnings,
|
|
3098
|
+
enabled: git.enabled,
|
|
3099
|
+
commits: git.commits,
|
|
3100
|
+
authors: git.authors,
|
|
3101
|
+
shallow: git.shallow
|
|
3102
|
+
};
|
|
3103
|
+
}
|
|
3104
|
+
});
|
|
3105
|
+
const churn = result.churn;
|
|
3106
|
+
return {
|
|
3107
|
+
...result,
|
|
3108
|
+
git: {
|
|
3109
|
+
enabled: churn?.enabled ?? false,
|
|
3110
|
+
commits: churn?.commits ?? 0,
|
|
3111
|
+
authors: churn?.authors ?? 0,
|
|
3112
|
+
shallow: churn?.shallow ?? false
|
|
3113
|
+
}
|
|
3114
|
+
};
|
|
2406
3115
|
}
|
|
2407
3116
|
|
|
2408
3117
|
// packages/metrics/src/risk.ts
|
|
@@ -2541,8 +3250,8 @@ function hashString(value) {
|
|
|
2541
3250
|
}
|
|
2542
3251
|
return hash >>> 0;
|
|
2543
3252
|
}
|
|
2544
|
-
function sectionForPath(
|
|
2545
|
-
const folders =
|
|
3253
|
+
function sectionForPath(path7) {
|
|
3254
|
+
const folders = path7.split("/").filter(Boolean).slice(0, -1);
|
|
2546
3255
|
if (folders.length === 0) return "(ra\xEDz)";
|
|
2547
3256
|
if (folders.length === 1) return folders[0];
|
|
2548
3257
|
return folders.slice(0, 3).join("/");
|
|
@@ -2612,7 +3321,7 @@ function buildRenderModel(cc, options = {}) {
|
|
|
2612
3321
|
const fileIndexById = /* @__PURE__ */ new Map();
|
|
2613
3322
|
walkFiles(cc.files, (entry) => {
|
|
2614
3323
|
const fullPath = entry.path;
|
|
2615
|
-
const
|
|
3324
|
+
const path7 = prefix && fullPath.startsWith(prefix) ? fullPath.slice(prefix.length) : fullPath;
|
|
2616
3325
|
const values = attributes[entry.node.id];
|
|
2617
3326
|
const rawArea = valueOf(values, areaMetric);
|
|
2618
3327
|
const index = files.length;
|
|
@@ -2620,7 +3329,7 @@ function buildRenderModel(cc, options = {}) {
|
|
|
2620
3329
|
files.push({
|
|
2621
3330
|
index,
|
|
2622
3331
|
nodeId: entry.node.id,
|
|
2623
|
-
path:
|
|
3332
|
+
path: path7,
|
|
2624
3333
|
name: entry.node.name,
|
|
2625
3334
|
section: -1,
|
|
2626
3335
|
area: Math.max(1, rawArea ?? 0),
|
|
@@ -2783,7 +3492,7 @@ function buildRenderModel(cc, options = {}) {
|
|
|
2783
3492
|
};
|
|
2784
3493
|
}
|
|
2785
3494
|
function buildRoots(cc, singleRoot, fileIndexById, files) {
|
|
2786
|
-
const build = (node,
|
|
3495
|
+
const build = (node, path7) => {
|
|
2787
3496
|
if (node.type === "File") {
|
|
2788
3497
|
const index = fileIndexById.get(node.id);
|
|
2789
3498
|
const file = index === void 0 ? void 0 : files[index];
|
|
@@ -2791,7 +3500,7 @@ function buildRoots(cc, singleRoot, fileIndexById, files) {
|
|
|
2791
3500
|
kind: "file",
|
|
2792
3501
|
key: `f:${index ?? -1}`,
|
|
2793
3502
|
name: node.name,
|
|
2794
|
-
path:
|
|
3503
|
+
path: path7,
|
|
2795
3504
|
value: file?.area ?? 1,
|
|
2796
3505
|
fileCount: 1,
|
|
2797
3506
|
section: file?.section ?? 0,
|
|
@@ -2799,13 +3508,13 @@ function buildRoots(cc, singleRoot, fileIndexById, files) {
|
|
|
2799
3508
|
};
|
|
2800
3509
|
}
|
|
2801
3510
|
const children = (node.children ?? []).map(
|
|
2802
|
-
(child) => build(child,
|
|
3511
|
+
(child) => build(child, path7 ? `${path7}/${child.name}` : child.name)
|
|
2803
3512
|
);
|
|
2804
3513
|
const folder = {
|
|
2805
3514
|
kind: "folder",
|
|
2806
|
-
key: `d:${
|
|
3515
|
+
key: `d:${path7}`,
|
|
2807
3516
|
name: node.name,
|
|
2808
|
-
path:
|
|
3517
|
+
path: path7,
|
|
2809
3518
|
value: children.reduce((sum, child) => sum + child.value, 0) || 1,
|
|
2810
3519
|
fileCount: children.reduce((sum, child) => sum + child.fileCount, 0),
|
|
2811
3520
|
section: -1,
|
|
@@ -3449,10 +4158,10 @@ function renderHtml(model) {
|
|
|
3449
4158
|
}
|
|
3450
4159
|
|
|
3451
4160
|
// apps/cli/src/io.ts
|
|
3452
|
-
import
|
|
4161
|
+
import fs3 from "node:fs";
|
|
3453
4162
|
import zlib from "node:zlib";
|
|
3454
4163
|
function readJsonFile2(file) {
|
|
3455
|
-
const buffer =
|
|
4164
|
+
const buffer = fs3.readFileSync(file);
|
|
3456
4165
|
const isGzip = buffer.length > 2 && buffer[0] === 31 && buffer[1] === 139;
|
|
3457
4166
|
const raw = isGzip ? zlib.gunzipSync(buffer) : buffer;
|
|
3458
4167
|
const text = raw.toString("utf8");
|
|
@@ -3500,14 +4209,14 @@ function runAnalyze(options) {
|
|
|
3500
4209
|
}
|
|
3501
4210
|
throw error;
|
|
3502
4211
|
}
|
|
3503
|
-
const outDirectory =
|
|
3504
|
-
options.out ??
|
|
4212
|
+
const outDirectory = path3.resolve(
|
|
4213
|
+
options.out ?? path3.join(path3.resolve(root), ".codarch")
|
|
3505
4214
|
);
|
|
3506
|
-
const snapshotPath =
|
|
3507
|
-
const mapPath =
|
|
4215
|
+
const snapshotPath = path3.join(outDirectory, "snapshot.cc.json");
|
|
4216
|
+
const mapPath = path3.join(outDirectory, "map.html");
|
|
3508
4217
|
try {
|
|
3509
|
-
|
|
3510
|
-
|
|
4218
|
+
fs4.mkdirSync(outDirectory, { recursive: true });
|
|
4219
|
+
fs4.writeFileSync(
|
|
3511
4220
|
snapshotPath,
|
|
3512
4221
|
`${JSON.stringify(cc, null, 2)}
|
|
3513
4222
|
`,
|
|
@@ -3529,7 +4238,7 @@ function runAnalyze(options) {
|
|
|
3529
4238
|
title: options.title
|
|
3530
4239
|
});
|
|
3531
4240
|
const html = renderHtml(model);
|
|
3532
|
-
|
|
4241
|
+
fs4.writeFileSync(mapPath, html, "utf8");
|
|
3533
4242
|
mapBytes = Buffer.byteLength(html, "utf8");
|
|
3534
4243
|
} catch (error) {
|
|
3535
4244
|
mapError = error instanceof RenderError ? error.message : error.message;
|
|
@@ -3538,14 +4247,14 @@ function runAnalyze(options) {
|
|
|
3538
4247
|
mapError = "no hay ficheros TypeScript/JavaScript que dibujar";
|
|
3539
4248
|
}
|
|
3540
4249
|
const snapshotBytes = Buffer.byteLength(
|
|
3541
|
-
|
|
4250
|
+
fs4.readFileSync(snapshotPath),
|
|
3542
4251
|
"utf8"
|
|
3543
4252
|
);
|
|
3544
4253
|
const lines = [];
|
|
3545
4254
|
lines.push("");
|
|
3546
4255
|
lines.push(" CodArch \xB7 an\xE1lisis");
|
|
3547
4256
|
lines.push("");
|
|
3548
|
-
lines.push(field("ra\xEDz",
|
|
4257
|
+
lines.push(field("ra\xEDz", path3.resolve(root)));
|
|
3549
4258
|
lines.push(field("snapshot", `${snapshotPath} (${formatBytes(snapshotBytes)})`));
|
|
3550
4259
|
if (mapError) {
|
|
3551
4260
|
lines.push(field("mapa", `omitido (${mapError})`));
|
|
@@ -3615,11 +4324,11 @@ function runAnalyze(options) {
|
|
|
3615
4324
|
}
|
|
3616
4325
|
|
|
3617
4326
|
// apps/cli/src/commands/diff.ts
|
|
3618
|
-
import
|
|
3619
|
-
import
|
|
4327
|
+
import fs6 from "node:fs";
|
|
4328
|
+
import path4 from "node:path";
|
|
3620
4329
|
|
|
3621
4330
|
// packages/metrics/src/config.ts
|
|
3622
|
-
import
|
|
4331
|
+
import fs5 from "node:fs";
|
|
3623
4332
|
import { parse as parseYaml } from "yaml";
|
|
3624
4333
|
var ConfigError = class extends Error {
|
|
3625
4334
|
constructor(message) {
|
|
@@ -3641,7 +4350,7 @@ function parseRuleConfig(input) {
|
|
|
3641
4350
|
function loadRuleConfig(file) {
|
|
3642
4351
|
let text;
|
|
3643
4352
|
try {
|
|
3644
|
-
text =
|
|
4353
|
+
text = fs5.readFileSync(file, "utf8");
|
|
3645
4354
|
} catch (error) {
|
|
3646
4355
|
throw new ConfigError(
|
|
3647
4356
|
`no se pudo leer ${file}: ${error.message}`
|
|
@@ -3771,29 +4480,29 @@ function parseRules(value, layerNames) {
|
|
|
3771
4480
|
});
|
|
3772
4481
|
return rules;
|
|
3773
4482
|
}
|
|
3774
|
-
function parseSeverity(value,
|
|
4483
|
+
function parseSeverity(value, path7) {
|
|
3775
4484
|
if (value === void 0) return "error";
|
|
3776
4485
|
if (typeof value !== "string" || !SEVERITIES.has(value)) {
|
|
3777
|
-
throw new ConfigError(`${
|
|
4486
|
+
throw new ConfigError(`${path7} debe ser info, warn o error`);
|
|
3778
4487
|
}
|
|
3779
4488
|
return value;
|
|
3780
4489
|
}
|
|
3781
|
-
function optionalNumber(value,
|
|
4490
|
+
function optionalNumber(value, path7) {
|
|
3782
4491
|
if (value === void 0) return void 0;
|
|
3783
4492
|
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
3784
|
-
throw new ConfigError(`${
|
|
4493
|
+
throw new ConfigError(`${path7} debe ser un n\xFAmero`);
|
|
3785
4494
|
}
|
|
3786
4495
|
return value;
|
|
3787
4496
|
}
|
|
3788
|
-
function asObject(value,
|
|
4497
|
+
function asObject(value, path7) {
|
|
3789
4498
|
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
3790
|
-
throw new ConfigError(`${
|
|
4499
|
+
throw new ConfigError(`${path7} debe ser un objeto`);
|
|
3791
4500
|
}
|
|
3792
4501
|
return value;
|
|
3793
4502
|
}
|
|
3794
|
-
function asString(value,
|
|
4503
|
+
function asString(value, path7) {
|
|
3795
4504
|
if (typeof value !== "string" || value.trim() === "") {
|
|
3796
|
-
throw new ConfigError(`${
|
|
4505
|
+
throw new ConfigError(`${path7} debe ser un texto no vac\xEDo`);
|
|
3797
4506
|
}
|
|
3798
4507
|
return value.trim();
|
|
3799
4508
|
}
|
|
@@ -4059,11 +4768,11 @@ function summarize(index) {
|
|
|
4059
4768
|
}
|
|
4060
4769
|
function difference(present, absent) {
|
|
4061
4770
|
const files = [];
|
|
4062
|
-
for (const [id,
|
|
4771
|
+
for (const [id, path7] of present.paths) {
|
|
4063
4772
|
if (absent.paths.has(id)) continue;
|
|
4064
4773
|
files.push({
|
|
4065
4774
|
id,
|
|
4066
|
-
path:
|
|
4775
|
+
path: path7,
|
|
4067
4776
|
metrics: sortedMetrics(present.metrics[id])
|
|
4068
4777
|
});
|
|
4069
4778
|
}
|
|
@@ -4071,7 +4780,7 @@ function difference(present, absent) {
|
|
|
4071
4780
|
}
|
|
4072
4781
|
function changedFiles(base, head) {
|
|
4073
4782
|
const changed = [];
|
|
4074
|
-
for (const [id,
|
|
4783
|
+
for (const [id, path7] of head.paths) {
|
|
4075
4784
|
if (!base.paths.has(id)) continue;
|
|
4076
4785
|
const baseValues = base.metrics[id] ?? {};
|
|
4077
4786
|
const headValues = head.metrics[id] ?? {};
|
|
@@ -4091,7 +4800,7 @@ function changedFiles(base, head) {
|
|
|
4091
4800
|
delta: baseValue !== null && headValue !== null ? headValue - baseValue : null
|
|
4092
4801
|
});
|
|
4093
4802
|
}
|
|
4094
|
-
if (changes.length > 0) changed.push({ id, path:
|
|
4803
|
+
if (changes.length > 0) changed.push({ id, path: path7, changes });
|
|
4095
4804
|
}
|
|
4096
4805
|
return changed.sort(compareChangedFiles);
|
|
4097
4806
|
}
|
|
@@ -4348,13 +5057,13 @@ function runDiff(options) {
|
|
|
4348
5057
|
console.error(`no se pudo comparar: ${error.message}`);
|
|
4349
5058
|
return 1;
|
|
4350
5059
|
}
|
|
4351
|
-
const outPath =
|
|
5060
|
+
const outPath = path4.resolve(options.out ?? "report.json");
|
|
4352
5061
|
let reportBytes = 0;
|
|
4353
5062
|
try {
|
|
4354
|
-
|
|
5063
|
+
fs6.mkdirSync(path4.dirname(outPath), { recursive: true });
|
|
4355
5064
|
const text = `${JSON.stringify(report, null, 2)}
|
|
4356
5065
|
`;
|
|
4357
|
-
|
|
5066
|
+
fs6.writeFileSync(outPath, text, "utf8");
|
|
4358
5067
|
reportBytes = Buffer.byteLength(text, "utf8");
|
|
4359
5068
|
} catch (error) {
|
|
4360
5069
|
console.error(
|
|
@@ -4490,7 +5199,7 @@ function loadSnapshot(file) {
|
|
|
4490
5199
|
}
|
|
4491
5200
|
function defaultConfigPath() {
|
|
4492
5201
|
for (const file of [".codarch.yml", ".codarch.yaml"]) {
|
|
4493
|
-
if (
|
|
5202
|
+
if (fs6.existsSync(file)) return file;
|
|
4494
5203
|
}
|
|
4495
5204
|
return void 0;
|
|
4496
5205
|
}
|
|
@@ -4542,7 +5251,7 @@ function runInspect(options) {
|
|
|
4542
5251
|
const metric = options.metric ?? defaultMetric(stats);
|
|
4543
5252
|
const top = metric ? topByMetric(cc, metric, options.top) : [];
|
|
4544
5253
|
const rootPrefix = cc.files.length === 1 ? `${cc.files[0]?.name}/` : "";
|
|
4545
|
-
const displayPath = (
|
|
5254
|
+
const displayPath = (path7) => rootPrefix && path7.startsWith(rootPrefix) ? path7.slice(rootPrefix.length) : path7;
|
|
4546
5255
|
if (options.metric && !stats.metricCoverage.some((entry) => entry.name === options.metric)) {
|
|
4547
5256
|
console.error(`la m\xE9trica "${options.metric}" no existe en este fichero`);
|
|
4548
5257
|
return 1;
|
|
@@ -4621,8 +5330,8 @@ function runInspect(options) {
|
|
|
4621
5330
|
}
|
|
4622
5331
|
|
|
4623
5332
|
// apps/cli/src/commands/render.ts
|
|
4624
|
-
import
|
|
4625
|
-
import
|
|
5333
|
+
import fs7 from "node:fs";
|
|
5334
|
+
import path5 from "node:path";
|
|
4626
5335
|
function defaultOutputPath(input) {
|
|
4627
5336
|
const lower = input.toLowerCase();
|
|
4628
5337
|
const suffixes = [".cc.json.gz", ".cc.json", ".json.gz", ".json", ".gz"];
|
|
@@ -4632,7 +5341,7 @@ function defaultOutputPath(input) {
|
|
|
4632
5341
|
return `${input}.html`;
|
|
4633
5342
|
}
|
|
4634
5343
|
function defaultProjectName(input) {
|
|
4635
|
-
let name =
|
|
5344
|
+
let name = path5.basename(input.replace(/\\/g, "/"));
|
|
4636
5345
|
const lower = name.toLowerCase();
|
|
4637
5346
|
const suffixes = [".cc.json.gz", ".cc.json", ".json.gz", ".json", ".gz"];
|
|
4638
5347
|
for (const suffix of suffixes) {
|
|
@@ -4699,8 +5408,8 @@ function runRender(options) {
|
|
|
4699
5408
|
const elapsed = Date.now() - started;
|
|
4700
5409
|
const out = options.out ?? defaultOutputPath(options.file);
|
|
4701
5410
|
try {
|
|
4702
|
-
|
|
4703
|
-
|
|
5411
|
+
fs7.mkdirSync(path5.dirname(path5.resolve(out)), { recursive: true });
|
|
5412
|
+
fs7.writeFileSync(out, html, "utf8");
|
|
4704
5413
|
} catch (error) {
|
|
4705
5414
|
console.error(`no se pudo escribir ${out}: ${error.message}`);
|
|
4706
5415
|
return 1;
|
|
@@ -4741,9 +5450,9 @@ function runRender(options) {
|
|
|
4741
5450
|
}
|
|
4742
5451
|
|
|
4743
5452
|
// apps/cli/src/commands/serve.ts
|
|
4744
|
-
import
|
|
5453
|
+
import fs8 from "node:fs";
|
|
4745
5454
|
import http from "node:http";
|
|
4746
|
-
import
|
|
5455
|
+
import path6 from "node:path";
|
|
4747
5456
|
import { fileURLToPath } from "node:url";
|
|
4748
5457
|
var MIME = {
|
|
4749
5458
|
".html": "text/html; charset=utf-8",
|
|
@@ -4769,7 +5478,7 @@ var IGNORED_BROWSE = /* @__PURE__ */ new Set([
|
|
|
4769
5478
|
"target"
|
|
4770
5479
|
]);
|
|
4771
5480
|
function runServe(options) {
|
|
4772
|
-
const root =
|
|
5481
|
+
const root = path6.resolve(options.root ?? ".");
|
|
4773
5482
|
const webRoot = options.web === false ? null : findWebRoot();
|
|
4774
5483
|
if (options.web !== false && !webRoot) {
|
|
4775
5484
|
console.error(
|
|
@@ -4784,10 +5493,10 @@ function runServe(options) {
|
|
|
4784
5493
|
const startWatcher = () => {
|
|
4785
5494
|
if (watcher) return null;
|
|
4786
5495
|
try {
|
|
4787
|
-
watcher =
|
|
5496
|
+
watcher = fs8.watch(state.root, { recursive: true }, (_event, filename) => {
|
|
4788
5497
|
if (!filename) return;
|
|
4789
|
-
const
|
|
4790
|
-
if (IGNORED_WATCH.test(
|
|
5498
|
+
const relative2 = filename.toString().replace(/\\/g, "/");
|
|
5499
|
+
if (IGNORED_WATCH.test(relative2)) return;
|
|
4791
5500
|
scheduleRefresh();
|
|
4792
5501
|
});
|
|
4793
5502
|
return null;
|
|
@@ -4847,8 +5556,8 @@ function runServe(options) {
|
|
|
4847
5556
|
broadcast(clients, "watch", { watch: state.watch });
|
|
4848
5557
|
};
|
|
4849
5558
|
const switchRoot = (nextRoot) => {
|
|
4850
|
-
const resolved =
|
|
4851
|
-
const stat =
|
|
5559
|
+
const resolved = path6.resolve(nextRoot);
|
|
5560
|
+
const stat = fs8.statSync(resolved);
|
|
4852
5561
|
if (!stat.isDirectory()) throw new Error("la ruta no es un directorio");
|
|
4853
5562
|
const next = analyzeState(resolved, state.watch);
|
|
4854
5563
|
stopWatcher();
|
|
@@ -4870,7 +5579,7 @@ function runServe(options) {
|
|
|
4870
5579
|
return state;
|
|
4871
5580
|
};
|
|
4872
5581
|
const meta = () => ({
|
|
4873
|
-
root:
|
|
5582
|
+
root: path6.basename(state.root),
|
|
4874
5583
|
rootPath: state.root,
|
|
4875
5584
|
watch: state.watch,
|
|
4876
5585
|
files: state.files,
|
|
@@ -5034,15 +5743,15 @@ function analyzeState(root, watch) {
|
|
|
5034
5743
|
};
|
|
5035
5744
|
}
|
|
5036
5745
|
function browseDirectories(root, requested) {
|
|
5037
|
-
const target = requested?.trim() ?
|
|
5038
|
-
const stat =
|
|
5746
|
+
const target = requested?.trim() ? path6.resolve(requested) : root;
|
|
5747
|
+
const stat = fs8.statSync(target);
|
|
5039
5748
|
if (!stat.isDirectory()) throw new Error("la ruta no es un directorio");
|
|
5040
|
-
const entries =
|
|
5749
|
+
const entries = fs8.readdirSync(target, { withFileTypes: true }).filter((entry) => entry.isDirectory() && !IGNORED_BROWSE.has(entry.name)).sort((left, right) => left.name.localeCompare(right.name)).slice(0, 500).map((entry) => ({
|
|
5041
5750
|
name: entry.name,
|
|
5042
|
-
path:
|
|
5751
|
+
path: path6.join(target, entry.name),
|
|
5043
5752
|
kind: "directory"
|
|
5044
5753
|
}));
|
|
5045
|
-
const parent =
|
|
5754
|
+
const parent = path6.dirname(target);
|
|
5046
5755
|
return {
|
|
5047
5756
|
path: target,
|
|
5048
5757
|
parent: parent === target ? null : parent,
|
|
@@ -5078,9 +5787,9 @@ function originAllowed(request, options) {
|
|
|
5078
5787
|
function findWebRoot() {
|
|
5079
5788
|
const candidates = [
|
|
5080
5789
|
fileURLToPath(new URL("./web", import.meta.url)),
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5790
|
+
path6.resolve(process.cwd(), "apps", "web", "dist"),
|
|
5791
|
+
path6.resolve(
|
|
5792
|
+
path6.dirname(fileURLToPath(import.meta.url)),
|
|
5084
5793
|
"..",
|
|
5085
5794
|
"..",
|
|
5086
5795
|
"..",
|
|
@@ -5089,14 +5798,14 @@ function findWebRoot() {
|
|
|
5089
5798
|
)
|
|
5090
5799
|
];
|
|
5091
5800
|
for (const candidate of candidates) {
|
|
5092
|
-
if (
|
|
5801
|
+
if (fs8.existsSync(path6.join(candidate, "index.html"))) return candidate;
|
|
5093
5802
|
}
|
|
5094
5803
|
return null;
|
|
5095
5804
|
}
|
|
5096
5805
|
function readReport(root) {
|
|
5097
|
-
const file =
|
|
5806
|
+
const file = path6.join(root, ".codarch", "report.json");
|
|
5098
5807
|
try {
|
|
5099
|
-
return JSON.parse(
|
|
5808
|
+
return JSON.parse(fs8.readFileSync(file, "utf8"));
|
|
5100
5809
|
} catch (error) {
|
|
5101
5810
|
if (error.code !== "ENOENT") {
|
|
5102
5811
|
console.error(`no se pudo leer ${file}: ${error.message}`);
|
|
@@ -5113,17 +5822,17 @@ function serveStatic(webRoot, pathname, headOnly, response) {
|
|
|
5113
5822
|
response.end();
|
|
5114
5823
|
return;
|
|
5115
5824
|
}
|
|
5116
|
-
const
|
|
5117
|
-
let file =
|
|
5118
|
-
if (!isWithin2(webRoot, file) || !
|
|
5119
|
-
file =
|
|
5825
|
+
const relative2 = decoded === "/" ? "index.html" : decoded.replace(/^\/+/, "");
|
|
5826
|
+
let file = path6.resolve(webRoot, relative2);
|
|
5827
|
+
if (!isWithin2(webRoot, file) || !fs8.existsSync(file) || !fs8.statSync(file).isFile()) {
|
|
5828
|
+
file = path6.join(webRoot, "index.html");
|
|
5120
5829
|
}
|
|
5121
5830
|
try {
|
|
5122
|
-
const body =
|
|
5831
|
+
const body = fs8.readFileSync(file);
|
|
5123
5832
|
response.writeHead(200, {
|
|
5124
|
-
"Content-Type": MIME[
|
|
5833
|
+
"Content-Type": MIME[path6.extname(file).toLowerCase()] ?? "application/octet-stream",
|
|
5125
5834
|
"Content-Length": body.length,
|
|
5126
|
-
"Cache-Control": file.includes(`${
|
|
5835
|
+
"Cache-Control": file.includes(`${path6.sep}assets${path6.sep}`) ? "public, max-age=31536000, immutable" : "no-store",
|
|
5127
5836
|
"X-Content-Type-Options": "nosniff"
|
|
5128
5837
|
});
|
|
5129
5838
|
if (headOnly) response.end();
|
|
@@ -5134,8 +5843,8 @@ function serveStatic(webRoot, pathname, headOnly, response) {
|
|
|
5134
5843
|
}
|
|
5135
5844
|
}
|
|
5136
5845
|
function isWithin2(root, candidate) {
|
|
5137
|
-
const
|
|
5138
|
-
return
|
|
5846
|
+
const relative2 = path6.relative(root, candidate);
|
|
5847
|
+
return relative2 === "" || !relative2.startsWith("..") && !path6.isAbsolute(relative2);
|
|
5139
5848
|
}
|
|
5140
5849
|
function sendJson(response, value) {
|
|
5141
5850
|
const body = `${JSON.stringify(value)}
|
|
@@ -5173,7 +5882,7 @@ data: ${JSON.stringify(data)}
|
|
|
5173
5882
|
}
|
|
5174
5883
|
|
|
5175
5884
|
// apps/cli/src/index.ts
|
|
5176
|
-
var VERSION = true ? "0.1.
|
|
5885
|
+
var VERSION = true ? "0.1.4" : "0.0.0";
|
|
5177
5886
|
var USAGE = `
|
|
5178
5887
|
CodArch \xB7 mapa vivo de la arquitectura de tu software
|
|
5179
5888
|
|