@folterung/project-memory 0.1.21 → 0.1.22
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/package.json +1 -1
- package/packages/cli/coverage/lcov-report/chunking/chunker.ts.html +1 -1
- package/packages/cli/coverage/lcov-report/chunking/hash.ts.html +1 -1
- package/packages/cli/coverage/lcov-report/chunking/index.html +1 -1
- package/packages/cli/coverage/lcov-report/chunking/types.ts.html +1 -1
- package/packages/cli/coverage/lcov-report/config/index.html +7 -7
- package/packages/cli/coverage/lcov-report/config/load.ts.html +16 -4
- package/packages/cli/coverage/lcov-report/config/types.ts.html +35 -5
- package/packages/cli/coverage/lcov-report/embedding/index.html +1 -1
- package/packages/cli/coverage/lcov-report/embedding/stub.ts.html +1 -1
- package/packages/cli/coverage/lcov-report/index.html +21 -21
- package/packages/cli/coverage/lcov-report/qdrant/index.html +1 -1
- package/packages/cli/coverage/lcov-report/qdrant/upsert.ts.html +1 -1
- package/packages/cli/coverage/lcov-report/scope/allowlist.ts.html +1 -1
- package/packages/cli/coverage/lcov-report/scope/architecture-anchors.ts.html +529 -0
- package/packages/cli/coverage/lcov-report/scope/ignore.ts.html +1 -1
- package/packages/cli/coverage/lcov-report/scope/index.html +24 -9
- package/packages/cli/coverage/lcov.info +255 -19
- package/packages/cli/coverage/tmp/{coverage-24604-1770174821315-0.json → coverage-43283-1770177058833-0.json} +1 -1
- package/packages/cli/coverage/tmp/{coverage-24605-1770174821362-0.json → coverage-43284-1770177058881-0.json} +1 -1
- package/packages/cli/coverage/tmp/{coverage-24606-1770174821361-0.json → coverage-43285-1770177058878-0.json} +1 -1
- package/packages/cli/coverage/tmp/{coverage-24607-1770174821359-0.json → coverage-43286-1770177058876-0.json} +1 -1
- package/packages/cli/coverage/tmp/{coverage-24608-1770174821367-0.json → coverage-43287-1770177058882-0.json} +1 -1
- package/packages/cli/coverage/tmp/{coverage-24609-1770174821359-0.json → coverage-43288-1770177058880-0.json} +1 -1
- package/packages/cli/coverage/tmp/{coverage-24610-1770174821360-0.json → coverage-43289-1770177058879-0.json} +1 -1
- package/packages/cli/coverage/tmp/{coverage-24611-1770174821416-0.json → coverage-43290-1770177058933-0.json} +1 -1
- package/packages/cli/coverage/tmp/{coverage-24612-1770174821392-0.json → coverage-43291-1770177058905-0.json} +1 -1
- package/packages/cli/coverage/tmp/coverage-43292-1770177058903-0.json +1 -0
- package/packages/cli/coverage/tmp/{coverage-24613-1770174821380-0.json → coverage-43293-1770177058897-0.json} +1 -1
- package/packages/cli/dist/config/load.js +4 -0
- package/packages/cli/dist/config/load.js.map +1 -1
- package/packages/cli/dist/config/types.d.ts +8 -0
- package/packages/cli/dist/config/types.js +2 -0
- package/packages/cli/dist/config/types.js.map +1 -1
- package/packages/cli/dist/phase2/deep-index.js +39 -5
- package/packages/cli/dist/phase2/deep-index.js.map +1 -1
- package/packages/cli/dist/scope/architecture-anchors.d.ts +37 -0
- package/packages/cli/dist/scope/architecture-anchors.js +125 -0
- package/packages/cli/dist/scope/architecture-anchors.js.map +1 -0
- package/packages/cli/dist/scope/architecture-anchors.test.d.ts +1 -0
- package/packages/cli/dist/scope/architecture-anchors.test.js +58 -0
- package/packages/cli/dist/scope/architecture-anchors.test.js.map +1 -0
- package/packages/cli/src/config/load.ts +4 -0
- package/packages/cli/src/config/types.ts +11 -1
- package/packages/cli/src/phase2/deep-index.ts +43 -5
- package/packages/cli/src/scope/architecture-anchors.test.ts +83 -0
- package/packages/cli/src/scope/architecture-anchors.ts +148 -0
- package/packages/mcp-server/dist/system-instructions.md +7 -0
- package/packages/mcp-server/system-instructions.md +7 -0
- package/packages/server/coverage/lcov-report/api/index.html +5 -5
- package/packages/server/coverage/lcov-report/api/points.ts.html +1 -1
- package/packages/server/coverage/lcov-report/api/search.ts.html +14 -5
- package/packages/server/coverage/lcov-report/api/store.ts.html +1 -1
- package/packages/server/coverage/lcov-report/embedding/index.html +1 -1
- package/packages/server/coverage/lcov-report/embedding/stub.ts.html +1 -1
- package/packages/server/coverage/lcov-report/index.html +7 -7
- package/packages/server/coverage/lcov-report/qdrant/client.ts.html +1 -1
- package/packages/server/coverage/lcov-report/qdrant/index.html +1 -1
- package/packages/server/coverage/lcov.info +20 -17
- package/packages/server/coverage/tmp/{coverage-24692-1770174822211-0.json → coverage-43380-1770177059752-0.json} +1 -1
- package/packages/server/coverage/tmp/{coverage-24693-1770174822463-0.json → coverage-43381-1770177059983-0.json} +1 -1
- package/packages/server/coverage/tmp/{coverage-24694-1770174822454-0.json → coverage-43382-1770177059974-0.json} +1 -1
- package/packages/server/coverage/tmp/{coverage-24695-1770174822463-0.json → coverage-43383-1770177059981-0.json} +1 -1
- package/packages/server/coverage/tmp/{coverage-24696-1770174822253-0.json → coverage-43384-1770177059795-0.json} +1 -1
- package/packages/server/dist/api/search.js +3 -1
- package/packages/server/dist/api/search.js.map +1 -1
- package/packages/server/src/api/search.ts +4 -1
|
@@ -5,6 +5,10 @@ import { DEFAULT_CONFIG, CONFIG_FILE } from "./types.js";
|
|
|
5
5
|
function mergeConfig(loaded) {
|
|
6
6
|
return {
|
|
7
7
|
indexing: loaded.indexing ?? DEFAULT_CONFIG.indexing,
|
|
8
|
+
architectureAnchors: {
|
|
9
|
+
...DEFAULT_CONFIG.architectureAnchors,
|
|
10
|
+
...loaded.architectureAnchors,
|
|
11
|
+
},
|
|
8
12
|
phase1: { ...DEFAULT_CONFIG.phase1, ...loaded.phase1 },
|
|
9
13
|
qdrant: { ...DEFAULT_CONFIG.qdrant, ...loaded.qdrant },
|
|
10
14
|
chunk: { ...DEFAULT_CONFIG.chunk, ...loaded.chunk },
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"load.js","sourceRoot":"","sources":["../../src/config/load.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,IAAI,MAAM,SAAS,CAAC;AAE3B,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzD,SAAS,WAAW,CAAC,MAAiB;IACpC,OAAO;QACL,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,cAAc,CAAC,QAAQ;QACpD,MAAM,EAAE,EAAE,GAAG,cAAc,CAAC,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE;QACtD,MAAM,EAAE,EAAE,GAAG,cAAc,CAAC,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE;QACtD,KAAK,EAAE,EAAE,GAAG,cAAc,CAAC,KAAK,EAAE,GAAG,MAAM,CAAC,KAAK,EAAE;QACnD,SAAS,EAAE,EAAE,GAAG,cAAc,CAAC,SAAS,EAAE,GAAG,MAAM,CAAC,SAAS,EAAE;KAChE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IACpC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,OAAO,WAAW,CAAC,EAAE,CAAC,CAAC;IACzB,CAAC;IACD,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACvC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAA0B,CAAC;IACvD,OAAO,WAAW,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,OAAO,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,OAAO,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC;AAC5C,CAAC"}
|
|
1
|
+
{"version":3,"file":"load.js","sourceRoot":"","sources":["../../src/config/load.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,IAAI,MAAM,SAAS,CAAC;AAE3B,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzD,SAAS,WAAW,CAAC,MAAiB;IACpC,OAAO;QACL,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,cAAc,CAAC,QAAQ;QACpD,mBAAmB,EAAE;YACnB,GAAG,cAAc,CAAC,mBAAmB;YACrC,GAAG,MAAM,CAAC,mBAAmB;SAC9B;QACD,MAAM,EAAE,EAAE,GAAG,cAAc,CAAC,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE;QACtD,MAAM,EAAE,EAAE,GAAG,cAAc,CAAC,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE;QACtD,KAAK,EAAE,EAAE,GAAG,cAAc,CAAC,KAAK,EAAE,GAAG,MAAM,CAAC,KAAK,EAAE;QACnD,SAAS,EAAE,EAAE,GAAG,cAAc,CAAC,SAAS,EAAE,GAAG,MAAM,CAAC,SAAS,EAAE;KAChE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;IACpC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACtB,OAAO,WAAW,CAAC,EAAE,CAAC,CAAC;IACzB,CAAC;IACD,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACvC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,CAA0B,CAAC;IACvD,OAAO,WAAW,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;AACnC,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,OAAO,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,OAAO,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,CAAC;AAC5C,CAAC"}
|
|
@@ -3,6 +3,10 @@ export interface MemConfig {
|
|
|
3
3
|
include?: string[];
|
|
4
4
|
exclude?: string[];
|
|
5
5
|
};
|
|
6
|
+
architectureAnchors?: {
|
|
7
|
+
enabled?: boolean;
|
|
8
|
+
allowOutsideInclude?: boolean;
|
|
9
|
+
};
|
|
6
10
|
phase1?: {
|
|
7
11
|
maxEntrypointFiles?: number;
|
|
8
12
|
maxEntrypointChunks?: number;
|
|
@@ -25,6 +29,10 @@ export declare const DEFAULT_CONFIG: Required<Pick<MemConfig, "phase1" | "qdrant
|
|
|
25
29
|
include?: string[];
|
|
26
30
|
exclude?: string[];
|
|
27
31
|
};
|
|
32
|
+
architectureAnchors: {
|
|
33
|
+
enabled: boolean;
|
|
34
|
+
allowOutsideInclude: boolean;
|
|
35
|
+
};
|
|
28
36
|
};
|
|
29
37
|
export declare const CONFIG_DIR = ".mem";
|
|
30
38
|
export declare const CONFIG_FILE = ".mem/config.yml";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/config/types.ts"],"names":[],"mappings":"AA2BA,MAAM,4BAA4B,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,mBAAmB,EAAE,KAAK,EAAE,CAAC;AAEnF,MAAM,CAAC,MAAM,cAAc,GAKvB;IACF,mBAAmB,EAAE,4BAA4B;IACjD,MAAM,EAAE;QACN,kBAAkB,EAAE,EAAE;QACtB,mBAAmB,EAAE,GAAG;KACzB;IACD,MAAM,EAAE;QACN,IAAI,EAAE,WAAW;QACjB,IAAI,EAAE,IAAI;QACV,UAAU,EAAE,gBAAgB;KAC7B;IACD,KAAK,EAAE;QACL,QAAQ,EAAE,GAAG;QACb,QAAQ,EAAE,EAAE;KACb;IACD,SAAS,EAAE;QACT,QAAQ,EAAE,OAAO;KAClB;IACD,QAAQ,EAAE,EAAE;CACb,CAAC;AAEF,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC;AACjC,MAAM,CAAC,MAAM,WAAW,GAAG,iBAAiB,CAAC;AAC7C,MAAM,CAAC,MAAM,cAAc,GAAG,YAAY,CAAC;AAC3C,MAAM,CAAC,MAAM,qBAAqB,GAAG,4BAA4B,CAAC;AAClE,MAAM,CAAC,MAAM,sBAAsB,GAAG,wBAAwB,CAAC"}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
|
|
1
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync, statSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import chalk from "chalk";
|
|
4
4
|
import { loadConfig } from "../config/load.js";
|
|
5
5
|
import { chunkFile } from "../chunking/chunker.js";
|
|
6
6
|
import { embedBatch, textWithPathForEmbedding } from "../embedding/stub.js";
|
|
7
7
|
import { createQdrantClient, ensureCollection, upsertPoints } from "../qdrant/upsert.js";
|
|
8
|
-
import { listInScopeFiles } from "../scope/allowlist.js";
|
|
8
|
+
import { listInScopeFiles, toRelativePath } from "../scope/allowlist.js";
|
|
9
9
|
import { createIgnoreFilter } from "../scope/ignore.js";
|
|
10
|
-
import {
|
|
10
|
+
import { getArchitectureAnchorKind, listArchitectureAnchorPaths, DEFAULT_SOFT_ANCHOR_ROOTS, DEFAULT_MAX_SOFT_ANCHOR_FILE_BYTES, } from "../scope/architecture-anchors.js";
|
|
11
11
|
import { DEEP_INDEX_STATE_FILE } from "../config/types.js";
|
|
12
12
|
const BATCH_SIZE = 8;
|
|
13
13
|
const BATCH_DELAY_MS = 200;
|
|
@@ -42,12 +42,36 @@ export async function runDeepIndex(cwd) {
|
|
|
42
42
|
const config = loadConfig(cwd);
|
|
43
43
|
const isIgnored = createIgnoreFilter(cwd, config.indexing?.exclude ?? []);
|
|
44
44
|
const inScopePaths = listInScopeFiles(cwd, config);
|
|
45
|
-
|
|
45
|
+
let eligiblePaths = [];
|
|
46
46
|
for (const abs of inScopePaths) {
|
|
47
47
|
const rel = toRelativePath(cwd, abs);
|
|
48
48
|
if (!isIgnored(rel))
|
|
49
49
|
eligiblePaths.push(abs);
|
|
50
50
|
}
|
|
51
|
+
const anchorsEnabled = config.architectureAnchors?.enabled !== false;
|
|
52
|
+
const allowOutsideInclude = config.architectureAnchors?.allowOutsideInclude === true;
|
|
53
|
+
if (anchorsEnabled && allowOutsideInclude) {
|
|
54
|
+
const anchorPaths = listArchitectureAnchorPaths(cwd, {
|
|
55
|
+
allowedRoots: DEFAULT_SOFT_ANCHOR_ROOTS,
|
|
56
|
+
maxSoftAnchorFileBytes: DEFAULT_MAX_SOFT_ANCHOR_FILE_BYTES,
|
|
57
|
+
});
|
|
58
|
+
const eligibleSet = new Set(eligiblePaths);
|
|
59
|
+
for (const abs of anchorPaths) {
|
|
60
|
+
const rel = toRelativePath(cwd, abs);
|
|
61
|
+
if (!isIgnored(rel))
|
|
62
|
+
eligibleSet.add(abs);
|
|
63
|
+
}
|
|
64
|
+
eligiblePaths = [...eligibleSet];
|
|
65
|
+
}
|
|
66
|
+
const pathToSize = new Map();
|
|
67
|
+
for (const abs of eligiblePaths) {
|
|
68
|
+
try {
|
|
69
|
+
pathToSize.set(toRelativePath(cwd, abs), statSync(abs).size);
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// skip
|
|
73
|
+
}
|
|
74
|
+
}
|
|
51
75
|
const allChunks = [];
|
|
52
76
|
for (const abs of eligiblePaths) {
|
|
53
77
|
try {
|
|
@@ -84,8 +108,18 @@ export async function runDeepIndex(cwd) {
|
|
|
84
108
|
const vectors = embedBatch(texts);
|
|
85
109
|
const indexedAt = new Date().toISOString();
|
|
86
110
|
const points = batch.map((c, j) => {
|
|
111
|
+
let kind = "chunk";
|
|
112
|
+
if (anchorsEnabled) {
|
|
113
|
+
const anchorKind = getArchitectureAnchorKind(c.metadata.path, {
|
|
114
|
+
fileSizeBytes: pathToSize.get(c.metadata.path),
|
|
115
|
+
allowedRoots: DEFAULT_SOFT_ANCHOR_ROOTS,
|
|
116
|
+
maxSoftAnchorFileBytes: DEFAULT_MAX_SOFT_ANCHOR_FILE_BYTES,
|
|
117
|
+
});
|
|
118
|
+
if (anchorKind != null)
|
|
119
|
+
kind = anchorKind;
|
|
120
|
+
}
|
|
87
121
|
const payload = {
|
|
88
|
-
kind
|
|
122
|
+
kind,
|
|
89
123
|
path: c.metadata.path,
|
|
90
124
|
text: texts[j],
|
|
91
125
|
indexedAt,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deep-index.js","sourceRoot":"","sources":["../../src/phase2/deep-index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"deep-index.js","sourceRoot":"","sources":["../../src/phase2/deep-index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Architecture anchors: deterministic path rules for tagging entrypoints, routing,
|
|
3
|
+
* DI, bootstrap, and config so they can be retrieved for system-overview queries.
|
|
4
|
+
* Two tiers: hard anchors (explicit paths, always tag) and soft anchors (broader
|
|
5
|
+
* globs restricted to allowed roots and optional file size).
|
|
6
|
+
* Binaries (pdf, images, archives, fonts, etc.) are never considered anchors.
|
|
7
|
+
*/
|
|
8
|
+
export type ArchitectureAnchorKind = "entrypoint" | "routing" | "bootstrap" | "di" | "config";
|
|
9
|
+
/** Extensions that are never considered architecture anchors (binaries / non-code). */
|
|
10
|
+
export declare const BINARY_EXTENSIONS: Set<string>;
|
|
11
|
+
/** Default roots under which soft anchors are allowed (reduces false positives). */
|
|
12
|
+
export declare const DEFAULT_SOFT_ANCHOR_ROOTS: string[];
|
|
13
|
+
/** Default max file size (bytes) for soft anchors; larger files are not tagged. */
|
|
14
|
+
export declare const DEFAULT_MAX_SOFT_ANCHOR_FILE_BYTES: number;
|
|
15
|
+
export interface GetArchitectureAnchorKindOptions {
|
|
16
|
+
fileSizeBytes?: number;
|
|
17
|
+
allowedRoots?: string[];
|
|
18
|
+
maxSoftAnchorFileBytes?: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Returns the architecture anchor kind for a relative path, or undefined if not an anchor.
|
|
22
|
+
* Hard anchors (explicit entrypoint/wiring paths) are always tagged when matched.
|
|
23
|
+
* Soft anchors (broader patterns) are only tagged when path is under allowedRoots
|
|
24
|
+
* and (when fileSizeBytes is provided) under maxSoftAnchorFileBytes.
|
|
25
|
+
* Paths with binary extensions are never anchors.
|
|
26
|
+
*/
|
|
27
|
+
export declare function getArchitectureAnchorKind(relativePath: string, options?: GetArchitectureAnchorKindOptions): ArchitectureAnchorKind | undefined;
|
|
28
|
+
export interface ListArchitectureAnchorPathsOptions {
|
|
29
|
+
allowedRoots?: string[];
|
|
30
|
+
maxSoftAnchorFileBytes?: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Returns absolute paths of files in the repo that match architecture anchor rules.
|
|
34
|
+
* Used when allowOutsideInclude is true to merge anchor paths into eligible paths.
|
|
35
|
+
* Binary extensions are excluded; soft anchors are restricted to allowedRoots and file size.
|
|
36
|
+
*/
|
|
37
|
+
export declare function listArchitectureAnchorPaths(cwd: string, options?: ListArchitectureAnchorPathsOptions): string[];
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import fg from "fast-glob";
|
|
2
|
+
import { statSync } from "node:fs";
|
|
3
|
+
/** Extensions that are never considered architecture anchors (binaries / non-code). */
|
|
4
|
+
export const BINARY_EXTENSIONS = new Set([
|
|
5
|
+
"pdf", "png", "jpg", "jpeg", "gif", "ico", "webp", "svg",
|
|
6
|
+
"woff", "woff2", "ttf", "eot", "otf",
|
|
7
|
+
"zip", "tar", "gz", "rar", "7z",
|
|
8
|
+
"exe", "dll", "so", "dylib", "bin",
|
|
9
|
+
]);
|
|
10
|
+
/** Default roots under which soft anchors are allowed (reduces false positives). */
|
|
11
|
+
export const DEFAULT_SOFT_ANCHOR_ROOTS = ["app/", "src/", "public/", "server/", "api/"];
|
|
12
|
+
/** Default max file size (bytes) for soft anchors; larger files are not tagged. */
|
|
13
|
+
export const DEFAULT_MAX_SOFT_ANCHOR_FILE_BYTES = 200 * 1024;
|
|
14
|
+
/**
|
|
15
|
+
* Returns the architecture anchor kind for a relative path, or undefined if not an anchor.
|
|
16
|
+
* Hard anchors (explicit entrypoint/wiring paths) are always tagged when matched.
|
|
17
|
+
* Soft anchors (broader patterns) are only tagged when path is under allowedRoots
|
|
18
|
+
* and (when fileSizeBytes is provided) under maxSoftAnchorFileBytes.
|
|
19
|
+
* Paths with binary extensions are never anchors.
|
|
20
|
+
*/
|
|
21
|
+
export function getArchitectureAnchorKind(relativePath, options) {
|
|
22
|
+
const normalized = relativePath.replace(/\\/g, "/");
|
|
23
|
+
const ext = extFromPath(normalized);
|
|
24
|
+
if (ext && BINARY_EXTENSIONS.has(ext.toLowerCase())) {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
const kind = matchHardAnchor(normalized) ?? matchSoftAnchor(normalized, options);
|
|
28
|
+
return kind;
|
|
29
|
+
}
|
|
30
|
+
function extFromPath(path) {
|
|
31
|
+
const i = path.lastIndexOf(".");
|
|
32
|
+
if (i === -1)
|
|
33
|
+
return "";
|
|
34
|
+
return path.slice(i + 1);
|
|
35
|
+
}
|
|
36
|
+
/** Hard anchors: explicit, narrow paths. No size/root constraints. */
|
|
37
|
+
function matchHardAnchor(normalized) {
|
|
38
|
+
const entrypointExts = ["ts", "tsx", "js", "jsx", "html", "php"];
|
|
39
|
+
if (pathMatches(normalized, "public/index", entrypointExts))
|
|
40
|
+
return "entrypoint";
|
|
41
|
+
if (pathMatches(normalized, "src/index", ["ts", "tsx", "js", "jsx"]))
|
|
42
|
+
return "entrypoint";
|
|
43
|
+
if (pathMatches(normalized, "server/index", ["ts", "js"]))
|
|
44
|
+
return "entrypoint";
|
|
45
|
+
if (pathMatches(normalized, "api/index", ["ts", "js"]))
|
|
46
|
+
return "entrypoint";
|
|
47
|
+
if (pathMatches(normalized, "app/index", ["ts", "tsx", "js", "jsx", "php"]))
|
|
48
|
+
return "entrypoint";
|
|
49
|
+
if (pathMatches(normalized, "app/routes", ["ts", "js"]))
|
|
50
|
+
return "routing";
|
|
51
|
+
if (pathMatches(normalized, "app/dependencies", ["ts", "js"]))
|
|
52
|
+
return "di";
|
|
53
|
+
if (pathMatches(normalized, "app/settings", ["ts", "js"]))
|
|
54
|
+
return "config";
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
function pathMatches(normalized, prefix, exts) {
|
|
58
|
+
for (const ext of exts) {
|
|
59
|
+
if (normalized === `${prefix}.${ext}`)
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
/** Soft anchors: broader patterns, only under allowed roots and optional size cap. */
|
|
65
|
+
function matchSoftAnchor(normalized, options) {
|
|
66
|
+
const roots = options?.allowedRoots ?? DEFAULT_SOFT_ANCHOR_ROOTS;
|
|
67
|
+
const underRoot = roots.some((r) => normalized === r.slice(0, -1) || normalized.startsWith(r));
|
|
68
|
+
if (!underRoot)
|
|
69
|
+
return undefined;
|
|
70
|
+
const maxBytes = options?.maxSoftAnchorFileBytes ?? DEFAULT_MAX_SOFT_ANCHOR_FILE_BYTES;
|
|
71
|
+
if (options?.fileSizeBytes != null && options.fileSizeBytes > maxBytes) {
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
if (normalized.includes("/routes/") || /\/routes\.(ts|js)$/.test(normalized))
|
|
75
|
+
return "routing";
|
|
76
|
+
if (/\/container[\w.-]*\.(ts|js)$/.test(normalized))
|
|
77
|
+
return "di";
|
|
78
|
+
if (/\/di[\w.-]*\.(ts|js)$/.test(normalized))
|
|
79
|
+
return "di";
|
|
80
|
+
if (/\/middleware[\w.-]*\.(ts|js)$/.test(normalized))
|
|
81
|
+
return "bootstrap";
|
|
82
|
+
if (/\/bootstrap[\w.-]*\.(ts|js)$/.test(normalized))
|
|
83
|
+
return "bootstrap";
|
|
84
|
+
if (/\/config[\w.-]*\.(ts|js|yml|yaml)$/.test(normalized))
|
|
85
|
+
return "config";
|
|
86
|
+
if (/\/settings[\w.-]*\.(ts|js)$/.test(normalized))
|
|
87
|
+
return "config";
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Returns absolute paths of files in the repo that match architecture anchor rules.
|
|
92
|
+
* Used when allowOutsideInclude is true to merge anchor paths into eligible paths.
|
|
93
|
+
* Binary extensions are excluded; soft anchors are restricted to allowedRoots and file size.
|
|
94
|
+
*/
|
|
95
|
+
export function listArchitectureAnchorPaths(cwd, options) {
|
|
96
|
+
const allowedRoots = options?.allowedRoots ?? DEFAULT_SOFT_ANCHOR_ROOTS;
|
|
97
|
+
const maxBytes = options?.maxSoftAnchorFileBytes ?? DEFAULT_MAX_SOFT_ANCHOR_FILE_BYTES;
|
|
98
|
+
const files = fg.sync("**/*", {
|
|
99
|
+
cwd,
|
|
100
|
+
dot: true,
|
|
101
|
+
onlyFiles: true,
|
|
102
|
+
absolute: true,
|
|
103
|
+
suppressErrors: true,
|
|
104
|
+
});
|
|
105
|
+
const result = [];
|
|
106
|
+
for (const abs of files) {
|
|
107
|
+
const rel = abs.slice(cwd.length).replace(/^[/\\]+/, "").replace(/\\/g, "/");
|
|
108
|
+
let fileSizeBytes;
|
|
109
|
+
try {
|
|
110
|
+
fileSizeBytes = statSync(abs).size;
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
const kind = getArchitectureAnchorKind(rel, {
|
|
116
|
+
fileSizeBytes,
|
|
117
|
+
allowedRoots,
|
|
118
|
+
maxSoftAnchorFileBytes: maxBytes,
|
|
119
|
+
});
|
|
120
|
+
if (kind != null)
|
|
121
|
+
result.push(abs);
|
|
122
|
+
}
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=architecture-anchors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"architecture-anchors.js","sourceRoot":"","sources":["../../src/scope/architecture-anchors.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { describe, it } from "node:test";
|
|
2
|
+
import assert from "node:assert";
|
|
3
|
+
import { getArchitectureAnchorKind, BINARY_EXTENSIONS, DEFAULT_SOFT_ANCHOR_ROOTS, } from "./architecture-anchors.js";
|
|
4
|
+
describe("getArchitectureAnchorKind", () => {
|
|
5
|
+
it("returns undefined for binary extensions", () => {
|
|
6
|
+
assert.strictEqual(getArchitectureAnchorKind("public/image.png"), undefined);
|
|
7
|
+
assert.strictEqual(getArchitectureAnchorKind("docs/readme.pdf"), undefined);
|
|
8
|
+
assert.strictEqual(getArchitectureAnchorKind("dist/app.dll"), undefined);
|
|
9
|
+
});
|
|
10
|
+
it("returns entrypoint for hard anchor paths", () => {
|
|
11
|
+
assert.strictEqual(getArchitectureAnchorKind("public/index.html"), "entrypoint");
|
|
12
|
+
assert.strictEqual(getArchitectureAnchorKind("src/index.ts"), "entrypoint");
|
|
13
|
+
assert.strictEqual(getArchitectureAnchorKind("app/index.js"), "entrypoint");
|
|
14
|
+
assert.strictEqual(getArchitectureAnchorKind("server/index.ts"), "entrypoint");
|
|
15
|
+
assert.strictEqual(getArchitectureAnchorKind("api/index.js"), "entrypoint");
|
|
16
|
+
});
|
|
17
|
+
it("returns routing for app/routes", () => {
|
|
18
|
+
assert.strictEqual(getArchitectureAnchorKind("app/routes.ts"), "routing");
|
|
19
|
+
assert.strictEqual(getArchitectureAnchorKind("app/routes.js"), "routing");
|
|
20
|
+
});
|
|
21
|
+
it("returns di for app/dependencies and container/di files", () => {
|
|
22
|
+
assert.strictEqual(getArchitectureAnchorKind("app/dependencies.ts"), "di");
|
|
23
|
+
assert.strictEqual(getArchitectureAnchorKind("src/container.ts"), "di");
|
|
24
|
+
assert.strictEqual(getArchitectureAnchorKind("app/di.ts"), "di");
|
|
25
|
+
});
|
|
26
|
+
it("returns config for app/settings and config files", () => {
|
|
27
|
+
assert.strictEqual(getArchitectureAnchorKind("app/settings.ts"), "config");
|
|
28
|
+
assert.strictEqual(getArchitectureAnchorKind("src/config.ts"), "config");
|
|
29
|
+
assert.strictEqual(getArchitectureAnchorKind("app/config.local.yml"), "config");
|
|
30
|
+
});
|
|
31
|
+
it("returns bootstrap for middleware and bootstrap under allowed roots", () => {
|
|
32
|
+
assert.strictEqual(getArchitectureAnchorKind("src/middleware.ts"), "bootstrap");
|
|
33
|
+
assert.strictEqual(getArchitectureAnchorKind("app/bootstrap.ts"), "bootstrap");
|
|
34
|
+
});
|
|
35
|
+
it("returns undefined for soft patterns outside allowed roots when roots provided", () => {
|
|
36
|
+
const roots = ["app/", "src/"];
|
|
37
|
+
assert.strictEqual(getArchitectureAnchorKind("lib/container.ts", { allowedRoots: roots }), undefined);
|
|
38
|
+
assert.strictEqual(getArchitectureAnchorKind("app/container.ts", { allowedRoots: roots }), "di");
|
|
39
|
+
});
|
|
40
|
+
it("returns undefined for soft anchor when file size over threshold", () => {
|
|
41
|
+
const overLimit = DEFAULT_SOFT_ANCHOR_ROOTS.length ? 300 * 1024 : 0;
|
|
42
|
+
assert.strictEqual(getArchitectureAnchorKind("src/config.ts", { fileSizeBytes: overLimit }), undefined);
|
|
43
|
+
assert.strictEqual(getArchitectureAnchorKind("src/config.ts", { fileSizeBytes: 1000 }), "config");
|
|
44
|
+
});
|
|
45
|
+
it("returns chunk-like path as undefined when not matching anchor", () => {
|
|
46
|
+
assert.strictEqual(getArchitectureAnchorKind("src/utils/helper.ts"), undefined);
|
|
47
|
+
assert.strictEqual(getArchitectureAnchorKind("app/components/Button.tsx"), undefined);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
describe("BINARY_EXTENSIONS", () => {
|
|
51
|
+
it("includes common binary types", () => {
|
|
52
|
+
assert(BINARY_EXTENSIONS.has("pdf"));
|
|
53
|
+
assert(BINARY_EXTENSIONS.has("png"));
|
|
54
|
+
assert(BINARY_EXTENSIONS.has("woff2"));
|
|
55
|
+
assert(BINARY_EXTENSIONS.has("dll"));
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
//# sourceMappingURL=architecture-anchors.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"architecture-anchors.test.js","sourceRoot":"","sources":["../../src/scope/architecture-anchors.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,6 +7,10 @@ import { DEFAULT_CONFIG, CONFIG_FILE } from "./types.js";
|
|
|
7
7
|
function mergeConfig(loaded: MemConfig): MemConfig {
|
|
8
8
|
return {
|
|
9
9
|
indexing: loaded.indexing ?? DEFAULT_CONFIG.indexing,
|
|
10
|
+
architectureAnchors: {
|
|
11
|
+
...DEFAULT_CONFIG.architectureAnchors,
|
|
12
|
+
...loaded.architectureAnchors,
|
|
13
|
+
},
|
|
10
14
|
phase1: { ...DEFAULT_CONFIG.phase1, ...loaded.phase1 },
|
|
11
15
|
qdrant: { ...DEFAULT_CONFIG.qdrant, ...loaded.qdrant },
|
|
12
16
|
chunk: { ...DEFAULT_CONFIG.chunk, ...loaded.chunk },
|
|
@@ -3,6 +3,10 @@ export interface MemConfig {
|
|
|
3
3
|
include?: string[];
|
|
4
4
|
exclude?: string[];
|
|
5
5
|
};
|
|
6
|
+
architectureAnchors?: {
|
|
7
|
+
enabled?: boolean;
|
|
8
|
+
allowOutsideInclude?: boolean;
|
|
9
|
+
};
|
|
6
10
|
phase1?: {
|
|
7
11
|
maxEntrypointFiles?: number;
|
|
8
12
|
maxEntrypointChunks?: number;
|
|
@@ -21,9 +25,15 @@ export interface MemConfig {
|
|
|
21
25
|
};
|
|
22
26
|
}
|
|
23
27
|
|
|
28
|
+
const DEFAULT_ARCHITECTURE_ANCHORS = { enabled: true, allowOutsideInclude: false };
|
|
29
|
+
|
|
24
30
|
export const DEFAULT_CONFIG: Required<
|
|
25
31
|
Pick<MemConfig, "phase1" | "qdrant" | "chunk" | "embedding">
|
|
26
|
-
> & {
|
|
32
|
+
> & {
|
|
33
|
+
indexing: { include?: string[]; exclude?: string[] };
|
|
34
|
+
architectureAnchors: { enabled: boolean; allowOutsideInclude: boolean };
|
|
35
|
+
} = {
|
|
36
|
+
architectureAnchors: DEFAULT_ARCHITECTURE_ANCHORS,
|
|
27
37
|
phase1: {
|
|
28
38
|
maxEntrypointFiles: 50,
|
|
29
39
|
maxEntrypointChunks: 300,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readFileSync, writeFileSync, mkdirSync, existsSync } from "node:fs";
|
|
1
|
+
import { readFileSync, writeFileSync, mkdirSync, existsSync, statSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import chalk from "chalk";
|
|
4
4
|
import { loadConfig } from "../config/load.js";
|
|
@@ -6,9 +6,14 @@ import { chunkFile } from "../chunking/chunker.js";
|
|
|
6
6
|
import type { Chunk } from "../chunking/types.js";
|
|
7
7
|
import { embedBatch, textWithPathForEmbedding } from "../embedding/stub.js";
|
|
8
8
|
import { createQdrantClient, ensureCollection, upsertPoints } from "../qdrant/upsert.js";
|
|
9
|
-
import { listInScopeFiles } from "../scope/allowlist.js";
|
|
9
|
+
import { listInScopeFiles, toRelativePath } from "../scope/allowlist.js";
|
|
10
10
|
import { createIgnoreFilter } from "../scope/ignore.js";
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
getArchitectureAnchorKind,
|
|
13
|
+
listArchitectureAnchorPaths,
|
|
14
|
+
DEFAULT_SOFT_ANCHOR_ROOTS,
|
|
15
|
+
DEFAULT_MAX_SOFT_ANCHOR_FILE_BYTES,
|
|
16
|
+
} from "../scope/architecture-anchors.js";
|
|
12
17
|
import { DEEP_INDEX_STATE_FILE } from "../config/types.js";
|
|
13
18
|
|
|
14
19
|
const BATCH_SIZE = 8;
|
|
@@ -51,12 +56,36 @@ export async function runDeepIndex(cwd: string): Promise<void> {
|
|
|
51
56
|
const config = loadConfig(cwd);
|
|
52
57
|
const isIgnored = createIgnoreFilter(cwd, config.indexing?.exclude ?? []);
|
|
53
58
|
const inScopePaths = listInScopeFiles(cwd, config);
|
|
54
|
-
|
|
59
|
+
let eligiblePaths: string[] = [];
|
|
55
60
|
for (const abs of inScopePaths) {
|
|
56
61
|
const rel = toRelativePath(cwd, abs);
|
|
57
62
|
if (!isIgnored(rel)) eligiblePaths.push(abs);
|
|
58
63
|
}
|
|
59
64
|
|
|
65
|
+
const anchorsEnabled = config.architectureAnchors?.enabled !== false;
|
|
66
|
+
const allowOutsideInclude = config.architectureAnchors?.allowOutsideInclude === true;
|
|
67
|
+
if (anchorsEnabled && allowOutsideInclude) {
|
|
68
|
+
const anchorPaths = listArchitectureAnchorPaths(cwd, {
|
|
69
|
+
allowedRoots: DEFAULT_SOFT_ANCHOR_ROOTS,
|
|
70
|
+
maxSoftAnchorFileBytes: DEFAULT_MAX_SOFT_ANCHOR_FILE_BYTES,
|
|
71
|
+
});
|
|
72
|
+
const eligibleSet = new Set(eligiblePaths);
|
|
73
|
+
for (const abs of anchorPaths) {
|
|
74
|
+
const rel = toRelativePath(cwd, abs);
|
|
75
|
+
if (!isIgnored(rel)) eligibleSet.add(abs);
|
|
76
|
+
}
|
|
77
|
+
eligiblePaths = [...eligibleSet];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const pathToSize = new Map<string, number>();
|
|
81
|
+
for (const abs of eligiblePaths) {
|
|
82
|
+
try {
|
|
83
|
+
pathToSize.set(toRelativePath(cwd, abs), statSync(abs).size);
|
|
84
|
+
} catch {
|
|
85
|
+
// skip
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
60
89
|
const allChunks: Chunk[] = [];
|
|
61
90
|
for (const abs of eligiblePaths) {
|
|
62
91
|
try {
|
|
@@ -97,8 +126,17 @@ export async function runDeepIndex(cwd: string): Promise<void> {
|
|
|
97
126
|
const vectors = embedBatch(texts);
|
|
98
127
|
const indexedAt = new Date().toISOString();
|
|
99
128
|
const points = batch.map((c, j) => {
|
|
129
|
+
let kind = "chunk";
|
|
130
|
+
if (anchorsEnabled) {
|
|
131
|
+
const anchorKind = getArchitectureAnchorKind(c.metadata.path, {
|
|
132
|
+
fileSizeBytes: pathToSize.get(c.metadata.path),
|
|
133
|
+
allowedRoots: DEFAULT_SOFT_ANCHOR_ROOTS,
|
|
134
|
+
maxSoftAnchorFileBytes: DEFAULT_MAX_SOFT_ANCHOR_FILE_BYTES,
|
|
135
|
+
});
|
|
136
|
+
if (anchorKind != null) kind = anchorKind;
|
|
137
|
+
}
|
|
100
138
|
const payload: { kind: string; path: string; text: string; startLine?: number; endLine?: number; symbol?: string; indexedAt: string; source: string } = {
|
|
101
|
-
kind
|
|
139
|
+
kind,
|
|
102
140
|
path: c.metadata.path,
|
|
103
141
|
text: texts[j],
|
|
104
142
|
indexedAt,
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { describe, it } from "node:test";
|
|
2
|
+
import assert from "node:assert";
|
|
3
|
+
import {
|
|
4
|
+
getArchitectureAnchorKind,
|
|
5
|
+
BINARY_EXTENSIONS,
|
|
6
|
+
DEFAULT_SOFT_ANCHOR_ROOTS,
|
|
7
|
+
} from "./architecture-anchors.js";
|
|
8
|
+
|
|
9
|
+
describe("getArchitectureAnchorKind", () => {
|
|
10
|
+
it("returns undefined for binary extensions", () => {
|
|
11
|
+
assert.strictEqual(getArchitectureAnchorKind("public/image.png"), undefined);
|
|
12
|
+
assert.strictEqual(getArchitectureAnchorKind("docs/readme.pdf"), undefined);
|
|
13
|
+
assert.strictEqual(getArchitectureAnchorKind("dist/app.dll"), undefined);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("returns entrypoint for hard anchor paths", () => {
|
|
17
|
+
assert.strictEqual(getArchitectureAnchorKind("public/index.html"), "entrypoint");
|
|
18
|
+
assert.strictEqual(getArchitectureAnchorKind("src/index.ts"), "entrypoint");
|
|
19
|
+
assert.strictEqual(getArchitectureAnchorKind("app/index.js"), "entrypoint");
|
|
20
|
+
assert.strictEqual(getArchitectureAnchorKind("server/index.ts"), "entrypoint");
|
|
21
|
+
assert.strictEqual(getArchitectureAnchorKind("api/index.js"), "entrypoint");
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("returns routing for app/routes", () => {
|
|
25
|
+
assert.strictEqual(getArchitectureAnchorKind("app/routes.ts"), "routing");
|
|
26
|
+
assert.strictEqual(getArchitectureAnchorKind("app/routes.js"), "routing");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("returns di for app/dependencies and container/di files", () => {
|
|
30
|
+
assert.strictEqual(getArchitectureAnchorKind("app/dependencies.ts"), "di");
|
|
31
|
+
assert.strictEqual(getArchitectureAnchorKind("src/container.ts"), "di");
|
|
32
|
+
assert.strictEqual(getArchitectureAnchorKind("app/di.ts"), "di");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("returns config for app/settings and config files", () => {
|
|
36
|
+
assert.strictEqual(getArchitectureAnchorKind("app/settings.ts"), "config");
|
|
37
|
+
assert.strictEqual(getArchitectureAnchorKind("src/config.ts"), "config");
|
|
38
|
+
assert.strictEqual(getArchitectureAnchorKind("app/config.local.yml"), "config");
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("returns bootstrap for middleware and bootstrap under allowed roots", () => {
|
|
42
|
+
assert.strictEqual(getArchitectureAnchorKind("src/middleware.ts"), "bootstrap");
|
|
43
|
+
assert.strictEqual(getArchitectureAnchorKind("app/bootstrap.ts"), "bootstrap");
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("returns undefined for soft patterns outside allowed roots when roots provided", () => {
|
|
47
|
+
const roots = ["app/", "src/"];
|
|
48
|
+
assert.strictEqual(
|
|
49
|
+
getArchitectureAnchorKind("lib/container.ts", { allowedRoots: roots }),
|
|
50
|
+
undefined
|
|
51
|
+
);
|
|
52
|
+
assert.strictEqual(
|
|
53
|
+
getArchitectureAnchorKind("app/container.ts", { allowedRoots: roots }),
|
|
54
|
+
"di"
|
|
55
|
+
);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("returns undefined for soft anchor when file size over threshold", () => {
|
|
59
|
+
const overLimit = DEFAULT_SOFT_ANCHOR_ROOTS.length ? 300 * 1024 : 0;
|
|
60
|
+
assert.strictEqual(
|
|
61
|
+
getArchitectureAnchorKind("src/config.ts", { fileSizeBytes: overLimit }),
|
|
62
|
+
undefined
|
|
63
|
+
);
|
|
64
|
+
assert.strictEqual(
|
|
65
|
+
getArchitectureAnchorKind("src/config.ts", { fileSizeBytes: 1000 }),
|
|
66
|
+
"config"
|
|
67
|
+
);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("returns chunk-like path as undefined when not matching anchor", () => {
|
|
71
|
+
assert.strictEqual(getArchitectureAnchorKind("src/utils/helper.ts"), undefined);
|
|
72
|
+
assert.strictEqual(getArchitectureAnchorKind("app/components/Button.tsx"), undefined);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
describe("BINARY_EXTENSIONS", () => {
|
|
77
|
+
it("includes common binary types", () => {
|
|
78
|
+
assert(BINARY_EXTENSIONS.has("pdf"));
|
|
79
|
+
assert(BINARY_EXTENSIONS.has("png"));
|
|
80
|
+
assert(BINARY_EXTENSIONS.has("woff2"));
|
|
81
|
+
assert(BINARY_EXTENSIONS.has("dll"));
|
|
82
|
+
});
|
|
83
|
+
});
|