@polycode-projects/seonix 0.1.0 → 0.2.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/bin/cli.mjs +95 -12
- package/package.json +5 -2
- package/src/ask-vocab.mjs +258 -0
- package/src/ask.mjs +762 -0
- package/src/browser.mjs +769 -0
- package/src/codegraph.mjs +352 -23
- package/src/cs_treesitter.mjs +2 -2
- package/src/extract.mjs +51 -8
- package/src/extract_lang.mjs +17 -2
- package/src/java_javaparser.mjs +54 -0
- package/src/java_treesitter.mjs +216 -0
- package/src/jsts_tsc.mjs +2 -2
- package/src/prose.mjs +145 -0
- package/src/schema-docs.mjs +225 -0
- package/src/server.mjs +35 -4
- package/src/temporal.mjs +559 -0
- package/src/viz.mjs +666 -94
- package/src/walk.mjs +52 -5
package/src/walk.mjs
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
// Shared deterministic file walker. Mirrors extract_ast.py's SKIP_DIRS so the
|
|
2
2
|
// spike extractors see the same source surface the Python path would.
|
|
3
|
-
|
|
3
|
+
// Also owns the `.seonixignore` matcher — a documented SUBSET of gitignore:
|
|
4
|
+
// blank lines and `#` comments skipped; `*` matches within a path segment,
|
|
5
|
+
// `**` across segments; a pattern containing `/` is anchored to the repo root
|
|
6
|
+
// (leading/trailing slashes stripped); one without `/` matches that name at
|
|
7
|
+
// any depth. No negation (`!`). A matched directory excludes its whole subtree.
|
|
8
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
4
9
|
import { join, relative, sep } from "node:path";
|
|
5
10
|
|
|
6
11
|
export const SKIP_DIRS = new Set([
|
|
@@ -9,10 +14,48 @@ export const SKIP_DIRS = new Set([
|
|
|
9
14
|
"bin", "obj", "out", "coverage", ".next", ".nuxt", ".angular", "wwwroot",
|
|
10
15
|
]);
|
|
11
16
|
|
|
17
|
+
export const IGNORE_FILE = ".seonixignore";
|
|
18
|
+
|
|
19
|
+
/** Parse `.seonixignore` text into compiled patterns (see header for semantics). */
|
|
20
|
+
export function parseIgnorePatterns(text) {
|
|
21
|
+
const out = [];
|
|
22
|
+
for (const raw of String(text).split("\n")) {
|
|
23
|
+
const line = raw.trim();
|
|
24
|
+
if (!line || line.startsWith("#")) continue;
|
|
25
|
+
const pat = line.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
26
|
+
if (!pat) continue;
|
|
27
|
+
const body = pat
|
|
28
|
+
.replace(/[.+?^${}()|[\]\\]/g, "\\$&")
|
|
29
|
+
.replace(/\*\*/g, "\u0000")
|
|
30
|
+
.replace(/\*/g, "[^/]*")
|
|
31
|
+
.replace(/\u0000/g, ".*");
|
|
32
|
+
// Anchored (contains "/") → match from the root; bare name → any depth.
|
|
33
|
+
// Trailing `(/|$)` makes a directory match cover its whole subtree.
|
|
34
|
+
out.push(pat.includes("/") ? new RegExp(`^${body}(/|$)`) : new RegExp(`(^|/)${body}(/|$)`));
|
|
35
|
+
}
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Build a matcher over compiled patterns: matcher(relPath) → true = ignored.
|
|
40
|
+
* `relPath` is repo-relative, forward-slash (file or directory). */
|
|
41
|
+
export function ignoreMatcher(patterns) {
|
|
42
|
+
if (!patterns || patterns.length === 0) return null;
|
|
43
|
+
return (rel) => patterns.some((re) => re.test(rel));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** Load `<root>/.seonixignore` → matcher, or null when absent/empty. */
|
|
47
|
+
export async function loadIgnores(root) {
|
|
48
|
+
let text;
|
|
49
|
+
try { text = await readFile(join(root, IGNORE_FILE), "utf8"); }
|
|
50
|
+
catch { return null; }
|
|
51
|
+
return ignoreMatcher(parseIgnorePatterns(text));
|
|
52
|
+
}
|
|
53
|
+
|
|
12
54
|
/** Recursively collect absolute file paths under `root` whose extension is in
|
|
13
55
|
* `exts` (lower-cased, with dot), skipping SKIP_DIRS and dot-dirs. Deterministic
|
|
14
|
-
* (sorted) so the emitted graph is byte-stable per commit.
|
|
15
|
-
|
|
56
|
+
* (sorted) so the emitted graph is byte-stable per commit. `ignore` (optional,
|
|
57
|
+
* from loadIgnores) prunes matched files and whole directories. */
|
|
58
|
+
export async function walk(root, exts, ignore = null) {
|
|
16
59
|
const want = new Set(exts.map((e) => e.toLowerCase()));
|
|
17
60
|
const out = [];
|
|
18
61
|
async function rec(dir) {
|
|
@@ -21,13 +64,17 @@ export async function walk(root, exts) {
|
|
|
21
64
|
catch { return; }
|
|
22
65
|
entries.sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
|
|
23
66
|
for (const e of entries) {
|
|
67
|
+
const abs = join(dir, e.name);
|
|
24
68
|
if (e.isDirectory()) {
|
|
25
69
|
if (SKIP_DIRS.has(e.name) || e.name.startsWith(".")) continue;
|
|
26
|
-
|
|
70
|
+
if (ignore && ignore(relPath(root, abs))) continue;
|
|
71
|
+
await rec(abs);
|
|
27
72
|
} else if (e.isFile()) {
|
|
28
73
|
const dot = e.name.lastIndexOf(".");
|
|
29
74
|
const ext = dot >= 0 ? e.name.slice(dot).toLowerCase() : "";
|
|
30
|
-
if (want.has(ext))
|
|
75
|
+
if (!want.has(ext)) continue;
|
|
76
|
+
if (ignore && ignore(relPath(root, abs))) continue;
|
|
77
|
+
out.push(abs);
|
|
31
78
|
}
|
|
32
79
|
}
|
|
33
80
|
}
|