bussing 0.0.1 → 0.0.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/dist/order.js ADDED
@@ -0,0 +1,164 @@
1
+ // Orden de limpieza: repositorios con problemas y los que dependen de ellos, en orden topológico.
2
+ // Entran los repositorios con problemas propios y, por sus dependencias fuertes (dependencies, optionalDependencies,
3
+ // peerDependencies), los que dependen de un repositorio con problemas que llegan a quien lo usa. Las dependencias fuertes se
4
+ // respetan siempre en el orden; las débiles (devDependencies) solo ordenan, y se descartan si cierran un ciclo.
5
+ import { fieldGravity } from './categories.js';
6
+ import { defined, mustGet } from './util.js';
7
+ function byName(a, b) {
8
+ return a.name < b.name ? -1 : a.name > b.name ? 1 : a.dir < b.dir ? -1 : a.dir > b.dir ? 1 : 0;
9
+ }
10
+ /** Componentes fuertemente conexas (Tarjan), para tratar cada ciclo de dependencias como un solo paso. */
11
+ function stronglyConnectedComponents(dirs, edges) {
12
+ const component = new Map();
13
+ const index = new Map();
14
+ const low = new Map();
15
+ const stack = [];
16
+ const onStack = new Set();
17
+ let counter = 0;
18
+ let components = 0;
19
+ function visit(dir) {
20
+ index.set(dir, counter);
21
+ low.set(dir, counter);
22
+ counter++;
23
+ stack.push(dir);
24
+ onStack.add(dir);
25
+ for (const next of edges.get(dir) ?? []) {
26
+ if (!index.has(next)) {
27
+ visit(next);
28
+ low.set(dir, Math.min(mustGet(low, dir), mustGet(low, next)));
29
+ }
30
+ else if (onStack.has(next)) {
31
+ low.set(dir, Math.min(mustGet(low, dir), mustGet(index, next)));
32
+ }
33
+ }
34
+ if (low.get(dir) === index.get(dir)) {
35
+ let member;
36
+ do {
37
+ member = defined(stack.pop(), 'elemento de la pila');
38
+ onStack.delete(member);
39
+ component.set(member, components);
40
+ } while (member !== dir);
41
+ components++;
42
+ }
43
+ }
44
+ for (const dir of dirs)
45
+ if (!index.has(dir))
46
+ visit(dir);
47
+ return component;
48
+ }
49
+ /** `true` si desde `from` se llega a `to` siguiendo las aristas. */
50
+ function reaches(edges, from, to) {
51
+ const visited = new Set();
52
+ const pending = [from];
53
+ while (pending.length > 0) {
54
+ const current = defined(pending.pop(), 'pendiente');
55
+ if (current === to)
56
+ return true;
57
+ if (visited.has(current))
58
+ continue;
59
+ visited.add(current);
60
+ pending.push(...(edges.get(current) ?? []));
61
+ }
62
+ return false;
63
+ }
64
+ /** `priority`: prioridad de cada paquete como dependencia débil (por omisión 0); ver `BussingOptions.dependencyPriority`. */
65
+ export function computeCleanupOrder(nodes, priority = new Map()) {
66
+ const byDir = new Map(nodes.map(function (node) { return [node.dir, node]; }));
67
+ const dependents = new Map();
68
+ for (const node of nodes) {
69
+ for (const dep of node.dependsOn)
70
+ dependents.set(dep.dir, [...(dependents.get(dep.dir) ?? []), node.dir]);
71
+ }
72
+ // Los repositorios con problemas propios y, transitivamente por las dependencias fuertes, los que dependen de ellos
73
+ // Entran los que tienen problemas propios; los que dependen (transitivamente) de uno cuyos problemas llegan a quien lo usa
74
+ // entran también y, a su vez, hacen entrar a los que dependen de ellos
75
+ const included = new Set(nodes.filter(function (node) { return node.mainProblem !== null; }).map(function (node) { return node.dir; }));
76
+ const reaching = new Set();
77
+ const pending = nodes.filter(function (node) { return node.reachesDependents; }).map(function (node) { return node.dir; });
78
+ while (pending.length > 0) {
79
+ const dir = defined(pending.pop(), 'pendiente');
80
+ if (reaching.has(dir))
81
+ continue;
82
+ reaching.add(dir);
83
+ included.add(dir);
84
+ pending.push(...(dependents.get(dir) ?? []));
85
+ }
86
+ const dirs = [...included].sort();
87
+ const strongEdges = new Map(dirs.map(function (dir) {
88
+ return [dir, mustGet(byDir, dir).dependsOn.map(function (dep) { return dep.dir; }).filter(function (dep) { return included.has(dep); })];
89
+ }));
90
+ // Los ciclos de dependencias fuertes forman un solo paso
91
+ const component = stronglyConnectedComponents(dirs, strongEdges);
92
+ const componentEdges = new Map();
93
+ function addComponentEdge(from, to) {
94
+ const set = componentEdges.get(from) ?? new Set();
95
+ set.add(to);
96
+ componentEdges.set(from, set);
97
+ }
98
+ for (const dir of dirs) {
99
+ for (const dep of mustGet(strongEdges, dir)) {
100
+ if (mustGet(component, dep) !== mustGet(component, dir))
101
+ addComponentEdge(mustGet(component, dir), mustGet(component, dep));
102
+ }
103
+ }
104
+ // Las dependencias débiles se respetan salvo que cierren un ciclo. Se agregan primero las de mayor prioridad (según la
105
+ // dependencia) y, a igual prioridad, por nombre, para que el resultado sea reproducible. Las que cerrarían un ciclo se postergan.
106
+ const acceptedWeak = new Map(dirs.map(function (dir) { return [dir, []]; }));
107
+ const deferredWeak = new Map(dirs.map(function (dir) { return [dir, []]; }));
108
+ const priorityOf = function (dir) { return priority.get(mustGet(byDir, dir).name) ?? 0; };
109
+ const weakEdges = [];
110
+ for (const dir of dirs) {
111
+ for (const dep of mustGet(byDir, dir).weakDependsOn)
112
+ if (included.has(dep))
113
+ weakEdges.push([dir, dep]);
114
+ }
115
+ weakEdges.sort(function ([dirA, depA], [dirB, depB]) {
116
+ return priorityOf(depB) - priorityOf(depA) || byName(mustGet(byDir, dirA), mustGet(byDir, dirB)) || byName(mustGet(byDir, depA), mustGet(byDir, depB));
117
+ });
118
+ for (const [dir, dep] of weakEdges) {
119
+ const from = mustGet(component, dir);
120
+ const to = mustGet(component, dep);
121
+ if (from === to)
122
+ continue;
123
+ if (reaches(componentEdges, to, from)) {
124
+ mustGet(deferredWeak, dir).push(dep);
125
+ }
126
+ else {
127
+ addComponentEdge(from, to);
128
+ mustGet(acceptedWeak, dir).push(dep);
129
+ }
130
+ }
131
+ // Nivel de cada componente: 0 si no depende de otra componente; si no, uno más que la de mayor nivel de la que depende
132
+ const levels = new Map();
133
+ function levelOf(id) {
134
+ const known = levels.get(id);
135
+ if (known !== undefined)
136
+ return known;
137
+ let level = 0;
138
+ for (const dep of componentEdges.get(id) ?? [])
139
+ level = Math.max(level, levelOf(dep) + 1);
140
+ levels.set(id, level);
141
+ return level;
142
+ }
143
+ const steps = dirs.map(function (dir) {
144
+ const node = mustGet(byDir, dir);
145
+ const id = mustGet(component, dir);
146
+ const names = function (list) { return list.map(function (d) { return mustGet(byDir, d).name; }).sort(); };
147
+ const deps = [...mustGet(strongEdges, dir).filter(function (dep) { return mustGet(component, dep) !== id; }), ...mustGet(acceptedWeak, dir)];
148
+ return {
149
+ name: node.name,
150
+ dir,
151
+ level: levelOf(id),
152
+ mainProblem: node.mainProblem,
153
+ dependencyField: node.mainProblem !== null ? null : node.dependsOn
154
+ .filter(function (dep) { return reaching.has(dep.dir); })
155
+ .map(function (dep) { return dep.field; })
156
+ .sort(function (a, b) { return fieldGravity(a) - fieldGravity(b); })[0] ?? null,
157
+ dependsOn: names([...new Set(deps)]),
158
+ deferred: names(mustGet(deferredWeak, dir)),
159
+ inCycleWith: names(dirs.filter(function (other) { return other !== dir && mustGet(component, other) === id; })),
160
+ };
161
+ });
162
+ return steps.sort(function (a, b) { return a.level - b.level || byName(a, b); });
163
+ }
164
+ //# sourceMappingURL=order.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"order.js","sourceRoot":"","sources":["../src/order.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { Packument, Registry } from './types.js';
2
+ export declare const DEFAULT_REGISTRY_URL = "https://registry.npmjs.org/";
3
+ /** Interpreta el documento de un paquete del registro (el formato completo, no el abreviado). */
4
+ export declare function parsePackument(text: string): Packument;
5
+ /** URL del documento de un paquete; en los paquetes con scope la barra se codifica (`@scope%2fname`). */
6
+ export declare function packumentUrl(registryUrl: string, name: string): string;
7
+ /**
8
+ * Verifica un valor de integridad SRI (`sha512-...`, posiblemente varios separados por espacios).
9
+ * Alcanza con que coincida uno de los algoritmos conocidos; lanza un error si ninguno coincide.
10
+ */
11
+ export declare function verifyIntegrity(data: Uint8Array, integrity: string, source: string): void;
12
+ /** Archivos regulares de un tarball (comprimido o no). Se descarta el primer segmento de cada ruta (normalmente `package/`). */
13
+ export declare function readTarball(data: Uint8Array): Promise<Map<string, Uint8Array>>;
14
+ /** Descripción de un error de fetch, incluida su causa (por ejemplo `ENOTFOUND` cuando no hay red o no se resuelve el nombre). */
15
+ export declare function describeFetchError(err: unknown): string;
16
+ /** Registro de npm accedido por HTTP. Cada paquete y cada tarball se descarga una sola vez por instancia. */
17
+ export declare function createNpmRegistry(registryUrl?: string): Registry;
@@ -0,0 +1,127 @@
1
+ // Acceso al registro de npm: metadatos de paquetes y contenido de tarballs.
2
+ import { createHash } from 'node:crypto';
3
+ import { guarantee, is } from 'guarantee-type';
4
+ import { Parser } from 'tar';
5
+ export const DEFAULT_REGISTRY_URL = 'https://registry.npmjs.org/';
6
+ const packumentDescription = is.object({
7
+ name: is.string,
8
+ 'dist-tags': is.optional.recordString.string,
9
+ versions: is.optional.recordString.object({
10
+ version: is.string,
11
+ gitHead: is.optional.string,
12
+ dist: is.object({
13
+ tarball: is.string,
14
+ integrity: is.optional.string,
15
+ }),
16
+ }),
17
+ });
18
+ /** Interpreta el documento de un paquete del registro (el formato completo, no el abreviado). */
19
+ export function parsePackument(text) {
20
+ const doc = guarantee(packumentDescription, JSON.parse(text));
21
+ const versions = {};
22
+ for (const [key, value] of Object.entries(doc.versions ?? {})) {
23
+ versions[key] = { version: value.version, gitHead: value.gitHead, tarball: value.dist.tarball, integrity: value.dist.integrity };
24
+ }
25
+ return { name: doc.name, distTags: doc['dist-tags'] ?? {}, versions };
26
+ }
27
+ /** URL del documento de un paquete; en los paquetes con scope la barra se codifica (`@scope%2fname`). */
28
+ export function packumentUrl(registryUrl, name) {
29
+ const base = registryUrl.endsWith('/') ? registryUrl : registryUrl + '/';
30
+ return base + encodeURIComponent(name).replace(/^%40/, '@');
31
+ }
32
+ /**
33
+ * Verifica un valor de integridad SRI (`sha512-...`, posiblemente varios separados por espacios).
34
+ * Alcanza con que coincida uno de los algoritmos conocidos; lanza un error si ninguno coincide.
35
+ */
36
+ export function verifyIntegrity(data, integrity, source) {
37
+ const known = integrity.split(/\s+/).filter(function (item) { return /^(sha512|sha384|sha256|sha1)-/.test(item); });
38
+ if (known.length === 0)
39
+ throw new Error(`Integridad con formato no reconocido para ${source}: ${integrity}`);
40
+ for (const item of known) {
41
+ const dash = item.indexOf('-');
42
+ const algorithm = item.slice(0, dash);
43
+ const expected = item.slice(dash + 1);
44
+ if (createHash(algorithm).update(data).digest('base64') === expected)
45
+ return;
46
+ }
47
+ throw new Error(`La integridad de ${source} no coincide con ${integrity}`);
48
+ }
49
+ /** Archivos regulares de un tarball (comprimido o no). Se descarta el primer segmento de cada ruta (normalmente `package/`). */
50
+ export function readTarball(data) {
51
+ return new Promise(function (resolve, reject) {
52
+ const files = new Map();
53
+ const parser = new Parser({
54
+ onReadEntry: function (entry) {
55
+ if (entry.type !== 'File') {
56
+ entry.resume();
57
+ return;
58
+ }
59
+ const chunks = [];
60
+ const path = entry.path.split('/').slice(1).join('/');
61
+ entry.on('data', function (chunk) { chunks.push(chunk); });
62
+ entry.on('end', function () { files.set(path, Buffer.concat(chunks)); });
63
+ },
64
+ });
65
+ parser.on('error', reject);
66
+ parser.on('close', function () { resolve(files); });
67
+ parser.end(Buffer.from(data));
68
+ });
69
+ }
70
+ /** Descripción de un error de fetch, incluida su causa (por ejemplo `ENOTFOUND` cuando no hay red o no se resuelve el nombre). */
71
+ export function describeFetchError(err) {
72
+ if (!(err instanceof Error))
73
+ return String(err);
74
+ const cause = err.cause;
75
+ if (cause instanceof Error)
76
+ return `${err.message}: ${'code' in cause && typeof cause.code === 'string' ? cause.code + ' ' : ''}${cause.message}`;
77
+ return err.message;
78
+ }
79
+ async function fetchOk(url, accept) {
80
+ let response;
81
+ try {
82
+ response = await fetch(url, { headers: { accept } });
83
+ }
84
+ catch (err) {
85
+ throw new Error(`No se pudo acceder a ${url} (${describeFetchError(err)})`);
86
+ }
87
+ if (response.status === 404)
88
+ return null;
89
+ if (!response.ok)
90
+ throw new Error(`GET ${url}: ${response.status} ${response.statusText}`);
91
+ return response;
92
+ }
93
+ /** Registro de npm accedido por HTTP. Cada paquete y cada tarball se descarga una sola vez por instancia. */
94
+ export function createNpmRegistry(registryUrl = DEFAULT_REGISTRY_URL) {
95
+ const packuments = new Map();
96
+ const tarballs = new Map();
97
+ return {
98
+ getPackument: function (name) {
99
+ let pending = packuments.get(name);
100
+ if (pending === undefined) {
101
+ pending = (async function () {
102
+ const response = await fetchOk(packumentUrl(registryUrl, name), 'application/json');
103
+ return response === null ? null : parsePackument(await response.text());
104
+ })();
105
+ packuments.set(name, pending);
106
+ }
107
+ return pending;
108
+ },
109
+ getTarballFiles: function (tarballUrl, integrity) {
110
+ let pending = tarballs.get(tarballUrl);
111
+ if (pending === undefined) {
112
+ pending = (async function () {
113
+ const response = await fetchOk(tarballUrl, 'application/octet-stream');
114
+ if (response === null)
115
+ throw new Error(`No existe el tarball ${tarballUrl}`);
116
+ const data = new Uint8Array(await response.arrayBuffer());
117
+ if (integrity !== undefined)
118
+ verifyIntegrity(data, integrity, tarballUrl);
119
+ return readTarball(data);
120
+ })();
121
+ tarballs.set(tarballUrl, pending);
122
+ }
123
+ return pending;
124
+ },
125
+ };
126
+ }
127
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,80 @@
1
+ import { type GuaranteedType } from 'guarantee-type';
2
+ import type { DependencyField } from './types.js';
3
+ export declare const DEPENDENCY_FIELDS: readonly DependencyField[];
4
+ /**
5
+ * Dependencias fuertes para el orden de limpieza: definen qué repositorios entran en la lista y se respetan siempre.
6
+ */
7
+ export declare const ORDER_DEPENDENCY_FIELDS: readonly DependencyField[];
8
+ /**
9
+ * Dependencias débiles para el orden de limpieza: se respetan salvo que cierren un ciclo. Entre los paquetes propios las
10
+ * devDependencies forman ciclos (por ejemplo, qa-control es devDependency de librerías de las que él mismo depende).
11
+ */
12
+ export declare const WEAK_ORDER_DEPENDENCY_FIELDS: readonly DependencyField[];
13
+ declare const packageJsonDescription: {
14
+ object: {
15
+ name: {
16
+ optional: {
17
+ string: import("guarantee-type").Opts;
18
+ };
19
+ };
20
+ version: {
21
+ optional: {
22
+ string: import("guarantee-type").Opts;
23
+ };
24
+ };
25
+ private: {
26
+ optional: {
27
+ boolean: import("guarantee-type").Opts;
28
+ };
29
+ };
30
+ dependencies: {
31
+ optional: {
32
+ recordString: {
33
+ string: import("guarantee-type").Opts;
34
+ };
35
+ };
36
+ };
37
+ devDependencies: {
38
+ optional: {
39
+ recordString: {
40
+ string: import("guarantee-type").Opts;
41
+ };
42
+ };
43
+ };
44
+ optionalDependencies: {
45
+ optional: {
46
+ recordString: {
47
+ string: import("guarantee-type").Opts;
48
+ };
49
+ };
50
+ };
51
+ peerDependencies: {
52
+ optional: {
53
+ recordString: {
54
+ string: import("guarantee-type").Opts;
55
+ };
56
+ };
57
+ };
58
+ };
59
+ };
60
+ export type PackageJson = GuaranteedType<typeof packageJsonDescription>;
61
+ /** Interpreta el contenido de un package.json. Lanza un error si no es JSON o no tiene la forma esperada. */
62
+ export declare function parsePackageJson(text: string): PackageJson;
63
+ export declare function readPackageJson(dir: string): Promise<PackageJson>;
64
+ export interface FoundRepos {
65
+ repos: string[];
66
+ /** Repositorios que se encontraron pero no se revisan por estar en `ignore`. */
67
+ ignored: string[];
68
+ }
69
+ /**
70
+ * Subcarpetas directas de cada raíz que tienen `package.json`, separando las que se llaman como algún elemento de `ignore`.
71
+ * Lanza un error si una raíz no existe o no es una carpeta.
72
+ */
73
+ export declare function findRepos(roots: string[], ignore?: string[]): Promise<FoundRepos>;
74
+ /** Dependencias declaradas en los campos indicados (por omisión, todos), con el campo en que figuran. */
75
+ export declare function declaredDependencies(pkg: PackageJson, fields?: readonly DependencyField[]): {
76
+ name: string;
77
+ spec: string;
78
+ field: DependencyField;
79
+ }[];
80
+ export {};
package/dist/repos.js ADDED
@@ -0,0 +1,86 @@
1
+ // Descubrimiento de repositorios y lectura de su package.json.
2
+ import { readdir, readFile, stat } from 'node:fs/promises';
3
+ import { join } from 'node:path';
4
+ import { guarantee, is } from 'guarantee-type';
5
+ export const DEPENDENCY_FIELDS = ['dependencies', 'devDependencies', 'optionalDependencies', 'peerDependencies'];
6
+ /**
7
+ * Dependencias fuertes para el orden de limpieza: definen qué repositorios entran en la lista y se respetan siempre.
8
+ */
9
+ export const ORDER_DEPENDENCY_FIELDS = ['dependencies', 'optionalDependencies', 'peerDependencies'];
10
+ /**
11
+ * Dependencias débiles para el orden de limpieza: se respetan salvo que cierren un ciclo. Entre los paquetes propios las
12
+ * devDependencies forman ciclos (por ejemplo, qa-control es devDependency de librerías de las que él mismo depende).
13
+ */
14
+ export const WEAK_ORDER_DEPENDENCY_FIELDS = ['devDependencies'];
15
+ const packageJsonDescription = is.object({
16
+ name: is.optional.string,
17
+ version: is.optional.string,
18
+ private: is.optional.boolean,
19
+ dependencies: is.optional.recordString.string,
20
+ devDependencies: is.optional.recordString.string,
21
+ optionalDependencies: is.optional.recordString.string,
22
+ peerDependencies: is.optional.recordString.string,
23
+ });
24
+ /** Interpreta el contenido de un package.json. Lanza un error si no es JSON o no tiene la forma esperada. */
25
+ export function parsePackageJson(text) {
26
+ return guarantee(packageJsonDescription, JSON.parse(text));
27
+ }
28
+ export async function readPackageJson(dir) {
29
+ return parsePackageJson(await readFile(join(dir, 'package.json'), 'utf8'));
30
+ }
31
+ async function isFile(path) {
32
+ try {
33
+ return (await stat(path)).isFile();
34
+ }
35
+ catch (err) {
36
+ if (err instanceof Error && 'code' in err && err.code === 'ENOENT')
37
+ return false;
38
+ throw err;
39
+ }
40
+ }
41
+ /**
42
+ * Subcarpetas directas de cada raíz que tienen `package.json`, separando las que se llaman como algún elemento de `ignore`.
43
+ * Lanza un error si una raíz no existe o no es una carpeta.
44
+ */
45
+ export async function findRepos(roots, ignore = []) {
46
+ if (roots.length === 0)
47
+ throw new Error('No se indicó ninguna carpeta para revisar');
48
+ const ignoreSet = new Set(ignore);
49
+ const repos = [];
50
+ const ignored = [];
51
+ for (const root of roots) {
52
+ let rootIsDir;
53
+ try {
54
+ rootIsDir = (await stat(root)).isDirectory();
55
+ }
56
+ catch (err) {
57
+ if (err instanceof Error && 'code' in err && err.code === 'ENOENT')
58
+ throw new Error(`La carpeta ${root} no existe`);
59
+ throw err;
60
+ }
61
+ if (!rootIsDir)
62
+ throw new Error(`${root} no es una carpeta`);
63
+ const entries = await readdir(root, { withFileTypes: true });
64
+ for (const entry of entries) {
65
+ const dir = join(root, entry.name);
66
+ // stat (no lstat) para incluir también carpetas alcanzadas por enlaces simbólicos o junctions
67
+ const isDir = entry.isDirectory() || (entry.isSymbolicLink() && (await stat(dir)).isDirectory());
68
+ if (isDir && await isFile(join(dir, 'package.json')))
69
+ (ignoreSet.has(entry.name) ? ignored : repos).push(dir);
70
+ }
71
+ }
72
+ return { repos: repos.sort(), ignored: ignored.sort() };
73
+ }
74
+ /** Dependencias declaradas en los campos indicados (por omisión, todos), con el campo en que figuran. */
75
+ export function declaredDependencies(pkg, fields = DEPENDENCY_FIELDS) {
76
+ const result = [];
77
+ for (const field of fields) {
78
+ const deps = pkg[field];
79
+ if (deps !== undefined) {
80
+ for (const [name, spec] of Object.entries(deps))
81
+ result.push({ name, spec, field });
82
+ }
83
+ }
84
+ return result;
85
+ }
86
+ //# sourceMappingURL=repos.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repos.js","sourceRoot":"","sources":["../src/repos.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,127 @@
1
+ /** Función que recibe los mensajes de progreso del core (el core nunca escribe en la salida). */
2
+ export type LogFunction = (message: string) => void;
3
+ /** Paquete tal como figura en el registro de npm (solo lo que bussing usa). */
4
+ export interface Packument {
5
+ name: string;
6
+ distTags: Record<string, string>;
7
+ versions: Record<string, PublishedVersion>;
8
+ }
9
+ export interface PublishedVersion {
10
+ version: string;
11
+ /** Commit desde el que se publicó la versión; npm lo registra al publicar desde un repositorio git. */
12
+ gitHead: string | undefined;
13
+ tarball: string;
14
+ integrity: string | undefined;
15
+ }
16
+ /** Acceso al registro de npm. Se puede reemplazar (por ejemplo en los tests). */
17
+ export interface Registry {
18
+ /** Devuelve `null` si el paquete no existe en el registro. */
19
+ getPackument(name: string): Promise<Packument | null>;
20
+ /** Devuelve los archivos regulares del tarball, con la ruta relativa a la raíz del paquete. */
21
+ getTarballFiles(tarballUrl: string, integrity: string | undefined): Promise<Map<string, Uint8Array>>;
22
+ }
23
+ export interface BussingOptions {
24
+ /** Carpetas raíz; cada subcarpeta directa con `package.json` es un repositorio a revisar. */
25
+ roots: string[];
26
+ /** Nombres de subcarpetas que no se revisan. */
27
+ ignore?: string[];
28
+ /**
29
+ * Prioridad de cada paquete como dependencia débil (devDependency) al romper ciclos; por omisión 0.
30
+ * Las dependencias de mayor prioridad se respetan antes en el orden; las de menor prioridad son las primeras en postergarse.
31
+ */
32
+ dependencyPriority?: Record<string, number>;
33
+ /** Por omisión, el registro público de npm. */
34
+ registry?: Registry;
35
+ log?: LogFunction;
36
+ }
37
+ export type DependencyField = 'dependencies' | 'devDependencies' | 'optionalDependencies' | 'peerDependencies';
38
+ export type CopyDifferenceKind = 'modified' | 'missing' | 'extra';
39
+ export interface CopyDifference {
40
+ path: string;
41
+ kind: CopyDifferenceKind;
42
+ }
43
+ export type Problem = {
44
+ kind: 'uncommitted';
45
+ files: string[];
46
+ } | {
47
+ kind: 'unpushed';
48
+ commits: number;
49
+ } | {
50
+ kind: 'no-upstream';
51
+ branch: string;
52
+ } | {
53
+ kind: 'not-published';
54
+ version: string;
55
+ } | {
56
+ kind: 'unpublished-version';
57
+ version: string;
58
+ latest: string | null;
59
+ } | {
60
+ kind: 'version-not-bumped';
61
+ version: string;
62
+ commitsAfterPublish: number;
63
+ } | {
64
+ kind: 'outdated-dependency';
65
+ dependency: string;
66
+ field: DependencyField;
67
+ declared: string;
68
+ local: string;
69
+ } | {
70
+ kind: 'linked-dependency';
71
+ dependency: string;
72
+ target: string;
73
+ } | {
74
+ kind: 'copied-dependency';
75
+ dependency: string;
76
+ /** Versión registrada en package-lock.json, contra cuyo tarball se compara. */
77
+ version: string;
78
+ /** Versión del package.json instalado (`null` si no se pudo leer). */
79
+ installedVersion: string | null;
80
+ differences: CopyDifference[];
81
+ };
82
+ export type ProblemKind = Problem['kind'];
83
+ /** Categorías de problemas, de la más grave a la menos grave (ver `PROBLEM_CATEGORIES` y `PROBLEM_CATEGORY`). */
84
+ export type ProblemCategory = 'uncommitted' | 'unpushed' | 'altered-node-modules'
85
+ /** Tiene dependencias desactualizadas y alguna de ellas, con problemas propios, va antes en el orden (`waiting-*`). */
86
+ | 'waiting-dependencies' | 'outdated-dependencies' | 'waiting-peer-dependencies' | 'outdated-peer-dependencies' | 'waiting-optional-dependencies' | 'outdated-optional-dependencies' | 'waiting-dev-dependencies' | 'outdated-dev-dependencies' | 'version-not-bumped' | 'unpublished';
87
+ export type CheckName = 'repo' | 'git' | 'publication' | 'cross-dependencies' | 'installation' | 'order';
88
+ /** Situación que impidió completar un control o que conviene revisar, pero que no es un problema en sí. */
89
+ export interface Warning {
90
+ check: CheckName;
91
+ message: string;
92
+ }
93
+ export interface RepoReport {
94
+ /** Carpeta del repositorio. */
95
+ dir: string;
96
+ /** Nombre del paquete (`null` si el `package.json` no se pudo leer o no tiene nombre). */
97
+ name: string | null;
98
+ version: string | null;
99
+ problems: Problem[];
100
+ warnings: Warning[];
101
+ }
102
+ export interface CleanupStep {
103
+ name: string;
104
+ dir: string;
105
+ /** Los pasos del mismo nivel no dependen entre sí. Se empieza por el nivel 0. */
106
+ level: number;
107
+ /** Categoría del problema propio más grave; `null` si está en la lista solo por sus dependencias. */
108
+ mainProblem: ProblemCategory | null;
109
+ /**
110
+ * Si está en la lista solo por sus dependencias (`mainProblem` es `null`): el campo más grave por el que depende de un
111
+ * repositorio con problemas que llegan a quien lo usa. `null` si tiene problemas propios.
112
+ */
113
+ dependencyField: DependencyField | null;
114
+ /** Repositorios de la lista de limpieza de los que depende. */
115
+ dependsOn: string[];
116
+ /** Repositorios con los que forma un ciclo de dependencias fuertes (vacío si no hay ciclo). */
117
+ inCycleWith: string[];
118
+ /** Dependencias débiles que no se respetan en el orden porque cerrarían un ciclo: se actualizan después. */
119
+ deferred: string[];
120
+ }
121
+ export interface BussingReport {
122
+ repos: RepoReport[];
123
+ /** Carpetas de repositorios que no se revisaron por estar en `ignore`. */
124
+ ignored: string[];
125
+ cleanupOrder: CleanupStep[];
126
+ warnings: Warning[];
127
+ }
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ // Tipos públicos de bussing: opciones, informe y problemas detectados.
2
+ export {};
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,uEAAuE"}
package/dist/util.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ /** Valor de una clave que, por construcción, tiene que estar en el Map. Lanza un error si no está. */
2
+ export declare function mustGet<K, V>(map: ReadonlyMap<K, V>, key: K): V;
3
+ /** Elemento que, por construcción, tiene que existir. Lanza un error si es `undefined`. */
4
+ export declare function defined<T>(value: T | undefined, what: string): T;