@descent-vtt/spec-harness 0.0.0 → 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/.claude-plugin/marketplace.json +16 -0
- package/.claude-plugin/plugin.json +17 -0
- package/.mcp.json +12 -0
- package/CHANGELOG.md +46 -0
- package/README.md +127 -9
- package/bin/spec-harness.js +19 -0
- package/dist/audit.d.ts +69 -0
- package/dist/audit.js +93 -0
- package/dist/audit.js.map +1 -0
- package/dist/branch.d.ts +26 -0
- package/dist/branch.js +100 -0
- package/dist/branch.js.map +1 -0
- package/dist/briefs.d.ts +49 -0
- package/dist/briefs.js +111 -0
- package/dist/briefs.js.map +1 -0
- package/dist/cli.d.ts +14 -0
- package/dist/cli.js +245 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands.d.ts +18 -0
- package/dist/commands.js +224 -0
- package/dist/commands.js.map +1 -0
- package/dist/config.d.ts +57 -0
- package/dist/config.js +167 -0
- package/dist/config.js.map +1 -0
- package/dist/context.d.ts +56 -0
- package/dist/context.js +125 -0
- package/dist/context.js.map +1 -0
- package/dist/document.d.ts +33 -0
- package/dist/document.js +9 -0
- package/dist/document.js.map +1 -0
- package/dist/fs.d.ts +29 -0
- package/dist/fs.js +85 -0
- package/dist/fs.js.map +1 -0
- package/dist/git.d.ts +57 -0
- package/dist/git.js +129 -0
- package/dist/git.js.map +1 -0
- package/dist/guard.d.ts +43 -0
- package/dist/guard.js +120 -0
- package/dist/guard.js.map +1 -0
- package/dist/hooks.d.ts +50 -0
- package/dist/hooks.js +109 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/junit.d.ts +30 -0
- package/dist/junit.js +166 -0
- package/dist/junit.js.map +1 -0
- package/dist/manifests.d.ts +52 -0
- package/dist/manifests.js +346 -0
- package/dist/manifests.js.map +1 -0
- package/dist/plugin.d.ts +45 -0
- package/dist/plugin.js +79 -0
- package/dist/plugin.js.map +1 -0
- package/dist/premises.d.ts +16 -0
- package/dist/premises.js +71 -0
- package/dist/premises.js.map +1 -0
- package/dist/probe.d.ts +108 -0
- package/dist/probe.js +203 -0
- package/dist/probe.js.map +1 -0
- package/dist/reader.d.ts +8 -0
- package/dist/reader.js +105 -0
- package/dist/reader.js.map +1 -0
- package/dist/round.d.ts +68 -0
- package/dist/round.js +339 -0
- package/dist/round.js.map +1 -0
- package/dist/rulings.d.ts +92 -0
- package/dist/rulings.js +160 -0
- package/dist/rulings.js.map +1 -0
- package/dist/sandbox.d.ts +28 -0
- package/dist/sandbox.js +110 -0
- package/dist/sandbox.js.map +1 -0
- package/dist/server.d.ts +13 -0
- package/dist/server.js +212 -0
- package/dist/server.js.map +1 -0
- package/dist/setup.d.ts +32 -0
- package/dist/setup.js +218 -0
- package/dist/setup.js.map +1 -0
- package/dist/siblings.d.ts +66 -0
- package/dist/siblings.js +134 -0
- package/dist/siblings.js.map +1 -0
- package/dist/types.d.ts +38 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/vendor/spec-core/jsonrpc/index.d.ts +2 -0
- package/dist/vendor/spec-core/jsonrpc/index.js +2 -0
- package/dist/vendor/spec-core/jsonrpc/index.js.map +1 -0
- package/dist/vendor/spec-core/jsonrpc/mcp.d.ts +157 -0
- package/dist/vendor/spec-core/jsonrpc/mcp.js +353 -0
- package/dist/vendor/spec-core/jsonrpc/mcp.js.map +1 -0
- package/dist/vendor/spec-core/markdown/frontmatter.d.ts +103 -0
- package/dist/vendor/spec-core/markdown/frontmatter.js +459 -0
- package/dist/vendor/spec-core/markdown/frontmatter.js.map +1 -0
- package/dist/vendor/spec-core/markdown/headings.d.ts +45 -0
- package/dist/vendor/spec-core/markdown/headings.js +199 -0
- package/dist/vendor/spec-core/markdown/headings.js.map +1 -0
- package/dist/vendor/spec-core/markdown/index.d.ts +5 -0
- package/dist/vendor/spec-core/markdown/index.js +4 -0
- package/dist/vendor/spec-core/markdown/index.js.map +1 -0
- package/dist/vendor/spec-core/markdown/layout.d.ts +39 -0
- package/dist/vendor/spec-core/markdown/layout.js +28 -0
- package/dist/vendor/spec-core/markdown/layout.js.map +1 -0
- package/dist/vendor/spec-core/markdown/links.d.ts +22 -0
- package/dist/vendor/spec-core/markdown/links.js +364 -0
- package/dist/vendor/spec-core/markdown/links.js.map +1 -0
- package/dist/vendor/spec-core/markdown/lists.d.ts +22 -0
- package/dist/vendor/spec-core/markdown/lists.js +127 -0
- package/dist/vendor/spec-core/markdown/lists.js.map +1 -0
- package/dist/vendor/spec-core/markdown/scan.d.ts +36 -0
- package/dist/vendor/spec-core/markdown/scan.js +439 -0
- package/dist/vendor/spec-core/markdown/scan.js.map +1 -0
- package/dist/vendor/spec-core/markdown/syntax.d.ts +75 -0
- package/dist/vendor/spec-core/markdown/syntax.js +181 -0
- package/dist/vendor/spec-core/markdown/syntax.js.map +1 -0
- package/dist/vendor/spec-core/markdown/tables.d.ts +18 -0
- package/dist/vendor/spec-core/markdown/tables.js +86 -0
- package/dist/vendor/spec-core/markdown/tables.js.map +1 -0
- package/dist/vendor/spec-core/markdown/types.d.ts +287 -0
- package/dist/vendor/spec-core/markdown/types.js +9 -0
- package/dist/vendor/spec-core/markdown/types.js.map +1 -0
- package/dist/vendor/spec-core/path/index.d.ts +1 -0
- package/dist/vendor/spec-core/path/index.js +2 -0
- package/dist/vendor/spec-core/path/index.js.map +1 -0
- package/dist/vendor/spec-core/path/posix.d.ts +83 -0
- package/dist/vendor/spec-core/path/posix.js +150 -0
- package/dist/vendor/spec-core/path/posix.js.map +1 -0
- package/dist/vendor/spec-core/pattern/automaton.d.ts +129 -0
- package/dist/vendor/spec-core/pattern/automaton.js +340 -0
- package/dist/vendor/spec-core/pattern/automaton.js.map +1 -0
- package/dist/vendor/spec-core/pattern/charset.d.ts +58 -0
- package/dist/vendor/spec-core/pattern/charset.js +116 -0
- package/dist/vendor/spec-core/pattern/charset.js.map +1 -0
- package/dist/vendor/spec-core/pattern/glob.d.ts +121 -0
- package/dist/vendor/spec-core/pattern/glob.js +481 -0
- package/dist/vendor/spec-core/pattern/glob.js.map +1 -0
- package/dist/vendor/spec-core/pattern/index.d.ts +6 -0
- package/dist/vendor/spec-core/pattern/index.js +4 -0
- package/dist/vendor/spec-core/pattern/index.js.map +1 -0
- package/dist/vendor/spec-core/pattern/regex.d.ts +67 -0
- package/dist/vendor/spec-core/pattern/regex.js +813 -0
- package/dist/vendor/spec-core/pattern/regex.js.map +1 -0
- package/dist/vendor/spec-core/text/index.d.ts +2 -0
- package/dist/vendor/spec-core/text/index.js +2 -0
- package/dist/vendor/spec-core/text/index.js.map +1 -0
- package/dist/vendor/spec-core/text/lines.d.ts +72 -0
- package/dist/vendor/spec-core/text/lines.js +156 -0
- package/dist/vendor/spec-core/text/lines.js.map +1 -0
- package/dist/versions.d.ts +42 -0
- package/dist/versions.js +57 -0
- package/dist/versions.js.map +1 -0
- package/dist/workspace.d.ts +77 -0
- package/dist/workspace.js +138 -0
- package/dist/workspace.js.map +1 -0
- package/hooks/hooks.json +28 -0
- package/package.json +86 -6
- package/skills/close-round/SKILL.md +38 -0
- package/skills/draft-brief/SKILL.md +64 -0
- package/skills/run-round/SKILL.md +46 -0
- package/skills/split-goal/SKILL.md +42 -0
- package/src/vendor/spec-core/LICENSE +21 -0
- package/src/vendor/spec-core/README.md +8 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/vendor/spec-core/path/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,OAAO,EACP,OAAO,EACP,cAAc,EACd,QAAQ,EACR,mBAAmB,EACnB,SAAS,EACT,SAAS,EACT,cAAc,EACd,YAAY,EACZ,aAAa,EACb,QAAQ,EACR,cAAc,EACd,OAAO,GACR,MAAM,YAAY,CAAC","sourcesContent":["export {\n basename,\n dirname,\n extname,\n isAbsolutePath,\n isInside,\n isRelativeReference,\n joinPosix,\n normalise,\n normalisePosix,\n relativePath,\n resolveInside,\n segments,\n splitReference,\n toPosix,\n} from './posix.js';\n"]}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* POSIX path arithmetic, independent of the host.
|
|
3
|
+
*
|
|
4
|
+
* Every path the spec-* tools compare is a repository-relative POSIX path, on
|
|
5
|
+
* Windows as much as on Linux. A finding, a graph node or a collision witness
|
|
6
|
+
* that spelled a path one way on one machine and another way on the next would
|
|
7
|
+
* make the same repository give two answers. Node's `path` module takes the
|
|
8
|
+
* host's side, so none of this uses it.
|
|
9
|
+
*
|
|
10
|
+
* Two families of function live here, and the difference matters:
|
|
11
|
+
*
|
|
12
|
+
* - Repository paths (`normalise`, `resolveInside`, `isInside`) may not leave
|
|
13
|
+
* the repository. A `..` that climbs past the root is an answer of its own -
|
|
14
|
+
* `null` - never a path silently clamped to the root.
|
|
15
|
+
* - General POSIX paths (`normalisePosix`, `joinPosix`) keep leading `..` and a
|
|
16
|
+
* leading `/`, for callers that resolve against something other than a
|
|
17
|
+
* repository root.
|
|
18
|
+
*/
|
|
19
|
+
/** A host path in POSIX form: every backslash becomes a slash. */
|
|
20
|
+
export declare function toPosix(value: string): string;
|
|
21
|
+
/**
|
|
22
|
+
* Whether a path names a place outright rather than relative to one.
|
|
23
|
+
*
|
|
24
|
+
* Both platforms' spellings, whichever this runs on: one repository is read on
|
|
25
|
+
* a Windows checkout and in Linux CI, so a path is absolute where it was
|
|
26
|
+
* written. `C:docs` counts - it is relative to a drive, not to a root, and
|
|
27
|
+
* prefixing it with a root would name a third place.
|
|
28
|
+
*/
|
|
29
|
+
export declare function isAbsolutePath(value: string): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Whether a link destination is a path relative to the file holding it: not
|
|
32
|
+
* empty, not a fragment, not rooted, and not a URL or `mailto:`.
|
|
33
|
+
*
|
|
34
|
+
* A Windows drive path has a one-letter "scheme" and is excluded with the rest,
|
|
35
|
+
* which is right: it is not relative to anything in the repository.
|
|
36
|
+
*/
|
|
37
|
+
export declare function isRelativeReference(target: string): boolean;
|
|
38
|
+
/** The path part of a link destination, and the `?query` or `#fragment` after it. */
|
|
39
|
+
export declare function splitReference(target: string): {
|
|
40
|
+
readonly path: string;
|
|
41
|
+
readonly suffix: string;
|
|
42
|
+
};
|
|
43
|
+
/** The non-empty segments of a POSIX path, without `.`. */
|
|
44
|
+
export declare function segments(value: string): string[];
|
|
45
|
+
/**
|
|
46
|
+
* A repository path in canonical form - no `.`, no empty segments, no leading
|
|
47
|
+
* or trailing slash, `..` resolved - or `null` when the path climbs out of the
|
|
48
|
+
* repository or is absolute.
|
|
49
|
+
*
|
|
50
|
+
* Backslashes are separators here: a path typed on Windows is the same path.
|
|
51
|
+
*/
|
|
52
|
+
export declare function normalise(value: string): string | null;
|
|
53
|
+
/**
|
|
54
|
+
* A relative path resolved against a repository directory, or `null` when it
|
|
55
|
+
* climbs out of the repository.
|
|
56
|
+
*/
|
|
57
|
+
export declare function resolveInside(directory: string, relative: string): string | null;
|
|
58
|
+
/** Whether a canonical repository path is the directory itself or lies beneath it. */
|
|
59
|
+
export declare function isInside(path: string, directory: string): boolean;
|
|
60
|
+
/** The directory holding a path, or `''` at the root. */
|
|
61
|
+
export declare function dirname(value: string): string;
|
|
62
|
+
/** The last segment of a path. */
|
|
63
|
+
export declare function basename(value: string): string;
|
|
64
|
+
/**
|
|
65
|
+
* The extension of the last segment, dot included and lower-cased, or `''`.
|
|
66
|
+
*
|
|
67
|
+
* A leading dot is a hidden name, not an extension: `.github` has none, and
|
|
68
|
+
* `.eslintrc.json` has `.json`.
|
|
69
|
+
*/
|
|
70
|
+
export declare function extname(value: string): string;
|
|
71
|
+
/**
|
|
72
|
+
* The relative path from a repository directory to a repository path: what a
|
|
73
|
+
* link written in that directory must say to reach it. `.` for the directory
|
|
74
|
+
* itself.
|
|
75
|
+
*/
|
|
76
|
+
export declare function relativePath(fromDirectory: string, to: string): string;
|
|
77
|
+
/**
|
|
78
|
+
* Removes `.` and `..` segments from a general POSIX path. Leading `..` of a
|
|
79
|
+
* relative path are kept; a `..` above `/` is dropped, as the kernel does.
|
|
80
|
+
*/
|
|
81
|
+
export declare function normalisePosix(value: string): string;
|
|
82
|
+
/** Joins general POSIX paths and normalises the result. */
|
|
83
|
+
export declare function joinPosix(...parts: readonly string[]): string;
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* POSIX path arithmetic, independent of the host.
|
|
3
|
+
*
|
|
4
|
+
* Every path the spec-* tools compare is a repository-relative POSIX path, on
|
|
5
|
+
* Windows as much as on Linux. A finding, a graph node or a collision witness
|
|
6
|
+
* that spelled a path one way on one machine and another way on the next would
|
|
7
|
+
* make the same repository give two answers. Node's `path` module takes the
|
|
8
|
+
* host's side, so none of this uses it.
|
|
9
|
+
*
|
|
10
|
+
* Two families of function live here, and the difference matters:
|
|
11
|
+
*
|
|
12
|
+
* - Repository paths (`normalise`, `resolveInside`, `isInside`) may not leave
|
|
13
|
+
* the repository. A `..` that climbs past the root is an answer of its own -
|
|
14
|
+
* `null` - never a path silently clamped to the root.
|
|
15
|
+
* - General POSIX paths (`normalisePosix`, `joinPosix`) keep leading `..` and a
|
|
16
|
+
* leading `/`, for callers that resolve against something other than a
|
|
17
|
+
* repository root.
|
|
18
|
+
*/
|
|
19
|
+
const ABSOLUTE = /^(?:[/\\]|[A-Za-z]:)/;
|
|
20
|
+
const SCHEME = /^[A-Za-z][A-Za-z0-9+.-]*:/;
|
|
21
|
+
/** A host path in POSIX form: every backslash becomes a slash. */
|
|
22
|
+
export function toPosix(value) {
|
|
23
|
+
return value.replace(/\\/g, '/');
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Whether a path names a place outright rather than relative to one.
|
|
27
|
+
*
|
|
28
|
+
* Both platforms' spellings, whichever this runs on: one repository is read on
|
|
29
|
+
* a Windows checkout and in Linux CI, so a path is absolute where it was
|
|
30
|
+
* written. `C:docs` counts - it is relative to a drive, not to a root, and
|
|
31
|
+
* prefixing it with a root would name a third place.
|
|
32
|
+
*/
|
|
33
|
+
export function isAbsolutePath(value) {
|
|
34
|
+
return ABSOLUTE.test(value);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Whether a link destination is a path relative to the file holding it: not
|
|
38
|
+
* empty, not a fragment, not rooted, and not a URL or `mailto:`.
|
|
39
|
+
*
|
|
40
|
+
* A Windows drive path has a one-letter "scheme" and is excluded with the rest,
|
|
41
|
+
* which is right: it is not relative to anything in the repository.
|
|
42
|
+
*/
|
|
43
|
+
export function isRelativeReference(target) {
|
|
44
|
+
if (target === '' || target.startsWith('#') || isAbsolutePath(target))
|
|
45
|
+
return false;
|
|
46
|
+
return !SCHEME.test(target);
|
|
47
|
+
}
|
|
48
|
+
/** The path part of a link destination, and the `?query` or `#fragment` after it. */
|
|
49
|
+
export function splitReference(target) {
|
|
50
|
+
const cut = target.search(/[?#]/);
|
|
51
|
+
return cut < 0 ? { path: target, suffix: '' } : { path: target.slice(0, cut), suffix: target.slice(cut) };
|
|
52
|
+
}
|
|
53
|
+
/** The non-empty segments of a POSIX path, without `.`. */
|
|
54
|
+
export function segments(value) {
|
|
55
|
+
return value.split('/').filter((part) => part !== '' && part !== '.');
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* A repository path in canonical form - no `.`, no empty segments, no leading
|
|
59
|
+
* or trailing slash, `..` resolved - or `null` when the path climbs out of the
|
|
60
|
+
* repository or is absolute.
|
|
61
|
+
*
|
|
62
|
+
* Backslashes are separators here: a path typed on Windows is the same path.
|
|
63
|
+
*/
|
|
64
|
+
export function normalise(value) {
|
|
65
|
+
const posix = toPosix(value);
|
|
66
|
+
if (isAbsolutePath(posix))
|
|
67
|
+
return null;
|
|
68
|
+
return resolveInside('', posix);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* A relative path resolved against a repository directory, or `null` when it
|
|
72
|
+
* climbs out of the repository.
|
|
73
|
+
*/
|
|
74
|
+
export function resolveInside(directory, relative) {
|
|
75
|
+
const out = segments(directory);
|
|
76
|
+
for (const part of segments(relative)) {
|
|
77
|
+
if (part !== '..') {
|
|
78
|
+
out.push(part);
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (out.length === 0)
|
|
82
|
+
return null;
|
|
83
|
+
out.pop();
|
|
84
|
+
}
|
|
85
|
+
return out.join('/');
|
|
86
|
+
}
|
|
87
|
+
/** Whether a canonical repository path is the directory itself or lies beneath it. */
|
|
88
|
+
export function isInside(path, directory) {
|
|
89
|
+
return directory === '' || path === directory || path.startsWith(`${directory}/`);
|
|
90
|
+
}
|
|
91
|
+
/** The directory holding a path, or `''` at the root. */
|
|
92
|
+
export function dirname(value) {
|
|
93
|
+
const slash = value.lastIndexOf('/');
|
|
94
|
+
return slash < 0 ? '' : value.slice(0, slash);
|
|
95
|
+
}
|
|
96
|
+
/** The last segment of a path. */
|
|
97
|
+
export function basename(value) {
|
|
98
|
+
return value.slice(value.lastIndexOf('/') + 1);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* The extension of the last segment, dot included and lower-cased, or `''`.
|
|
102
|
+
*
|
|
103
|
+
* A leading dot is a hidden name, not an extension: `.github` has none, and
|
|
104
|
+
* `.eslintrc.json` has `.json`.
|
|
105
|
+
*/
|
|
106
|
+
export function extname(value) {
|
|
107
|
+
const base = basename(value);
|
|
108
|
+
const dot = base.lastIndexOf('.');
|
|
109
|
+
return dot <= 0 ? '' : base.slice(dot).toLowerCase();
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* The relative path from a repository directory to a repository path: what a
|
|
113
|
+
* link written in that directory must say to reach it. `.` for the directory
|
|
114
|
+
* itself.
|
|
115
|
+
*/
|
|
116
|
+
export function relativePath(fromDirectory, to) {
|
|
117
|
+
const from = segments(fromDirectory);
|
|
118
|
+
const target = segments(to);
|
|
119
|
+
let common = 0;
|
|
120
|
+
while (common < from.length && common < target.length && from[common] === target[common])
|
|
121
|
+
common += 1;
|
|
122
|
+
const up = from.slice(common).map(() => '..');
|
|
123
|
+
const joined = [...up, ...target.slice(common)].join('/');
|
|
124
|
+
return joined === '' ? '.' : joined;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Removes `.` and `..` segments from a general POSIX path. Leading `..` of a
|
|
128
|
+
* relative path are kept; a `..` above `/` is dropped, as the kernel does.
|
|
129
|
+
*/
|
|
130
|
+
export function normalisePosix(value) {
|
|
131
|
+
const absolute = value.startsWith('/');
|
|
132
|
+
const out = [];
|
|
133
|
+
for (const part of segments(value)) {
|
|
134
|
+
if (part !== '..') {
|
|
135
|
+
out.push(part);
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
if (out.length > 0 && out[out.length - 1] !== '..')
|
|
139
|
+
out.pop();
|
|
140
|
+
else if (!absolute)
|
|
141
|
+
out.push('..');
|
|
142
|
+
}
|
|
143
|
+
const joined = out.join('/');
|
|
144
|
+
return absolute ? `/${joined}` : joined;
|
|
145
|
+
}
|
|
146
|
+
/** Joins general POSIX paths and normalises the result. */
|
|
147
|
+
export function joinPosix(...parts) {
|
|
148
|
+
return normalisePosix(parts.filter((part) => part.length > 0).join('/'));
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=posix.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"posix.js","sourceRoot":"","sources":["../../../../src/vendor/spec-core/path/posix.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * POSIX path arithmetic, independent of the host.\n *\n * Every path the spec-* tools compare is a repository-relative POSIX path, on\n * Windows as much as on Linux. A finding, a graph node or a collision witness\n * that spelled a path one way on one machine and another way on the next would\n * make the same repository give two answers. Node's `path` module takes the\n * host's side, so none of this uses it.\n *\n * Two families of function live here, and the difference matters:\n *\n * - Repository paths (`normalise`, `resolveInside`, `isInside`) may not leave\n * the repository. A `..` that climbs past the root is an answer of its own -\n * `null` - never a path silently clamped to the root.\n * - General POSIX paths (`normalisePosix`, `joinPosix`) keep leading `..` and a\n * leading `/`, for callers that resolve against something other than a\n * repository root.\n */\n\nconst ABSOLUTE = /^(?:[/\\\\]|[A-Za-z]:)/;\nconst SCHEME = /^[A-Za-z][A-Za-z0-9+.-]*:/;\n\n/** A host path in POSIX form: every backslash becomes a slash. */\nexport function toPosix(value: string): string {\n return value.replace(/\\\\/g, '/');\n}\n\n/**\n * Whether a path names a place outright rather than relative to one.\n *\n * Both platforms' spellings, whichever this runs on: one repository is read on\n * a Windows checkout and in Linux CI, so a path is absolute where it was\n * written. `C:docs` counts - it is relative to a drive, not to a root, and\n * prefixing it with a root would name a third place.\n */\nexport function isAbsolutePath(value: string): boolean {\n return ABSOLUTE.test(value);\n}\n\n/**\n * Whether a link destination is a path relative to the file holding it: not\n * empty, not a fragment, not rooted, and not a URL or `mailto:`.\n *\n * A Windows drive path has a one-letter \"scheme\" and is excluded with the rest,\n * which is right: it is not relative to anything in the repository.\n */\nexport function isRelativeReference(target: string): boolean {\n if (target === '' || target.startsWith('#') || isAbsolutePath(target)) return false;\n return !SCHEME.test(target);\n}\n\n/** The path part of a link destination, and the `?query` or `#fragment` after it. */\nexport function splitReference(target: string): { readonly path: string; readonly suffix: string } {\n const cut = target.search(/[?#]/);\n return cut < 0 ? { path: target, suffix: '' } : { path: target.slice(0, cut), suffix: target.slice(cut) };\n}\n\n/** The non-empty segments of a POSIX path, without `.`. */\nexport function segments(value: string): string[] {\n return value.split('/').filter((part) => part !== '' && part !== '.');\n}\n\n/**\n * A repository path in canonical form - no `.`, no empty segments, no leading\n * or trailing slash, `..` resolved - or `null` when the path climbs out of the\n * repository or is absolute.\n *\n * Backslashes are separators here: a path typed on Windows is the same path.\n */\nexport function normalise(value: string): string | null {\n const posix = toPosix(value);\n if (isAbsolutePath(posix)) return null;\n return resolveInside('', posix);\n}\n\n/**\n * A relative path resolved against a repository directory, or `null` when it\n * climbs out of the repository.\n */\nexport function resolveInside(directory: string, relative: string): string | null {\n const out = segments(directory);\n for (const part of segments(relative)) {\n if (part !== '..') {\n out.push(part);\n continue;\n }\n if (out.length === 0) return null;\n out.pop();\n }\n return out.join('/');\n}\n\n/** Whether a canonical repository path is the directory itself or lies beneath it. */\nexport function isInside(path: string, directory: string): boolean {\n return directory === '' || path === directory || path.startsWith(`${directory}/`);\n}\n\n/** The directory holding a path, or `''` at the root. */\nexport function dirname(value: string): string {\n const slash = value.lastIndexOf('/');\n return slash < 0 ? '' : value.slice(0, slash);\n}\n\n/** The last segment of a path. */\nexport function basename(value: string): string {\n return value.slice(value.lastIndexOf('/') + 1);\n}\n\n/**\n * The extension of the last segment, dot included and lower-cased, or `''`.\n *\n * A leading dot is a hidden name, not an extension: `.github` has none, and\n * `.eslintrc.json` has `.json`.\n */\nexport function extname(value: string): string {\n const base = basename(value);\n const dot = base.lastIndexOf('.');\n return dot <= 0 ? '' : base.slice(dot).toLowerCase();\n}\n\n/**\n * The relative path from a repository directory to a repository path: what a\n * link written in that directory must say to reach it. `.` for the directory\n * itself.\n */\nexport function relativePath(fromDirectory: string, to: string): string {\n const from = segments(fromDirectory);\n const target = segments(to);\n let common = 0;\n while (common < from.length && common < target.length && from[common] === target[common]) common += 1;\n const up = from.slice(common).map(() => '..');\n const joined = [...up, ...target.slice(common)].join('/');\n return joined === '' ? '.' : joined;\n}\n\n/**\n * Removes `.` and `..` segments from a general POSIX path. Leading `..` of a\n * relative path are kept; a `..` above `/` is dropped, as the kernel does.\n */\nexport function normalisePosix(value: string): string {\n const absolute = value.startsWith('/');\n const out: string[] = [];\n for (const part of segments(value)) {\n if (part !== '..') {\n out.push(part);\n continue;\n }\n if (out.length > 0 && out[out.length - 1] !== '..') out.pop();\n else if (!absolute) out.push('..');\n }\n const joined = out.join('/');\n return absolute ? `/${joined}` : joined;\n}\n\n/** Joins general POSIX paths and normalises the result. */\nexport function joinPosix(...parts: readonly string[]): string {\n return normalisePosix(parts.filter((part) => part.length > 0).join('/'));\n}\n"]}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Non-deterministic finite automata over code points: built by Thompson's
|
|
3
|
+
* construction, run by keeping a set of live states, and searched for a
|
|
4
|
+
* shortest string several of them accept and several others refuse.
|
|
5
|
+
*
|
|
6
|
+
* Why an automaton rather than a `RegExp`: a glob such as `*-*-*-*-*-*x`
|
|
7
|
+
* handed to a backtracking engine tries every way of dividing a long name
|
|
8
|
+
* between its stars, and one spec-* tool measured 28 seconds for one path. A
|
|
9
|
+
* set of live states visits each state at most once per character, so a match
|
|
10
|
+
* costs at most the pattern's size times the path's length, whatever the
|
|
11
|
+
* pattern says.
|
|
12
|
+
*
|
|
13
|
+
* Why the same automaton for the witness: whether two scopes can name the same
|
|
14
|
+
* file, and whether one lies wholly inside another, are questions about the
|
|
15
|
+
* languages the patterns accept. Asked of the automata that do the matching,
|
|
16
|
+
* the answers cannot drift from what matching does.
|
|
17
|
+
*/
|
|
18
|
+
import { type CharSet } from './charset.js';
|
|
19
|
+
/** A compiled automaton. Immutable once built, and safe to share. */
|
|
20
|
+
export interface Automaton {
|
|
21
|
+
readonly kinds: Uint8Array;
|
|
22
|
+
/** A CHAR's next state, a SPLIT's first branch, a JUMP's target. */
|
|
23
|
+
readonly first: Int32Array;
|
|
24
|
+
/** A SPLIT's second branch. */
|
|
25
|
+
readonly second: Int32Array;
|
|
26
|
+
/** A CHAR's set; unused for the others. */
|
|
27
|
+
readonly sets: readonly (CharSet | null)[];
|
|
28
|
+
readonly start: number;
|
|
29
|
+
readonly caseSensitive: boolean;
|
|
30
|
+
}
|
|
31
|
+
/** A piece of an automaton under construction: where it starts, and the arrows still unaimed. */
|
|
32
|
+
export interface Fragment {
|
|
33
|
+
readonly start: number;
|
|
34
|
+
readonly holes: readonly Hole[];
|
|
35
|
+
}
|
|
36
|
+
interface Hole {
|
|
37
|
+
readonly state: number;
|
|
38
|
+
readonly slot: 1 | 2;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Ceiling on the size of one automaton.
|
|
42
|
+
*
|
|
43
|
+
* Brace alternatives are compiled side by side, so a pattern's size is the
|
|
44
|
+
* sum of its alternatives'. Far above anything a scope list says; it exists
|
|
45
|
+
* so that a pathological pattern is refused while compiling rather than
|
|
46
|
+
* matched slowly.
|
|
47
|
+
*/
|
|
48
|
+
export declare const MAX_STATES = 65536;
|
|
49
|
+
export declare class AutomatonTooLarge extends Error {
|
|
50
|
+
constructor();
|
|
51
|
+
}
|
|
52
|
+
/** Thompson's construction, one fragment at a time. */
|
|
53
|
+
export declare class Builder {
|
|
54
|
+
private readonly kinds;
|
|
55
|
+
private readonly first;
|
|
56
|
+
private readonly second;
|
|
57
|
+
private readonly sets;
|
|
58
|
+
private add;
|
|
59
|
+
private patch;
|
|
60
|
+
/** One character from a set. */
|
|
61
|
+
char(set: CharSet): Fragment;
|
|
62
|
+
/** The empty string. */
|
|
63
|
+
empty(): Fragment;
|
|
64
|
+
/** Each fragment after the one before it. */
|
|
65
|
+
sequence(parts: readonly Fragment[]): Fragment;
|
|
66
|
+
/** Any one of the fragments. */
|
|
67
|
+
either(options: readonly Fragment[]): Fragment;
|
|
68
|
+
/** Zero or more of a fragment. */
|
|
69
|
+
star(body: Fragment): Fragment;
|
|
70
|
+
/** One or more of a fragment. */
|
|
71
|
+
plus(body: Fragment): Fragment;
|
|
72
|
+
/** Zero or one of a fragment. */
|
|
73
|
+
optional(body: Fragment): Fragment;
|
|
74
|
+
/** Closes the automaton: every unaimed arrow reaches acceptance. */
|
|
75
|
+
finish(body: Fragment, caseSensitive: boolean): Automaton;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* A reusable matcher over one automaton.
|
|
79
|
+
*
|
|
80
|
+
* Holds its buffers between subjects; it is not reentrant, and nothing needs
|
|
81
|
+
* it to be - matching calls out to nothing.
|
|
82
|
+
*/
|
|
83
|
+
export declare class Matcher {
|
|
84
|
+
private readonly automaton;
|
|
85
|
+
private readonly visited;
|
|
86
|
+
private stamp;
|
|
87
|
+
private readonly stack;
|
|
88
|
+
private live;
|
|
89
|
+
private next;
|
|
90
|
+
constructor(automaton: Automaton);
|
|
91
|
+
/** Whether the automaton accepts the whole of a subject. */
|
|
92
|
+
test(subject: string): boolean;
|
|
93
|
+
}
|
|
94
|
+
/** The answer to a witness search. */
|
|
95
|
+
export type Witness = {
|
|
96
|
+
readonly kind: 'found';
|
|
97
|
+
readonly path: string;
|
|
98
|
+
} | {
|
|
99
|
+
readonly kind: 'none';
|
|
100
|
+
}
|
|
101
|
+
/** The search met its budget before deciding. Rare, and never a guess either way. */
|
|
102
|
+
| {
|
|
103
|
+
readonly kind: 'undecided';
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* How many distinct search states a witness search may visit. The search is
|
|
107
|
+
* polynomial in the sizes of the automata it must satisfy and, for the ones
|
|
108
|
+
* it must avoid, bounded by the subsets of their states it reaches; scope
|
|
109
|
+
* patterns reach a handful. The bound turns a pathological input into an
|
|
110
|
+
* `undecided` rather than a hang.
|
|
111
|
+
*/
|
|
112
|
+
export declare const WITNESS_BUDGET = 200000;
|
|
113
|
+
/**
|
|
114
|
+
* A shortest path every automaton in `include` accepts and none in `exclude`
|
|
115
|
+
* does, spelled with readable characters where there is a choice.
|
|
116
|
+
*
|
|
117
|
+
* Breadth-first over the product of one live state per included automaton
|
|
118
|
+
* (existential: some run of each must accept) and the whole live set per
|
|
119
|
+
* excluded one (universal: no run of it may). Characters are tried at the
|
|
120
|
+
* boundary points of every set in play, which meets every combination of
|
|
121
|
+
* answers those sets can give, so the search is exact: `none` means no path
|
|
122
|
+
* exists, not that none was found. The first path reached is a shortest one.
|
|
123
|
+
*
|
|
124
|
+
* Case-sensitive automata only. Every scope comparison in the family is
|
|
125
|
+
* case-sensitive, and folding case exactly would need every set's closure
|
|
126
|
+
* under case mapping.
|
|
127
|
+
*/
|
|
128
|
+
export declare function findWitness(include: readonly Automaton[], exclude?: readonly Automaton[], budget?: number): Witness;
|
|
129
|
+
export {};
|