@lepid-labs/weft-core 0.1.0
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/LICENSE +21 -0
- package/dist/anchors/__tests__/markdown.test.d.ts +2 -0
- package/dist/anchors/__tests__/markdown.test.d.ts.map +1 -0
- package/dist/anchors/__tests__/markdown.test.js +130 -0
- package/dist/anchors/__tests__/markdown.test.js.map +1 -0
- package/dist/anchors/__tests__/openapi.test.d.ts +2 -0
- package/dist/anchors/__tests__/openapi.test.d.ts.map +1 -0
- package/dist/anchors/__tests__/openapi.test.js +115 -0
- package/dist/anchors/__tests__/openapi.test.js.map +1 -0
- package/dist/anchors/index.d.ts +35 -0
- package/dist/anchors/index.d.ts.map +1 -0
- package/dist/anchors/index.js +68 -0
- package/dist/anchors/index.js.map +1 -0
- package/dist/anchors/markdown.d.ts +15 -0
- package/dist/anchors/markdown.d.ts.map +1 -0
- package/dist/anchors/markdown.js +71 -0
- package/dist/anchors/markdown.js.map +1 -0
- package/dist/anchors/openapi.d.ts +24 -0
- package/dist/anchors/openapi.d.ts.map +1 -0
- package/dist/anchors/openapi.js +75 -0
- package/dist/anchors/openapi.js.map +1 -0
- package/dist/browser.d.ts +10 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +8 -0
- package/dist/browser.js.map +1 -0
- package/dist/config.d.ts +47 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +393 -0
- package/dist/config.js.map +1 -0
- package/dist/config.test.d.ts +2 -0
- package/dist/config.test.d.ts.map +1 -0
- package/dist/config.test.js +454 -0
- package/dist/config.test.js.map +1 -0
- package/dist/content.d.ts +37 -0
- package/dist/content.d.ts.map +1 -0
- package/dist/content.js +57 -0
- package/dist/content.js.map +1 -0
- package/dist/content.test.d.ts +2 -0
- package/dist/content.test.d.ts.map +1 -0
- package/dist/content.test.js +100 -0
- package/dist/content.test.js.map +1 -0
- package/dist/contributions.d.ts +64 -0
- package/dist/contributions.d.ts.map +1 -0
- package/dist/contributions.js +184 -0
- package/dist/contributions.js.map +1 -0
- package/dist/contributions.test.d.ts +2 -0
- package/dist/contributions.test.d.ts.map +1 -0
- package/dist/contributions.test.js +202 -0
- package/dist/contributions.test.js.map +1 -0
- package/dist/fetch/auth.d.ts +15 -0
- package/dist/fetch/auth.d.ts.map +1 -0
- package/dist/fetch/auth.js +38 -0
- package/dist/fetch/auth.js.map +1 -0
- package/dist/fetch/cache.d.ts +25 -0
- package/dist/fetch/cache.d.ts.map +1 -0
- package/dist/fetch/cache.js +68 -0
- package/dist/fetch/cache.js.map +1 -0
- package/dist/fetch/cache.test.d.ts +2 -0
- package/dist/fetch/cache.test.d.ts.map +1 -0
- package/dist/fetch/cache.test.js +73 -0
- package/dist/fetch/cache.test.js.map +1 -0
- package/dist/fetch/clone.d.ts +26 -0
- package/dist/fetch/clone.d.ts.map +1 -0
- package/dist/fetch/clone.js +105 -0
- package/dist/fetch/clone.js.map +1 -0
- package/dist/fetch/fetch.test.d.ts +2 -0
- package/dist/fetch/fetch.test.d.ts.map +1 -0
- package/dist/fetch/fetch.test.js +167 -0
- package/dist/fetch/fetch.test.js.map +1 -0
- package/dist/fetch/resolve.d.ts +34 -0
- package/dist/fetch/resolve.d.ts.map +1 -0
- package/dist/fetch/resolve.js +59 -0
- package/dist/fetch/resolve.js.map +1 -0
- package/dist/freshness.d.ts +29 -0
- package/dist/freshness.d.ts.map +1 -0
- package/dist/freshness.js +170 -0
- package/dist/freshness.js.map +1 -0
- package/dist/freshness.test.d.ts +2 -0
- package/dist/freshness.test.d.ts.map +1 -0
- package/dist/freshness.test.js +209 -0
- package/dist/freshness.test.js.map +1 -0
- package/dist/frontmatter.d.ts +15 -0
- package/dist/frontmatter.d.ts.map +1 -0
- package/dist/frontmatter.js +24 -0
- package/dist/frontmatter.js.map +1 -0
- package/dist/frontmatter.test.d.ts +2 -0
- package/dist/frontmatter.test.d.ts.map +1 -0
- package/dist/frontmatter.test.js +54 -0
- package/dist/frontmatter.test.js.map +1 -0
- package/dist/git.d.ts +55 -0
- package/dist/git.d.ts.map +1 -0
- package/dist/git.js +127 -0
- package/dist/git.js.map +1 -0
- package/dist/git.test.d.ts +2 -0
- package/dist/git.test.d.ts.map +1 -0
- package/dist/git.test.js +198 -0
- package/dist/git.test.js.map +1 -0
- package/dist/includes.d.ts +53 -0
- package/dist/includes.d.ts.map +1 -0
- package/dist/includes.js +73 -0
- package/dist/includes.js.map +1 -0
- package/dist/includes.test.d.ts +2 -0
- package/dist/includes.test.d.ts.map +1 -0
- package/dist/includes.test.js +106 -0
- package/dist/includes.test.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/links/__tests__/markdown.test.d.ts +2 -0
- package/dist/links/__tests__/markdown.test.d.ts.map +1 -0
- package/dist/links/__tests__/markdown.test.js +173 -0
- package/dist/links/__tests__/markdown.test.js.map +1 -0
- package/dist/links/__tests__/sidecar.test.d.ts +2 -0
- package/dist/links/__tests__/sidecar.test.d.ts.map +1 -0
- package/dist/links/__tests__/sidecar.test.js +238 -0
- package/dist/links/__tests__/sidecar.test.js.map +1 -0
- package/dist/links/index.d.ts +3 -0
- package/dist/links/index.d.ts.map +1 -0
- package/dist/links/index.js +3 -0
- package/dist/links/index.js.map +1 -0
- package/dist/links/markdown.d.ts +13 -0
- package/dist/links/markdown.d.ts.map +1 -0
- package/dist/links/markdown.js +93 -0
- package/dist/links/markdown.js.map +1 -0
- package/dist/links/sidecar.d.ts +12 -0
- package/dist/links/sidecar.d.ts.map +1 -0
- package/dist/links/sidecar.js +88 -0
- package/dist/links/sidecar.js.map +1 -0
- package/dist/manifest.d.ts +45 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +269 -0
- package/dist/manifest.js.map +1 -0
- package/dist/manifest.test.d.ts +2 -0
- package/dist/manifest.test.d.ts.map +1 -0
- package/dist/manifest.test.js +625 -0
- package/dist/manifest.test.js.map +1 -0
- package/dist/multi-repo.test.d.ts +2 -0
- package/dist/multi-repo.test.d.ts.map +1 -0
- package/dist/multi-repo.test.js +179 -0
- package/dist/multi-repo.test.js.map +1 -0
- package/dist/node-path.d.ts +13 -0
- package/dist/node-path.d.ts.map +1 -0
- package/dist/node-path.js +21 -0
- package/dist/node-path.js.map +1 -0
- package/dist/node-path.test.d.ts +2 -0
- package/dist/node-path.test.d.ts.map +1 -0
- package/dist/node-path.test.js +29 -0
- package/dist/node-path.test.js.map +1 -0
- package/dist/published-links.d.ts +16 -0
- package/dist/published-links.d.ts.map +1 -0
- package/dist/published-links.js +59 -0
- package/dist/published-links.js.map +1 -0
- package/dist/published-links.test.d.ts +2 -0
- package/dist/published-links.test.d.ts.map +1 -0
- package/dist/published-links.test.js +82 -0
- package/dist/published-links.test.js.map +1 -0
- package/dist/repos.d.ts +32 -0
- package/dist/repos.d.ts.map +1 -0
- package/dist/repos.js +46 -0
- package/dist/repos.js.map +1 -0
- package/dist/repos.test.d.ts +2 -0
- package/dist/repos.test.d.ts.map +1 -0
- package/dist/repos.test.js +61 -0
- package/dist/repos.test.js.map +1 -0
- package/dist/scalar-source.d.ts +15 -0
- package/dist/scalar-source.d.ts.map +1 -0
- package/dist/scalar-source.js +21 -0
- package/dist/scalar-source.js.map +1 -0
- package/dist/search.d.ts +14 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +59 -0
- package/dist/search.js.map +1 -0
- package/dist/service-concurrency.test.d.ts +2 -0
- package/dist/service-concurrency.test.d.ts.map +1 -0
- package/dist/service-concurrency.test.js +89 -0
- package/dist/service-concurrency.test.js.map +1 -0
- package/dist/service-history.test.d.ts +2 -0
- package/dist/service-history.test.d.ts.map +1 -0
- package/dist/service-history.test.js +76 -0
- package/dist/service-history.test.js.map +1 -0
- package/dist/service.d.ts +118 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/service.js +347 -0
- package/dist/service.js.map +1 -0
- package/dist/service.test.d.ts +2 -0
- package/dist/service.test.d.ts.map +1 -0
- package/dist/service.test.js +313 -0
- package/dist/service.test.js.map +1 -0
- package/dist/types.d.ts +403 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/validate/__tests__/artifacts.test.d.ts +2 -0
- package/dist/validate/__tests__/artifacts.test.d.ts.map +1 -0
- package/dist/validate/__tests__/artifacts.test.js +167 -0
- package/dist/validate/__tests__/artifacts.test.js.map +1 -0
- package/dist/validate/__tests__/assertions.test.d.ts +2 -0
- package/dist/validate/__tests__/assertions.test.d.ts.map +1 -0
- package/dist/validate/__tests__/assertions.test.js +254 -0
- package/dist/validate/__tests__/assertions.test.js.map +1 -0
- package/dist/validate/__tests__/duplicates.test.d.ts +2 -0
- package/dist/validate/__tests__/duplicates.test.d.ts.map +1 -0
- package/dist/validate/__tests__/duplicates.test.js +130 -0
- package/dist/validate/__tests__/duplicates.test.js.map +1 -0
- package/dist/validate/__tests__/edge-resolution.test.d.ts +2 -0
- package/dist/validate/__tests__/edge-resolution.test.d.ts.map +1 -0
- package/dist/validate/__tests__/edge-resolution.test.js +279 -0
- package/dist/validate/__tests__/edge-resolution.test.js.map +1 -0
- package/dist/validate/__tests__/history.test.d.ts +2 -0
- package/dist/validate/__tests__/history.test.d.ts.map +1 -0
- package/dist/validate/__tests__/history.test.js +93 -0
- package/dist/validate/__tests__/history.test.js.map +1 -0
- package/dist/validate/__tests__/includes.test.d.ts +2 -0
- package/dist/validate/__tests__/includes.test.d.ts.map +1 -0
- package/dist/validate/__tests__/includes.test.js +93 -0
- package/dist/validate/__tests__/includes.test.js.map +1 -0
- package/dist/validate/__tests__/registry.test.d.ts +2 -0
- package/dist/validate/__tests__/registry.test.d.ts.map +1 -0
- package/dist/validate/__tests__/registry.test.js +78 -0
- package/dist/validate/__tests__/registry.test.js.map +1 -0
- package/dist/validate/__tests__/run.test.d.ts +2 -0
- package/dist/validate/__tests__/run.test.d.ts.map +1 -0
- package/dist/validate/__tests__/run.test.js +215 -0
- package/dist/validate/__tests__/run.test.js.map +1 -0
- package/dist/validate/history.d.ts +23 -0
- package/dist/validate/history.d.ts.map +1 -0
- package/dist/validate/history.js +45 -0
- package/dist/validate/history.js.map +1 -0
- package/dist/validate/index.d.ts +10 -0
- package/dist/validate/index.d.ts.map +1 -0
- package/dist/validate/index.js +9 -0
- package/dist/validate/index.js.map +1 -0
- package/dist/validate/registry.d.ts +27 -0
- package/dist/validate/registry.d.ts.map +1 -0
- package/dist/validate/registry.js +67 -0
- package/dist/validate/registry.js.map +1 -0
- package/dist/validate/rules/artifacts.d.ts +25 -0
- package/dist/validate/rules/artifacts.d.ts.map +1 -0
- package/dist/validate/rules/artifacts.js +87 -0
- package/dist/validate/rules/artifacts.js.map +1 -0
- package/dist/validate/rules/assertions.d.ts +19 -0
- package/dist/validate/rules/assertions.d.ts.map +1 -0
- package/dist/validate/rules/assertions.js +149 -0
- package/dist/validate/rules/assertions.js.map +1 -0
- package/dist/validate/rules/duplicates.d.ts +20 -0
- package/dist/validate/rules/duplicates.d.ts.map +1 -0
- package/dist/validate/rules/duplicates.js +0 -0
- package/dist/validate/rules/duplicates.js.map +1 -0
- package/dist/validate/rules/edge-resolution.d.ts +15 -0
- package/dist/validate/rules/edge-resolution.d.ts.map +1 -0
- package/dist/validate/rules/edge-resolution.js +185 -0
- package/dist/validate/rules/edge-resolution.js.map +1 -0
- package/dist/validate/rules/includes.d.ts +21 -0
- package/dist/validate/rules/includes.d.ts.map +1 -0
- package/dist/validate/rules/includes.js +112 -0
- package/dist/validate/rules/includes.js.map +1 -0
- package/dist/validate/run.d.ts +20 -0
- package/dist/validate/run.d.ts.map +1 -0
- package/dist/validate/run.js +90 -0
- package/dist/validate/run.js.map +1 -0
- package/dist/validate/types.d.ts +101 -0
- package/dist/validate/types.d.ts.map +1 -0
- package/dist/validate/types.js +2 -0
- package/dist/validate/types.js.map +1 -0
- package/package.json +54 -0
package/dist/repos.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import { isAbsolute, resolve } from "node:path";
|
|
3
|
+
/** `org/repo`: exactly two non-empty segments, no whitespace. */
|
|
4
|
+
export const REPO_IDENTITY = /^[^/\s]+\/[^/\s]+$/;
|
|
5
|
+
/**
|
|
6
|
+
* Resolve the configured `repos` map to absolute checkout paths.
|
|
7
|
+
*
|
|
8
|
+
* `~` expands to the home directory here rather than being left to the shell,
|
|
9
|
+
* because the value arrives from a YAML file no shell ever touches.
|
|
10
|
+
*/
|
|
11
|
+
export function resolveRepos(repos, rootDir) {
|
|
12
|
+
const map = new Map();
|
|
13
|
+
for (const [identity, path] of Object.entries(repos ?? {})) {
|
|
14
|
+
const expanded = path === "~" || path.startsWith("~/") ? resolve(homedir(), path.slice(2)) : path;
|
|
15
|
+
map.set(identity, isAbsolute(expanded) ? expanded : resolve(rootDir, expanded));
|
|
16
|
+
}
|
|
17
|
+
return map;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Parse a GitHub blob URL into repo identity, in-repo path and fragment.
|
|
21
|
+
*
|
|
22
|
+
* Any `blob/<ref>/` segment is accepted — weft serves the working tree, so
|
|
23
|
+
* which ref the URL claims is a validation question, not a resolution one. The
|
|
24
|
+
* ref is taken to be a single path segment; a branch name containing `/` is
|
|
25
|
+
* indistinguishable from the leading directories of the path in a blob URL, so
|
|
26
|
+
* such a URL resolves to a path that exists in no docs root and stays an
|
|
27
|
+
* ordinary external link.
|
|
28
|
+
*/
|
|
29
|
+
export function parseGitHubBlobUrl(url) {
|
|
30
|
+
const match = /^https?:\/\/(?:www\.)?github\.com\/([^/\s]+\/[^/\s]+)\/blob\/[^/\s]+\/([^#\s]+)(#.+)?$/.exec(url);
|
|
31
|
+
if (!match)
|
|
32
|
+
return undefined;
|
|
33
|
+
let path;
|
|
34
|
+
try {
|
|
35
|
+
path = decodeURIComponent(match[2]);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
repo: match[1],
|
|
42
|
+
path,
|
|
43
|
+
...(match[3] ? { anchor: match[3] } : {}),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=repos.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repos.js","sourceRoot":"","sources":["../src/repos.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAKhD,iEAAiE;AACjE,MAAM,CAAC,MAAM,aAAa,GAAG,oBAAoB,CAAC;AAElD;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,KAAyC,EAAE,OAAe;IACtF,MAAM,GAAG,GAAY,IAAI,GAAG,EAAE,CAAC;IAC/B,KAAK,MAAM,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,CAAC;QAC5D,MAAM,QAAQ,GACb,IAAI,KAAK,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAClF,GAAG,CAAC,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;IACjF,CAAC;IACD,OAAO,GAAG,CAAC;AACZ,CAAC;AAYD;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC7C,MAAM,KAAK,GACV,wFAAwF,CAAC,IAAI,CAC5F,GAAG,CACH,CAAC;IACH,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAE7B,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACJ,IAAI,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,OAAO;QACN,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;QACd,IAAI;QACJ,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACzC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repos.test.d.ts","sourceRoot":"","sources":["../src/repos.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import { resolve } from "node:path";
|
|
3
|
+
import { describe, expect, it } from "vitest";
|
|
4
|
+
import { parseGitHubBlobUrl, resolveRepos } from "./repos.js";
|
|
5
|
+
const ROOT = resolve("/project");
|
|
6
|
+
describe("resolveRepos", () => {
|
|
7
|
+
it("returns an empty map for an absent config", () => {
|
|
8
|
+
expect(resolveRepos(undefined, ROOT).size).toBe(0);
|
|
9
|
+
});
|
|
10
|
+
it("resolves relative paths against the root dir", () => {
|
|
11
|
+
const repos = resolveRepos({ "acme/alpha": "../alpha" }, ROOT);
|
|
12
|
+
expect(repos.get("acme/alpha")).toBe(resolve(ROOT, "../alpha"));
|
|
13
|
+
});
|
|
14
|
+
it("keeps absolute paths as they are", () => {
|
|
15
|
+
const abs = resolve("/checkouts/beta");
|
|
16
|
+
const repos = resolveRepos({ "acme/beta": abs }, ROOT);
|
|
17
|
+
expect(repos.get("acme/beta")).toBe(abs);
|
|
18
|
+
});
|
|
19
|
+
it("expands ~ to the home directory", () => {
|
|
20
|
+
const repos = resolveRepos({ "acme/beta": "~/src/beta" }, ROOT);
|
|
21
|
+
expect(repos.get("acme/beta")).toBe(resolve(homedir(), "src/beta"));
|
|
22
|
+
});
|
|
23
|
+
it("does not expand ~ in the middle of a path", () => {
|
|
24
|
+
const repos = resolveRepos({ "acme/beta": "checkouts/~beta" }, ROOT);
|
|
25
|
+
expect(repos.get("acme/beta")).toBe(resolve(ROOT, "checkouts/~beta"));
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
describe("parseGitHubBlobUrl", () => {
|
|
29
|
+
it("parses repo identity, path and anchor", () => {
|
|
30
|
+
expect(parseGitHubBlobUrl("https://github.com/acme/alpha/blob/main/docs/api.md#endpoints")).toEqual({
|
|
31
|
+
repo: "acme/alpha",
|
|
32
|
+
path: "docs/api.md",
|
|
33
|
+
anchor: "#endpoints",
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
it("accepts any ref segment — weft serves the working tree", () => {
|
|
37
|
+
expect(parseGitHubBlobUrl("https://github.com/acme/alpha/blob/v2.1/docs/api.md")).toEqual({
|
|
38
|
+
repo: "acme/alpha",
|
|
39
|
+
path: "docs/api.md",
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
it("accepts http and a www prefix", () => {
|
|
43
|
+
expect(parseGitHubBlobUrl("http://www.github.com/acme/alpha/blob/main/README.md")).toEqual({
|
|
44
|
+
repo: "acme/alpha",
|
|
45
|
+
path: "README.md",
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
it("decodes percent-encoded paths", () => {
|
|
49
|
+
expect(parseGitHubBlobUrl("https://github.com/acme/alpha/blob/main/docs/release%20notes.md")?.path).toBe("docs/release notes.md");
|
|
50
|
+
});
|
|
51
|
+
it("returns undefined for tree URLs, other hosts, and non-blob paths", () => {
|
|
52
|
+
expect(parseGitHubBlobUrl("https://github.com/acme/alpha/tree/main/docs")).toBeUndefined();
|
|
53
|
+
expect(parseGitHubBlobUrl("https://gitlab.com/acme/alpha/blob/main/a.md")).toBeUndefined();
|
|
54
|
+
expect(parseGitHubBlobUrl("https://github.com/acme/alpha")).toBeUndefined();
|
|
55
|
+
expect(parseGitHubBlobUrl("https://github.com/acme/alpha/issues/12")).toBeUndefined();
|
|
56
|
+
});
|
|
57
|
+
it("returns undefined for a malformed percent encoding", () => {
|
|
58
|
+
expect(parseGitHubBlobUrl("https://github.com/acme/alpha/blob/main/%E0%A4%A.md")).toBeUndefined();
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
//# sourceMappingURL=repos.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repos.test.js","sourceRoot":"","sources":["../src/repos.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A YAML scalar's text exactly as it was written.
|
|
3
|
+
*
|
|
4
|
+
* YAML types unquoted scalars, and for the identifiers Weft carries around that
|
|
5
|
+
* is a loss rather than a convenience: `2.10` becomes the number 2.1, and a
|
|
6
|
+
* content hash whose sixteen hex characters happen to all be digits becomes an
|
|
7
|
+
* integer with its leading zeros gone. Either way the value stops matching the
|
|
8
|
+
* text the author wrote, and the mismatch exists only in the parse.
|
|
9
|
+
*
|
|
10
|
+
* The parser keeps each scalar's source text for exactly this reason, so prefer
|
|
11
|
+
* it and leave quoting to the author's taste. Returns undefined for an absent or
|
|
12
|
+
* empty value, which callers treat as "not declared".
|
|
13
|
+
*/
|
|
14
|
+
export declare function scalarText(node: unknown): string | undefined;
|
|
15
|
+
//# sourceMappingURL=scalar-source.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scalar-source.d.ts","sourceRoot":"","sources":["../src/scalar-source.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;GAYG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAK5D"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { isScalar } from "yaml";
|
|
2
|
+
/**
|
|
3
|
+
* A YAML scalar's text exactly as it was written.
|
|
4
|
+
*
|
|
5
|
+
* YAML types unquoted scalars, and for the identifiers Weft carries around that
|
|
6
|
+
* is a loss rather than a convenience: `2.10` becomes the number 2.1, and a
|
|
7
|
+
* content hash whose sixteen hex characters happen to all be digits becomes an
|
|
8
|
+
* integer with its leading zeros gone. Either way the value stops matching the
|
|
9
|
+
* text the author wrote, and the mismatch exists only in the parse.
|
|
10
|
+
*
|
|
11
|
+
* The parser keeps each scalar's source text for exactly this reason, so prefer
|
|
12
|
+
* it and leave quoting to the author's taste. Returns undefined for an absent or
|
|
13
|
+
* empty value, which callers treat as "not declared".
|
|
14
|
+
*/
|
|
15
|
+
export function scalarText(node) {
|
|
16
|
+
if (!isScalar(node) || node.value === null || node.value === undefined)
|
|
17
|
+
return undefined;
|
|
18
|
+
const source = typeof node.source === "string" ? node.source.trim() : "";
|
|
19
|
+
return source || String(node.value);
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=scalar-source.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scalar-source.js","sourceRoot":"","sources":["../src/scalar-source.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AAEhC;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,UAAU,CAAC,IAAa;IACvC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IAEzF,MAAM,MAAM,GAAG,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACzE,OAAO,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACrC,CAAC"}
|
package/dist/search.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Manifest, SearchResult } from "./types.js";
|
|
2
|
+
export declare class SearchIndex {
|
|
3
|
+
private index;
|
|
4
|
+
constructor();
|
|
5
|
+
/**
|
|
6
|
+
* Build the search index from a manifest. `resolvePath` maps a node id to an
|
|
7
|
+
* absolute file path — a function rather than a directory, since node ids may
|
|
8
|
+
* span several docs roots.
|
|
9
|
+
*/
|
|
10
|
+
build(manifest: Manifest, resolvePath: (nodeId: string) => string | undefined): void;
|
|
11
|
+
/** Search the index. */
|
|
12
|
+
search(query: string): SearchResult[];
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=search.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AASzD,qBAAa,WAAW;IACvB,OAAO,CAAC,KAAK,CAAwB;;IAcrC;;;;OAIG;IACH,KAAK,CAAC,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAAG,SAAS,GAAG,IAAI;IA8BpF,wBAAwB;IACxB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,EAAE;CASrC"}
|
package/dist/search.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import MiniSearch from "minisearch";
|
|
3
|
+
export class SearchIndex {
|
|
4
|
+
index;
|
|
5
|
+
constructor() {
|
|
6
|
+
this.index = new MiniSearch({
|
|
7
|
+
fields: ["title", "content", "anchors"],
|
|
8
|
+
storeFields: ["title"],
|
|
9
|
+
searchOptions: {
|
|
10
|
+
boost: { title: 3, anchors: 2, content: 1 },
|
|
11
|
+
fuzzy: 0.2,
|
|
12
|
+
prefix: true,
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Build the search index from a manifest. `resolvePath` maps a node id to an
|
|
18
|
+
* absolute file path — a function rather than a directory, since node ids may
|
|
19
|
+
* span several docs roots.
|
|
20
|
+
*/
|
|
21
|
+
build(manifest, resolvePath) {
|
|
22
|
+
this.index.removeAll();
|
|
23
|
+
// Artifacts are excluded outright. Reading a PDF as UTF-8 does not throw —
|
|
24
|
+
// it yields a lossy decode — so the catch below would never fire and the
|
|
25
|
+
// index would fill with binary noise that matches queries by accident.
|
|
26
|
+
const searchable = manifest.nodes.filter((node) => node.type !== "artifact");
|
|
27
|
+
const docs = searchable.map((node) => {
|
|
28
|
+
let content = "";
|
|
29
|
+
const path = resolvePath(node.id);
|
|
30
|
+
try {
|
|
31
|
+
if (path)
|
|
32
|
+
content = readFileSync(path, "utf-8");
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// File may not exist or be unreadable
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
id: node.id,
|
|
39
|
+
title: node.title,
|
|
40
|
+
content,
|
|
41
|
+
// Index the heading text alongside the slug: a reader searches for
|
|
42
|
+
// "Data Flow", not "data-flow".
|
|
43
|
+
anchors: node.anchors.map((a) => `${a.slug} ${a.text}`).join(" "),
|
|
44
|
+
};
|
|
45
|
+
});
|
|
46
|
+
this.index.addAll(docs);
|
|
47
|
+
}
|
|
48
|
+
/** Search the index. */
|
|
49
|
+
search(query) {
|
|
50
|
+
const results = this.index.search(query);
|
|
51
|
+
return results.map((r) => ({
|
|
52
|
+
id: r.id,
|
|
53
|
+
title: r.title,
|
|
54
|
+
score: r.score,
|
|
55
|
+
match: r.match,
|
|
56
|
+
}));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../src/search.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,UAAU,MAAM,YAAY,CAAC;AAUpC,MAAM,OAAO,WAAW;IACf,KAAK,CAAwB;IAErC;QACC,IAAI,CAAC,KAAK,GAAG,IAAI,UAAU,CAAY;YACtC,MAAM,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,SAAS,CAAC;YACvC,WAAW,EAAE,CAAC,OAAO,CAAC;YACtB,aAAa,EAAE;gBACd,KAAK,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE;gBAC3C,KAAK,EAAE,GAAG;gBACV,MAAM,EAAE,IAAI;aACZ;SACD,CAAC,CAAC;IACJ,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,QAAkB,EAAE,WAAmD;QAC5E,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,CAAC;QAEvB,2EAA2E;QAC3E,yEAAyE;QACzE,uEAAuE;QACvE,MAAM,UAAU,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,UAAU,CAAC,CAAC;QAE7E,MAAM,IAAI,GAAgB,UAAU,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;YACjD,IAAI,OAAO,GAAG,EAAE,CAAC;YACjB,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YAClC,IAAI,CAAC;gBACJ,IAAI,IAAI;oBAAE,OAAO,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YACjD,CAAC;YAAC,MAAM,CAAC;gBACR,sCAAsC;YACvC,CAAC;YAED,OAAO;gBACN,EAAE,EAAE,IAAI,CAAC,EAAE;gBACX,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,OAAO;gBACP,mEAAmE;gBACnE,gCAAgC;gBAChC,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;aACjE,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACzB,CAAC;IAED,wBAAwB;IACxB,MAAM,CAAC,KAAa;QACnB,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACzC,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC1B,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,KAAK,EAAG,CAAkC,CAAC,KAAK;YAChD,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,KAAK,EAAE,CAAC,CAAC,KAAK;SACd,CAAC,CAAC,CAAC;IACL,CAAC;CACD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-concurrency.test.d.ts","sourceRoot":"","sources":["../src/service-concurrency.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { cpSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
6
|
+
import { WeftService } from "./service.js";
|
|
7
|
+
const __dirname = resolve(fileURLToPath(import.meta.url), "..");
|
|
8
|
+
const FIXTURES_DIR = resolve(__dirname, "__fixtures__");
|
|
9
|
+
/**
|
|
10
|
+
* Hooks into the mocked `checkFreshness` below: `hold` keeps a check open
|
|
11
|
+
* after it has its answer in hand, so a test can complete a `rebuild()` in
|
|
12
|
+
* exactly the window between computing a freshness result and caching it —
|
|
13
|
+
* the interleaving an MCP server handling concurrent tool calls produces
|
|
14
|
+
* naturally, and one no amount of sequencing through the public API can pin
|
|
15
|
+
* down deterministically.
|
|
16
|
+
*/
|
|
17
|
+
const gate = {
|
|
18
|
+
hold: null,
|
|
19
|
+
reached: null,
|
|
20
|
+
calls: 0,
|
|
21
|
+
};
|
|
22
|
+
vi.mock("./freshness.js", async (importOriginal) => {
|
|
23
|
+
const actual = await importOriginal();
|
|
24
|
+
return {
|
|
25
|
+
...actual,
|
|
26
|
+
checkFreshness: async (...args) => {
|
|
27
|
+
gate.calls++;
|
|
28
|
+
const result = await actual.checkFreshness(...args);
|
|
29
|
+
gate.reached?.();
|
|
30
|
+
if (gate.hold)
|
|
31
|
+
await gate.hold;
|
|
32
|
+
return result;
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
});
|
|
36
|
+
const tempDirs = [];
|
|
37
|
+
function createWritableService() {
|
|
38
|
+
const dir = mkdtempSync(resolve(tmpdir(), "weft-concurrency-"));
|
|
39
|
+
tempDirs.push(dir);
|
|
40
|
+
cpSync(resolve(FIXTURES_DIR, "docs"), resolve(dir, "docs"), { recursive: true });
|
|
41
|
+
const service = new WeftService({
|
|
42
|
+
rootDir: dir,
|
|
43
|
+
docsDir: "docs",
|
|
44
|
+
entryPoint: "docs/README.md",
|
|
45
|
+
ignore: [],
|
|
46
|
+
});
|
|
47
|
+
return { dir, service };
|
|
48
|
+
}
|
|
49
|
+
afterEach(() => {
|
|
50
|
+
gate.hold = null;
|
|
51
|
+
gate.reached = null;
|
|
52
|
+
gate.calls = 0;
|
|
53
|
+
for (const dir of tempDirs.splice(0))
|
|
54
|
+
rmSync(dir, { recursive: true, force: true });
|
|
55
|
+
});
|
|
56
|
+
describe("WeftService freshness under concurrency", () => {
|
|
57
|
+
it("never caches a check that a rebuild overtook", async () => {
|
|
58
|
+
const { dir, service } = createWritableService();
|
|
59
|
+
await service.getManifest();
|
|
60
|
+
writeFileSync(resolve(dir, "docs", "architecture.md"), "# Changed\n");
|
|
61
|
+
let release;
|
|
62
|
+
gate.hold = new Promise((r) => {
|
|
63
|
+
release = r;
|
|
64
|
+
});
|
|
65
|
+
const reached = new Promise((r) => {
|
|
66
|
+
gate.reached = r;
|
|
67
|
+
});
|
|
68
|
+
const inFlight = service.freshness();
|
|
69
|
+
// The check has computed `stale` but not yet written it to the cache.
|
|
70
|
+
await reached;
|
|
71
|
+
await service.rebuild();
|
|
72
|
+
release();
|
|
73
|
+
// The overlapped caller still gets the honest answer for when it asked…
|
|
74
|
+
expect((await inFlight).status).toBe("stale");
|
|
75
|
+
// …but that answer was not cached over the rebuild's state: within the
|
|
76
|
+
// cache window, the next call re-checks and sees the rebuilt manifest.
|
|
77
|
+
expect((await service.freshness()).status).toBe("fresh");
|
|
78
|
+
});
|
|
79
|
+
it("coalesces concurrent cache misses onto one tree re-read", async () => {
|
|
80
|
+
const { service } = createWritableService();
|
|
81
|
+
await service.getManifest();
|
|
82
|
+
gate.calls = 0;
|
|
83
|
+
const [first, second] = await Promise.all([service.freshness(), service.freshness()]);
|
|
84
|
+
expect(first.status).toBe("fresh");
|
|
85
|
+
expect(second.status).toBe("fresh");
|
|
86
|
+
expect(gate.calls).toBe(1);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
//# sourceMappingURL=service-concurrency.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-concurrency.test.js","sourceRoot":"","sources":["../src/service-concurrency.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-history.test.d.ts","sourceRoot":"","sources":["../src/service-history.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { resolve } from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
4
|
+
import { WeftService } from "./service.js";
|
|
5
|
+
import { ValidatorRegistry } from "./validate/index.js";
|
|
6
|
+
// The point of these tests is counting subprocess spawns, so the walk itself
|
|
7
|
+
// is stubbed: every call lands in `walks` and yields an empty history, which
|
|
8
|
+
// both the indexer and validation accept as "git had nothing to say".
|
|
9
|
+
const walks = [];
|
|
10
|
+
vi.mock("./git.js", async (importOriginal) => {
|
|
11
|
+
const original = await importOriginal();
|
|
12
|
+
const fileHistory = async (dir, depth = "full") => {
|
|
13
|
+
walks.push({ dir, depth });
|
|
14
|
+
return { dates: new Map(), blobs: new Map(), renames: new Map() };
|
|
15
|
+
};
|
|
16
|
+
return {
|
|
17
|
+
...original,
|
|
18
|
+
fileHistory,
|
|
19
|
+
lastCommitDates: async (dir) => (await fileHistory(dir, "dates")).dates,
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
const __dirname = resolve(fileURLToPath(import.meta.url), "..");
|
|
23
|
+
const FIXTURES_DIR = resolve(__dirname, "__fixtures__");
|
|
24
|
+
function createService() {
|
|
25
|
+
const config = {
|
|
26
|
+
rootDir: FIXTURES_DIR,
|
|
27
|
+
docsDir: "docs",
|
|
28
|
+
entryPoint: "docs/README.md",
|
|
29
|
+
ignore: [],
|
|
30
|
+
};
|
|
31
|
+
return new WeftService(config);
|
|
32
|
+
}
|
|
33
|
+
/** A registry whose one rule reads no history. */
|
|
34
|
+
function historylessRegistry() {
|
|
35
|
+
return new ValidatorRegistry().register({
|
|
36
|
+
rules: [{ id: "no-history", description: "Reads no history", defaultSeverity: "info" }],
|
|
37
|
+
run: () => [],
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
beforeEach(() => {
|
|
41
|
+
walks.length = 0;
|
|
42
|
+
});
|
|
43
|
+
describe("WeftService history walks", () => {
|
|
44
|
+
it("walks git once per root, at full depth, when check builds and validates", async () => {
|
|
45
|
+
// The regression in #54: indexing walked for dates and validation walked
|
|
46
|
+
// again identically, so a one-root `weft check` ran `git log` twice.
|
|
47
|
+
const service = createService();
|
|
48
|
+
await service.validate();
|
|
49
|
+
expect(walks).toEqual([{ dir: resolve(FIXTURES_DIR, "docs"), depth: "full" }]);
|
|
50
|
+
});
|
|
51
|
+
it("walks once at dates depth for a plain rebuild", async () => {
|
|
52
|
+
const service = createService();
|
|
53
|
+
await service.rebuild();
|
|
54
|
+
expect(walks).toEqual([{ dir: resolve(FIXTURES_DIR, "docs"), depth: "dates" }]);
|
|
55
|
+
});
|
|
56
|
+
it("walks once at dates depth when no enabled rule reads history", async () => {
|
|
57
|
+
const service = createService();
|
|
58
|
+
await service.validate(historylessRegistry());
|
|
59
|
+
expect(walks.map((walk) => walk.depth)).toEqual(["dates"]);
|
|
60
|
+
});
|
|
61
|
+
it("upgrades a dates walk to full once, then serves validation from cache", async () => {
|
|
62
|
+
const service = createService();
|
|
63
|
+
await service.rebuild();
|
|
64
|
+
await service.validate();
|
|
65
|
+
await service.validate();
|
|
66
|
+
expect(walks.map((walk) => walk.depth)).toEqual(["dates", "full"]);
|
|
67
|
+
});
|
|
68
|
+
it("walks afresh after a rebuild invalidates the cached history", async () => {
|
|
69
|
+
const service = createService();
|
|
70
|
+
await service.validate();
|
|
71
|
+
await service.rebuild();
|
|
72
|
+
await service.validate();
|
|
73
|
+
expect(walks.map((walk) => walk.depth)).toEqual(["full", "dates", "full"]);
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
//# sourceMappingURL=service-history.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-history.test.js","sourceRoot":"","sources":["../src/service-history.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9D,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,6EAA6E;AAC7E,6EAA6E;AAC7E,sEAAsE;AACtE,MAAM,KAAK,GAA2C,EAAE,CAAC;AAEzD,EAAE,CAAC,IAAI,CAAC,UAAU,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE;IAC5C,MAAM,QAAQ,GAAG,MAAM,cAAc,EAA6B,CAAC;IACnE,MAAM,WAAW,GAAG,KAAK,EAAE,GAAW,EAAE,QAAsB,MAAM,EAAE,EAAE;QACvE,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC;QAC3B,OAAO,EAAE,KAAK,EAAE,IAAI,GAAG,EAAE,EAAE,KAAK,EAAE,IAAI,GAAG,EAAE,EAAE,OAAO,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC;IACnE,CAAC,CAAC;IACF,OAAO;QACN,GAAG,QAAQ;QACX,WAAW;QACX,eAAe,EAAE,KAAK,EAAE,GAAW,EAAE,EAAE,CAAC,CAAC,MAAM,WAAW,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK;KAC/E,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;AAChE,MAAM,YAAY,GAAG,OAAO,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;AAExD,SAAS,aAAa;IACrB,MAAM,MAAM,GAAe;QAC1B,OAAO,EAAE,YAAY;QACrB,OAAO,EAAE,MAAM;QACf,UAAU,EAAE,gBAAgB;QAC5B,MAAM,EAAE,EAAE;KACV,CAAC;IACF,OAAO,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC;AAChC,CAAC;AAED,kDAAkD;AAClD,SAAS,mBAAmB;IAC3B,OAAO,IAAI,iBAAiB,EAAE,CAAC,QAAQ,CAAC;QACvC,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,YAAY,EAAE,WAAW,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,EAAE,CAAC;QACvF,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE;KACb,CAAC,CAAC;AACJ,CAAC;AAED,UAAU,CAAC,GAAG,EAAE;IACf,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,2BAA2B,EAAE,GAAG,EAAE;IAC1C,EAAE,CAAC,yEAAyE,EAAE,KAAK,IAAI,EAAE;QACxF,yEAAyE;QACzE,qEAAqE;QACrE,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;QAEhC,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC;QAEzB,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,YAAY,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;IAChF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,KAAK,IAAI,EAAE;QAC9D,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;QAEhC,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;QAExB,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,YAAY,EAAE,MAAM,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8DAA8D,EAAE,KAAK,IAAI,EAAE;QAC7E,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;QAEhC,MAAM,OAAO,CAAC,QAAQ,CAAC,mBAAmB,EAAE,CAAC,CAAC;QAE9C,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uEAAuE,EAAE,KAAK,IAAI,EAAE;QACtF,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;QAEhC,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;QACxB,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC;QACzB,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC;QAEzB,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,KAAK,IAAI,EAAE;QAC5E,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;QAEhC,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC;QACzB,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;QACxB,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAC;QAEzB,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { type DocsRoot } from "./config.js";
|
|
2
|
+
import { type HistoryDepth } from "./git.js";
|
|
3
|
+
import type { Freshness, Manifest, SearchResult, WeftConfig, WeftEdge } from "./types.js";
|
|
4
|
+
import { type ValidationResult, type ValidatorRegistry } from "./validate/index.js";
|
|
5
|
+
export declare class WeftService {
|
|
6
|
+
private config;
|
|
7
|
+
private roots;
|
|
8
|
+
private graphs;
|
|
9
|
+
/**
|
|
10
|
+
* The last history walk per root, tagged with how deep it went. A rebuild
|
|
11
|
+
* replaces its targets' entries, so an entry is always as fresh as the
|
|
12
|
+
* graph built beside it. `validate` upgrades a `"dates"` entry to `"full"`
|
|
13
|
+
* on demand; the reverse never happens implicitly — a full walk answers a
|
|
14
|
+
* dates question, not the other way round.
|
|
15
|
+
*/
|
|
16
|
+
private histories;
|
|
17
|
+
private manifest;
|
|
18
|
+
private searchIndex;
|
|
19
|
+
private freshnessCache;
|
|
20
|
+
/**
|
|
21
|
+
* Bumped by every rebuild. A `freshness()` check spans an `await` over a
|
|
22
|
+
* full tree re-read, so a rebuild can complete underneath it — clearing
|
|
23
|
+
* the cache is not enough, because the in-flight check would then resume
|
|
24
|
+
* and write its pre-rebuild answer back. The check records the generation
|
|
25
|
+
* it started under and only caches if no rebuild happened in between.
|
|
26
|
+
*/
|
|
27
|
+
private freshnessGeneration;
|
|
28
|
+
/** In-flight check, so concurrent cache misses share one tree re-read. */
|
|
29
|
+
private freshnessInFlight;
|
|
30
|
+
constructor(config: WeftConfig);
|
|
31
|
+
get weftConfig(): WeftConfig;
|
|
32
|
+
/** All configured docs roots — one per project, or a single implicit root. */
|
|
33
|
+
get docsRoots(): DocsRoot[];
|
|
34
|
+
/** True when node ids are namespaced by project slug. */
|
|
35
|
+
get namespaced(): boolean;
|
|
36
|
+
/** Get the docs directory absolute path. In multi-project mode, the first project's. */
|
|
37
|
+
get docsDir(): string;
|
|
38
|
+
/** Path of the merged manifest. Always under `rootDir` when the docs root is not. */
|
|
39
|
+
get manifestPath(): string;
|
|
40
|
+
/**
|
|
41
|
+
* Path of a single project's manifest.
|
|
42
|
+
*
|
|
43
|
+
* A root living in another checkout gets its manifest under this project's
|
|
44
|
+
* own `.weft/` — writing into a repo we do not own would dirty its git
|
|
45
|
+
* status on every index. `manifestInRepo` opts a co-owned repo back in.
|
|
46
|
+
*/
|
|
47
|
+
projectManifestPath(slug: string): string;
|
|
48
|
+
/** Path of the index listing every project manifest. */
|
|
49
|
+
get projectsIndexPath(): string;
|
|
50
|
+
/** Resolve a node id to an absolute file path, or undefined if it escapes its root. */
|
|
51
|
+
resolveNodePath(nodeId: string): string | undefined;
|
|
52
|
+
/** Walk one root's git history at the given depth and remember the result. */
|
|
53
|
+
private walkHistory;
|
|
54
|
+
/**
|
|
55
|
+
* Build or rebuild the manifest from the filesystem. Pass a project slug to
|
|
56
|
+
* rescan only that project — the rest of the graph is reused.
|
|
57
|
+
*
|
|
58
|
+
* The history walk each root pays here is shared with `validate`: at the
|
|
59
|
+
* default `"dates"` depth it skips rename detection, since indexing only
|
|
60
|
+
* wants commit dates. `validate` builds at `"full"` depth instead when a
|
|
61
|
+
* history-reading rule is enabled, so `weft check` walks git exactly once
|
|
62
|
+
* per root rather than once for indexing and again for validation.
|
|
63
|
+
*
|
|
64
|
+
* The inputs hash always spans every root, even for a single-project
|
|
65
|
+
* rescan: it is the baseline for the whole merged manifest, not just the
|
|
66
|
+
* project that changed, so a partial rebuild that skipped roots outside
|
|
67
|
+
* `slug` would leave the hash wrong specifically in multi-project mode.
|
|
68
|
+
*/
|
|
69
|
+
rebuild(slug?: string, historyDepth?: HistoryDepth): Promise<Manifest>;
|
|
70
|
+
/** Get the current manifest, building it if necessary. */
|
|
71
|
+
getManifest(): Promise<Manifest>;
|
|
72
|
+
/**
|
|
73
|
+
* Whether the manifest still reflects its docs tree.
|
|
74
|
+
*
|
|
75
|
+
* Answering honestly costs a full re-read of the docs tree, so the result
|
|
76
|
+
* is cached for {@link FRESHNESS_CACHE_MS} — see that constant for why.
|
|
77
|
+
* `rebuild` clears the cache immediately.
|
|
78
|
+
*/
|
|
79
|
+
freshness(): Promise<Freshness>;
|
|
80
|
+
/**
|
|
81
|
+
* Write the manifest to disk. In multi-project mode this writes one manifest
|
|
82
|
+
* per project, an index of them, and the merged manifest at the project root.
|
|
83
|
+
* Returns every path written.
|
|
84
|
+
*/
|
|
85
|
+
writeManifest(): Promise<string[]>;
|
|
86
|
+
/**
|
|
87
|
+
* Read a document's content.
|
|
88
|
+
*
|
|
89
|
+
* An artifact is refused rather than read. Reading a binary as UTF-8 does not
|
|
90
|
+
* throw — it returns a lossy decode — so without this the caller receives
|
|
91
|
+
* nonsense wearing every sign of success, a 200 and a body, instead of an
|
|
92
|
+
* error it can act on.
|
|
93
|
+
*/
|
|
94
|
+
read(nodeId: string): string;
|
|
95
|
+
/**
|
|
96
|
+
* Run the validation stage over the current manifest, building it first if
|
|
97
|
+
* necessary. Pass a registry to run a different set of checks than the
|
|
98
|
+
* built-in ones.
|
|
99
|
+
*
|
|
100
|
+
* History is shared with the build rather than walked again: a graph built
|
|
101
|
+
* here is built at `"full"` depth when a history-reading rule is enabled,
|
|
102
|
+
* and a graph built earlier at `"dates"` depth has each root upgraded once
|
|
103
|
+
* and remembered until its next rebuild.
|
|
104
|
+
*/
|
|
105
|
+
validate(registry?: ValidatorRegistry): Promise<ValidationResult>;
|
|
106
|
+
/** Search the index. */
|
|
107
|
+
search(query: string): Promise<SearchResult[]>;
|
|
108
|
+
/** Traverse the graph: find edges connected to a node. */
|
|
109
|
+
traverse(nodeId: string, direction?: "outgoing" | "incoming" | "both"): Promise<WeftEdge[]>;
|
|
110
|
+
/**
|
|
111
|
+
* Watch every docs root for changes, rebuilding the changed project on change.
|
|
112
|
+
*
|
|
113
|
+
* A root inside the fetch cache is a checkout pinned to a commit — nothing
|
|
114
|
+
* edits it, so it is not watched.
|
|
115
|
+
*/
|
|
116
|
+
watch(callback?: (manifest: Manifest) => void): () => void;
|
|
117
|
+
}
|
|
118
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,QAAQ,EAAiD,MAAM,aAAa,CAAC;AAI3F,OAAO,EAAoB,KAAK,YAAY,EAAe,MAAM,UAAU,CAAC;AAG5E,OAAO,KAAK,EACX,SAAS,EACT,QAAQ,EAGR,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,MAAM,YAAY,CAAC;AACpB,OAAO,EACN,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EAKtB,MAAM,qBAAqB,CAAC;AAa7B,qBAAa,WAAW;IACvB,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,KAAK,CAAa;IAC1B,OAAO,CAAC,MAAM,CAAgC;IAC9C;;;;;;OAMG;IACH,OAAO,CAAC,SAAS,CAAoE;IACrF,OAAO,CAAC,QAAQ,CAAyB;IACzC,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,cAAc,CAAyD;IAC/E;;;;;;OAMG;IACH,OAAO,CAAC,mBAAmB,CAAK;IAChC,0EAA0E;IAC1E,OAAO,CAAC,iBAAiB,CAAoE;gBAEjF,MAAM,EAAE,UAAU;IAM9B,IAAI,UAAU,IAAI,UAAU,CAE3B;IAED,8EAA8E;IAC9E,IAAI,SAAS,IAAI,QAAQ,EAAE,CAE1B;IAED,yDAAyD;IACzD,IAAI,UAAU,IAAI,OAAO,CAExB;IAED,wFAAwF;IACxF,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED,qFAAqF;IACrF,IAAI,YAAY,IAAI,MAAM,CAIzB;IAED;;;;;;OAMG;IACH,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IASzC,wDAAwD;IACxD,IAAI,iBAAiB,IAAI,MAAM,CAE9B;IAED,uFAAuF;IACvF,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAUnD,8EAA8E;YAChE,WAAW;IAMzB;;;;;;;;;;;;;;OAcG;IACG,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,YAAY,GAAE,YAAsB,GAAG,OAAO,CAAC,QAAQ,CAAC;IAuCrF,0DAA0D;IACpD,WAAW,IAAI,OAAO,CAAC,QAAQ,CAAC;IAOtC;;;;;;OAMG;IACG,SAAS,IAAI,OAAO,CAAC,SAAS,CAAC;IAqCrC;;;;OAIG;IACG,aAAa,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAmCxC;;;;;;;OAOG;IACH,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM;IAa5B;;;;;;;;;OASG;IACG,QAAQ,CAAC,QAAQ,GAAE,iBAAqC,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAqB1F,wBAAwB;IAClB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAKpD,0DAA0D;IACpD,QAAQ,CACb,MAAM,EAAE,MAAM,EACd,SAAS,GAAE,UAAU,GAAG,UAAU,GAAG,MAAe,GAClD,OAAO,CAAC,QAAQ,EAAE,CAAC;IAatB;;;;;OAKG;IACH,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,GAAG,MAAM,IAAI;CAsC1D"}
|