@graphty/layout 1.2.3 → 1.2.5
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/src/algorithms/index.d.ts +5 -0
- package/dist/src/algorithms/index.js +6 -0
- package/dist/src/algorithms/index.js.map +1 -0
- package/dist/src/algorithms/optimization/index.d.ts +7 -0
- package/dist/src/algorithms/optimization/index.js +7 -0
- package/dist/src/algorithms/optimization/index.js.map +1 -0
- package/dist/src/algorithms/optimization/kamada-kawai-solver.d.ts +32 -0
- package/dist/src/algorithms/optimization/kamada-kawai-solver.js +176 -0
- package/dist/src/algorithms/optimization/kamada-kawai-solver.js.map +1 -0
- package/dist/src/algorithms/optimization/lbfgs.d.ts +13 -0
- package/dist/src/algorithms/optimization/lbfgs.js +56 -0
- package/dist/src/algorithms/optimization/lbfgs.js.map +1 -0
- package/dist/src/algorithms/optimization/line-search.d.ts +15 -0
- package/dist/src/algorithms/optimization/line-search.js +37 -0
- package/dist/src/algorithms/optimization/line-search.js.map +1 -0
- package/dist/src/algorithms/optimization/types.d.ts +5 -0
- package/dist/src/algorithms/optimization/types.js +5 -0
- package/dist/src/algorithms/optimization/types.js.map +1 -0
- package/dist/src/algorithms/planarity/check.d.ts +17 -0
- package/dist/src/algorithms/planarity/check.js +30 -0
- package/dist/src/algorithms/planarity/check.js.map +1 -0
- package/dist/src/algorithms/planarity/embedding.d.ts +29 -0
- package/dist/src/algorithms/planarity/embedding.js +179 -0
- package/dist/src/algorithms/planarity/embedding.js.map +1 -0
- package/dist/src/algorithms/planarity/index.d.ts +7 -0
- package/dist/src/algorithms/planarity/index.js +8 -0
- package/dist/src/algorithms/planarity/index.js.map +1 -0
- package/dist/src/algorithms/planarity/lr-test.d.ts +15 -0
- package/dist/src/algorithms/planarity/lr-test.js +54 -0
- package/dist/src/algorithms/planarity/lr-test.js.map +1 -0
- package/dist/src/algorithms/planarity/special-graphs.d.ts +28 -0
- package/dist/src/algorithms/planarity/special-graphs.js +108 -0
- package/dist/src/algorithms/planarity/special-graphs.js.map +1 -0
- package/dist/src/generators/basic.d.ts +28 -0
- package/dist/src/generators/basic.js +79 -0
- package/dist/src/generators/basic.js.map +1 -0
- package/dist/src/generators/bipartite.d.ts +16 -0
- package/dist/src/generators/bipartite.js +40 -0
- package/dist/src/generators/bipartite.js.map +1 -0
- package/dist/src/generators/grid.d.ts +11 -0
- package/dist/src/generators/grid.js +37 -0
- package/dist/src/generators/grid.js.map +1 -0
- package/dist/src/generators/index.d.ts +8 -0
- package/dist/src/generators/index.js +9 -0
- package/dist/src/generators/index.js.map +1 -0
- package/dist/src/generators/random.d.ts +12 -0
- package/dist/src/generators/random.js +34 -0
- package/dist/src/generators/random.js.map +1 -0
- package/dist/src/generators/scale-free.d.ts +12 -0
- package/dist/src/generators/scale-free.js +62 -0
- package/dist/src/generators/scale-free.js.map +1 -0
- package/dist/src/index.d.ts +10 -0
- package/dist/src/index.js +15 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/layouts/basic/index.d.ts +4 -0
- package/dist/src/layouts/basic/index.js +5 -0
- package/dist/src/layouts/basic/index.js.map +1 -0
- package/dist/src/layouts/basic/random.d.ts +14 -0
- package/dist/src/layouts/basic/random.js +27 -0
- package/dist/src/layouts/basic/random.js.map +1 -0
- package/dist/src/layouts/force-directed/arf.d.ts +13 -0
- package/dist/src/layouts/force-directed/arf.js +103 -0
- package/dist/src/layouts/force-directed/arf.js.map +1 -0
- package/dist/src/layouts/force-directed/forceatlas2.d.ts +22 -0
- package/dist/src/layouts/force-directed/forceatlas2.js +340 -0
- package/dist/src/layouts/force-directed/forceatlas2.js.map +1 -0
- package/dist/src/layouts/force-directed/fruchterman-reingold.d.ts +19 -0
- package/dist/src/layouts/force-directed/fruchterman-reingold.js +131 -0
- package/dist/src/layouts/force-directed/fruchterman-reingold.js.map +1 -0
- package/dist/src/layouts/force-directed/index.d.ts +8 -0
- package/dist/src/layouts/force-directed/index.js +9 -0
- package/dist/src/layouts/force-directed/index.js.map +1 -0
- package/dist/src/layouts/force-directed/kamada-kawai.d.ts +15 -0
- package/dist/src/layouts/force-directed/kamada-kawai.js +87 -0
- package/dist/src/layouts/force-directed/kamada-kawai.js.map +1 -0
- package/dist/src/layouts/force-directed/spring.d.ts +19 -0
- package/dist/src/layouts/force-directed/spring.js +23 -0
- package/dist/src/layouts/force-directed/spring.js.map +1 -0
- package/dist/src/layouts/geometric/circular.d.ts +14 -0
- package/dist/src/layouts/geometric/circular.js +67 -0
- package/dist/src/layouts/geometric/circular.js.map +1 -0
- package/dist/src/layouts/geometric/index.d.ts +6 -0
- package/dist/src/layouts/geometric/index.js +7 -0
- package/dist/src/layouts/geometric/index.js.map +1 -0
- package/dist/src/layouts/geometric/shell.d.ts +15 -0
- package/dist/src/layouts/geometric/shell.js +67 -0
- package/dist/src/layouts/geometric/shell.js.map +1 -0
- package/dist/src/layouts/geometric/spiral.d.ts +16 -0
- package/dist/src/layouts/geometric/spiral.js +73 -0
- package/dist/src/layouts/geometric/spiral.js.map +1 -0
- package/dist/src/layouts/hierarchical/bfs.d.ts +12 -0
- package/dist/src/layouts/hierarchical/bfs.js +62 -0
- package/dist/src/layouts/hierarchical/bfs.js.map +1 -0
- package/dist/src/layouts/hierarchical/bipartite.d.ts +16 -0
- package/dist/src/layouts/hierarchical/bipartite.js +72 -0
- package/dist/src/layouts/hierarchical/bipartite.js.map +1 -0
- package/dist/src/layouts/hierarchical/index.d.ts +6 -0
- package/dist/src/layouts/hierarchical/index.js +7 -0
- package/dist/src/layouts/hierarchical/index.js.map +1 -0
- package/dist/src/layouts/hierarchical/multipartite.d.ts +12 -0
- package/dist/src/layouts/hierarchical/multipartite.js +73 -0
- package/dist/src/layouts/hierarchical/multipartite.js.map +1 -0
- package/dist/src/layouts/index.d.ts +8 -0
- package/dist/src/layouts/index.js +9 -0
- package/dist/src/layouts/index.js.map +1 -0
- package/dist/src/layouts/specialized/index.d.ts +5 -0
- package/dist/src/layouts/specialized/index.js +6 -0
- package/dist/src/layouts/specialized/index.js.map +1 -0
- package/dist/src/layouts/specialized/planar.d.ts +14 -0
- package/dist/src/layouts/specialized/planar.js +47 -0
- package/dist/src/layouts/specialized/planar.js.map +1 -0
- package/dist/src/layouts/specialized/spectral.d.ts +14 -0
- package/dist/src/layouts/specialized/spectral.js +106 -0
- package/dist/src/layouts/specialized/spectral.js.map +1 -0
- package/dist/src/types/embedding.d.ts +9 -0
- package/dist/src/types/embedding.js +5 -0
- package/dist/src/types/embedding.js.map +1 -0
- package/dist/src/types/graph.d.ts +10 -0
- package/dist/src/types/graph.js +5 -0
- package/dist/src/types/graph.js.map +1 -0
- package/dist/src/types/index.d.ts +6 -0
- package/dist/src/types/index.js +7 -0
- package/dist/src/types/index.js.map +1 -0
- package/dist/src/types/layout.d.ts +6 -0
- package/dist/src/types/layout.js +5 -0
- package/dist/src/types/layout.js.map +1 -0
- package/dist/src/utils/graph.d.ts +34 -0
- package/dist/src/utils/graph.js +69 -0
- package/dist/src/utils/graph.js.map +1 -0
- package/dist/src/utils/index.d.ts +8 -0
- package/dist/src/utils/index.js +9 -0
- package/dist/src/utils/index.js.map +1 -0
- package/dist/src/utils/numpy.d.ts +17 -0
- package/dist/src/utils/numpy.js +101 -0
- package/dist/src/utils/numpy.js.map +1 -0
- package/dist/src/utils/params.d.ts +17 -0
- package/dist/src/utils/params.js +22 -0
- package/dist/src/utils/params.js.map +1 -0
- package/dist/src/utils/random.d.ts +14 -0
- package/dist/src/utils/random.js +42 -0
- package/dist/src/utils/random.js.map +1 -0
- package/dist/src/utils/rescale.d.ts +21 -0
- package/dist/src/utils/rescale.js +194 -0
- package/dist/src/utils/rescale.js.map +1 -0
- package/dist/vitest.config.js +1 -1
- package/dist/vitest.config.js.map +1 -1
- package/package.json +19 -4
- package/src/layouts/force-directed/forceatlas2.ts +23 -4
- package/src/utils/rescale.ts +90 -15
- package/.env.example +0 -11
- package/.github/workflows/ci.yml +0 -101
- package/.releaserc.json +0 -22
- package/CHANGELOG.md +0 -52
- package/CLAUDE.md +0 -104
- package/CONTRIBUTING.md +0 -1
- package/DEPLOYMENT.md +0 -59
- package/build-examples-script.js +0 -26
- package/commitlint.config.js +0 -37
- package/examples/3d-force-directed.html +0 -611
- package/examples/3d-kamada-kawai.html +0 -379
- package/examples/3d-layout-comparison.html +0 -448
- package/examples/3d-spherical-layout.html +0 -319
- package/examples/arf-layout.html +0 -524
- package/examples/bfs-layout.html +0 -487
- package/examples/bipartite-layout.html +0 -382
- package/examples/circular-layout.html +0 -292
- package/examples/forceatlas2-layout.html +0 -588
- package/examples/index.html +0 -241
- package/examples/kamada-kawai-layout.html +0 -425
- package/examples/layout-helpers.js +0 -23
- package/examples/layout.js +0 -2304
- package/examples/multipartite-layout.html +0 -410
- package/examples/planar-layout.html +0 -388
- package/examples/random-layout.html +0 -328
- package/examples/shell-layout.html +0 -323
- package/examples/spectral-layout.html +0 -335
- package/examples/spiral-layout.html +0 -447
- package/examples/spring-layout.html +0 -313
- package/test/arf-layout.test.ts +0 -443
- package/test/bfs-layout.test.ts +0 -427
- package/test/bipartite-layout.test.ts +0 -344
- package/test/circular-layout.test.ts +0 -442
- package/test/forceatlas2-layout.test.ts +0 -405
- package/test/fruchterman-reingold-layout.test.ts +0 -477
- package/test/graph-generators.test.ts +0 -450
- package/test/kamada-kawai-layout.test.ts +0 -623
- package/test/multipartite-layout.test.ts +0 -404
- package/test/planar-layout.test.ts +0 -266
- package/test/random-layout.test.ts +0 -254
- package/test/rescale-layout.test.ts +0 -373
- package/test/shell-layout.test.ts +0 -347
- package/test/spectral-layout.test.ts +0 -378
- package/test/spiral-layout.test.ts +0 -338
- package/test/spring-layout.test.ts +0 -241
- package/test/test-utils.ts +0 -34
- package/test/utils-graph.test.ts +0 -155
- package/test/utils-index.test.ts +0 -77
- package/test/utils-numpy.test.ts +0 -272
- package/test/utils-params.test.ts +0 -99
- package/test/utils-random.test.ts +0 -229
- package/tsconfig.json +0 -16
- package/vite.config.js +0 -36
- package/vitest.config.ts +0 -30
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Random number generator for seed-based randomization
|
|
3
|
+
* Maintains exact same functionality as original implementation
|
|
4
|
+
*/
|
|
5
|
+
export declare class RandomNumberGenerator {
|
|
6
|
+
private seed;
|
|
7
|
+
private m;
|
|
8
|
+
private a;
|
|
9
|
+
private c;
|
|
10
|
+
private _state;
|
|
11
|
+
constructor(seed?: number);
|
|
12
|
+
_next(): number;
|
|
13
|
+
rand(shape?: number | number[] | null): number | number[] | number[][];
|
|
14
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Random number generator for seed-based randomization
|
|
3
|
+
* Maintains exact same functionality as original implementation
|
|
4
|
+
*/
|
|
5
|
+
export class RandomNumberGenerator {
|
|
6
|
+
constructor(seed) {
|
|
7
|
+
this.seed = seed || Math.floor(Math.random() * 1000000);
|
|
8
|
+
this.m = 2 ** 35 - 31;
|
|
9
|
+
this.a = 185852;
|
|
10
|
+
this.c = 1;
|
|
11
|
+
this._state = this.seed % this.m;
|
|
12
|
+
}
|
|
13
|
+
_next() {
|
|
14
|
+
this._state = (this.a * this._state + this.c) % this.m;
|
|
15
|
+
return this._state / this.m;
|
|
16
|
+
}
|
|
17
|
+
rand(shape = null) {
|
|
18
|
+
if (shape === null) {
|
|
19
|
+
return this._next();
|
|
20
|
+
}
|
|
21
|
+
if (typeof shape === 'number') {
|
|
22
|
+
const result = [];
|
|
23
|
+
for (let i = 0; i < shape; i++) {
|
|
24
|
+
result.push(this._next());
|
|
25
|
+
}
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
if (shape.length === 1) {
|
|
29
|
+
const result = [];
|
|
30
|
+
for (let i = 0; i < shape[0]; i++) {
|
|
31
|
+
result.push(this._next());
|
|
32
|
+
}
|
|
33
|
+
return result;
|
|
34
|
+
}
|
|
35
|
+
const result = [];
|
|
36
|
+
for (let i = 0; i < shape[0]; i++) {
|
|
37
|
+
result.push(this.rand(shape.slice(1)));
|
|
38
|
+
}
|
|
39
|
+
return result;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=random.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"random.js","sourceRoot":"","sources":["../../../src/utils/random.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,OAAO,qBAAqB;IAOhC,YAAY,IAAa;QACvB,IAAI,CAAC,IAAI,GAAG,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC;QACxD,IAAI,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,EAAE,CAAC;QACtB,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC;QAChB,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;QACX,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC;IACnC,CAAC;IAED,KAAK;QACH,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;QACvD,OAAO,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC;IAC9B,CAAC;IAED,IAAI,CAAC,QAAkC,IAAI;QACzC,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACnB,OAAO,IAAI,CAAC,KAAK,EAAE,CAAC;QACtB,CAAC;QAED,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,MAAM,MAAM,GAAa,EAAE,CAAC;YAC5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC/B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;YAC5B,CAAC;YACD,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,MAAM,MAAM,GAAa,EAAE,CAAC;YAC5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBAClC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;YAC5B,CAAC;YACD,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,MAAM,MAAM,GAAU,EAAE,CAAC;QACzB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAClC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACzC,CAAC;QACD,OAAO,MAAM,CAAC;IAChB,CAAC;CACF"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layout rescaling utilities
|
|
3
|
+
*/
|
|
4
|
+
import { PositionMap } from '../types';
|
|
5
|
+
/**
|
|
6
|
+
* Returns scaled position array/dict to (-scale, scale) in all axes.
|
|
7
|
+
*
|
|
8
|
+
* @param pos - Position dictionary or array
|
|
9
|
+
* @param scale - Scale factor for positions
|
|
10
|
+
* @param center - Coordinate pair around which to center the layout
|
|
11
|
+
* @returns Rescaled positions dictionary
|
|
12
|
+
*/
|
|
13
|
+
export declare function rescaleLayout(pos: PositionMap | number[][], scale?: number, center?: number[] | null): PositionMap | number[][];
|
|
14
|
+
/**
|
|
15
|
+
* Return a dictionary of scaled positions centered at (0, 0).
|
|
16
|
+
*
|
|
17
|
+
* @param pos - Dictionary of positions
|
|
18
|
+
* @param scale - Scale factor for positions
|
|
19
|
+
* @returns Dictionary of scaled positions
|
|
20
|
+
*/
|
|
21
|
+
export declare function rescaleLayoutDict(pos: PositionMap, scale?: number): PositionMap;
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layout rescaling utilities
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Returns scaled position array/dict to (-scale, scale) in all axes.
|
|
6
|
+
*
|
|
7
|
+
* @param pos - Position dictionary or array
|
|
8
|
+
* @param scale - Scale factor for positions
|
|
9
|
+
* @param center - Coordinate pair around which to center the layout
|
|
10
|
+
* @returns Rescaled positions dictionary
|
|
11
|
+
*/
|
|
12
|
+
export function rescaleLayout(pos, scale = 1, center = null) {
|
|
13
|
+
// Check if pos is empty
|
|
14
|
+
if (Array.isArray(pos)) {
|
|
15
|
+
if (pos.length === 0)
|
|
16
|
+
return [];
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
if (Object.keys(pos).length === 0)
|
|
20
|
+
return {};
|
|
21
|
+
}
|
|
22
|
+
// Extract position values
|
|
23
|
+
const posValues = Array.isArray(pos) ? pos : Object.values(pos);
|
|
24
|
+
const dim = posValues[0].length;
|
|
25
|
+
// Fix Bug #1: Default center should match dimensionality
|
|
26
|
+
if (!center) {
|
|
27
|
+
center = Array(dim).fill(0);
|
|
28
|
+
}
|
|
29
|
+
// Use the maximum dimension between positions and center
|
|
30
|
+
const targetDim = Math.max(dim, center.length);
|
|
31
|
+
// Calculate center of positions, handling NaN values (Bug #3)
|
|
32
|
+
const posCenter = Array(dim).fill(0);
|
|
33
|
+
const counts = Array(dim).fill(0);
|
|
34
|
+
for (const p of posValues) {
|
|
35
|
+
for (let i = 0; i < dim; i++) {
|
|
36
|
+
if (!isNaN(p[i])) {
|
|
37
|
+
posCenter[i] += p[i];
|
|
38
|
+
counts[i]++;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
// Average by actual count, not total length
|
|
43
|
+
for (let i = 0; i < dim; i++) {
|
|
44
|
+
posCenter[i] = counts[i] > 0 ? posCenter[i] / counts[i] : 0;
|
|
45
|
+
}
|
|
46
|
+
// Center positions
|
|
47
|
+
let centeredPos = {};
|
|
48
|
+
if (Array.isArray(pos)) {
|
|
49
|
+
centeredPos = pos.map(p => {
|
|
50
|
+
const centered = Array(targetDim).fill(0);
|
|
51
|
+
for (let i = 0; i < targetDim; i++) {
|
|
52
|
+
centered[i] = (i < p.length ? p[i] : 0) - (i < posCenter.length ? posCenter[i] : 0);
|
|
53
|
+
}
|
|
54
|
+
return centered;
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
for (const [node, p] of Object.entries(pos)) {
|
|
59
|
+
const centered = Array(targetDim).fill(0);
|
|
60
|
+
for (let i = 0; i < targetDim; i++) {
|
|
61
|
+
centered[i] = (i < p.length ? p[i] : 0) - (i < posCenter.length ? posCenter[i] : 0);
|
|
62
|
+
}
|
|
63
|
+
centeredPos[node] = centered;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
// Find maximum distance from center, handling NaN values (Bug #3)
|
|
67
|
+
let maxDistance = 0;
|
|
68
|
+
const centeredValues = Array.isArray(centeredPos) ? centeredPos : Object.values(centeredPos);
|
|
69
|
+
for (const p of centeredValues) {
|
|
70
|
+
// Calculate distance, treating NaN as 0 for distance calculation
|
|
71
|
+
let sumSquares = 0;
|
|
72
|
+
for (const val of p) {
|
|
73
|
+
if (!isNaN(val)) {
|
|
74
|
+
sumSquares += val * val;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const distance = Math.sqrt(sumSquares);
|
|
78
|
+
if (!isNaN(distance)) {
|
|
79
|
+
maxDistance = Math.max(maxDistance, distance);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Rescale
|
|
83
|
+
let scaledPos = Array.isArray(pos) ? [] : {};
|
|
84
|
+
if (maxDistance > 0) {
|
|
85
|
+
const scaleFactor = scale / maxDistance;
|
|
86
|
+
if (Array.isArray(pos)) {
|
|
87
|
+
scaledPos = centeredPos.map((p, idx) => p.map((val, i) => {
|
|
88
|
+
// Check if this dimension existed in the original position
|
|
89
|
+
const origPos = pos[idx];
|
|
90
|
+
if (i >= origPos.length) {
|
|
91
|
+
// This dimension was added, use center value
|
|
92
|
+
return center[i];
|
|
93
|
+
}
|
|
94
|
+
// Preserve NaN values (Bug #3)
|
|
95
|
+
if (isNaN(val))
|
|
96
|
+
return NaN;
|
|
97
|
+
return val * scaleFactor + center[i];
|
|
98
|
+
}));
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
for (const [node, p] of Object.entries(centeredPos)) {
|
|
102
|
+
const origPos = pos[node];
|
|
103
|
+
scaledPos[node] = p.map((val, i) => {
|
|
104
|
+
// Check if this dimension existed in the original position
|
|
105
|
+
if (i >= origPos.length) {
|
|
106
|
+
// This dimension was added, use center value
|
|
107
|
+
return center[i];
|
|
108
|
+
}
|
|
109
|
+
// Preserve NaN values (Bug #3)
|
|
110
|
+
if (isNaN(val))
|
|
111
|
+
return NaN;
|
|
112
|
+
return val * scaleFactor + center[i];
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
// All nodes at the same position - extend to target dimensionality
|
|
119
|
+
if (Array.isArray(pos)) {
|
|
120
|
+
scaledPos = pos.map(p => {
|
|
121
|
+
const result = Array(targetDim);
|
|
122
|
+
for (let i = 0; i < targetDim; i++) {
|
|
123
|
+
if (i < p.length) {
|
|
124
|
+
result[i] = isNaN(p[i]) ? NaN : center[i];
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
result[i] = center[i];
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return result;
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
for (const [node, p] of Object.entries(pos)) {
|
|
135
|
+
const result = Array(targetDim);
|
|
136
|
+
for (let i = 0; i < targetDim; i++) {
|
|
137
|
+
if (i < p.length) {
|
|
138
|
+
result[i] = isNaN(p[i]) ? NaN : center[i];
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
result[i] = center[i];
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
scaledPos[node] = result;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return scaledPos;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Return a dictionary of scaled positions centered at (0, 0).
|
|
152
|
+
*
|
|
153
|
+
* @param pos - Dictionary of positions
|
|
154
|
+
* @param scale - Scale factor for positions
|
|
155
|
+
* @returns Dictionary of scaled positions
|
|
156
|
+
*/
|
|
157
|
+
export function rescaleLayoutDict(pos, scale = 1) {
|
|
158
|
+
if (Object.keys(pos).length === 0) {
|
|
159
|
+
return {};
|
|
160
|
+
}
|
|
161
|
+
// Extract positions as array
|
|
162
|
+
const posArray = Object.values(pos);
|
|
163
|
+
// Find center of positions
|
|
164
|
+
const center = [];
|
|
165
|
+
for (let d = 0; d < posArray[0].length; d++) {
|
|
166
|
+
center[d] = posArray.reduce((sum, p) => sum + p[d], 0) / posArray.length;
|
|
167
|
+
}
|
|
168
|
+
// Center positions
|
|
169
|
+
const centeredPos = {};
|
|
170
|
+
for (const [node, p] of Object.entries(pos)) {
|
|
171
|
+
centeredPos[node] = p.map((val, d) => val - center[d]);
|
|
172
|
+
}
|
|
173
|
+
// Find maximum distance from center
|
|
174
|
+
let maxDist = 0;
|
|
175
|
+
for (const p of Object.values(centeredPos)) {
|
|
176
|
+
const dist = Math.sqrt(p.reduce((sum, val) => sum + val * val, 0));
|
|
177
|
+
maxDist = Math.max(maxDist, dist);
|
|
178
|
+
}
|
|
179
|
+
// Scale positions
|
|
180
|
+
const scaledPos = {};
|
|
181
|
+
if (maxDist > 0) {
|
|
182
|
+
for (const [node, p] of Object.entries(centeredPos)) {
|
|
183
|
+
scaledPos[node] = p.map(val => val * scale / maxDist);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
// All points at the center
|
|
188
|
+
for (const node of Object.keys(centeredPos)) {
|
|
189
|
+
scaledPos[node] = Array(centeredPos[node].length).fill(0);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
return scaledPos;
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=rescale.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rescale.js","sourceRoot":"","sources":["../../../src/utils/rescale.ts"],"names":[],"mappings":"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"}
|
package/dist/vitest.config.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vitest.config.js","sourceRoot":"","sources":["../vitest.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C,eAAe,YAAY,CAAC;IAC1B,IAAI,EAAE;QACJ,OAAO,EAAE,IAAI;QACb,WAAW,EAAE,WAAW;QACxB,IAAI,EAAE,OAAO;QACb,WAAW,EAAE,KAAK;QAClB,QAAQ,EAAE;YACR,QAAQ,EAAE,IAAI;YACd,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;YAC1C,OAAO,EAAE,CAAC,aAAa,CAAC;YACxB,OAAO,EAAE,CAAC,WAAW,EAAE,cAAc,CAAC;YACtC,GAAG,EAAE,IAAI;YACT,UAAU,EAAE;gBACV,KAAK,EAAE,EAAE;gBACT,SAAS,EAAE,EAAE;gBACb,QAAQ,EAAE,EAAE;gBACZ,UAAU,EAAE,EAAE;aACf;SACF;QACD,OAAO,EAAE,CAAC,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"vitest.config.js","sourceRoot":"","sources":["../vitest.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C,eAAe,YAAY,CAAC;IAC1B,IAAI,EAAE;QACJ,OAAO,EAAE,IAAI;QACb,WAAW,EAAE,WAAW;QACxB,IAAI,EAAE,OAAO;QACb,WAAW,EAAE,KAAK;QAClB,QAAQ,EAAE;YACR,QAAQ,EAAE,IAAI;YACd,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;YAC1C,OAAO,EAAE,CAAC,aAAa,CAAC;YACxB,OAAO,EAAE,CAAC,WAAW,EAAE,cAAc,CAAC;YACtC,GAAG,EAAE,IAAI;YACT,UAAU,EAAE;gBACV,KAAK,EAAE,EAAE;gBACT,SAAS,EAAE,EAAE;gBACb,QAAQ,EAAE,EAAE;gBACZ,UAAU,EAAE,EAAE;aACf;SACF;QACD,OAAO,EAAE,CAAC,mBAAmB,EAAE,mBAAmB,CAAC;QACnD,SAAS,EAAE,CAAC,SAAS,CAAC;KACvB;IACD,OAAO,EAAE;QACP,KAAK,EAAE;YACL,GAAG,EAAE,MAAM;SACZ;KACF;CACF,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@graphty/layout",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.5",
|
|
4
4
|
"description": "graph layout algorithms based on networkx",
|
|
5
5
|
"author": "Adam Powers <apowers@ato.ms>",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
7
7
|
"type": "module",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/src/index.js",
|
|
11
|
+
"types": "./dist/src/index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"types": "dist/src/index.d.ts",
|
|
15
|
+
"files": [
|
|
16
|
+
"dist/",
|
|
17
|
+
"src/",
|
|
18
|
+
"README.md",
|
|
19
|
+
"LICENSE"
|
|
20
|
+
],
|
|
8
21
|
"directories": {
|
|
9
22
|
"example": "examples"
|
|
10
23
|
},
|
|
@@ -15,12 +28,13 @@
|
|
|
15
28
|
"test:coverage": "vitest run --coverage",
|
|
16
29
|
"prepare": "husky",
|
|
17
30
|
"build": "tsc",
|
|
18
|
-
"build:
|
|
31
|
+
"build:bundle": "node scripts/build-bundle.js",
|
|
32
|
+
"build:all": "npm run build && npm run build:bundle",
|
|
19
33
|
"watch": "tsc --watch",
|
|
20
34
|
"dev": "tsc --watch",
|
|
21
35
|
"commit": "cz",
|
|
22
|
-
"serve": "npm run build:
|
|
23
|
-
"examples": "npm run build:
|
|
36
|
+
"serve": "npm run build:bundle && vite",
|
|
37
|
+
"examples": "npm run build:bundle && vite"
|
|
24
38
|
},
|
|
25
39
|
"repository": {
|
|
26
40
|
"type": "git",
|
|
@@ -54,6 +68,7 @@
|
|
|
54
68
|
"husky": "^9.1.7",
|
|
55
69
|
"semantic-release": "^24.2.7",
|
|
56
70
|
"typescript": "^5.3.3",
|
|
71
|
+
"vite": "^7.0.5",
|
|
57
72
|
"vitest": "^3.2.4"
|
|
58
73
|
}
|
|
59
74
|
}
|
|
@@ -66,7 +66,11 @@ export function forceatlas2Layout(
|
|
|
66
66
|
// Use provided positions
|
|
67
67
|
posArray = new Array(nodes.length);
|
|
68
68
|
for (let i = 0; i < nodes.length; i++) {
|
|
69
|
-
|
|
69
|
+
const nodePos = pos[nodes[i]];
|
|
70
|
+
posArray[i] = new Array(dim);
|
|
71
|
+
for (let d = 0; d < dim; d++) {
|
|
72
|
+
posArray[i][d] = d < nodePos.length ? nodePos[d] : (rng.rand() as number * 2 - 1);
|
|
73
|
+
}
|
|
70
74
|
}
|
|
71
75
|
} else {
|
|
72
76
|
// Some nodes don't have positions, initialize within the range of existing positions
|
|
@@ -75,9 +79,20 @@ export function forceatlas2Layout(
|
|
|
75
79
|
|
|
76
80
|
// Find min and max of existing positions
|
|
77
81
|
for (const node in pos) {
|
|
82
|
+
const nodePos = pos[node];
|
|
78
83
|
for (let d = 0; d < dim; d++) {
|
|
79
|
-
|
|
80
|
-
|
|
84
|
+
if (d < nodePos.length) {
|
|
85
|
+
minPos[d] = Math.min(minPos[d], nodePos[d]);
|
|
86
|
+
maxPos[d] = Math.max(maxPos[d], nodePos[d]);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// If min/max are still infinity for some dimensions, use default range
|
|
92
|
+
for (let d = 0; d < dim; d++) {
|
|
93
|
+
if (!isFinite(minPos[d]) || !isFinite(maxPos[d])) {
|
|
94
|
+
minPos[d] = -1;
|
|
95
|
+
maxPos[d] = 1;
|
|
81
96
|
}
|
|
82
97
|
}
|
|
83
98
|
|
|
@@ -85,7 +100,11 @@ export function forceatlas2Layout(
|
|
|
85
100
|
for (let i = 0; i < nodes.length; i++) {
|
|
86
101
|
const node = nodes[i];
|
|
87
102
|
if (pos[node]) {
|
|
88
|
-
|
|
103
|
+
const nodePos = pos[node];
|
|
104
|
+
posArray[i] = new Array(dim);
|
|
105
|
+
for (let d = 0; d < dim; d++) {
|
|
106
|
+
posArray[i][d] = d < nodePos.length ? nodePos[d] : (rng.rand() as number * 2 - 1);
|
|
107
|
+
}
|
|
89
108
|
} else {
|
|
90
109
|
posArray[i] = Array(dim).fill(0).map((_, d) =>
|
|
91
110
|
minPos[d] + (rng.rand() as number) * (maxPos[d] - minPos[d])
|
package/src/utils/rescale.ts
CHANGED
|
@@ -15,7 +15,7 @@ import { PositionMap } from '../types';
|
|
|
15
15
|
export function rescaleLayout(
|
|
16
16
|
pos: PositionMap | number[][],
|
|
17
17
|
scale: number = 1,
|
|
18
|
-
center: number[] =
|
|
18
|
+
center: number[] | null = null
|
|
19
19
|
): PositionMap | number[][] {
|
|
20
20
|
// Check if pos is empty
|
|
21
21
|
if (Array.isArray(pos)) {
|
|
@@ -28,30 +28,67 @@ export function rescaleLayout(
|
|
|
28
28
|
const posValues: number[][] = Array.isArray(pos) ? pos : Object.values(pos);
|
|
29
29
|
const dim = posValues[0].length;
|
|
30
30
|
|
|
31
|
-
//
|
|
31
|
+
// Fix Bug #1: Default center should match dimensionality
|
|
32
|
+
if (!center) {
|
|
33
|
+
center = Array(dim).fill(0);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Use the maximum dimension between positions and center
|
|
37
|
+
const targetDim = Math.max(dim, center.length);
|
|
38
|
+
|
|
39
|
+
// Calculate center of positions, handling NaN values (Bug #3)
|
|
32
40
|
const posCenter = Array(dim).fill(0);
|
|
41
|
+
const counts = Array(dim).fill(0);
|
|
42
|
+
|
|
33
43
|
for (const p of posValues) {
|
|
34
44
|
for (let i = 0; i < dim; i++) {
|
|
35
|
-
|
|
45
|
+
if (!isNaN(p[i])) {
|
|
46
|
+
posCenter[i] += p[i];
|
|
47
|
+
counts[i]++;
|
|
48
|
+
}
|
|
36
49
|
}
|
|
37
50
|
}
|
|
51
|
+
|
|
52
|
+
// Average by actual count, not total length
|
|
53
|
+
for (let i = 0; i < dim; i++) {
|
|
54
|
+
posCenter[i] = counts[i] > 0 ? posCenter[i] / counts[i] : 0;
|
|
55
|
+
}
|
|
38
56
|
|
|
39
57
|
// Center positions
|
|
40
58
|
let centeredPos: PositionMap | number[][] = {};
|
|
41
59
|
if (Array.isArray(pos)) {
|
|
42
|
-
centeredPos = pos.map(p =>
|
|
60
|
+
centeredPos = pos.map(p => {
|
|
61
|
+
const centered = Array(targetDim).fill(0);
|
|
62
|
+
for (let i = 0; i < targetDim; i++) {
|
|
63
|
+
centered[i] = (i < p.length ? p[i] : 0) - (i < posCenter.length ? posCenter[i] : 0);
|
|
64
|
+
}
|
|
65
|
+
return centered;
|
|
66
|
+
});
|
|
43
67
|
} else {
|
|
44
68
|
for (const [node, p] of Object.entries(pos)) {
|
|
45
|
-
|
|
69
|
+
const centered = Array(targetDim).fill(0);
|
|
70
|
+
for (let i = 0; i < targetDim; i++) {
|
|
71
|
+
centered[i] = (i < p.length ? p[i] : 0) - (i < posCenter.length ? posCenter[i] : 0);
|
|
72
|
+
}
|
|
73
|
+
(centeredPos as PositionMap)[node] = centered;
|
|
46
74
|
}
|
|
47
75
|
}
|
|
48
76
|
|
|
49
|
-
// Find maximum distance from center
|
|
77
|
+
// Find maximum distance from center, handling NaN values (Bug #3)
|
|
50
78
|
let maxDistance = 0;
|
|
51
79
|
const centeredValues = Array.isArray(centeredPos) ? centeredPos : Object.values(centeredPos);
|
|
52
80
|
for (const p of centeredValues) {
|
|
53
|
-
|
|
54
|
-
|
|
81
|
+
// Calculate distance, treating NaN as 0 for distance calculation
|
|
82
|
+
let sumSquares = 0;
|
|
83
|
+
for (const val of p) {
|
|
84
|
+
if (!isNaN(val)) {
|
|
85
|
+
sumSquares += val * val;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const distance = Math.sqrt(sumSquares);
|
|
89
|
+
if (!isNaN(distance)) {
|
|
90
|
+
maxDistance = Math.max(maxDistance, distance);
|
|
91
|
+
}
|
|
55
92
|
}
|
|
56
93
|
|
|
57
94
|
// Rescale
|
|
@@ -61,21 +98,59 @@ export function rescaleLayout(
|
|
|
61
98
|
const scaleFactor = scale / maxDistance;
|
|
62
99
|
|
|
63
100
|
if (Array.isArray(pos)) {
|
|
64
|
-
(scaledPos as number[][]) = (centeredPos as number[][]).map(p =>
|
|
65
|
-
p.map((val, i) =>
|
|
101
|
+
(scaledPos as number[][]) = (centeredPos as number[][]).map((p, idx) =>
|
|
102
|
+
p.map((val, i) => {
|
|
103
|
+
// Check if this dimension existed in the original position
|
|
104
|
+
const origPos = pos[idx];
|
|
105
|
+
if (i >= origPos.length) {
|
|
106
|
+
// This dimension was added, use center value
|
|
107
|
+
return center![i];
|
|
108
|
+
}
|
|
109
|
+
// Preserve NaN values (Bug #3)
|
|
110
|
+
if (isNaN(val)) return NaN;
|
|
111
|
+
return val * scaleFactor + center![i];
|
|
112
|
+
})
|
|
66
113
|
);
|
|
67
114
|
} else {
|
|
68
115
|
for (const [node, p] of Object.entries(centeredPos as PositionMap)) {
|
|
69
|
-
|
|
116
|
+
const origPos = pos[node];
|
|
117
|
+
(scaledPos as PositionMap)[node] = p.map((val, i) => {
|
|
118
|
+
// Check if this dimension existed in the original position
|
|
119
|
+
if (i >= origPos.length) {
|
|
120
|
+
// This dimension was added, use center value
|
|
121
|
+
return center![i];
|
|
122
|
+
}
|
|
123
|
+
// Preserve NaN values (Bug #3)
|
|
124
|
+
if (isNaN(val)) return NaN;
|
|
125
|
+
return val * scaleFactor + center![i];
|
|
126
|
+
});
|
|
70
127
|
}
|
|
71
128
|
}
|
|
72
129
|
} else {
|
|
73
|
-
// All nodes at the same position
|
|
130
|
+
// All nodes at the same position - extend to target dimensionality
|
|
74
131
|
if (Array.isArray(pos)) {
|
|
75
|
-
(scaledPos as number[][]) =
|
|
132
|
+
(scaledPos as number[][]) = pos.map(p => {
|
|
133
|
+
const result = Array(targetDim);
|
|
134
|
+
for (let i = 0; i < targetDim; i++) {
|
|
135
|
+
if (i < p.length) {
|
|
136
|
+
result[i] = isNaN(p[i]) ? NaN : center![i];
|
|
137
|
+
} else {
|
|
138
|
+
result[i] = center![i];
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return result;
|
|
142
|
+
});
|
|
76
143
|
} else {
|
|
77
|
-
for (const node of Object.
|
|
78
|
-
|
|
144
|
+
for (const [node, p] of Object.entries(pos)) {
|
|
145
|
+
const result = Array(targetDim);
|
|
146
|
+
for (let i = 0; i < targetDim; i++) {
|
|
147
|
+
if (i < p.length) {
|
|
148
|
+
result[i] = isNaN(p[i]) ? NaN : center![i];
|
|
149
|
+
} else {
|
|
150
|
+
result[i] = center![i];
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
(scaledPos as PositionMap)[node] = result;
|
|
79
154
|
}
|
|
80
155
|
}
|
|
81
156
|
}
|
package/.env.example
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
# Development Server Configuration
|
|
2
|
-
# Copy this file to .env and adjust values as needed
|
|
3
|
-
|
|
4
|
-
# Server host (defaults to true for network exposure)
|
|
5
|
-
# HOST=localhost
|
|
6
|
-
# HOST=0.0.0.0
|
|
7
|
-
# HOST=my.server.com
|
|
8
|
-
|
|
9
|
-
# Server port (defaults to 3000)
|
|
10
|
-
# PORT=3000
|
|
11
|
-
# PORT=8080
|
package/.github/workflows/ci.yml
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
name: CI
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [ main, develop ]
|
|
6
|
-
pull_request:
|
|
7
|
-
branches: [ main ]
|
|
8
|
-
|
|
9
|
-
jobs:
|
|
10
|
-
test:
|
|
11
|
-
name: Test
|
|
12
|
-
runs-on: ubuntu-latest
|
|
13
|
-
|
|
14
|
-
strategy:
|
|
15
|
-
matrix:
|
|
16
|
-
node-version: [18.x, 20.x, 22.x]
|
|
17
|
-
|
|
18
|
-
steps:
|
|
19
|
-
- name: Checkout code
|
|
20
|
-
uses: actions/checkout@v4
|
|
21
|
-
|
|
22
|
-
- name: Setup Node.js ${{ matrix.node-version }}
|
|
23
|
-
uses: actions/setup-node@v4
|
|
24
|
-
with:
|
|
25
|
-
node-version: ${{ matrix.node-version }}
|
|
26
|
-
cache: 'npm'
|
|
27
|
-
|
|
28
|
-
- name: Install dependencies
|
|
29
|
-
run: npm ci
|
|
30
|
-
|
|
31
|
-
- name: Run TypeScript compiler
|
|
32
|
-
run: npm run build
|
|
33
|
-
|
|
34
|
-
- name: Run tests
|
|
35
|
-
run: npm run test:run
|
|
36
|
-
|
|
37
|
-
- name: Run tests with coverage
|
|
38
|
-
run: npm run test:coverage
|
|
39
|
-
if: matrix.node-version == '20.x'
|
|
40
|
-
|
|
41
|
-
- name: Upload coverage reports to Coveralls
|
|
42
|
-
uses: coverallsapp/github-action@v2
|
|
43
|
-
if: matrix.node-version == '20.x'
|
|
44
|
-
with:
|
|
45
|
-
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
46
|
-
file: ./coverage/lcov.info
|
|
47
|
-
|
|
48
|
-
lint:
|
|
49
|
-
name: Lint
|
|
50
|
-
runs-on: ubuntu-latest
|
|
51
|
-
|
|
52
|
-
steps:
|
|
53
|
-
- name: Checkout code
|
|
54
|
-
uses: actions/checkout@v4
|
|
55
|
-
|
|
56
|
-
- name: Setup Node.js
|
|
57
|
-
uses: actions/setup-node@v4
|
|
58
|
-
with:
|
|
59
|
-
node-version: '20.x'
|
|
60
|
-
cache: 'npm'
|
|
61
|
-
|
|
62
|
-
- name: Install dependencies
|
|
63
|
-
run: npm ci
|
|
64
|
-
|
|
65
|
-
- name: Check TypeScript types
|
|
66
|
-
run: npx tsc --noEmit
|
|
67
|
-
|
|
68
|
-
- name: Run commitlint on PR title
|
|
69
|
-
if: github.event_name == 'pull_request'
|
|
70
|
-
run: echo "${{ github.event.pull_request.title }}" | npx commitlint
|
|
71
|
-
|
|
72
|
-
release:
|
|
73
|
-
name: Release
|
|
74
|
-
runs-on: ubuntu-latest
|
|
75
|
-
needs: [test, lint]
|
|
76
|
-
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
|
77
|
-
|
|
78
|
-
steps:
|
|
79
|
-
- name: Checkout code
|
|
80
|
-
uses: actions/checkout@v4
|
|
81
|
-
with:
|
|
82
|
-
fetch-depth: 0
|
|
83
|
-
token: ${{ secrets.GITHUB_TOKEN }}
|
|
84
|
-
|
|
85
|
-
- name: Setup Node.js
|
|
86
|
-
uses: actions/setup-node@v4
|
|
87
|
-
with:
|
|
88
|
-
node-version: '20.x'
|
|
89
|
-
cache: 'npm'
|
|
90
|
-
|
|
91
|
-
- name: Install dependencies
|
|
92
|
-
run: npm ci
|
|
93
|
-
|
|
94
|
-
- name: Build package
|
|
95
|
-
run: npm run build
|
|
96
|
-
|
|
97
|
-
- name: Release
|
|
98
|
-
env:
|
|
99
|
-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
100
|
-
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
101
|
-
run: npx semantic-release
|