@reqlan/analytical 0.5.4 → 0.6.1
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/README.md +22 -3
- package/out/analysis/git-dates-analyser.js +41 -12
- package/out/analysis/git-dates-analyser.js.map +1 -1
- package/out/core/analytical-store.d.ts +9 -2
- package/out/core/analytical-store.js +7 -5
- package/out/core/analytical-store.js.map +1 -1
- package/out/core/application-memory.d.ts +17 -2
- package/out/core/application-memory.js +23 -5
- package/out/core/application-memory.js.map +1 -1
- package/out/core/base-discovery.d.ts +40 -0
- package/out/core/base-discovery.js +166 -0
- package/out/core/base-discovery.js.map +1 -0
- package/out/core/context-model.d.ts +17 -0
- package/out/core/context-model.js.map +1 -1
- package/out/core/create-base.d.ts +11 -0
- package/out/core/create-base.js +33 -0
- package/out/core/create-base.js.map +1 -0
- package/out/core/rqignore.d.ts +25 -0
- package/out/core/rqignore.js +149 -0
- package/out/core/rqignore.js.map +1 -0
- package/out/core/types.d.ts +5 -1
- package/out/core/types.js.map +1 -1
- package/out/create-runtime.d.ts +29 -4
- package/out/create-runtime.js +47 -8
- package/out/create-runtime.js.map +1 -1
- package/out/export/html-export-assets.d.ts +2 -2
- package/out/export/html-export-assets.js +259 -239
- package/out/export/html-export-assets.js.map +1 -1
- package/out/graph/physics-core.d.ts +141 -0
- package/out/graph/physics-core.js +237 -0
- package/out/graph/physics-core.js.map +1 -0
- package/out/headless-index-service.d.ts +6 -23
- package/out/headless-index-service.js +5 -171
- package/out/headless-index-service.js.map +1 -1
- package/out/index-store/base-registry.d.ts +57 -0
- package/out/index-store/base-registry.js +192 -0
- package/out/index-store/base-registry.js.map +1 -0
- package/out/index-store/index-diagnostics-store.d.ts +72 -0
- package/out/index-store/index-diagnostics-store.js +238 -0
- package/out/index-store/index-diagnostics-store.js.map +1 -0
- package/out/index-store/index-file-error.d.ts +16 -0
- package/out/index-store/index-file-error.js +27 -0
- package/out/index-store/index-file-error.js.map +1 -0
- package/out/index-store/index-parse-issues.d.ts +9 -0
- package/out/index-store/index-parse-issues.js +62 -0
- package/out/index-store/index-parse-issues.js.map +1 -0
- package/out/index-store/index-status.d.ts +20 -0
- package/out/index-store/index-status.js +2 -0
- package/out/index-store/index-status.js.map +1 -0
- package/out/index-store/overview-coverage.d.ts +23 -0
- package/out/index-store/overview-coverage.js +254 -0
- package/out/index-store/overview-coverage.js.map +1 -0
- package/out/index-store/schema.d.ts +1 -1
- package/out/index-store/schema.js +4 -1
- package/out/index-store/schema.js.map +1 -1
- package/out/index-store/sqlite-store.d.ts +31 -2
- package/out/index-store/sqlite-store.js +152 -13
- package/out/index-store/sqlite-store.js.map +1 -1
- package/out/index-store/webview-table-queries.d.ts +65 -1
- package/out/index-store/webview-table-queries.js +188 -26
- package/out/index-store/webview-table-queries.js.map +1 -1
- package/out/index-store/workspace-index-file.d.ts +27 -0
- package/out/index-store/workspace-index-file.js +98 -0
- package/out/index-store/workspace-index-file.js.map +1 -0
- package/out/index-store/workspace-index-sync.d.ts +53 -0
- package/out/index-store/workspace-index-sync.js +164 -0
- package/out/index-store/workspace-index-sync.js.map +1 -0
- package/out/index-store/workspace-index.d.ts +80 -0
- package/out/index-store/workspace-index.js +525 -0
- package/out/index-store/workspace-index.js.map +1 -0
- package/out/index-store/workspace-mtime.d.ts +14 -0
- package/out/index-store/workspace-mtime.js +56 -0
- package/out/index-store/workspace-mtime.js.map +1 -0
- package/out/index.d.ts +25 -6
- package/out/index.js +12 -3
- package/out/index.js.map +1 -1
- package/package.json +7 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html-export-assets.js","sourceRoot":"","sources":["../../src/export/html-export-assets.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG
|
|
1
|
+
{"version":3,"file":"html-export-assets.js","sourceRoot":"","sources":["../../src/export/html-export-assets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,2FAA2F;AAC3F,SAAS,sBAAsB;IAC3B,OAAO,YAAY,CAAC,IAAI,GAAG,CAAC,0BAA0B,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;SAC5E,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;AACrC,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0V5B,CAAC;AAEF,MAAM,CAAC,MAAM,MAAM,GAAG;EACpB,sBAAsB,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAm4BzB,CAAC;AAEF,MAAM,UAAU,sBAAsB,CAAC,SAAkB;IACrD,OAAO,wCAAwC,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,KAAK,CAAC;AAC3G,CAAC"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
export namespace ReqlanGraphPhysics {
|
|
2
|
+
export let DEFAULT_PHYSICS_SETTINGS: PhysicsCoreSettings;
|
|
3
|
+
export { hashAngleImpl as hashAngle };
|
|
4
|
+
export { accumulateForcesImpl as accumulateForces };
|
|
5
|
+
export { integrateFromForcesImpl as integrateFromForces };
|
|
6
|
+
export { stepPhysicsImpl as stepPhysics };
|
|
7
|
+
}
|
|
8
|
+
export const DEFAULT_PHYSICS_SETTINGS: PhysicsCoreSettings;
|
|
9
|
+
/**
|
|
10
|
+
* Shared Obsidian-style force step for Ideas Summary live physics and HTML export.
|
|
11
|
+
* Gravity + edge springs + inverse-square repulsion; spatial grid for large n.
|
|
12
|
+
* Plain ESM so the HTML export can embed it by stripping `export` keywords.
|
|
13
|
+
*/
|
|
14
|
+
/** @typedef {{
|
|
15
|
+
* gravity: number,
|
|
16
|
+
* repulsion: number,
|
|
17
|
+
* linkStrength: number,
|
|
18
|
+
* linkDistance: number,
|
|
19
|
+
* damping: number,
|
|
20
|
+
* maxVelocity: number,
|
|
21
|
+
* minSeparation: number,
|
|
22
|
+
* restSpeed: number,
|
|
23
|
+
* restTicks: number,
|
|
24
|
+
* repulsionCutoff?: number
|
|
25
|
+
* }} PhysicsCoreSettings */
|
|
26
|
+
/** @typedef {{
|
|
27
|
+
* ids: string[],
|
|
28
|
+
* xs: Float64Array,
|
|
29
|
+
* ys: Float64Array,
|
|
30
|
+
* fxs: Float64Array,
|
|
31
|
+
* fys: Float64Array,
|
|
32
|
+
* velocities: Map<string, { vx: number, vy: number }>,
|
|
33
|
+
* pinnedIds: ReadonlySet<string>,
|
|
34
|
+
* edges: ReadonlyArray<{ sourceId: string, targetId: string }>
|
|
35
|
+
* }} PhysicsStepState */
|
|
36
|
+
/**
|
|
37
|
+
* Deterministic angle in [0, 2π) derived from a string.
|
|
38
|
+
* @param {string} seed
|
|
39
|
+
*/
|
|
40
|
+
export function hashAngle(seed: string): number;
|
|
41
|
+
/**
|
|
42
|
+
* Zero fxs/fys then add gravity, repulsion, and edge springs.
|
|
43
|
+
* Callers may add extra forces (e.g. group constraints) before integrateFromForces.
|
|
44
|
+
* @param {PhysicsStepState} state
|
|
45
|
+
* @param {PhysicsCoreSettings} settings
|
|
46
|
+
*/
|
|
47
|
+
export function accumulateForces(state: PhysicsStepState, settings: PhysicsCoreSettings): void;
|
|
48
|
+
/**
|
|
49
|
+
* Semi-implicit Euler with damping; mutates xs/ys and velocities. Returns average speed.
|
|
50
|
+
* @param {PhysicsStepState} state
|
|
51
|
+
* @param {PhysicsCoreSettings} settings
|
|
52
|
+
* @returns {number}
|
|
53
|
+
*/
|
|
54
|
+
export function integrateFromForces(state: PhysicsStepState, settings: PhysicsCoreSettings): number;
|
|
55
|
+
/**
|
|
56
|
+
* @param {PhysicsStepState} state
|
|
57
|
+
* @param {PhysicsCoreSettings} settings
|
|
58
|
+
* @returns {number}
|
|
59
|
+
*/
|
|
60
|
+
export function stepPhysics(state: PhysicsStepState, settings: PhysicsCoreSettings): number;
|
|
61
|
+
export type PhysicsCoreSettings = {
|
|
62
|
+
gravity: number;
|
|
63
|
+
repulsion: number;
|
|
64
|
+
linkStrength: number;
|
|
65
|
+
linkDistance: number;
|
|
66
|
+
damping: number;
|
|
67
|
+
maxVelocity: number;
|
|
68
|
+
minSeparation: number;
|
|
69
|
+
restSpeed: number;
|
|
70
|
+
restTicks: number;
|
|
71
|
+
repulsionCutoff?: number;
|
|
72
|
+
};
|
|
73
|
+
export type PhysicsStepState = {
|
|
74
|
+
ids: string[];
|
|
75
|
+
xs: Float64Array;
|
|
76
|
+
ys: Float64Array;
|
|
77
|
+
fxs: Float64Array;
|
|
78
|
+
fys: Float64Array;
|
|
79
|
+
velocities: Map<string, {
|
|
80
|
+
vx: number;
|
|
81
|
+
vy: number;
|
|
82
|
+
}>;
|
|
83
|
+
pinnedIds: ReadonlySet<string>;
|
|
84
|
+
edges: ReadonlyArray<{
|
|
85
|
+
sourceId: string;
|
|
86
|
+
targetId: string;
|
|
87
|
+
}>;
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* Shared Obsidian-style force step for Ideas Summary live physics and HTML export.
|
|
91
|
+
* Gravity + edge springs + inverse-square repulsion; spatial grid for large n.
|
|
92
|
+
* Plain ESM so the HTML export can embed it by stripping `export` keywords.
|
|
93
|
+
*/
|
|
94
|
+
/** @typedef {{
|
|
95
|
+
* gravity: number,
|
|
96
|
+
* repulsion: number,
|
|
97
|
+
* linkStrength: number,
|
|
98
|
+
* linkDistance: number,
|
|
99
|
+
* damping: number,
|
|
100
|
+
* maxVelocity: number,
|
|
101
|
+
* minSeparation: number,
|
|
102
|
+
* restSpeed: number,
|
|
103
|
+
* restTicks: number,
|
|
104
|
+
* repulsionCutoff?: number
|
|
105
|
+
* }} PhysicsCoreSettings */
|
|
106
|
+
/** @typedef {{
|
|
107
|
+
* ids: string[],
|
|
108
|
+
* xs: Float64Array,
|
|
109
|
+
* ys: Float64Array,
|
|
110
|
+
* fxs: Float64Array,
|
|
111
|
+
* fys: Float64Array,
|
|
112
|
+
* velocities: Map<string, { vx: number, vy: number }>,
|
|
113
|
+
* pinnedIds: ReadonlySet<string>,
|
|
114
|
+
* edges: ReadonlyArray<{ sourceId: string, targetId: string }>
|
|
115
|
+
* }} PhysicsStepState */
|
|
116
|
+
/**
|
|
117
|
+
* Deterministic angle in [0, 2π) derived from a string.
|
|
118
|
+
* @param {string} seed
|
|
119
|
+
*/
|
|
120
|
+
declare function hashAngleImpl(seed: string): number;
|
|
121
|
+
/**
|
|
122
|
+
* Zero fxs/fys then add gravity, repulsion, and edge springs.
|
|
123
|
+
* Callers may add extra forces (e.g. group constraints) before integrateFromForces.
|
|
124
|
+
* @param {PhysicsStepState} state
|
|
125
|
+
* @param {PhysicsCoreSettings} settings
|
|
126
|
+
*/
|
|
127
|
+
declare function accumulateForcesImpl(state: PhysicsStepState, settings: PhysicsCoreSettings): void;
|
|
128
|
+
/**
|
|
129
|
+
* Semi-implicit Euler with damping; mutates xs/ys and velocities. Returns average speed.
|
|
130
|
+
* @param {PhysicsStepState} state
|
|
131
|
+
* @param {PhysicsCoreSettings} settings
|
|
132
|
+
* @returns {number}
|
|
133
|
+
*/
|
|
134
|
+
declare function integrateFromForcesImpl(state: PhysicsStepState, settings: PhysicsCoreSettings): number;
|
|
135
|
+
/**
|
|
136
|
+
* @param {PhysicsStepState} state
|
|
137
|
+
* @param {PhysicsCoreSettings} settings
|
|
138
|
+
* @returns {number}
|
|
139
|
+
*/
|
|
140
|
+
declare function stepPhysicsImpl(state: PhysicsStepState, settings: PhysicsCoreSettings): number;
|
|
141
|
+
export {};
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Obsidian-style force step for Ideas Summary live physics and HTML export.
|
|
3
|
+
* Gravity + edge springs + inverse-square repulsion; spatial grid for large n.
|
|
4
|
+
* Plain ESM so the HTML export can embed it by stripping `export` keywords.
|
|
5
|
+
*/
|
|
6
|
+
/** @typedef {{
|
|
7
|
+
* gravity: number,
|
|
8
|
+
* repulsion: number,
|
|
9
|
+
* linkStrength: number,
|
|
10
|
+
* linkDistance: number,
|
|
11
|
+
* damping: number,
|
|
12
|
+
* maxVelocity: number,
|
|
13
|
+
* minSeparation: number,
|
|
14
|
+
* restSpeed: number,
|
|
15
|
+
* restTicks: number,
|
|
16
|
+
* repulsionCutoff?: number
|
|
17
|
+
* }} PhysicsCoreSettings */
|
|
18
|
+
/** @typedef {{
|
|
19
|
+
* ids: string[],
|
|
20
|
+
* xs: Float64Array,
|
|
21
|
+
* ys: Float64Array,
|
|
22
|
+
* fxs: Float64Array,
|
|
23
|
+
* fys: Float64Array,
|
|
24
|
+
* velocities: Map<string, { vx: number, vy: number }>,
|
|
25
|
+
* pinnedIds: ReadonlySet<string>,
|
|
26
|
+
* edges: ReadonlyArray<{ sourceId: string, targetId: string }>
|
|
27
|
+
* }} PhysicsStepState */
|
|
28
|
+
/**
|
|
29
|
+
* Deterministic angle in [0, 2π) derived from a string.
|
|
30
|
+
* @param {string} seed
|
|
31
|
+
*/
|
|
32
|
+
function hashAngleImpl(seed) {
|
|
33
|
+
let hash = 0;
|
|
34
|
+
for (let index = 0; index < seed.length; index += 1) {
|
|
35
|
+
hash = (hash * 31 + seed.charCodeAt(index)) | 0;
|
|
36
|
+
}
|
|
37
|
+
return ((hash >>> 0) % 6283) / 1000;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* @param {number} i
|
|
41
|
+
* @param {number} j
|
|
42
|
+
* @param {string[]} ids
|
|
43
|
+
* @param {Float64Array} xs
|
|
44
|
+
* @param {Float64Array} ys
|
|
45
|
+
* @param {Float64Array} fxs
|
|
46
|
+
* @param {Float64Array} fys
|
|
47
|
+
* @param {number} repulsion
|
|
48
|
+
* @param {number} minSeparationSq
|
|
49
|
+
* @param {number} cutoffSq
|
|
50
|
+
*/
|
|
51
|
+
function applyRepulsion(i, j, ids, xs, ys, fxs, fys, repulsion, minSeparationSq, cutoffSq) {
|
|
52
|
+
let dx = xs[j] - xs[i];
|
|
53
|
+
let dy = ys[j] - ys[i];
|
|
54
|
+
let distSq = dx * dx + dy * dy;
|
|
55
|
+
if (distSq > cutoffSq) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
if (distSq < 1e-6) {
|
|
59
|
+
const angle = hashAngleImpl(ids[i] + ids[j]);
|
|
60
|
+
dx = Math.cos(angle);
|
|
61
|
+
dy = Math.sin(angle);
|
|
62
|
+
distSq = 1;
|
|
63
|
+
}
|
|
64
|
+
const clampedSq = Math.max(distSq, minSeparationSq);
|
|
65
|
+
const dist = Math.sqrt(distSq);
|
|
66
|
+
const force = repulsion / clampedSq;
|
|
67
|
+
const fx = (dx / dist) * force;
|
|
68
|
+
const fy = (dy / dist) * force;
|
|
69
|
+
fxs[i] -= fx;
|
|
70
|
+
fys[i] -= fy;
|
|
71
|
+
fxs[j] += fx;
|
|
72
|
+
fys[j] += fy;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Zero fxs/fys then add gravity, repulsion, and edge springs.
|
|
76
|
+
* Callers may add extra forces (e.g. group constraints) before integrateFromForces.
|
|
77
|
+
* @param {PhysicsStepState} state
|
|
78
|
+
* @param {PhysicsCoreSettings} settings
|
|
79
|
+
*/
|
|
80
|
+
function accumulateForcesImpl(state, settings) {
|
|
81
|
+
const { ids, xs, ys, fxs, fys, edges } = state;
|
|
82
|
+
const count = ids.length;
|
|
83
|
+
fxs.fill(0);
|
|
84
|
+
fys.fill(0);
|
|
85
|
+
if (count === 0) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const { gravity, repulsion, linkStrength, linkDistance, minSeparation, repulsionCutoff = 420 } = settings;
|
|
89
|
+
let centroidX = 0;
|
|
90
|
+
let centroidY = 0;
|
|
91
|
+
for (let i = 0; i < count; i += 1) {
|
|
92
|
+
centroidX += xs[i];
|
|
93
|
+
centroidY += ys[i];
|
|
94
|
+
}
|
|
95
|
+
centroidX /= count;
|
|
96
|
+
centroidY /= count;
|
|
97
|
+
for (let i = 0; i < count; i += 1) {
|
|
98
|
+
fxs[i] -= gravity * (xs[i] - centroidX);
|
|
99
|
+
fys[i] -= gravity * (ys[i] - centroidY);
|
|
100
|
+
}
|
|
101
|
+
const minSeparationSq = minSeparation * minSeparation;
|
|
102
|
+
const cutoff = Math.max(minSeparation * 2, repulsionCutoff);
|
|
103
|
+
const cutoffSq = cutoff * cutoff;
|
|
104
|
+
if (count <= 80) {
|
|
105
|
+
for (let i = 0; i < count; i += 1) {
|
|
106
|
+
for (let j = i + 1; j < count; j += 1) {
|
|
107
|
+
applyRepulsion(i, j, ids, xs, ys, fxs, fys, repulsion, minSeparationSq, cutoffSq);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
const cellSize = cutoff;
|
|
113
|
+
/** @type {Map<string, number[]>} */
|
|
114
|
+
const grid = new Map();
|
|
115
|
+
for (let i = 0; i < count; i += 1) {
|
|
116
|
+
const key = `${Math.floor(xs[i] / cellSize)},${Math.floor(ys[i] / cellSize)}`;
|
|
117
|
+
let bucket = grid.get(key);
|
|
118
|
+
if (!bucket) {
|
|
119
|
+
bucket = [];
|
|
120
|
+
grid.set(key, bucket);
|
|
121
|
+
}
|
|
122
|
+
bucket.push(i);
|
|
123
|
+
}
|
|
124
|
+
for (let i = 0; i < count; i += 1) {
|
|
125
|
+
const cx = Math.floor(xs[i] / cellSize);
|
|
126
|
+
const cy = Math.floor(ys[i] / cellSize);
|
|
127
|
+
for (let ox = -1; ox <= 1; ox += 1) {
|
|
128
|
+
for (let oy = -1; oy <= 1; oy += 1) {
|
|
129
|
+
const bucket = grid.get(`${cx + ox},${cy + oy}`);
|
|
130
|
+
if (!bucket)
|
|
131
|
+
continue;
|
|
132
|
+
for (let b = 0; b < bucket.length; b += 1) {
|
|
133
|
+
const j = bucket[b];
|
|
134
|
+
if (j <= i)
|
|
135
|
+
continue;
|
|
136
|
+
applyRepulsion(i, j, ids, xs, ys, fxs, fys, repulsion, minSeparationSq, cutoffSq);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
const indexById = new Map();
|
|
143
|
+
for (let i = 0; i < count; i += 1) {
|
|
144
|
+
indexById.set(ids[i], i);
|
|
145
|
+
}
|
|
146
|
+
for (let e = 0; e < edges.length; e += 1) {
|
|
147
|
+
const edge = edges[e];
|
|
148
|
+
const sourceIndex = indexById.get(edge.sourceId);
|
|
149
|
+
const targetIndex = indexById.get(edge.targetId);
|
|
150
|
+
if (sourceIndex === undefined || targetIndex === undefined || sourceIndex === targetIndex) {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
const dx = xs[targetIndex] - xs[sourceIndex];
|
|
154
|
+
const dy = ys[targetIndex] - ys[sourceIndex];
|
|
155
|
+
const dist = Math.sqrt(dx * dx + dy * dy);
|
|
156
|
+
if (dist < 1e-3) {
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
const force = linkStrength * (dist - linkDistance);
|
|
160
|
+
const fx = (dx / dist) * force;
|
|
161
|
+
const fy = (dy / dist) * force;
|
|
162
|
+
fxs[sourceIndex] += fx;
|
|
163
|
+
fys[sourceIndex] += fy;
|
|
164
|
+
fxs[targetIndex] -= fx;
|
|
165
|
+
fys[targetIndex] -= fy;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Semi-implicit Euler with damping; mutates xs/ys and velocities. Returns average speed.
|
|
170
|
+
* @param {PhysicsStepState} state
|
|
171
|
+
* @param {PhysicsCoreSettings} settings
|
|
172
|
+
* @returns {number}
|
|
173
|
+
*/
|
|
174
|
+
function integrateFromForcesImpl(state, settings) {
|
|
175
|
+
const { ids, xs, ys, fxs, fys, velocities, pinnedIds } = state;
|
|
176
|
+
const { damping, maxVelocity } = settings;
|
|
177
|
+
const count = ids.length;
|
|
178
|
+
let speedSum = 0;
|
|
179
|
+
let movingCount = 0;
|
|
180
|
+
for (let i = 0; i < count; i += 1) {
|
|
181
|
+
const id = ids[i];
|
|
182
|
+
if (pinnedIds.has(id)) {
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
const velocity = velocities.get(id) || { vx: 0, vy: 0 };
|
|
186
|
+
let vx = (velocity.vx + fxs[i]) * damping;
|
|
187
|
+
let vy = (velocity.vy + fys[i]) * damping;
|
|
188
|
+
const speed = Math.sqrt(vx * vx + vy * vy);
|
|
189
|
+
if (speed > maxVelocity) {
|
|
190
|
+
const scale = maxVelocity / speed;
|
|
191
|
+
vx *= scale;
|
|
192
|
+
vy *= scale;
|
|
193
|
+
}
|
|
194
|
+
velocity.vx = vx;
|
|
195
|
+
velocity.vy = vy;
|
|
196
|
+
velocities.set(id, velocity);
|
|
197
|
+
xs[i] += vx;
|
|
198
|
+
ys[i] += vy;
|
|
199
|
+
speedSum += Math.min(speed, maxVelocity);
|
|
200
|
+
movingCount += 1;
|
|
201
|
+
}
|
|
202
|
+
return movingCount > 0 ? speedSum / movingCount : 0;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* @param {PhysicsStepState} state
|
|
206
|
+
* @param {PhysicsCoreSettings} settings
|
|
207
|
+
* @returns {number}
|
|
208
|
+
*/
|
|
209
|
+
function stepPhysicsImpl(state, settings) {
|
|
210
|
+
accumulateForcesImpl(state, settings);
|
|
211
|
+
return integrateFromForcesImpl(state, settings);
|
|
212
|
+
}
|
|
213
|
+
export const ReqlanGraphPhysics = {
|
|
214
|
+
/** @type {PhysicsCoreSettings} */
|
|
215
|
+
DEFAULT_PHYSICS_SETTINGS: {
|
|
216
|
+
gravity: 0.002,
|
|
217
|
+
repulsion: 20000,
|
|
218
|
+
linkStrength: 0.015,
|
|
219
|
+
linkDistance: 120,
|
|
220
|
+
damping: 0.5,
|
|
221
|
+
maxVelocity: 10,
|
|
222
|
+
minSeparation: 24,
|
|
223
|
+
restSpeed: 0.02,
|
|
224
|
+
restTicks: 90,
|
|
225
|
+
repulsionCutoff: 420
|
|
226
|
+
},
|
|
227
|
+
hashAngle: hashAngleImpl,
|
|
228
|
+
accumulateForces: accumulateForcesImpl,
|
|
229
|
+
integrateFromForces: integrateFromForcesImpl,
|
|
230
|
+
stepPhysics: stepPhysicsImpl
|
|
231
|
+
};
|
|
232
|
+
export const DEFAULT_PHYSICS_SETTINGS = ReqlanGraphPhysics.DEFAULT_PHYSICS_SETTINGS;
|
|
233
|
+
export const hashAngle = hashAngleImpl;
|
|
234
|
+
export const accumulateForces = accumulateForcesImpl;
|
|
235
|
+
export const integrateFromForces = integrateFromForcesImpl;
|
|
236
|
+
export const stepPhysics = stepPhysicsImpl;
|
|
237
|
+
//# sourceMappingURL=physics-core.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"physics-core.js","sourceRoot":"","sources":["../../src/graph/physics-core.js"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;;4BAW4B;AAE5B;;;;;;;;;yBASyB;AAEzB;;;GAGG;AACH,SAAS,aAAa,CAAC,IAAI;IACvB,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QAClD,IAAI,GAAG,CAAC,IAAI,GAAG,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC;IACpD,CAAC;IACD,OAAO,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC;AACxC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAS,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,eAAe,EAAE,QAAQ;IACrF,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;IACvB,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;IACvB,IAAI,MAAM,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;IAC/B,IAAI,MAAM,GAAG,QAAQ,EAAE,CAAC;QACpB,OAAO;IACX,CAAC;IACD,IAAI,MAAM,GAAG,IAAI,EAAE,CAAC;QAChB,MAAM,KAAK,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7C,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACrB,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACrB,MAAM,GAAG,CAAC,CAAC;IACf,CAAC;IACD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,eAAe,CAAC,CAAC;IACpD,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC/B,MAAM,KAAK,GAAG,SAAS,GAAG,SAAS,CAAC;IACpC,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,GAAG,KAAK,CAAC;IAC/B,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,GAAG,KAAK,CAAC;IAC/B,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACb,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACb,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IACb,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AACjB,CAAC;AAED;;;;;GAKG;AACH,SAAS,oBAAoB,CAAC,KAAK,EAAE,QAAQ;IACzC,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,KAAK,CAAC;IAC/C,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC;IACzB,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACZ,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACZ,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;QACd,OAAO;IACX,CAAC;IAED,MAAM,EACF,OAAO,EACP,SAAS,EACT,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,eAAe,GAAG,GAAG,EACxB,GAAG,QAAQ,CAAC;IAEb,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAChC,SAAS,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QACnB,SAAS,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACvB,CAAC;IACD,SAAS,IAAI,KAAK,CAAC;IACnB,SAAS,IAAI,KAAK,CAAC;IACnB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAChC,GAAG,CAAC,CAAC,CAAC,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;QACxC,GAAG,CAAC,CAAC,CAAC,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;IAC5C,CAAC;IAED,MAAM,eAAe,GAAG,aAAa,GAAG,aAAa,CAAC;IACtD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,aAAa,GAAG,CAAC,EAAE,eAAe,CAAC,CAAC;IAC5D,MAAM,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;IAEjC,IAAI,KAAK,IAAI,EAAE,EAAE,CAAC;QACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YAChC,KAAK,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;gBACpC,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,eAAe,EAAE,QAAQ,CAAC,CAAC;YACtF,CAAC;QACL,CAAC;IACL,CAAC;SAAM,CAAC;QACJ,MAAM,QAAQ,GAAG,MAAM,CAAC;QACxB,oCAAoC;QACpC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAE,CAAC;QACvB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YAChC,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC;YAC9E,IAAI,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC3B,IAAI,CAAC,MAAM,EAAE,CAAC;gBACV,MAAM,GAAG,EAAE,CAAC;gBACZ,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;YAC1B,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACnB,CAAC;QACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;YAChC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC;YACxC,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC;YACxC,KAAK,IAAI,EAAE,GAAG,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC;gBACjC,KAAK,IAAI,EAAE,GAAG,CAAC,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,EAAE,CAAC;oBACjC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;oBACjD,IAAI,CAAC,MAAM;wBAAE,SAAS;oBACtB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;wBACxC,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;wBACpB,IAAI,CAAC,IAAI,CAAC;4BAAE,SAAS;wBACrB,cAAc,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,eAAe,EAAE,QAAQ,CAAC,CAAC;oBACtF,CAAC;gBACL,CAAC;YACL,CAAC;QACL,CAAC;IACL,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,GAAG,EAAE,CAAC;IAC5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAChC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC7B,CAAC;IACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QACvC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,MAAM,WAAW,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACjD,MAAM,WAAW,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACjD,IAAI,WAAW,KAAK,SAAS,IAAI,WAAW,KAAK,SAAS,IAAI,WAAW,KAAK,WAAW,EAAE,CAAC;YACxF,SAAS;QACb,CAAC;QACD,MAAM,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,CAAC;QAC7C,MAAM,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,CAAC;QAC7C,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;QAC1C,IAAI,IAAI,GAAG,IAAI,EAAE,CAAC;YACd,SAAS;QACb,CAAC;QACD,MAAM,KAAK,GAAG,YAAY,GAAG,CAAC,IAAI,GAAG,YAAY,CAAC,CAAC;QACnD,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,GAAG,KAAK,CAAC;QAC/B,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,GAAG,KAAK,CAAC;QAC/B,GAAG,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;QACvB,GAAG,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;QACvB,GAAG,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;QACvB,GAAG,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;IAC3B,CAAC;AACL,CAAC;AAED;;;;;GAKG;AACH,SAAS,uBAAuB,CAAC,KAAK,EAAE,QAAQ;IAC5C,MAAM,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;IAC/D,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,GAAG,QAAQ,CAAC;IAC1C,MAAM,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC;IACzB,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,IAAI,WAAW,GAAG,CAAC,CAAC;IACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAChC,MAAM,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;QAClB,IAAI,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YACpB,SAAS;QACb,CAAC;QACD,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC;QACxD,IAAI,EAAE,GAAG,CAAC,QAAQ,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;QAC1C,IAAI,EAAE,GAAG,CAAC,QAAQ,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;QAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC;QAC3C,IAAI,KAAK,GAAG,WAAW,EAAE,CAAC;YACtB,MAAM,KAAK,GAAG,WAAW,GAAG,KAAK,CAAC;YAClC,EAAE,IAAI,KAAK,CAAC;YACZ,EAAE,IAAI,KAAK,CAAC;QAChB,CAAC;QACD,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC;QACjB,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC;QACjB,UAAU,CAAC,GAAG,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;QAC7B,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACZ,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACZ,QAAQ,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;QACzC,WAAW,IAAI,CAAC,CAAC;IACrB,CAAC;IACD,OAAO,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;AACxD,CAAC;AAED;;;;GAIG;AACH,SAAS,eAAe,CAAC,KAAK,EAAE,QAAQ;IACpC,oBAAoB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IACtC,OAAO,uBAAuB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;AACpD,CAAC;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAC9B,kCAAkC;IAClC,wBAAwB,EAAE;QACtB,OAAO,EAAE,KAAK;QACd,SAAS,EAAE,KAAK;QAChB,YAAY,EAAE,KAAK;QACnB,YAAY,EAAE,GAAG;QACjB,OAAO,EAAE,GAAG;QACZ,WAAW,EAAE,EAAE;QACf,aAAa,EAAE,EAAE;QACjB,SAAS,EAAE,IAAI;QACf,SAAS,EAAE,EAAE;QACb,eAAe,EAAE,GAAG;KACvB;IACD,SAAS,EAAE,aAAa;IACxB,gBAAgB,EAAE,oBAAoB;IACtC,mBAAmB,EAAE,uBAAuB;IAC5C,WAAW,EAAE,eAAe;CAC/B,CAAC;AAEF,MAAM,CAAC,MAAM,wBAAwB,GAAG,kBAAkB,CAAC,wBAAwB,CAAC;AACpF,MAAM,CAAC,MAAM,SAAS,GAAG,aAAa,CAAC;AACvC,MAAM,CAAC,MAAM,gBAAgB,GAAG,oBAAoB,CAAC;AACrD,MAAM,CAAC,MAAM,mBAAmB,GAAG,uBAAuB,CAAC;AAC3D,MAAM,CAAC,MAAM,WAAW,GAAG,eAAe,CAAC"}
|
|
@@ -1,23 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
private sqlite?;
|
|
8
|
-
private readonly services;
|
|
9
|
-
constructor(analytical: AnalyticalStore, storagePath: string, workspaceRoot: string);
|
|
10
|
-
get isReady(): boolean;
|
|
11
|
-
get indexStore(): SqliteIndexStore;
|
|
12
|
-
activate(): Promise<void>;
|
|
13
|
-
deactivate(): Promise<void>;
|
|
14
|
-
syncWorkspace(): Promise<void>;
|
|
15
|
-
indexFilePath(filePath: string): Promise<void>;
|
|
16
|
-
relativePath(fileUri: string): string;
|
|
17
|
-
resolveFileUri(pathInput: string): string;
|
|
18
|
-
listRqFiles(pathPrefix?: string): string[];
|
|
19
|
-
private rqFilePaths;
|
|
20
|
-
private collectRqFiles;
|
|
21
|
-
private walkDirectory;
|
|
22
|
-
private parseDocument;
|
|
23
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Headless ideas index — re-exports the shared {@link WorkspaceIndex}.
|
|
3
|
+
* Prefer importing `WorkspaceIndex` for new code.
|
|
4
|
+
*/
|
|
5
|
+
export { WorkspaceIndex, WorkspaceIndex as HeadlessIndexService } from './index-store/workspace-index.js';
|
|
6
|
+
export type { IndexStatusSnapshot, IndexSyncProgress } from './index-store/index-status.js';
|
|
@@ -1,172 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
import { normalizeIndexedDocument, resolveWorkspaceFileUri } from './core/workspace-paths.js';
|
|
7
|
-
import { extractIndexedDocument } from './index-store/idea-extractor.js';
|
|
8
|
-
import { SqliteIndexStore } from './index-store/sqlite-store.js';
|
|
9
|
-
import { isSecretRqPath } from './export/secret-rq.js';
|
|
10
|
-
export class HeadlessIndexService {
|
|
11
|
-
constructor(analytical, storagePath, workspaceRoot) {
|
|
12
|
-
this.analytical = analytical;
|
|
13
|
-
this.storagePath = storagePath;
|
|
14
|
-
this.workspaceRoot = workspaceRoot;
|
|
15
|
-
this.services = createReqlanServices({ ...NodeFileSystem });
|
|
16
|
-
this.rqFilePaths = [];
|
|
17
|
-
}
|
|
18
|
-
get isReady() {
|
|
19
|
-
return this.analytical.getState().indexState === 'ready';
|
|
20
|
-
}
|
|
21
|
-
get indexStore() {
|
|
22
|
-
if (!this.sqlite) {
|
|
23
|
-
throw new Error('Index store is not open');
|
|
24
|
-
}
|
|
25
|
-
return this.sqlite;
|
|
26
|
-
}
|
|
27
|
-
async activate() {
|
|
28
|
-
const { dispatchIndex, recordIndexError } = this.analytical.getState();
|
|
29
|
-
dispatchIndex('activate');
|
|
30
|
-
try {
|
|
31
|
-
const dbPath = join(this.storagePath, 'ideas-index.sqlite');
|
|
32
|
-
this.sqlite = await SqliteIndexStore.open(dbPath);
|
|
33
|
-
dispatchIndex('opened');
|
|
34
|
-
await this.syncWorkspace();
|
|
35
|
-
}
|
|
36
|
-
catch (error) {
|
|
37
|
-
dispatchIndex('fail');
|
|
38
|
-
recordIndexError('Failed to open idea index', error);
|
|
39
|
-
throw error;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
async deactivate() {
|
|
43
|
-
const { canDispatchIndex, dispatchIndex } = this.analytical.getState();
|
|
44
|
-
if (canDispatchIndex('deactivate')) {
|
|
45
|
-
dispatchIndex('deactivate');
|
|
46
|
-
}
|
|
47
|
-
await this.sqlite?.close();
|
|
48
|
-
this.sqlite = undefined;
|
|
49
|
-
}
|
|
50
|
-
async syncWorkspace() {
|
|
51
|
-
if (!this.sqlite) {
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
const { dispatchIndex, setIndexReady, recordIndexError } = this.analytical.getState();
|
|
55
|
-
if (!dispatchIndex('sync')) {
|
|
56
|
-
return;
|
|
57
|
-
}
|
|
58
|
-
try {
|
|
59
|
-
const files = await this.collectRqFiles();
|
|
60
|
-
for (const filePath of files) {
|
|
61
|
-
try {
|
|
62
|
-
await this.indexFilePath(filePath);
|
|
63
|
-
}
|
|
64
|
-
catch (error) {
|
|
65
|
-
recordIndexError(`Failed to index ${relative(this.workspaceRoot, filePath)}`, error, {
|
|
66
|
-
fileUri: relative(this.workspaceRoot, filePath).replace(/\\/g, '/'),
|
|
67
|
-
phase: 'sync'
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
if (!dispatchIndex('synced')) {
|
|
72
|
-
recordIndexError('Index sync finished but state transition to ready failed', undefined);
|
|
73
|
-
}
|
|
74
|
-
const counts = await this.sqlite.counts();
|
|
75
|
-
setIndexReady({ ideaCount: counts.ideas, edgeCount: counts.edges });
|
|
76
|
-
}
|
|
77
|
-
catch (error) {
|
|
78
|
-
dispatchIndex('fail');
|
|
79
|
-
recordIndexError('Workspace sync failed', error);
|
|
80
|
-
throw error;
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
async indexFilePath(filePath) {
|
|
84
|
-
if (!this.sqlite) {
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
const document = await this.parseDocument(filePath);
|
|
88
|
-
if (!document) {
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
const extractedRaw = extractIndexedDocument(document);
|
|
92
|
-
if (!extractedRaw) {
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
const extracted = normalizeIndexedDocument(extractedRaw, this.workspaceRoot);
|
|
96
|
-
const fileUri = extracted.fileUri;
|
|
97
|
-
const existingHash = await this.sqlite.getDocumentHash(fileUri);
|
|
98
|
-
if (existingHash === extracted.contentHash) {
|
|
99
|
-
const storedEdges = await this.sqlite.countEdgesFromFile(fileUri);
|
|
100
|
-
if (storedEdges >= extracted.edges.length) {
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
for (const idea of extracted.ideas) {
|
|
105
|
-
idea.contentHash = extracted.contentHash;
|
|
106
|
-
}
|
|
107
|
-
await this.sqlite.upsertDocument(fileUri, extracted.contentHash, extracted.ideas, extracted.edges);
|
|
108
|
-
this.analytical.getState().recordDocumentUpdate(fileUri, extracted.ideas.length);
|
|
109
|
-
}
|
|
110
|
-
relativePath(fileUri) {
|
|
111
|
-
if (!fileUri.startsWith('file://') && !fileUri.startsWith('/')) {
|
|
112
|
-
return fileUri;
|
|
113
|
-
}
|
|
114
|
-
try {
|
|
115
|
-
const filePath = URI.parse(fileUri).fsPath;
|
|
116
|
-
return relative(this.workspaceRoot, filePath).replace(/\\/g, '/');
|
|
117
|
-
}
|
|
118
|
-
catch {
|
|
119
|
-
return fileUri;
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
resolveFileUri(pathInput) {
|
|
123
|
-
return resolveWorkspaceFileUri(pathInput, this.workspaceRoot);
|
|
124
|
-
}
|
|
125
|
-
listRqFiles(pathPrefix = '') {
|
|
126
|
-
return [...this.rqFilePaths]
|
|
127
|
-
.map(filePath => relative(this.workspaceRoot, filePath))
|
|
128
|
-
.filter(relativePath => !pathPrefix || relativePath.includes(pathPrefix))
|
|
129
|
-
.sort((left, right) => left.localeCompare(right));
|
|
130
|
-
}
|
|
131
|
-
async collectRqFiles() {
|
|
132
|
-
const results = [];
|
|
133
|
-
await this.walkDirectory(this.workspaceRoot, results);
|
|
134
|
-
this.rqFilePaths = results;
|
|
135
|
-
return results;
|
|
136
|
-
}
|
|
137
|
-
async walkDirectory(directory, results) {
|
|
138
|
-
let entries;
|
|
139
|
-
try {
|
|
140
|
-
entries = await readdir(directory, { withFileTypes: true });
|
|
141
|
-
}
|
|
142
|
-
catch {
|
|
143
|
-
return;
|
|
144
|
-
}
|
|
145
|
-
for (const entry of entries) {
|
|
146
|
-
if (entry.name.startsWith('.') || entry.name === 'node_modules') {
|
|
147
|
-
continue;
|
|
148
|
-
}
|
|
149
|
-
const fullPath = join(directory, entry.name);
|
|
150
|
-
if (entry.isDirectory()) {
|
|
151
|
-
await this.walkDirectory(fullPath, results);
|
|
152
|
-
continue;
|
|
153
|
-
}
|
|
154
|
-
if (entry.isFile() && entry.name.endsWith('.rq') && !isSecretRqPath(entry.name)) {
|
|
155
|
-
results.push(fullPath);
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
async parseDocument(filePath) {
|
|
160
|
-
try {
|
|
161
|
-
const text = await readFile(filePath, 'utf8');
|
|
162
|
-
const langiumUri = URI.file(filePath);
|
|
163
|
-
const document = this.services.shared.workspace.LangiumDocumentFactory.fromString(text, langiumUri);
|
|
164
|
-
await this.services.shared.workspace.DocumentBuilder.build([document], { validation: false });
|
|
165
|
-
return document;
|
|
166
|
-
}
|
|
167
|
-
catch {
|
|
168
|
-
return undefined;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Headless ideas index — re-exports the shared {@link WorkspaceIndex}.
|
|
3
|
+
* Prefer importing `WorkspaceIndex` for new code.
|
|
4
|
+
*/
|
|
5
|
+
export { WorkspaceIndex, WorkspaceIndex as HeadlessIndexService } from './index-store/workspace-index.js';
|
|
172
6
|
//# sourceMappingURL=headless-index-service.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"headless-index-service.js","sourceRoot":"","sources":["../src/headless-index-service.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"headless-index-service.js","sourceRoot":"","sources":["../src/headless-index-service.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EACH,cAAc,EACd,cAAc,IAAI,oBAAoB,EACzC,MAAM,kCAAkC,CAAC"}
|