Skip to content

Commit 9430b22

Browse files
committed
wip - improve topological sort
1 parent b28f5c9 commit 9430b22

File tree

9 files changed

+292
-128
lines changed

9 files changed

+292
-128
lines changed

build/cami.cdn.js

Lines changed: 37 additions & 30 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

build/cami.cdn.js.map

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

build/cami.module.js

Lines changed: 37 additions & 30 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

build/cami.module.js.map

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/javascripts/cami.cdn.js

Lines changed: 37 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ var cami = (() => {
6161
// src/cami.js
6262
var cami_exports = {};
6363
__export(cami_exports, {
64+
DependencyTracker: () => DependencyTracker,
6465
Observable: () => Observable,
6566
ObservableState: () => ObservableState,
6667
ObservableStore: () => ObservableStore,
@@ -2012,61 +2013,67 @@ var cami = (() => {
20122013
static detectCycles() {
20132014
const visited = /* @__PURE__ */ new Set();
20142015
const recursionStack = /* @__PURE__ */ new Set();
2015-
const cyclePath = [];
20162016
function dfs(node) {
20172017
visited.add(node);
20182018
recursionStack.add(node);
2019-
cyclePath.push(node);
20202019
const neighbors = _DependencyTracker.dependencyGraph.get(node) || /* @__PURE__ */ new Set();
20212020
for (const neighbor of neighbors) {
20222021
if (!visited.has(neighbor)) {
20232022
if (dfs(neighbor))
2024-
return true;
2023+
return [node, neighbor];
20252024
} else if (recursionStack.has(neighbor)) {
2026-
const cycleStart = cyclePath.indexOf(neighbor);
2027-
const cycle = cyclePath.slice(cycleStart);
2028-
console.warn(`Cyclic dependency detected: ${cycle.map((n) => n.__name || "unnamed").join(" -> ")}`);
2025+
return [node, neighbor];
20292026
}
20302027
}
20312028
recursionStack.delete(node);
2032-
cyclePath.pop();
2033-
return false;
2029+
return null;
20342030
}
20352031
for (const node of _DependencyTracker.dependencyGraph.keys()) {
20362032
if (!visited.has(node)) {
2037-
try {
2038-
if (dfs(node))
2039-
return true;
2040-
} catch (error) {
2041-
if (error.message.startsWith("Cyclic dependency detected:")) {
2042-
console.warn(error.message);
2043-
} else {
2044-
throw error;
2045-
}
2033+
const cycle = dfs(node);
2034+
if (cycle) {
2035+
throw new Error(`Dependency cycle detected: ${cycle[0]} <-> ${cycle[1]}`);
20462036
}
20472037
}
20482038
}
2049-
return false;
20502039
}
20512040
static clearGraph() {
20522041
_DependencyTracker.dependencyGraph.clear();
20532042
}
20542043
static topologicalSort() {
20552044
const visited = /* @__PURE__ */ new Set();
20562045
const stack = [];
2057-
function dfs(node) {
2058-
visited.add(node);
2059-
const neighbors = _DependencyTracker.dependencyGraph.get(node) || /* @__PURE__ */ new Set();
2060-
for (const neighbor of neighbors) {
2061-
if (!visited.has(neighbor)) {
2062-
dfs(neighbor);
2063-
}
2064-
}
2065-
stack.push(node);
2066-
}
2046+
const tempMark = /* @__PURE__ */ new Set();
2047+
const nodeStack = [];
20672048
for (const node of _DependencyTracker.dependencyGraph.keys()) {
2068-
if (!visited.has(node)) {
2069-
dfs(node);
2049+
if (visited.has(node))
2050+
continue;
2051+
nodeStack.push(node);
2052+
while (nodeStack.length > 0) {
2053+
const current2 = nodeStack[nodeStack.length - 1];
2054+
if (tempMark.has(current2)) {
2055+
throw new Error("Graph has a cycle");
2056+
}
2057+
if (!visited.has(current2)) {
2058+
tempMark.add(current2);
2059+
const neighbors = _DependencyTracker.dependencyGraph.get(current2) || /* @__PURE__ */ new Set();
2060+
let allVisited = true;
2061+
for (const neighbor of neighbors) {
2062+
if (!visited.has(neighbor)) {
2063+
nodeStack.push(neighbor);
2064+
allVisited = false;
2065+
break;
2066+
}
2067+
}
2068+
if (allVisited) {
2069+
visited.add(current2);
2070+
tempMark.delete(current2);
2071+
stack.push(current2);
2072+
nodeStack.pop();
2073+
}
2074+
} else {
2075+
nodeStack.pop();
2076+
}
20702077
}
20712078
}
20722079
return stack.reverse();

src/cami.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import { produce } from "immer";
1313
import { ReactiveElement } from './reactive-element.js';
1414
import { ObservableStore, store } from './observables/observable-store.js';
1515
import { Observable } from './observables/observable.js';
16-
import { ObservableState, effect } from './observables/observable-state.js';
16+
import { ObservableState, effect, DependencyTracker } from './observables/observable-state.js';
1717
import { __config } from './config.js';
1818
import { __trace } from './trace.js';
1919

@@ -31,4 +31,4 @@ const { debug, events } = __config;
3131
* @exports debug - The debug property from __config
3232
* @exports events - The events property from __config
3333
*/
34-
export { store, html, svg, ReactiveElement, Observable, ObservableState, ObservableStore, debug, events, effect };
34+
export { store, html, svg, ReactiveElement, Observable, ObservableState, ObservableStore, debug, events, effect, DependencyTracker };

0 commit comments

Comments
 (0)