@heychunky/core 0.29.1 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/graph.d.ts +57 -0
- package/dist/admin/graph.d.ts.map +1 -0
- package/dist/admin/graph.js +90 -0
- package/dist/admin/graph.js.map +1 -0
- package/dist/admin/index.d.ts +1 -0
- package/dist/admin/index.d.ts.map +1 -1
- package/dist/admin/index.js +1 -0
- package/dist/admin/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What an app is made of, and what a change to one part would reach.
|
|
3
|
+
*
|
|
4
|
+
* An app is chunks and chunks depend on each other, which is the shape that
|
|
5
|
+
* decides whether a change is small. Nothing showed it, and the chunk READMEs
|
|
6
|
+
* that describe it in prose go stale the first time somebody deletes an import
|
|
7
|
+
* and not a sentence.
|
|
8
|
+
*
|
|
9
|
+
* So the edges are read rather than restated. `@chunks/<name>` is the boundary
|
|
10
|
+
* the app itself declares in its manifest aliases, so a scan of the chunk
|
|
11
|
+
* sources is the whole graph — the same discipline as everything else here:
|
|
12
|
+
* derive the fact, never keep a second copy of it.
|
|
13
|
+
*
|
|
14
|
+
* Three callers want this. The console draws it, the CLI prints it, and a run
|
|
15
|
+
* reads it to know when it has left its chunk, so it lives where none of them
|
|
16
|
+
* owns it.
|
|
17
|
+
*/
|
|
18
|
+
/** One chunk, and what it reaches. */
|
|
19
|
+
export interface ChunkNode {
|
|
20
|
+
name: string;
|
|
21
|
+
/** Chunks this one imports from, sorted. */
|
|
22
|
+
dependsOn: string[];
|
|
23
|
+
/** Chunks that import this one, sorted. */
|
|
24
|
+
dependedOnBy: string[];
|
|
25
|
+
/**
|
|
26
|
+
* Every chunk reachable by following dependents — what a change here could
|
|
27
|
+
* break. The number that answers "is this a small change".
|
|
28
|
+
*/
|
|
29
|
+
blastRadius: string[];
|
|
30
|
+
}
|
|
31
|
+
export interface ChunkGraph {
|
|
32
|
+
chunks: ChunkNode[];
|
|
33
|
+
/**
|
|
34
|
+
* Pairs that import each other.
|
|
35
|
+
*
|
|
36
|
+
* Reported because they are the reason a blast radius is twelve rather than
|
|
37
|
+
* two: a cycle collapses everything it touches into one cluster, and an app
|
|
38
|
+
* whose graph has cycles has no clean layering to read.
|
|
39
|
+
*/
|
|
40
|
+
cycles: [string, string][];
|
|
41
|
+
}
|
|
42
|
+
/** A chunk's sources, as the scan needs them: its name and its file contents. */
|
|
43
|
+
export interface ChunkSource {
|
|
44
|
+
name: string;
|
|
45
|
+
/** Every text file in the chunk. Contents only; paths are not needed. */
|
|
46
|
+
files: string[];
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Build the graph from a set of chunks and their sources.
|
|
50
|
+
*
|
|
51
|
+
* Pure, so it can be tested against a real app's shape without a network, and
|
|
52
|
+
* so the expensive half — fetching the sources — is somebody else's problem.
|
|
53
|
+
* An edge to a chunk that is not in the set is dropped: an app importing
|
|
54
|
+
* something it does not have is a broken app, not an extra node.
|
|
55
|
+
*/
|
|
56
|
+
export declare function chunkGraph(sources: readonly ChunkSource[]): ChunkGraph;
|
|
57
|
+
//# sourceMappingURL=graph.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../src/admin/graph.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,sCAAsC;AACtC,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,4CAA4C;IAC5C,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,2CAA2C;IAC3C,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB;;;OAGG;IACH,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB;;;;;;OAMG;IACH,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;CAC5B;AAED,iFAAiF;AACjF,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,yEAAyE;IACzE,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAWD;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,OAAO,EAAE,SAAS,WAAW,EAAE,GAAG,UAAU,CAoCtE"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What an app is made of, and what a change to one part would reach.
|
|
3
|
+
*
|
|
4
|
+
* An app is chunks and chunks depend on each other, which is the shape that
|
|
5
|
+
* decides whether a change is small. Nothing showed it, and the chunk READMEs
|
|
6
|
+
* that describe it in prose go stale the first time somebody deletes an import
|
|
7
|
+
* and not a sentence.
|
|
8
|
+
*
|
|
9
|
+
* So the edges are read rather than restated. `@chunks/<name>` is the boundary
|
|
10
|
+
* the app itself declares in its manifest aliases, so a scan of the chunk
|
|
11
|
+
* sources is the whole graph — the same discipline as everything else here:
|
|
12
|
+
* derive the fact, never keep a second copy of it.
|
|
13
|
+
*
|
|
14
|
+
* Three callers want this. The console draws it, the CLI prints it, and a run
|
|
15
|
+
* reads it to know when it has left its chunk, so it lives where none of them
|
|
16
|
+
* owns it.
|
|
17
|
+
*/
|
|
18
|
+
/**
|
|
19
|
+
* An import of another chunk, by the alias an app declares for its chunks root.
|
|
20
|
+
*
|
|
21
|
+
* Deliberately not a TypeScript parse. The alias is the boundary, so the name
|
|
22
|
+
* after it is the edge — and a scan that cannot be wrong about syntax it does
|
|
23
|
+
* not read is worth more here than one that understands every import form.
|
|
24
|
+
*/
|
|
25
|
+
const EDGE = /@chunks\/([a-z0-9][a-z0-9-]*)/gi;
|
|
26
|
+
/**
|
|
27
|
+
* Build the graph from a set of chunks and their sources.
|
|
28
|
+
*
|
|
29
|
+
* Pure, so it can be tested against a real app's shape without a network, and
|
|
30
|
+
* so the expensive half — fetching the sources — is somebody else's problem.
|
|
31
|
+
* An edge to a chunk that is not in the set is dropped: an app importing
|
|
32
|
+
* something it does not have is a broken app, not an extra node.
|
|
33
|
+
*/
|
|
34
|
+
export function chunkGraph(sources) {
|
|
35
|
+
const names = new Set(sources.map((s) => s.name));
|
|
36
|
+
const out = new Map();
|
|
37
|
+
for (const { name, files } of sources) {
|
|
38
|
+
const found = new Set();
|
|
39
|
+
for (const text of files) {
|
|
40
|
+
for (const [, to] of text.matchAll(EDGE)) {
|
|
41
|
+
const chunk = to.toLowerCase();
|
|
42
|
+
// A chunk importing itself is a file next door, not an edge.
|
|
43
|
+
if (chunk !== name && names.has(chunk))
|
|
44
|
+
found.add(chunk);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
out.set(name, found);
|
|
48
|
+
}
|
|
49
|
+
const into = new Map([...names].map((n) => [n, new Set()]));
|
|
50
|
+
for (const [from, tos] of out) {
|
|
51
|
+
for (const to of tos)
|
|
52
|
+
into.get(to).add(from);
|
|
53
|
+
}
|
|
54
|
+
const chunks = [...names].sort().map((name) => ({
|
|
55
|
+
name,
|
|
56
|
+
dependsOn: [...out.get(name)].sort(),
|
|
57
|
+
dependedOnBy: [...into.get(name)].sort(),
|
|
58
|
+
blastRadius: [...reach(name, into)].sort(),
|
|
59
|
+
}));
|
|
60
|
+
const cycles = [];
|
|
61
|
+
for (const [a, tos] of out) {
|
|
62
|
+
for (const b of tos) {
|
|
63
|
+
if (a < b && out.get(b)?.has(a))
|
|
64
|
+
cycles.push([a, b]);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
cycles.sort(([a], [b]) => a.localeCompare(b));
|
|
68
|
+
return { chunks, cycles };
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Everything reachable by following dependents, excluding the start.
|
|
72
|
+
*
|
|
73
|
+
* Iterative rather than recursive because the graphs that most need this are
|
|
74
|
+
* the ones with cycles, and a cycle is where a naive recursion does not come
|
|
75
|
+
* back.
|
|
76
|
+
*/
|
|
77
|
+
function reach(start, into) {
|
|
78
|
+
const seen = new Set();
|
|
79
|
+
const stack = [start];
|
|
80
|
+
while (stack.length) {
|
|
81
|
+
for (const up of into.get(stack.pop()) ?? []) {
|
|
82
|
+
if (up !== start && !seen.has(up)) {
|
|
83
|
+
seen.add(up);
|
|
84
|
+
stack.push(up);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return seen;
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=graph.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph.js","sourceRoot":"","sources":["../../src/admin/graph.ts"],"names":[],"mappings":"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"}
|
package/dist/admin/index.d.ts
CHANGED
|
@@ -28,6 +28,7 @@ export * from "./appkeys.ts";
|
|
|
28
28
|
export * from "./runs.ts";
|
|
29
29
|
export * from "./entrypoints.ts";
|
|
30
30
|
export * from "./chunks.ts";
|
|
31
|
+
export * from "./graph.ts";
|
|
31
32
|
export * from "./services/github.ts";
|
|
32
33
|
export * from "./services/vercel.ts";
|
|
33
34
|
export * from "./services/neon.ts";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,cAAc,wBAAwB,CAAC;AACvC,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,cAAc,wBAAwB,CAAC;AACvC,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAG3B,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC"}
|
package/dist/admin/index.js
CHANGED
|
@@ -28,6 +28,7 @@ export * from "./appkeys.js";
|
|
|
28
28
|
export * from "./runs.js";
|
|
29
29
|
export * from "./entrypoints.js";
|
|
30
30
|
export * from "./chunks.js";
|
|
31
|
+
export * from "./graph.js";
|
|
31
32
|
// One file per service, matching the registry.
|
|
32
33
|
export * from "./services/github.js";
|
|
33
34
|
export * from "./services/vercel.js";
|
package/dist/admin/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,cAAc,wBAAwB,CAAC;AACvC,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/admin/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,cAAc,wBAAwB,CAAC;AACvC,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,YAAY,CAAC;AAC3B,cAAc,UAAU,CAAC;AACzB,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAE3B,+CAA+C;AAC/C,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,0BAA0B,CAAC;AACzC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,yBAAyB,CAAC"}
|