@descent-vtt/spec-graph 0.14.1 → 0.15.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/CHANGELOG.md +40 -0
- package/README.md +47 -17
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +57 -15
- package/dist/cli.js.map +1 -1
- package/dist/diff.js.map +1 -1
- package/dist/directives.js.map +1 -1
- package/dist/extract.js.map +1 -1
- package/dist/glob.js.map +1 -1
- package/dist/graph.js.map +1 -1
- package/dist/select.js +4 -3
- package/dist/select.js.map +1 -1
- package/package.json +1 -1
package/dist/glob.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"glob.js","sourceRoot":"","sources":["../src/glob.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Pattern matching and directory walking.\n *\n * The patterns are the `path` dialect every spec-* tool reads, from spec-core:\n * `**`, `*`, `?`, `{a,b}`, `[abc]` and `[!a-z]`, matched against whole\n * repository-relative POSIX paths by an automaton that cannot backtrack, with\n * case respected on every host (ADR-0022). What stays here is spec-graph's own:\n * how a list with `!` entries in it reads, which directories a walk never\n * enters, and how a reference target - which is not a path - is matched.\n */\n\nimport type { Dirent } from 'node:fs';\nimport { readdir, realpath, stat } from 'node:fs/promises';\n\nimport { isAbsolutePath, joinPosix, toPosix } from './paths.js';\nimport {\n compileGlob as compileFamilyGlob,\n GlobError,\n isGlobSyntax,\n parseGlob,\n parseGlobList,\n rebaseGlob,\n type Glob,\n type GlobList,\n type GlobOptions as FamilyGlobOptions,\n type RegexMatcher,\n} from './vendor/spec-core/pattern/index.js';\n\n/** Directories skipped unless a pattern explicitly names them. */\nexport const DEFAULT_IGNORED_DIRECTORIES: readonly string[] = Object.freeze([\n '.git',\n '.hg',\n '.svn',\n '.cache',\n '.next',\n '.nuxt',\n '.turbo',\n '.venv',\n 'node_modules',\n 'bower_components',\n 'vendor',\n 'dist',\n 'build',\n 'out',\n 'target',\n 'coverage',\n '__pycache__',\n]);\n\n/** Files larger than this are skipped: a specification is not a binary. */\nexport const MAX_FILE_SIZE = 4 * 1024 * 1024;\n\nexport interface WalkedFile {\n /** Repository-relative POSIX path. */\n readonly path: string;\n /** Absolute host path, for reading. */\n readonly absolute: string;\n readonly size: number;\n}\n\nexport interface WalkOptions {\n readonly root: string;\n readonly patterns: readonly string[];\n readonly ignore?: readonly string[] | undefined;\n readonly maxFileSize?: number | undefined;\n /**\n * Follow links. Off by default: a link can lead out of the repository. A\n * link back into a directory the walk is inside is never followed.\n */\n readonly followSymlinks?: boolean | undefined;\n}\n\n/**\n * How a path pattern is read everywhere in spec-graph.\n *\n * A literal names a file or a directory and everything beneath it, which is\n * what `--ignore docs/drafts` has always meant. A `\\` is a separator, because a\n * pattern typed on a Windows shell arrives with them and spec-graph has always\n * read them that way; it cannot also be an escape.\n */\nconst PATH: FamilyGlobOptions = { dialect: 'path', caseSensitive: true, literal: 'either', backslash: 'separator' };\n\n/** True when the string contains glob syntax rather than being a literal path. */\nexport function isGlob(pattern: string): boolean {\n return isGlobSyntax(pattern);\n}\n\n/**\n * Compiles a glob to an anchored regular expression, in the dialect spec-graph\n * read before it adopted spec-core's.\n *\n * @deprecated Nothing matches with this. It stays for callers who want a\n * `RegExp`, and as the record of the old reading that `tests/glob.test.ts`\n * holds every difference against, each one named in ADR-0022. It no longer\n * folds case on Windows alone: an answer must not depend on the host.\n */\nexport function globToRegExp(pattern: string): RegExp {\n return new RegExp(`^${globSource(pattern)}$`);\n}\n\nexport interface GlobOptions {\n /** Fold case. Off unless asked for, on every host. */\n readonly ignoreCase?: boolean | undefined;\n}\n\n/**\n * Compiles one glob to a matcher over whole repository-relative paths.\n *\n * A pattern with no glob syntax names that path and nothing beneath it; a bare\n * directory meaning its contents is a reading of {@link createGlobMatcher}'s.\n * Throws a `GlobError` that names the glob as it was written.\n *\n * Matching is linear in the path whatever the pattern. It was not always: a\n * glob's stars are not nested, but each is a `[^/]*` to `RegExp`, and a subject\n * that fails is divided between them every way there is - `*-*-*-x` took two\n * minutes over a 10,000-character reference target (ADR-0017).\n */\nexport function compileGlob(pattern: string, options: GlobOptions = {}): RegexMatcher {\n // `literal: 'file'` is the dialect's reading of any value but `directory`\n // and `either`, so a mutant that blanks it reads the same. It is spelled out\n // because what an unknown value means is spec-core's to change.\n const glob = compileFamilyGlob(pattern, { ...PATH, literal: 'file', caseSensitive: options.ignoreCase !== true });\n return { test: (path) => glob.match(path), size: glob.automaton.kinds.length };\n}\n\n/** The expression a glob stood for before 0.9.0, before anchors and flags. */\nfunction globSource(pattern: string): string {\n let source = '';\n let i = 0;\n const braces: number[] = [];\n\n while (i < pattern.length) {\n const ch = pattern[i] as string;\n\n if (ch === '*') {\n const doubled = pattern[i + 1] === '*';\n if (doubled) {\n const slashAfter = pattern[i + 2] === '/';\n // `a/**/b` must also match `a/b`, so the separator is folded in.\n source += slashAfter ? '(?:.*/)?' : '.*';\n i += slashAfter ? 3 : 2;\n } else {\n source += '[^/]*';\n i += 1;\n }\n continue;\n }\n\n if (ch === '?') {\n source += '[^/]';\n i += 1;\n continue;\n }\n\n if (ch === '[') {\n const close = pattern.indexOf(']', i + 1);\n if (close === -1) {\n source += '\\\\[';\n i += 1;\n continue;\n }\n const body = pattern.slice(i + 1, close);\n source += `[${body.startsWith('!') ? `^${escapeClass(body.slice(1))}` : escapeClass(body)}]`;\n i = close + 1;\n continue;\n }\n\n if (ch === '{') {\n braces.push(source.length);\n source += '(?:';\n i += 1;\n continue;\n }\n if (ch === '}' && braces.length > 0) {\n braces.pop();\n source += ')';\n i += 1;\n continue;\n }\n if (ch === ',' && braces.length > 0) {\n source += '|';\n i += 1;\n continue;\n }\n\n source += ch.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&');\n i += 1;\n }\n\n // Otherwise reported as an unmatched parenthesis, in a glob that has none.\n if (braces.length > 0) throw new Error(`invalid glob \"${pattern}\": unclosed \"{\"`);\n return source;\n}\n\nfunction escapeClass(body: string): string {\n return body.replace(/[\\\\^\\]]/g, '\\\\$&');\n}\n\nexport interface GlobMatcher {\n (path: string): boolean;\n}\n\n/** Compiles a list of path patterns, or throws naming the one that is not a glob. */\nfunction pathList(patterns: readonly string[]): GlobList {\n const parsed = parseGlobList(patterns, PATH);\n if (!parsed.ok) throw new Error(`invalid glob ${parsed.error}`);\n return parsed.list;\n}\n\n/**\n * Builds a matcher from include patterns, honouring `!` negations.\n *\n * Later patterns win, so `docs/**\\/*.md` followed by `!docs/drafts/**` reads the\n * way a `.gitignore` does. A pattern with no glob syntax in it names a file, or\n * a directory and everything beneath it; `docs/` names only what is beneath.\n */\nexport function createGlobMatcher(patterns: readonly string[]): GlobMatcher {\n const list = pathList(patterns);\n return (path: string): boolean => list.match(path);\n}\n\n/**\n * A list entry typed in `directory`, below the root, rewritten to read from the\n * root, or refused naming the entry as it was typed (ADR-0018).\n *\n * Each brace alternative is rebased as that text written alone would be, so\n * `{/docs,x}` typed in `sub` is `{/docs,sub/x}`: a leading `/` roots it\n * wherever it was typed. A leading `..` climbs out of `directory`, and one past\n * the root is refused, as is a directory whose name a pattern would read as\n * syntax.\n */\nexport function rebasePattern(entry: string, directory: string): string {\n const rebased = rebaseGlob(entry, directory, PATH);\n if (!rebased.ok) throw new GlobError(entry, rebased.error);\n return rebased.pattern;\n}\n\n/**\n * Each dot in a reference pattern that may begin a segment, which is escaped:\n * a `.` or `..` segment then reads as the name it is, one or two dots, where\n * the dialect would drop the one and refuse the other.\n *\n * Braces expand before segments are read, so a dot written beside a brace or a\n * comma may begin a segment of an alternative: `docs/{.,x}` is `docs/.` or\n * `docs/x`, `.{/gone.md,x}` is `./gone.md` or `.x`, and `{docs/,x/}.` ends in a\n * segment `.` either way. An escaped dot is the same character as a dot in a\n * name, so escaping one that begins `.x`, or the braces leave inside a name as\n * in `a{.,b}`, reads the same, and nothing needs to tell those apart:\n * escaping each whole `.` or `..` segment instead reads each of 43,069\n * generated patterns the same, refusals included (ADR-0022).\n */\nconst SEGMENT_DOT = /(?<=^|[/{,}])\\./g;\n\n/**\n * How a reference target is matched. Every option is spelled out, though the\n * dialect reads `{}` the same way today: its defaults are spec-core's to\n * change, and this reading is spec-graph's to keep. A mutant that drops one,\n * or all of them, is equivalent until then.\n */\nconst TARGET: FamilyGlobOptions = { dialect: 'path', caseSensitive: false, literal: 'file' };\n\n/**\n * A refusal of a reference pattern in the words it was typed in.\n *\n * The dialect writes its advice for a `**` inside a name from the text it was\n * given, and that text held a `\\` before each dot {@link SEGMENT_DOT} escaped:\n * `../notes/**.md` was told `\\.\\./notes/**\\/*.md`. Given the pattern again with\n * a character it does not hold in place of each of those dots, the dialect\n * refuses it for the same reason, since both are one literal character and\n * neither is a direction, and each stand-in is read back as the dot it was.\n * Counting down from U+E000 would find a stand-in as well, among the\n * surrogates, so that mutant is equivalent.\n */\nfunction asTyped(typed: string, reason: string): string {\n let point = 0xe000;\n while (typed.includes(String.fromCodePoint(point))) point += 1;\n const stand = String.fromCodePoint(point);\n const again = parseGlob(typed.replace(SEGMENT_DOT, stand), TARGET);\n // Stand-ins and escaped dots compile or fail alike, so `again` never\n // compiles here, and a mutant that reads it as compiled is equivalent.\n return again.ok ? reason : again.error.replaceAll(stand, '.');\n}\n\n/**\n * Builds a predicate over reference *targets*, not paths.\n *\n * Separate from {@link createGlobMatcher} on purpose. That one is\n * path-oriented: a bare name there is a directory and everything under it. A\n * reference target has no such structure - `trap 55` is a name, not a location\n * - so a bare pattern matches it literally and nothing else.\n *\n * Case is ignored, on every platform, because a citation's spelling is the\n * author's and not the filesystem's. The fold is simple case mapping, one code\n * point at a time and without a locale, so every host gives the same answer:\n * U+00B5 (micro sign) and U+03BC (mu) stay two targets, as they have been since\n * a Windows-only `i` flag made them one there (ADR-0017).\n *\n * A target is text a document holds rather than a path on this host, and two\n * things follow. A `\\` escapes the character after it: there is no Windows\n * separator to allow for. And a `.` or `..` segment is text, in a brace\n * alternative as anywhere else: in a path the dialect drops the one and\n * refuses the other as climbing out of the root, but `../../notes/gone.md` is\n * a link somebody wrote and may want left alone. A pattern that is refused is\n * named, and advised, as it was typed.\n */\nexport function createReferenceFilter(patterns: readonly string[]): (target: string) => boolean {\n // A blank pattern reaches the dialect, which refuses it, as every pattern\n // spec-graph reads is refused when it names nothing. It used to be dropped,\n // so an unset variable in `--ignore-ref \"$TAGS\"` went unnoticed.\n const globs: Glob[] = patterns.map((pattern) => {\n const typed = pattern.trim();\n const parsed = parseGlob(typed.replace(SEGMENT_DOT, '\\\\.'), TARGET);\n if (!parsed.ok) throw new GlobError(pattern, asTyped(typed, parsed.error));\n return parsed.glob;\n });\n return (target: string): boolean => {\n const value = target.trim();\n return globs.some((glob) => glob.match(value));\n };\n}\n\n/**\n * The literal directory a pattern's matches all sit under, or `''` for the root.\n *\n * `{docs,specs}/**` has two, and this is the directory they share; the walk\n * itself starts at each.\n */\nexport function globBase(pattern: string): string {\n const { glob } = pathList([pattern]).entries[0] as { readonly glob: Glob };\n const bases = glob.bases.map((base) => base.split('/'));\n const shared = bases[0] as string[];\n let length = shared.length;\n for (const base of bases) {\n let same = 0;\n // `<=` would read one past the end, where both sides are undefined and\n // equal, and slice the same prefix: an equivalent mutant, left untested.\n while (same < length && base[same] === shared[same]) same += 1;\n length = same;\n }\n return shared.slice(0, length).join('/');\n}\n\n/**\n * Whether a base names directories the walk from the root would reach, each\n * with exactly that spelling and none a link it would not follow.\n *\n * A walk starts where a pattern's literal prefix points rather than at the\n * root, and on a filesystem that ignores case, `readdir('Docs')` lists `docs`.\n * Every file under it would come back spelled `Docs/...` - a node id, a\n * baseline key - and `Docs/**` would find it on Windows and macOS and nothing\n * on Linux. Asking each parent for the name gives git's answer on every host. A\n * base with an empty segment is rooted at `/`, which is never inside the root.\n *\n * Reading a directory by its path follows every link in the path, so\n * `docs/linked/*.md` was read through the link `docs/linked`, which the walk\n * from the root passes over. Asking each parent for the entry says which it\n * is, and a base beyond a link is left as silently as the walk leaves the link.\n *\n * Where links are followed, the answer is the real path of each directory\n * above the base, the root included, for the walk to tell a cycle by; a base\n * beyond a link back into one of them is one the walk from the root never\n * reaches, and is left the same way. Where they are not, it is empty and never\n * read, so a mutant that fills it anyway is equivalent. `null` is a base the\n * walk does not start at.\n */\nasync function reachable(root: string, base: string, followSymlinks: boolean | undefined): Promise<Set<string> | null> {\n const above = new Set<string>();\n if (base.length === 0) return above;\n let directory = root;\n for (const segment of base.split('/')) {\n let entries: Dirent[];\n try {\n entries = await readdir(directory, { withFileTypes: true });\n } catch {\n // Answering a set here would change nothing a test can see: the walk\n // would then read a directory beneath this one, fail the same way, and\n // find nothing.\n return null;\n }\n const entry = entries.find((candidate) => candidate.name === segment);\n if (entry === undefined || (entry.isSymbolicLink() && !followSymlinks)) return null;\n if (followSymlinks) {\n // The directory was just listed, so asking for its real path fails only\n // where it went in between, and the walk would find nothing there: a\n // mutant that answers otherwise is equivalent.\n const real = await realpath(directory).catch(() => null);\n if (real === null || above.has(real)) return null;\n above.add(real);\n }\n directory = `${directory}/${segment}`;\n }\n return above;\n}\n\n/**\n * Walks the tree and returns every file matching the patterns.\n *\n * Directories are pruned as early as possible: a repository with a 2 GB\n * `node_modules` should cost nothing to scan.\n */\nexport async function walkFiles(options: WalkOptions): Promise<WalkedFile[]> {\n const root = toPosix(options.root).replace(/\\/+$/, '');\n const patterns = pathList(options.patterns);\n const maxSize = options.maxFileSize ?? MAX_FILE_SIZE;\n\n // Ignores come in two shapes and both are documented. A bare name prunes any\n // directory called that, at any depth, the way a `.gitignore` line does.\n // Anything carrying a separator or glob syntax is matched against the\n // repository-relative path, which is what `--ignore \"docs/drafts/**\"` means -\n // and treating that as a directory name silently excluded nothing at all.\n // A mutant that defaults this to `['Stryker was here']` prunes directories of\n // that name, which no repository has: equivalent, and left untested.\n const ignores = options.ignore ?? [];\n // The empty pattern is no directory's name, so it goes to the dialect, which\n // refuses it as it refuses an empty include: a pattern that names nothing is\n // a typo or an unset variable, and was an ignore that ignored nothing. So\n // does a blank one, which was read as a directory called \" \".\n const plainName = (pattern: string): boolean =>\n pattern.trim().length > 0 && !isGlob(pattern) && !pattern.includes('/') && !pattern.startsWith('!');\n // A `!` before a name gives the name back, as a `.gitignore` line does, and\n // the last bare entry to name a directory decides whether it is pruned. It\n // was read as a directory called `!docs`, so `--ignore docs --ignore \"!docs\"`\n // pruned `docs` and said nothing. The default list is a list of names too,\n // and gives way to one: `--ignore \"!vendor\"` reads every `vendor`. A `!` alone\n // or before another is no name, and goes to the dialect, which refuses both.\n const bare = (pattern: string): boolean => plainName(pattern) || (pattern.startsWith('!') && plainName(pattern.slice(1)));\n const named = new Map<string, boolean>();\n for (const pattern of ignores.filter(bare)) {\n const negated = pattern.startsWith('!');\n named.set(negated ? pattern.slice(1) : pattern, !negated);\n }\n const skippedByDefault = new Set(DEFAULT_IGNORED_DIRECTORIES);\n const ignoreList = pathList(ignores.filter((pattern) => !bare(pattern)));\n const excluded = (path: string): boolean => ignoreList.match(path);\n\n // Only walk the directories the patterns can possibly reach: each pattern's\n // literal prefix, one per brace alternative. A negated pattern adds none: it\n // takes files back, and starting a walk at its prefix would enter what the\n // walk skips - `!node_modules/**/*.txt` beside `**/*.md` would read every\n // Markdown file in `node_modules`. No positive pattern at all walks nothing,\n // which is the answer.\n const bases = new Set<string>();\n // The paths a positive pattern names outright: `docs/vendor`, or each literal\n // a brace expands to. Such a name may be a file, so its walk starts in the\n // directory above, which pruned `vendor` on its way in: `docs/vendor` found\n // nothing where `docs/vendor/` read the directory. The default list gives way\n // to the directory a pattern names as it gives way to one a pattern starts\n // inside. A negated name adds none, for the reason it adds no base.\n const literals = new Set<string>();\n for (const entry of patterns.entries) {\n if (entry.negated) continue;\n for (const base of entry.glob.bases) bases.add(base);\n // The dialect is what knows a literal when it reads one, so each pattern\n // is compiled a second time to be told of them. That glob is thrown away:\n // the reading answered here decides nothing, and a mutant that changes it\n // is equivalent.\n parseGlob(entry.glob.source, {\n ...PATH,\n literal: (path) => {\n literals.add(path);\n return 'either';\n },\n });\n }\n // Every base is walked, even one inside another, because the outer walk\n // prunes `vendor` and the rest of the default list on its way down, and a\n // pattern that starts inside one of those is read from there. Dropping the\n // inner base as already covered meant `docs/**/*.md` beside\n // `docs/vendor/specs/*.md` found less than the second pattern alone. An\n // `--ignore` is not overruled that way: it is the user's. A walk that starts\n // at a base never passed through the directories above it, so each of them,\n // and the base, is asked what the walk from the root would have asked on its\n // way down. A bare name prunes at any depth - `--ignore adr` still takes out\n // `adr/`, which the default `adr/**/*.md` starts inside - and a path takes\n // out what it matches, so under `--ignore \"docs/*\"` `docs/drafts/**/*.md`\n // finds what `docs/**/*.md` finds, which is nothing there. The root is not\n // asked, as the walk from it never asks: `*` matches the empty path, and\n // `**/*.md` under `--ignore \"*\" --ignore \"!{docs,specs}\"` would read nothing\n // where it reads those two.\n const startable = (base: string): boolean => {\n if (base.length === 0) return true;\n const segments = base.split('/');\n return !segments.some((segment, i) => named.get(segment) === true || excluded(segments.slice(0, i + 1).join('/')));\n };\n // Whether the walk leaves a directory it meets, asked of a followed link to\n // one as well: a link called `node_modules`, which pnpm writes, or one an\n // `--ignore` names, is the directory it leads to under that name and path,\n // and was entered whatever they were. Pruning a whole subtree is an\n // optimisation; a pattern that only matches the files inside it is still\n // honoured when they are filtered. A bare `--ignore` name prunes a directory\n // a pattern names as well: only the default list gives way, to a pattern and\n // to a `!` before its name.\n const pruned = (name: string, path: string): boolean =>\n (named.get(name) ?? (skippedByDefault.has(name) && !literals.has(path))) || excluded(path);\n const out = new Map<string, WalkedFile>();\n // Where two walks overlap, whichever reaches a directory first reads it and\n // the other stops there. Reading it twice would find the same files under\n // the same keys, so the two mutants that drop this are equivalent.\n const visited = new Set<string>();\n // Where links are followed, the real path of each directory from the root to\n // the one being read. A link whose real path is among them leads back into a\n // directory the walk is inside, and following it read the same files again\n // under a longer path each time round, until the host refused the path: on\n // Windows, 64 copies of each. It is passed over as silently as a link is\n // when links are not followed. A link to anywhere else is followed, one to a\n // directory the walk has already read beside this one included, since only\n // a directory on the way here can make a cycle. The walks run one at a time,\n // so one set serves them all. Only a followed link can make a cycle, so with\n // links not followed no real path is asked for, and a mutant that asks finds\n // none: equivalent.\n let inside = new Set<string>();\n\n const walk = async (relative: string): Promise<void> => {\n const absolute = relative.length === 0 ? root : `${root}/${relative}`;\n if (visited.has(absolute)) return;\n visited.add(absolute);\n if (!options.followSymlinks) return read(relative, absolute);\n // A directory with no real path is one that cannot be listed either, so\n // a mutant that reads it rather than returning reads nothing more.\n const real = await realpath(absolute).catch(() => null);\n if (real === null || inside.has(real)) return;\n inside.add(real);\n await read(relative, absolute);\n inside.delete(real);\n };\n\n const read = async (relative: string, absolute: string): Promise<void> => {\n let entries;\n try {\n entries = await readdir(absolute, { withFileTypes: true });\n } catch {\n // An unreadable directory is not a reason to fail the whole run.\n return;\n }\n\n for (const entry of entries) {\n const child = relative.length === 0 ? entry.name : `${relative}/${entry.name}`;\n\n if (entry.isDirectory()) {\n if (!pruned(entry.name, child)) await walk(child);\n continue;\n }\n\n if (entry.isSymbolicLink()) {\n if (!options.followSymlinks) continue;\n try {\n const info = await stat(`${root}/${child}`);\n if (info.isDirectory()) {\n if (!pruned(entry.name, child)) await walk(child);\n continue;\n }\n if (!patterns.match(child) || excluded(child) || info.size > maxSize) continue;\n out.set(child, { path: child, absolute: `${root}/${child}`, size: info.size });\n } catch {\n // A link to nothing has nothing to read.\n }\n continue;\n }\n\n if (!entry.isFile()) continue;\n if (!patterns.match(child) || excluded(child)) continue;\n\n try {\n const info = await stat(`${root}/${child}`);\n if (info.size > maxSize) continue;\n out.set(child, { path: child, absolute: `${root}/${child}`, size: info.size });\n } catch {\n // Gone between the listing and the look: there is nothing to read.\n }\n }\n };\n\n for (const base of bases) {\n const above = startable(base) ? await reachable(root, base, options.followSymlinks) : null;\n if (above === null) continue;\n inside = above;\n await walk(base);\n }\n\n // No two paths are equal, since they are the keys of `out`, so the order\n // needs only `<`, and `<=` would read the same.\n return [...out.values()].sort((a, b) => (a.path < b.path ? -1 : 1));\n}\n\n/**\n * Resolves a repository-relative path against the root, in POSIX form.\n *\n * An absolute path already names one place, and joining it under the root names\n * another: `--baseline /tmp/b.json` read `<root>/tmp/b.json`, found nothing\n * there, and accepted nothing without saying so.\n */\nexport function underRoot(root: string, relative: string): string {\n if (isAbsolutePath(relative)) return toPosix(relative);\n return joinPosix(toPosix(root), relative);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"glob.js","sourceRoot":"","sources":["../src/glob.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAE3D,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC;AAChE,OAAO,EACL,WAAW,IAAI,iBAAiB,EAChC,SAAS,EACT,YAAY,EACZ,SAAS,EACT,aAAa,EACb,UAAU,GAKX,MAAM,qCAAqC,CAAC;AAE7C,kEAAkE;AAClE,MAAM,CAAC,MAAM,2BAA2B,GAAsB,MAAM,CAAC,MAAM,CAAC;IAC1E,MAAM;IACN,KAAK;IACL,MAAM;IACN,QAAQ;IACR,OAAO;IACP,OAAO;IACP,QAAQ;IACR,OAAO;IACP,cAAc;IACd,kBAAkB;IAClB,QAAQ;IACR,MAAM;IACN,OAAO;IACP,KAAK;IACL,QAAQ;IACR,UAAU;IACV,aAAa;CACd,CAAC,CAAC;AAEH,2EAA2E;AAC3E,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AAsB7C;;;;;;;GAOG;AACH,MAAM,IAAI,GAAsB,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;AAEpH,kFAAkF;AAClF,MAAM,UAAU,MAAM,CAAC,OAAe;IACpC,OAAO,YAAY,CAAC,OAAO,CAAC,CAAC;AAC/B,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,OAAO,IAAI,MAAM,CAAC,IAAI,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;AAChD,CAAC;AAOD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,WAAW,CAAC,OAAe,EAAE,OAAO,GAAgB,EAAE;IACpE,0EAA0E;IAC1E,6EAA6E;IAC7E,gEAAgE;IAChE,MAAM,IAAI,GAAG,iBAAiB,CAAC,OAAO,EAAE,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC,CAAC;IAClH,OAAO,EAAE,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;AACjF,CAAC;AAED,8EAA8E;AAC9E,SAAS,UAAU,CAAC,OAAe;IACjC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,OAAO,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;QAC1B,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,CAAW,CAAC;QAEhC,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC;YACvC,IAAI,OAAO,EAAE,CAAC;gBACZ,MAAM,UAAU,GAAG,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC;gBAC1C,iEAAiE;gBACjE,MAAM,IAAI,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;gBACzC,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC1B,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,OAAO,CAAC;gBAClB,CAAC,IAAI,CAAC,CAAC;YACT,CAAC;YACD,SAAS;QACX,CAAC;QAED,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACf,MAAM,IAAI,MAAM,CAAC;YACjB,CAAC,IAAI,CAAC,CAAC;YACP,SAAS;QACX,CAAC;QAED,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACf,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;YAC1C,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;gBACjB,MAAM,IAAI,KAAK,CAAC;gBAChB,CAAC,IAAI,CAAC,CAAC;gBACP,SAAS;YACX,CAAC;YACD,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;YACzC,MAAM,IAAI,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC;YAC7F,CAAC,GAAG,KAAK,GAAG,CAAC,CAAC;YACd,SAAS;QACX,CAAC;QAED,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACf,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC;YAChB,CAAC,IAAI,CAAC,CAAC;YACP,SAAS;QACX,CAAC;QACD,IAAI,EAAE,KAAK,GAAG,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpC,MAAM,CAAC,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,GAAG,CAAC;YACd,CAAC,IAAI,CAAC,CAAC;YACP,SAAS;QACX,CAAC;QACD,IAAI,EAAE,KAAK,GAAG,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACpC,MAAM,IAAI,GAAG,CAAC;YACd,CAAC,IAAI,CAAC,CAAC;YACP,SAAS;QACX,CAAC;QAED,MAAM,IAAI,EAAE,CAAC,OAAO,CAAC,mBAAmB,EAAE,MAAM,CAAC,CAAC;QAClD,CAAC,IAAI,CAAC,CAAC;IACT,CAAC;IAED,2EAA2E;IAC3E,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,iBAAiB,OAAO,iBAAiB,CAAC,CAAC;IAClF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,WAAW,CAAC,IAAY;IAC/B,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;AAC1C,CAAC;AAMD,qFAAqF;AACrF,SAAS,QAAQ,CAAC,QAA2B;IAC3C,MAAM,MAAM,GAAG,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAC7C,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,gBAAgB,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;IAChE,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAA2B;IAC3D,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAChC,OAAO,CAAC,IAAY,EAAW,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AACrD,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,aAAa,CAAC,KAAa,EAAE,SAAiB;IAC5D,MAAM,OAAO,GAAG,UAAU,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC;IACnD,IAAI,CAAC,OAAO,CAAC,EAAE;QAAE,MAAM,IAAI,SAAS,CAAC,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;IAC3D,OAAO,OAAO,CAAC,OAAO,CAAC;AACzB,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,GAAG,kBAAkB,CAAC;AAEvC;;;;;GAKG;AACH,MAAM,MAAM,GAAsB,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC;AAE7F;;;;;;;;;;;GAWG;AACH,SAAS,OAAO,CAAC,KAAa,EAAE,MAAc;IAC5C,IAAI,KAAK,GAAG,MAAM,CAAC;IACnB,OAAO,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAAE,KAAK,IAAI,CAAC,CAAC;IAC/D,MAAM,KAAK,GAAG,MAAM,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;IAC1C,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,CAAC;IACnE,qEAAqE;IACrE,uEAAuE;IACvE,OAAO,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;AAChE,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,UAAU,qBAAqB,CAAC,QAA2B;IAC/D,0EAA0E;IAC1E,4EAA4E;IAC5E,iEAAiE;IACjE,MAAM,KAAK,GAAW,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7C,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,CAAC;QACpE,IAAI,CAAC,MAAM,CAAC,EAAE;YAAE,MAAM,IAAI,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAC3E,OAAO,MAAM,CAAC,IAAI,CAAC;IACrB,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,MAAc,EAAW,EAAE;QACjC,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;QAC5B,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;IACjD,CAAC,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,QAAQ,CAAC,OAAe;IACtC,MAAM,EAAE,IAAI,EAAE,GAAG,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAE,CAAC;IACjD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;IACxD,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,CAAa,CAAC;IACpC,IAAI,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;IAC3B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,GAAG,CAAC,CAAC;QACb,uEAAuE;QACvE,yEAAyE;QACzE,OAAO,IAAI,GAAG,MAAM,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC,IAAI,CAAC;YAAE,IAAI,IAAI,CAAC,CAAC;QAC/D,MAAM,GAAG,IAAI,CAAC;IAChB,CAAC;IACD,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC3C,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,KAAK,UAAU,SAAS,CAAC,IAAY,EAAE,IAAY,EAAE,cAAmC;IACtF,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACpC,IAAI,SAAS,GAAG,IAAI,CAAC;IACrB,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACtC,IAAI,OAAiB,CAAC;QACtB,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,OAAO,CAAC,SAAS,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9D,CAAC;QAAC,MAAM,CAAC;YACP,qEAAqE;YACrE,uEAAuE;YACvE,gBAAgB;YAChB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC;QACtE,IAAI,KAAK,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,cAAc,EAAE,IAAI,CAAC,cAAc,CAAC;YAAE,OAAO,IAAI,CAAC;QACpF,IAAI,cAAc,EAAE,CAAC;YACnB,wEAAwE;YACxE,qEAAqE;YACrE,+CAA+C;YAC/C,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;YACzD,IAAI,IAAI,KAAK,IAAI,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,OAAO,IAAI,CAAC;YAClD,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClB,CAAC;QACD,SAAS,GAAG,GAAG,SAAS,IAAI,OAAO,EAAE,CAAC;IACxC,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,OAAoB;IAClD,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACvD,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAG,OAAO,CAAC,WAAW,IAAI,aAAa,CAAC;IAErD,6EAA6E;IAC7E,yEAAyE;IACzE,sEAAsE;IACtE,8EAA8E;IAC9E,0EAA0E;IAC1E,8EAA8E;IAC9E,qEAAqE;IACrE,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC;IACrC,6EAA6E;IAC7E,6EAA6E;IAC7E,0EAA0E;IAC1E,8DAA8D;IAC9D,MAAM,SAAS,GAAG,CAAC,OAAe,EAAW,EAAE,CAC7C,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IACtG,4EAA4E;IAC5E,2EAA2E;IAC3E,8EAA8E;IAC9E,2EAA2E;IAC3E,+EAA+E;IAC/E,6EAA6E;IAC7E,MAAM,IAAI,GAAG,CAAC,OAAe,EAAW,EAAE,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC1H,MAAM,KAAK,GAAG,IAAI,GAAG,EAAmB,CAAC;IACzC,KAAK,MAAM,OAAO,IAAI,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC;QAC3C,MAAM,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QACxC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC;IAC5D,CAAC;IACD,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,2BAA2B,CAAC,CAAC;IAC9D,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IACzE,MAAM,QAAQ,GAAG,CAAC,IAAY,EAAW,EAAE,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAEnE,4EAA4E;IAC5E,6EAA6E;IAC7E,2EAA2E;IAC3E,0EAA0E;IAC1E,6EAA6E;IAC7E,uBAAuB;IACvB,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,8EAA8E;IAC9E,2EAA2E;IAC3E,4EAA4E;IAC5E,8EAA8E;IAC9E,2EAA2E;IAC3E,oEAAoE;IACpE,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;QACrC,IAAI,KAAK,CAAC,OAAO;YAAE,SAAS;QAC5B,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK;YAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACrD,yEAAyE;QACzE,0EAA0E;QAC1E,0EAA0E;QAC1E,iBAAiB;QACjB,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE;YAC3B,GAAG,IAAI;YACP,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;gBAChB,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBACnB,OAAO,QAAQ,CAAC;YAClB,CAAC;SACF,CAAC,CAAC;IACL,CAAC;IACD,wEAAwE;IACxE,0EAA0E;IAC1E,2EAA2E;IAC3E,4DAA4D;IAC5D,wEAAwE;IACxE,6EAA6E;IAC7E,4EAA4E;IAC5E,6EAA6E;IAC7E,6EAA6E;IAC7E,2EAA2E;IAC3E,0EAA0E;IAC1E,2EAA2E;IAC3E,yEAAyE;IACzE,6EAA6E;IAC7E,4BAA4B;IAC5B,MAAM,SAAS,GAAG,CAAC,IAAY,EAAW,EAAE;QAC1C,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACjC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,IAAI,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACrH,CAAC,CAAC;IACF,4EAA4E;IAC5E,0EAA0E;IAC1E,2EAA2E;IAC3E,oEAAoE;IACpE,yEAAyE;IACzE,6EAA6E;IAC7E,6EAA6E;IAC7E,4BAA4B;IAC5B,MAAM,MAAM,GAAG,CAAC,IAAY,EAAE,IAAY,EAAW,EAAE,CACrD,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC7F,MAAM,GAAG,GAAG,IAAI,GAAG,EAAsB,CAAC;IAC1C,4EAA4E;IAC5E,0EAA0E;IAC1E,mEAAmE;IACnE,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,6EAA6E;IAC7E,6EAA6E;IAC7E,2EAA2E;IAC3E,2EAA2E;IAC3E,yEAAyE;IACzE,6EAA6E;IAC7E,2EAA2E;IAC3E,6EAA6E;IAC7E,6EAA6E;IAC7E,6EAA6E;IAC7E,oBAAoB;IACpB,IAAI,MAAM,GAAG,IAAI,GAAG,EAAU,CAAC;IAE/B,MAAM,IAAI,GAAG,KAAK,EAAE,QAAgB,EAAiB,EAAE;QACrD,MAAM,QAAQ,GAAG,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,QAAQ,EAAE,CAAC;QACtE,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC;YAAE,OAAO;QAClC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACtB,IAAI,CAAC,OAAO,CAAC,cAAc;YAAE,OAAO,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC7D,wEAAwE;QACxE,mEAAmE;QACnE,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;QACxD,IAAI,IAAI,KAAK,IAAI,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,OAAO;QAC9C,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACjB,MAAM,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACtB,CAAC,CAAC;IAEF,MAAM,IAAI,GAAG,KAAK,EAAE,QAAgB,EAAE,QAAgB,EAAiB,EAAE;QACvE,IAAI,OAAO,CAAC;QACZ,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,OAAO,CAAC,QAAQ,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7D,CAAC;QAAC,MAAM,CAAC;YACP,iEAAiE;YACjE,OAAO;QACT,CAAC;QAED,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;YAE/E,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC;oBAAE,MAAM,IAAI,CAAC,KAAK,CAAC,CAAC;gBAClD,SAAS;YACX,CAAC;YAED,IAAI,KAAK,CAAC,cAAc,EAAE,EAAE,CAAC;gBAC3B,IAAI,CAAC,OAAO,CAAC,cAAc;oBAAE,SAAS;gBACtC,IAAI,CAAC;oBACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,GAAG,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC;oBAC5C,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;wBACvB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC;4BAAE,MAAM,IAAI,CAAC,KAAK,CAAC,CAAC;wBAClD,SAAS;oBACX,CAAC;oBACD,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,IAAI,CAAC,IAAI,GAAG,OAAO;wBAAE,SAAS;oBAC/E,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,IAAI,IAAI,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;gBACjF,CAAC;gBAAC,MAAM,CAAC;oBACP,yCAAyC;gBAC3C,CAAC;gBACD,SAAS;YACX,CAAC;YAED,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;gBAAE,SAAS;YAC9B,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC;gBAAE,SAAS;YAExD,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,GAAG,IAAI,IAAI,KAAK,EAAE,CAAC,CAAC;gBAC5C,IAAI,IAAI,CAAC,IAAI,GAAG,OAAO;oBAAE,SAAS;gBAClC,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,IAAI,IAAI,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;YACjF,CAAC;YAAC,MAAM,CAAC;gBACP,mEAAmE;YACrE,CAAC;QACH,CAAC;IACH,CAAC,CAAC;IAEF,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;QAC3F,IAAI,KAAK,KAAK,IAAI;YAAE,SAAS;QAC7B,MAAM,GAAG,KAAK,CAAC;QACf,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;IACnB,CAAC;IAED,yEAAyE;IACzE,gDAAgD;IAChD,OAAO,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACtE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,IAAY,EAAE,QAAgB;IACtD,IAAI,cAAc,CAAC,QAAQ,CAAC;QAAE,OAAO,OAAO,CAAC,QAAQ,CAAC,CAAC;IACvD,OAAO,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,CAAC;AAC5C,CAAC","sourcesContent":["/**\n * Pattern matching and directory walking.\n *\n * The patterns are the `path` dialect every spec-* tool reads, from spec-core:\n * `**`, `*`, `?`, `{a,b}`, `[abc]` and `[!a-z]`, matched against whole\n * repository-relative POSIX paths by an automaton that cannot backtrack, with\n * case respected on every host (ADR-0022). What stays here is spec-graph's own:\n * how a list with `!` entries in it reads, which directories a walk never\n * enters, and how a reference target - which is not a path - is matched.\n */\n\nimport type { Dirent } from 'node:fs';\nimport { readdir, realpath, stat } from 'node:fs/promises';\n\nimport { isAbsolutePath, joinPosix, toPosix } from './paths.js';\nimport {\n compileGlob as compileFamilyGlob,\n GlobError,\n isGlobSyntax,\n parseGlob,\n parseGlobList,\n rebaseGlob,\n type Glob,\n type GlobList,\n type GlobOptions as FamilyGlobOptions,\n type RegexMatcher,\n} from './vendor/spec-core/pattern/index.js';\n\n/** Directories skipped unless a pattern explicitly names them. */\nexport const DEFAULT_IGNORED_DIRECTORIES: readonly string[] = Object.freeze([\n '.git',\n '.hg',\n '.svn',\n '.cache',\n '.next',\n '.nuxt',\n '.turbo',\n '.venv',\n 'node_modules',\n 'bower_components',\n 'vendor',\n 'dist',\n 'build',\n 'out',\n 'target',\n 'coverage',\n '__pycache__',\n]);\n\n/** Files larger than this are skipped: a specification is not a binary. */\nexport const MAX_FILE_SIZE = 4 * 1024 * 1024;\n\nexport interface WalkedFile {\n /** Repository-relative POSIX path. */\n readonly path: string;\n /** Absolute host path, for reading. */\n readonly absolute: string;\n readonly size: number;\n}\n\nexport interface WalkOptions {\n readonly root: string;\n readonly patterns: readonly string[];\n readonly ignore?: readonly string[] | undefined;\n readonly maxFileSize?: number | undefined;\n /**\n * Follow links. Off by default: a link can lead out of the repository. A\n * link back into a directory the walk is inside is never followed.\n */\n readonly followSymlinks?: boolean | undefined;\n}\n\n/**\n * How a path pattern is read everywhere in spec-graph.\n *\n * A literal names a file or a directory and everything beneath it, which is\n * what `--ignore docs/drafts` has always meant. A `\\` is a separator, because a\n * pattern typed on a Windows shell arrives with them and spec-graph has always\n * read them that way; it cannot also be an escape.\n */\nconst PATH: FamilyGlobOptions = { dialect: 'path', caseSensitive: true, literal: 'either', backslash: 'separator' };\n\n/** True when the string contains glob syntax rather than being a literal path. */\nexport function isGlob(pattern: string): boolean {\n return isGlobSyntax(pattern);\n}\n\n/**\n * Compiles a glob to an anchored regular expression, in the dialect spec-graph\n * read before it adopted spec-core's.\n *\n * @deprecated Nothing matches with this. It stays for callers who want a\n * `RegExp`, and as the record of the old reading that `tests/glob.test.ts`\n * holds every difference against, each one named in ADR-0022. It no longer\n * folds case on Windows alone: an answer must not depend on the host.\n */\nexport function globToRegExp(pattern: string): RegExp {\n return new RegExp(`^${globSource(pattern)}$`);\n}\n\nexport interface GlobOptions {\n /** Fold case. Off unless asked for, on every host. */\n readonly ignoreCase?: boolean | undefined;\n}\n\n/**\n * Compiles one glob to a matcher over whole repository-relative paths.\n *\n * A pattern with no glob syntax names that path and nothing beneath it; a bare\n * directory meaning its contents is a reading of {@link createGlobMatcher}'s.\n * Throws a `GlobError` that names the glob as it was written.\n *\n * Matching is linear in the path whatever the pattern. It was not always: a\n * glob's stars are not nested, but each is a `[^/]*` to `RegExp`, and a subject\n * that fails is divided between them every way there is - `*-*-*-x` took two\n * minutes over a 10,000-character reference target (ADR-0017).\n */\nexport function compileGlob(pattern: string, options: GlobOptions = {}): RegexMatcher {\n // `literal: 'file'` is the dialect's reading of any value but `directory`\n // and `either`, so a mutant that blanks it reads the same. It is spelled out\n // because what an unknown value means is spec-core's to change.\n const glob = compileFamilyGlob(pattern, { ...PATH, literal: 'file', caseSensitive: options.ignoreCase !== true });\n return { test: (path) => glob.match(path), size: glob.automaton.kinds.length };\n}\n\n/** The expression a glob stood for before 0.9.0, before anchors and flags. */\nfunction globSource(pattern: string): string {\n let source = '';\n let i = 0;\n const braces: number[] = [];\n\n while (i < pattern.length) {\n const ch = pattern[i] as string;\n\n if (ch === '*') {\n const doubled = pattern[i + 1] === '*';\n if (doubled) {\n const slashAfter = pattern[i + 2] === '/';\n // `a/**/b` must also match `a/b`, so the separator is folded in.\n source += slashAfter ? '(?:.*/)?' : '.*';\n i += slashAfter ? 3 : 2;\n } else {\n source += '[^/]*';\n i += 1;\n }\n continue;\n }\n\n if (ch === '?') {\n source += '[^/]';\n i += 1;\n continue;\n }\n\n if (ch === '[') {\n const close = pattern.indexOf(']', i + 1);\n if (close === -1) {\n source += '\\\\[';\n i += 1;\n continue;\n }\n const body = pattern.slice(i + 1, close);\n source += `[${body.startsWith('!') ? `^${escapeClass(body.slice(1))}` : escapeClass(body)}]`;\n i = close + 1;\n continue;\n }\n\n if (ch === '{') {\n braces.push(source.length);\n source += '(?:';\n i += 1;\n continue;\n }\n if (ch === '}' && braces.length > 0) {\n braces.pop();\n source += ')';\n i += 1;\n continue;\n }\n if (ch === ',' && braces.length > 0) {\n source += '|';\n i += 1;\n continue;\n }\n\n source += ch.replace(/[.+^${}()|[\\]\\\\]/g, '\\\\$&');\n i += 1;\n }\n\n // Otherwise reported as an unmatched parenthesis, in a glob that has none.\n if (braces.length > 0) throw new Error(`invalid glob \"${pattern}\": unclosed \"{\"`);\n return source;\n}\n\nfunction escapeClass(body: string): string {\n return body.replace(/[\\\\^\\]]/g, '\\\\$&');\n}\n\nexport interface GlobMatcher {\n (path: string): boolean;\n}\n\n/** Compiles a list of path patterns, or throws naming the one that is not a glob. */\nfunction pathList(patterns: readonly string[]): GlobList {\n const parsed = parseGlobList(patterns, PATH);\n if (!parsed.ok) throw new Error(`invalid glob ${parsed.error}`);\n return parsed.list;\n}\n\n/**\n * Builds a matcher from include patterns, honouring `!` negations.\n *\n * Later patterns win, so `docs/**\\/*.md` followed by `!docs/drafts/**` reads the\n * way a `.gitignore` does. A pattern with no glob syntax in it names a file, or\n * a directory and everything beneath it; `docs/` names only what is beneath.\n */\nexport function createGlobMatcher(patterns: readonly string[]): GlobMatcher {\n const list = pathList(patterns);\n return (path: string): boolean => list.match(path);\n}\n\n/**\n * A list entry typed in `directory`, below the root, rewritten to read from the\n * root, or refused naming the entry as it was typed (ADR-0018).\n *\n * Each brace alternative is rebased as that text written alone would be, so\n * `{/docs,x}` typed in `sub` is `{/docs,sub/x}`: a leading `/` roots it\n * wherever it was typed. A leading `..` climbs out of `directory`, and one past\n * the root is refused, as is a directory whose name a pattern would read as\n * syntax.\n */\nexport function rebasePattern(entry: string, directory: string): string {\n const rebased = rebaseGlob(entry, directory, PATH);\n if (!rebased.ok) throw new GlobError(entry, rebased.error);\n return rebased.pattern;\n}\n\n/**\n * Each dot in a reference pattern that may begin a segment, which is escaped:\n * a `.` or `..` segment then reads as the name it is, one or two dots, where\n * the dialect would drop the one and refuse the other.\n *\n * Braces expand before segments are read, so a dot written beside a brace or a\n * comma may begin a segment of an alternative: `docs/{.,x}` is `docs/.` or\n * `docs/x`, `.{/gone.md,x}` is `./gone.md` or `.x`, and `{docs/,x/}.` ends in a\n * segment `.` either way. An escaped dot is the same character as a dot in a\n * name, so escaping one that begins `.x`, or the braces leave inside a name as\n * in `a{.,b}`, reads the same, and nothing needs to tell those apart:\n * escaping each whole `.` or `..` segment instead reads each of 43,069\n * generated patterns the same, refusals included (ADR-0022).\n */\nconst SEGMENT_DOT = /(?<=^|[/{,}])\\./g;\n\n/**\n * How a reference target is matched. Every option is spelled out, though the\n * dialect reads `{}` the same way today: its defaults are spec-core's to\n * change, and this reading is spec-graph's to keep. A mutant that drops one,\n * or all of them, is equivalent until then.\n */\nconst TARGET: FamilyGlobOptions = { dialect: 'path', caseSensitive: false, literal: 'file' };\n\n/**\n * A refusal of a reference pattern in the words it was typed in.\n *\n * The dialect writes its advice for a `**` inside a name from the text it was\n * given, and that text held a `\\` before each dot {@link SEGMENT_DOT} escaped:\n * `../notes/**.md` was told `\\.\\./notes/**\\/*.md`. Given the pattern again with\n * a character it does not hold in place of each of those dots, the dialect\n * refuses it for the same reason, since both are one literal character and\n * neither is a direction, and each stand-in is read back as the dot it was.\n * Counting down from U+E000 would find a stand-in as well, among the\n * surrogates, so that mutant is equivalent.\n */\nfunction asTyped(typed: string, reason: string): string {\n let point = 0xe000;\n while (typed.includes(String.fromCodePoint(point))) point += 1;\n const stand = String.fromCodePoint(point);\n const again = parseGlob(typed.replace(SEGMENT_DOT, stand), TARGET);\n // Stand-ins and escaped dots compile or fail alike, so `again` never\n // compiles here, and a mutant that reads it as compiled is equivalent.\n return again.ok ? reason : again.error.replaceAll(stand, '.');\n}\n\n/**\n * Builds a predicate over reference *targets*, not paths.\n *\n * Separate from {@link createGlobMatcher} on purpose. That one is\n * path-oriented: a bare name there is a directory and everything under it. A\n * reference target has no such structure - `trap 55` is a name, not a location\n * - so a bare pattern matches it literally and nothing else.\n *\n * Case is ignored, on every platform, because a citation's spelling is the\n * author's and not the filesystem's. The fold is simple case mapping, one code\n * point at a time and without a locale, so every host gives the same answer:\n * U+00B5 (micro sign) and U+03BC (mu) stay two targets, as they have been since\n * a Windows-only `i` flag made them one there (ADR-0017).\n *\n * A target is text a document holds rather than a path on this host, and two\n * things follow. A `\\` escapes the character after it: there is no Windows\n * separator to allow for. And a `.` or `..` segment is text, in a brace\n * alternative as anywhere else: in a path the dialect drops the one and\n * refuses the other as climbing out of the root, but `../../notes/gone.md` is\n * a link somebody wrote and may want left alone. A pattern that is refused is\n * named, and advised, as it was typed.\n */\nexport function createReferenceFilter(patterns: readonly string[]): (target: string) => boolean {\n // A blank pattern reaches the dialect, which refuses it, as every pattern\n // spec-graph reads is refused when it names nothing. It used to be dropped,\n // so an unset variable in `--ignore-ref \"$TAGS\"` went unnoticed.\n const globs: Glob[] = patterns.map((pattern) => {\n const typed = pattern.trim();\n const parsed = parseGlob(typed.replace(SEGMENT_DOT, '\\\\.'), TARGET);\n if (!parsed.ok) throw new GlobError(pattern, asTyped(typed, parsed.error));\n return parsed.glob;\n });\n return (target: string): boolean => {\n const value = target.trim();\n return globs.some((glob) => glob.match(value));\n };\n}\n\n/**\n * The literal directory a pattern's matches all sit under, or `''` for the root.\n *\n * `{docs,specs}/**` has two, and this is the directory they share; the walk\n * itself starts at each.\n */\nexport function globBase(pattern: string): string {\n const { glob } = pathList([pattern]).entries[0]!;\n const bases = glob.bases.map((base) => base.split('/'));\n const shared = bases[0] as string[];\n let length = shared.length;\n for (const base of bases) {\n let same = 0;\n // `<=` would read one past the end, where both sides are undefined and\n // equal, and slice the same prefix: an equivalent mutant, left untested.\n while (same < length && base[same] === shared[same]) same += 1;\n length = same;\n }\n return shared.slice(0, length).join('/');\n}\n\n/**\n * Whether a base names directories the walk from the root would reach, each\n * with exactly that spelling and none a link it would not follow.\n *\n * A walk starts where a pattern's literal prefix points rather than at the\n * root, and on a filesystem that ignores case, `readdir('Docs')` lists `docs`.\n * Every file under it would come back spelled `Docs/...` - a node id, a\n * baseline key - and `Docs/**` would find it on Windows and macOS and nothing\n * on Linux. Asking each parent for the name gives git's answer on every host. A\n * base with an empty segment is rooted at `/`, which is never inside the root.\n *\n * Reading a directory by its path follows every link in the path, so\n * `docs/linked/*.md` was read through the link `docs/linked`, which the walk\n * from the root passes over. Asking each parent for the entry says which it\n * is, and a base beyond a link is left as silently as the walk leaves the link.\n *\n * Where links are followed, the answer is the real path of each directory\n * above the base, the root included, for the walk to tell a cycle by; a base\n * beyond a link back into one of them is one the walk from the root never\n * reaches, and is left the same way. Where they are not, it is empty and never\n * read, so a mutant that fills it anyway is equivalent. `null` is a base the\n * walk does not start at.\n */\nasync function reachable(root: string, base: string, followSymlinks: boolean | undefined): Promise<Set<string> | null> {\n const above = new Set<string>();\n if (base.length === 0) return above;\n let directory = root;\n for (const segment of base.split('/')) {\n let entries: Dirent[];\n try {\n entries = await readdir(directory, { withFileTypes: true });\n } catch {\n // Answering a set here would change nothing a test can see: the walk\n // would then read a directory beneath this one, fail the same way, and\n // find nothing.\n return null;\n }\n const entry = entries.find((candidate) => candidate.name === segment);\n if (entry === undefined || (entry.isSymbolicLink() && !followSymlinks)) return null;\n if (followSymlinks) {\n // The directory was just listed, so asking for its real path fails only\n // where it went in between, and the walk would find nothing there: a\n // mutant that answers otherwise is equivalent.\n const real = await realpath(directory).catch(() => null);\n if (real === null || above.has(real)) return null;\n above.add(real);\n }\n directory = `${directory}/${segment}`;\n }\n return above;\n}\n\n/**\n * Walks the tree and returns every file matching the patterns.\n *\n * Directories are pruned as early as possible: a repository with a 2 GB\n * `node_modules` should cost nothing to scan.\n */\nexport async function walkFiles(options: WalkOptions): Promise<WalkedFile[]> {\n const root = toPosix(options.root).replace(/\\/+$/, '');\n const patterns = pathList(options.patterns);\n const maxSize = options.maxFileSize ?? MAX_FILE_SIZE;\n\n // Ignores come in two shapes and both are documented. A bare name prunes any\n // directory called that, at any depth, the way a `.gitignore` line does.\n // Anything carrying a separator or glob syntax is matched against the\n // repository-relative path, which is what `--ignore \"docs/drafts/**\"` means -\n // and treating that as a directory name silently excluded nothing at all.\n // A mutant that defaults this to `['Stryker was here']` prunes directories of\n // that name, which no repository has: equivalent, and left untested.\n const ignores = options.ignore ?? [];\n // The empty pattern is no directory's name, so it goes to the dialect, which\n // refuses it as it refuses an empty include: a pattern that names nothing is\n // a typo or an unset variable, and was an ignore that ignored nothing. So\n // does a blank one, which was read as a directory called \" \".\n const plainName = (pattern: string): boolean =>\n pattern.trim().length > 0 && !isGlob(pattern) && !pattern.includes('/') && !pattern.startsWith('!');\n // A `!` before a name gives the name back, as a `.gitignore` line does, and\n // the last bare entry to name a directory decides whether it is pruned. It\n // was read as a directory called `!docs`, so `--ignore docs --ignore \"!docs\"`\n // pruned `docs` and said nothing. The default list is a list of names too,\n // and gives way to one: `--ignore \"!vendor\"` reads every `vendor`. A `!` alone\n // or before another is no name, and goes to the dialect, which refuses both.\n const bare = (pattern: string): boolean => plainName(pattern) || (pattern.startsWith('!') && plainName(pattern.slice(1)));\n const named = new Map<string, boolean>();\n for (const pattern of ignores.filter(bare)) {\n const negated = pattern.startsWith('!');\n named.set(negated ? pattern.slice(1) : pattern, !negated);\n }\n const skippedByDefault = new Set(DEFAULT_IGNORED_DIRECTORIES);\n const ignoreList = pathList(ignores.filter((pattern) => !bare(pattern)));\n const excluded = (path: string): boolean => ignoreList.match(path);\n\n // Only walk the directories the patterns can possibly reach: each pattern's\n // literal prefix, one per brace alternative. A negated pattern adds none: it\n // takes files back, and starting a walk at its prefix would enter what the\n // walk skips - `!node_modules/**/*.txt` beside `**/*.md` would read every\n // Markdown file in `node_modules`. No positive pattern at all walks nothing,\n // which is the answer.\n const bases = new Set<string>();\n // The paths a positive pattern names outright: `docs/vendor`, or each literal\n // a brace expands to. Such a name may be a file, so its walk starts in the\n // directory above, which pruned `vendor` on its way in: `docs/vendor` found\n // nothing where `docs/vendor/` read the directory. The default list gives way\n // to the directory a pattern names as it gives way to one a pattern starts\n // inside. A negated name adds none, for the reason it adds no base.\n const literals = new Set<string>();\n for (const entry of patterns.entries) {\n if (entry.negated) continue;\n for (const base of entry.glob.bases) bases.add(base);\n // The dialect is what knows a literal when it reads one, so each pattern\n // is compiled a second time to be told of them. That glob is thrown away:\n // the reading answered here decides nothing, and a mutant that changes it\n // is equivalent.\n parseGlob(entry.glob.source, {\n ...PATH,\n literal: (path) => {\n literals.add(path);\n return 'either';\n },\n });\n }\n // Every base is walked, even one inside another, because the outer walk\n // prunes `vendor` and the rest of the default list on its way down, and a\n // pattern that starts inside one of those is read from there. Dropping the\n // inner base as already covered meant `docs/**/*.md` beside\n // `docs/vendor/specs/*.md` found less than the second pattern alone. An\n // `--ignore` is not overruled that way: it is the user's. A walk that starts\n // at a base never passed through the directories above it, so each of them,\n // and the base, is asked what the walk from the root would have asked on its\n // way down. A bare name prunes at any depth - `--ignore adr` still takes out\n // `adr/`, which the default `adr/**/*.md` starts inside - and a path takes\n // out what it matches, so under `--ignore \"docs/*\"` `docs/drafts/**/*.md`\n // finds what `docs/**/*.md` finds, which is nothing there. The root is not\n // asked, as the walk from it never asks: `*` matches the empty path, and\n // `**/*.md` under `--ignore \"*\" --ignore \"!{docs,specs}\"` would read nothing\n // where it reads those two.\n const startable = (base: string): boolean => {\n if (base.length === 0) return true;\n const segments = base.split('/');\n return !segments.some((segment, i) => named.get(segment) === true || excluded(segments.slice(0, i + 1).join('/')));\n };\n // Whether the walk leaves a directory it meets, asked of a followed link to\n // one as well: a link called `node_modules`, which pnpm writes, or one an\n // `--ignore` names, is the directory it leads to under that name and path,\n // and was entered whatever they were. Pruning a whole subtree is an\n // optimisation; a pattern that only matches the files inside it is still\n // honoured when they are filtered. A bare `--ignore` name prunes a directory\n // a pattern names as well: only the default list gives way, to a pattern and\n // to a `!` before its name.\n const pruned = (name: string, path: string): boolean =>\n (named.get(name) ?? (skippedByDefault.has(name) && !literals.has(path))) || excluded(path);\n const out = new Map<string, WalkedFile>();\n // Where two walks overlap, whichever reaches a directory first reads it and\n // the other stops there. Reading it twice would find the same files under\n // the same keys, so the two mutants that drop this are equivalent.\n const visited = new Set<string>();\n // Where links are followed, the real path of each directory from the root to\n // the one being read. A link whose real path is among them leads back into a\n // directory the walk is inside, and following it read the same files again\n // under a longer path each time round, until the host refused the path: on\n // Windows, 64 copies of each. It is passed over as silently as a link is\n // when links are not followed. A link to anywhere else is followed, one to a\n // directory the walk has already read beside this one included, since only\n // a directory on the way here can make a cycle. The walks run one at a time,\n // so one set serves them all. Only a followed link can make a cycle, so with\n // links not followed no real path is asked for, and a mutant that asks finds\n // none: equivalent.\n let inside = new Set<string>();\n\n const walk = async (relative: string): Promise<void> => {\n const absolute = relative.length === 0 ? root : `${root}/${relative}`;\n if (visited.has(absolute)) return;\n visited.add(absolute);\n if (!options.followSymlinks) return read(relative, absolute);\n // A directory with no real path is one that cannot be listed either, so\n // a mutant that reads it rather than returning reads nothing more.\n const real = await realpath(absolute).catch(() => null);\n if (real === null || inside.has(real)) return;\n inside.add(real);\n await read(relative, absolute);\n inside.delete(real);\n };\n\n const read = async (relative: string, absolute: string): Promise<void> => {\n let entries;\n try {\n entries = await readdir(absolute, { withFileTypes: true });\n } catch {\n // An unreadable directory is not a reason to fail the whole run.\n return;\n }\n\n for (const entry of entries) {\n const child = relative.length === 0 ? entry.name : `${relative}/${entry.name}`;\n\n if (entry.isDirectory()) {\n if (!pruned(entry.name, child)) await walk(child);\n continue;\n }\n\n if (entry.isSymbolicLink()) {\n if (!options.followSymlinks) continue;\n try {\n const info = await stat(`${root}/${child}`);\n if (info.isDirectory()) {\n if (!pruned(entry.name, child)) await walk(child);\n continue;\n }\n if (!patterns.match(child) || excluded(child) || info.size > maxSize) continue;\n out.set(child, { path: child, absolute: `${root}/${child}`, size: info.size });\n } catch {\n // A link to nothing has nothing to read.\n }\n continue;\n }\n\n if (!entry.isFile()) continue;\n if (!patterns.match(child) || excluded(child)) continue;\n\n try {\n const info = await stat(`${root}/${child}`);\n if (info.size > maxSize) continue;\n out.set(child, { path: child, absolute: `${root}/${child}`, size: info.size });\n } catch {\n // Gone between the listing and the look: there is nothing to read.\n }\n }\n };\n\n for (const base of bases) {\n const above = startable(base) ? await reachable(root, base, options.followSymlinks) : null;\n if (above === null) continue;\n inside = above;\n await walk(base);\n }\n\n // No two paths are equal, since they are the keys of `out`, so the order\n // needs only `<`, and `<=` would read the same.\n return [...out.values()].sort((a, b) => (a.path < b.path ? -1 : 1));\n}\n\n/**\n * Resolves a repository-relative path against the root, in POSIX form.\n *\n * An absolute path already names one place, and joining it under the root names\n * another: `--baseline /tmp/b.json` read `<root>/tmp/b.json`, found nothing\n * there, and accepted nothing without saying so.\n */\nexport function underRoot(root: string, relative: string): string {\n if (isAbsolutePath(relative)) return toPosix(relative);\n return joinPosix(toPosix(root), relative);\n}\n"]}
|
package/dist/graph.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph.js","sourceRoot":"","sources":["../src/graph.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAuCzC,8EAA8E;AAC9E,MAAM,UAAU,UAAU,CAAC,KAG1B;IACC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IAC1B,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IAEvF,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC3C,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC3C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAChC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IAChC,CAAC;IAED,MAAM,SAAS,GAAmB,EAAE,CAAC;IACrC,MAAM,KAAK,GAAe,EAAE,CAAC;IAC7B,MAAM,eAAe,GAAG,IAAI,GAAG,EAAsB,CAAC;IACtD,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;QAClC,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU;YAAE,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;aAC9C,CAAC;YACJ,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjB,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAAG,CAAC,IAAiC,EAAE,KAA2B,EAAmB,EAAE;QACjG,IAAI,CAAC,IAAI;YAAE,OAAO,WAAW,CAAC;QAC9B,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAC9C,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAC1D,CAAC,CAAC;IAEF,MAAM,KAAK,GAAc;QACvB,KAAK;QACL,KAAK;QACL,SAAS;QACT,KAAK;QAEL,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3B,QAAQ,EAAE,CAAC,EAAE,EAAE,EAAE;YACf,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC5B,OAAO,KAAK,EAAE,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;QACxD,CAAC;QACD,cAAc,EAAE,CAAC,EAAE,EAAE,EAAE;YACrB,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC5B,IAAI,CAAC,KAAK;gBAAE,OAAO,SAAS,CAAC;YAC7B,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU;gBAAE,OAAO,KAAK,CAAC;YAC5C,qEAAqE;YACrE,wEAAwE;YACxE,kDAAkD;YAClD,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YACxC,OAAO,KAAK,EAAE,IAAI,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;QACxD,CAAC;QACD,OAAO,EAAE,CAAC,UAAU,EAAE,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,WAAW;QAEvE,GAAG,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC;QACnD,EAAE,EAAE,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC;QAElD,KAAK,CAAC,EAAE,EAAE,KAAK;YACb,MAAM,KAAK,GAAG,IAAI,GAAG,EAA2B,CAAC;YACjD,MAAM,KAAK,GAAa,CAAC,EAAE,CAAC,CAAC;YAC7B,MAAM,MAAM,GAAG,IAAI,GAAG,CAA0B,CAAC,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;YAErE,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxB,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,EAAY,CAAC;gBACxC,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAoB,CAAC;gBACtD,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,EAAE,CAAC;oBACxD,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,EAAE,KAAK,EAAE;wBAAE,SAAS;oBACpD,MAAM,IAAI,GAAG,CAAC,GAAG,MAAM,EAAE,IAAI,CAAC,CAAC;oBAC/B,IAAI,IAAI,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC;wBACnB,+DAA+D;wBAC/D,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;4BAAE,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;wBACxC,SAAS;oBACX,CAAC;oBACD,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;oBAC1B,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;oBACzB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBACtB,CAAC;YACH,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,CAAC,KAAK,EAAE,OAAO;YACnB,MAAM,QAAQ,GAAG,CAAC,EAAU,EAAU,EAAE,CAAC,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC;YAC9E,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,CAAC;gBACzB,OAAO,MAAM,CAAC,CAAC,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;YAChF,CAAC;YACD,MAAM,OAAO,GAAG,CAAC,EAAU,EAAU,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC;YAC3E,MAAM,SAAS,GAAG,IAAI,GAAG,EAAuB,CAAC;YACjD,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC;gBAClC,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;oBACrC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBAChC,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;oBAC5B,qEAAqE;oBACrE,sCAAsC;oBACtC,IAAI,IAAI,KAAK,EAAE;wBAAE,SAAS;oBAC1B,MAAM,GAAG,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,EAAU,CAAC;oBACrD,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;oBACZ,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;gBAC3B,CAAC;YACH,CAAC;YACD,OAAO,MAAM,CACX,SAAS,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,EACxC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,CACvC,CAAC;QACJ,CAAC;KACF,CAAC;IAEF,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,WAAW,GAAoB,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AACvD,MAAM,WAAW,GAAwB,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;AAE3D,SAAS,IAAI,CAAI,GAAqB,EAAE,GAAW,EAAE,KAAQ;IAC3D,MAAM,IAAI,GAAG,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC1B,IAAI,IAAI;QAAE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;;QACtB,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;AAC7B,CAAC;AAED,gFAAgF;AAChF,gFAAgF;AAChF,gFAAgF;AAEhF;;;;;;;;;GASG;AACH,SAAS,MAAM,CAAC,GAAsB,EAAE,UAAoC;IAC1E,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC1C,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC1C,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAClC,wEAAwE;IACxE,yEAAyE;IACzE,2CAA2C;IAC3C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,UAAU,GAAe,EAAE,CAAC;IAClC,IAAI,OAAO,GAAG,CAAC,CAAC;IAEhB,KAAK,MAAM,IAAI,IAAI,GAAG,EAAE,CAAC;QACvB,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,SAAS;QAEhC,MAAM,IAAI,GAAuD;YAC/D,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE;SAClD,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC3B,OAAO,IAAI,CAAC,CAAC;QACb,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAElB,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAqD,CAAC;YACxF,iEAAiE;YACjE,yEAAyE;YACzE,wBAAwB;YACxB,IAAI,KAAK,CAAC,IAAI,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC;gBACvC,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAW,CAAC;gBACnD,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC;gBAChB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;oBACxB,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;oBAC5B,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;oBAC5B,OAAO,IAAI,CAAC,CAAC;oBACb,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;oBAClB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;oBACnB,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;gBACjE,CAAC;qBAAM,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;oBAC9B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAW,EAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAW,CAAC,CAAC,CAAC;gBACjG,CAAC;gBACD,SAAS;YACX,CAAC;YAED,IAAI,CAAC,GAAG,EAAE,CAAC;YACX,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YACrC,IAAI,MAAM,EAAE,CAAC;gBACX,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAW,EAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAW,CAAC,CAAC,CAAC;YACtG,CAAC;YAED,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;gBACpD,MAAM,SAAS,GAAa,EAAE,CAAC;gBAC/B,SAAS,CAAC;oBACR,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,EAAY,CAAC;oBACrC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;oBACvB,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;oBACvB,IAAI,MAAM,KAAK,KAAK,CAAC,EAAE;wBAAE,MAAM;gBACjC,CAAC;gBACD,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC;oBAAE,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC,CAAC;qBAC1D,IAAI,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;oBAAE,UAAU,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YAC/E,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,gFAAgF;AAChF,gFAAgF;AAChF,gFAAgF;AAEhF,uEAAuE;AACvE,MAAM,CAAC,MAAM,gBAAgB,GAAwB,MAAM,CAAC,MAAM,CAC/D,MAAM,CAAC,IAAI,CAAC,WAAW,CAAgB,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,mBAAmB,CAAC,CACjG,CAAC;AAEF,+DAA+D;AAC/D,MAAM,CAAC,MAAM,kBAAkB,GAAwB,MAAM,CAAC,MAAM,CACjE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAgB,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,CACzF,CAAC","sourcesContent":["/**\n * The specification graph.\n *\n * An immutable, fully indexed view over the resolved corpus. Construction pays\n * for adjacency in both directions once so that every rule, query and report is\n * a lookup rather than a scan - the difference between a linter that runs on\n * every save and one that gets moved to a nightly job and then ignored.\n *\n * The algorithms here are the ones the rules genuinely need and no more:\n * adjacency, reachability, and Tarjan's strongly connected components for\n * finding circular delegations.\n */\n\nimport type { DocumentNode, Edge, EdgeKind, ItemNode, SpecNode } from './types.js';\nimport { EDGE_TRAITS } from './types.js';\n\nexport interface SpecGraph {\n readonly nodes: ReadonlyMap<string, SpecNode>;\n readonly edges: readonly Edge[];\n readonly documents: readonly DocumentNode[];\n readonly items: readonly ItemNode[];\n\n node(id: string): SpecNode | undefined;\n document(id: string): DocumentNode | undefined;\n /** The document a node belongs to: itself, or the item's owner. */\n owningDocument(id: string): DocumentNode | undefined;\n itemsOf(documentId: string): readonly ItemNode[];\n\n /** Edges leaving `id`, optionally filtered by kind. */\n out(id: string, kinds?: readonly EdgeKind[]): readonly Edge[];\n /** Edges entering `id`, optionally filtered by kind. */\n in(id: string, kinds?: readonly EdgeKind[]): readonly Edge[];\n\n /**\n * Every node reachable from `id` over the given edge kinds, with the shortest\n * path to each. `id` itself is included only when a cycle returns to it.\n */\n reach(id: string, kinds: readonly EdgeKind[]): ReadonlyMap<string, readonly Edge[]>;\n\n /**\n * Strongly connected components with more than one member, over the given\n * edge kinds, and each node with an edge to itself as a component of one.\n * Each is a real cycle.\n *\n * With `byDocument`, relations are projected onto the documents that own\n * their endpoints before the search. That is what catches two documents\n * ping-ponging one obligation: the delegation runs item -> document in each\n * direction, so there is no cycle among the raw nodes even though the two\n * documents are plainly passing the same question back and forth.\n */\n cycles(kinds: readonly EdgeKind[], options?: { byDocument?: boolean }): readonly (readonly string[])[];\n}\n\n/** Builds the graph. Edges naming an unknown node are dropped, not stored. */\nexport function buildGraph(input: {\n readonly nodes: ReadonlyMap<string, SpecNode>;\n readonly edges: readonly Edge[];\n}): SpecGraph {\n const nodes = input.nodes;\n const edges = input.edges.filter((edge) => nodes.has(edge.from) && nodes.has(edge.to));\n\n const outgoing = new Map<string, Edge[]>();\n const incoming = new Map<string, Edge[]>();\n for (const edge of edges) {\n push(outgoing, edge.from, edge);\n push(incoming, edge.to, edge);\n }\n\n const documents: DocumentNode[] = [];\n const items: ItemNode[] = [];\n const itemsByDocument = new Map<string, ItemNode[]>();\n for (const node of nodes.values()) {\n if (node.kind === 'document') documents.push(node);\n else {\n items.push(node);\n push(itemsByDocument, node.document, node);\n }\n }\n\n const filter = (list: readonly Edge[] | undefined, kinds?: readonly EdgeKind[]): readonly Edge[] => {\n if (!list) return EMPTY_EDGES;\n if (!kinds || kinds.length === 0) return list;\n return list.filter((edge) => kinds.includes(edge.kind));\n };\n\n const graph: SpecGraph = {\n nodes,\n edges,\n documents,\n items,\n\n node: (id) => nodes.get(id),\n document: (id) => {\n const found = nodes.get(id);\n return found?.kind === 'document' ? found : undefined;\n },\n owningDocument: (id) => {\n const found = nodes.get(id);\n if (!found) return undefined;\n if (found.kind === 'document') return found;\n // An item's document is a document, or is missing from a graph built\n // from some documents and not others - never an item. So the check only\n // narrows the type, and its mutant is equivalent.\n const owner = nodes.get(found.document);\n return owner?.kind === 'document' ? owner : undefined;\n },\n itemsOf: (documentId) => itemsByDocument.get(documentId) ?? EMPTY_ITEMS,\n\n out: (id, kinds) => filter(outgoing.get(id), kinds),\n in: (id, kinds) => filter(incoming.get(id), kinds),\n\n reach(id, kinds) {\n const paths = new Map<string, readonly Edge[]>();\n const queue: string[] = [id];\n const pathTo = new Map<string, readonly Edge[]>([[id, EMPTY_EDGES]]);\n\n while (queue.length > 0) {\n const current = queue.shift() as string;\n const prefix = pathTo.get(current) as readonly Edge[];\n for (const edge of filter(outgoing.get(current), kinds)) {\n if (pathTo.has(edge.to) && edge.to !== id) continue;\n const path = [...prefix, edge];\n if (edge.to === id) {\n // A cycle back to the origin: record it, but do not re-expand.\n if (!paths.has(id)) paths.set(id, path);\n continue;\n }\n pathTo.set(edge.to, path);\n paths.set(edge.to, path);\n queue.push(edge.to);\n }\n }\n return paths;\n },\n\n cycles(kinds, options) {\n const relevant = (id: string): Edge[] => [...filter(outgoing.get(id), kinds)];\n if (!options?.byDocument) {\n return tarjan([...nodes.keys()], (id) => relevant(id).map((edge) => edge.to));\n }\n const ownerOf = (id: string): string => graph.owningDocument(id)?.id ?? id;\n const projected = new Map<string, Set<string>>();\n for (const node of nodes.values()) {\n for (const edge of relevant(node.id)) {\n const from = ownerOf(edge.from);\n const to = ownerOf(edge.to);\n // A relation that stays inside one document is a self-reference, not\n // a cycle, and has a rule of its own.\n if (from === to) continue;\n const set = projected.get(from) ?? new Set<string>();\n set.add(to);\n projected.set(from, set);\n }\n }\n return tarjan(\n documents.map((document) => document.id),\n (id) => [...(projected.get(id) ?? [])],\n );\n },\n };\n\n return graph;\n}\n\nconst EMPTY_EDGES: readonly Edge[] = Object.freeze([]);\nconst EMPTY_ITEMS: readonly ItemNode[] = Object.freeze([]);\n\nfunction push<T>(map: Map<string, T[]>, key: string, value: T): void {\n const list = map.get(key);\n if (list) list.push(value);\n else map.set(key, [value]);\n}\n\n/* -------------------------------------------------------------------------- */\n/* Cycles */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Tarjan's strongly connected components, iterative.\n *\n * Iterative rather than recursive because a monorepo's reference graph can be\n * deep enough to blow the call stack, and a linter that crashes on the largest\n * repository in the company is a linter nobody trusts on the small ones either.\n *\n * Takes a successor function so the same search serves both the raw graph and\n * the document-level projection.\n */\nfunction tarjan(ids: readonly string[], successors: (id: string) => string[]): string[][] {\n const indexOf = new Map<string, number>();\n const lowLink = new Map<string, number>();\n const onStack = new Set<string>();\n // A component is popped down to its own root and no further, so nothing\n // beneath the first root pushed is ever popped: a stack that starts with\n // something in it is an equivalent mutant.\n const stack: string[] = [];\n const components: string[][] = [];\n let counter = 0;\n\n for (const root of ids) {\n if (indexOf.has(root)) continue;\n\n const work: { id: string; next: number; children: string[] }[] = [\n { id: root, next: 0, children: successors(root) },\n ];\n indexOf.set(root, counter);\n lowLink.set(root, counter);\n counter += 1;\n stack.push(root);\n onStack.add(root);\n\n while (work.length > 0) {\n const frame = work[work.length - 1] as { id: string; next: number; children: string[] };\n // `<=` reads one child past the end: `undefined`, a node with no\n // successors that is settled on its own at once and is in no cycle. That\n // mutant is equivalent.\n if (frame.next < frame.children.length) {\n const child = frame.children[frame.next] as string;\n frame.next += 1;\n if (!indexOf.has(child)) {\n indexOf.set(child, counter);\n lowLink.set(child, counter);\n counter += 1;\n stack.push(child);\n onStack.add(child);\n work.push({ id: child, next: 0, children: successors(child) });\n } else if (onStack.has(child)) {\n lowLink.set(frame.id, Math.min(lowLink.get(frame.id) as number, indexOf.get(child) as number));\n }\n continue;\n }\n\n work.pop();\n const parent = work[work.length - 1];\n if (parent) {\n lowLink.set(parent.id, Math.min(lowLink.get(parent.id) as number, lowLink.get(frame.id) as number));\n }\n\n if (lowLink.get(frame.id) === indexOf.get(frame.id)) {\n const component: string[] = [];\n for (;;) {\n const popped = stack.pop() as string;\n onStack.delete(popped);\n component.push(popped);\n if (popped === frame.id) break;\n }\n if (component.length > 1) components.push(component.reverse());\n else if (successors(frame.id).includes(frame.id)) components.push(component);\n }\n }\n }\n\n return components;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Derived predicates */\n/* -------------------------------------------------------------------------- */\n\n/** Edge kinds that move an obligation from one document to another. */\nexport const OBLIGATION_EDGES: readonly EdgeKind[] = Object.freeze(\n (Object.keys(EDGE_TRAITS) as EdgeKind[]).filter((kind) => EDGE_TRAITS[kind].transfersObligation),\n);\n\n/** Edge kinds whose source depends on what the target says. */\nexport const LOAD_BEARING_EDGES: readonly EdgeKind[] = Object.freeze(\n (Object.keys(EDGE_TRAITS) as EdgeKind[]).filter((kind) => EDGE_TRAITS[kind].loadBearing),\n);\n"]}
|
|
1
|
+
{"version":3,"file":"graph.js","sourceRoot":"","sources":["../src/graph.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The specification graph.\n *\n * An immutable, fully indexed view over the resolved corpus. Construction pays\n * for adjacency in both directions once so that every rule, query and report is\n * a lookup rather than a scan - the difference between a linter that runs on\n * every save and one that gets moved to a nightly job and then ignored.\n *\n * The algorithms here are the ones the rules genuinely need and no more:\n * adjacency, reachability, and Tarjan's strongly connected components for\n * finding circular delegations.\n */\n\nimport type { DocumentNode, Edge, EdgeKind, ItemNode, SpecNode } from './types.js';\nimport { EDGE_TRAITS } from './types.js';\n\nexport interface SpecGraph {\n readonly nodes: ReadonlyMap<string, SpecNode>;\n readonly edges: readonly Edge[];\n readonly documents: readonly DocumentNode[];\n readonly items: readonly ItemNode[];\n\n node(id: string): SpecNode | undefined;\n document(id: string): DocumentNode | undefined;\n /** The document a node belongs to: itself, or the item's owner. */\n owningDocument(id: string): DocumentNode | undefined;\n itemsOf(documentId: string): readonly ItemNode[];\n\n /** Edges leaving `id`, optionally filtered by kind. */\n out(id: string, kinds?: readonly EdgeKind[]): readonly Edge[];\n /** Edges entering `id`, optionally filtered by kind. */\n in(id: string, kinds?: readonly EdgeKind[]): readonly Edge[];\n\n /**\n * Every node reachable from `id` over the given edge kinds, with the shortest\n * path to each. `id` itself is included only when a cycle returns to it.\n */\n reach(id: string, kinds: readonly EdgeKind[]): ReadonlyMap<string, readonly Edge[]>;\n\n /**\n * Strongly connected components with more than one member, over the given\n * edge kinds, and each node with an edge to itself as a component of one.\n * Each is a real cycle.\n *\n * With `byDocument`, relations are projected onto the documents that own\n * their endpoints before the search. That is what catches two documents\n * ping-ponging one obligation: the delegation runs item -> document in each\n * direction, so there is no cycle among the raw nodes even though the two\n * documents are plainly passing the same question back and forth.\n */\n cycles(kinds: readonly EdgeKind[], options?: { byDocument?: boolean }): readonly (readonly string[])[];\n}\n\n/** Builds the graph. Edges naming an unknown node are dropped, not stored. */\nexport function buildGraph(input: {\n readonly nodes: ReadonlyMap<string, SpecNode>;\n readonly edges: readonly Edge[];\n}): SpecGraph {\n const nodes = input.nodes;\n const edges = input.edges.filter((edge) => nodes.has(edge.from) && nodes.has(edge.to));\n\n const outgoing = new Map<string, Edge[]>();\n const incoming = new Map<string, Edge[]>();\n for (const edge of edges) {\n push(outgoing, edge.from, edge);\n push(incoming, edge.to, edge);\n }\n\n const documents: DocumentNode[] = [];\n const items: ItemNode[] = [];\n const itemsByDocument = new Map<string, ItemNode[]>();\n for (const node of nodes.values()) {\n if (node.kind === 'document') documents.push(node);\n else {\n items.push(node);\n push(itemsByDocument, node.document, node);\n }\n }\n\n const filter = (list: readonly Edge[] | undefined, kinds?: readonly EdgeKind[]): readonly Edge[] => {\n if (!list) return EMPTY_EDGES;\n if (!kinds || kinds.length === 0) return list;\n return list.filter((edge) => kinds.includes(edge.kind));\n };\n\n const graph: SpecGraph = {\n nodes,\n edges,\n documents,\n items,\n\n node: (id) => nodes.get(id),\n document: (id) => {\n const found = nodes.get(id);\n return found?.kind === 'document' ? found : undefined;\n },\n owningDocument: (id) => {\n const found = nodes.get(id);\n if (!found) return undefined;\n if (found.kind === 'document') return found;\n // An item's document is a document, or is missing from a graph built\n // from some documents and not others - never an item. So the check only\n // narrows the type, and its mutant is equivalent.\n const owner = nodes.get(found.document);\n return owner?.kind === 'document' ? owner : undefined;\n },\n itemsOf: (documentId) => itemsByDocument.get(documentId) ?? EMPTY_ITEMS,\n\n out: (id, kinds) => filter(outgoing.get(id), kinds),\n in: (id, kinds) => filter(incoming.get(id), kinds),\n\n reach(id, kinds) {\n const paths = new Map<string, readonly Edge[]>();\n const queue: string[] = [id];\n const pathTo = new Map<string, readonly Edge[]>([[id, EMPTY_EDGES]]);\n\n while (queue.length > 0) {\n const current = queue.shift() as string;\n const prefix = pathTo.get(current) as readonly Edge[];\n for (const edge of filter(outgoing.get(current), kinds)) {\n if (pathTo.has(edge.to) && edge.to !== id) continue;\n const path = [...prefix, edge];\n if (edge.to === id) {\n // A cycle back to the origin: record it, but do not re-expand.\n if (!paths.has(id)) paths.set(id, path);\n continue;\n }\n pathTo.set(edge.to, path);\n paths.set(edge.to, path);\n queue.push(edge.to);\n }\n }\n return paths;\n },\n\n cycles(kinds, options) {\n const relevant = (id: string): Edge[] => [...filter(outgoing.get(id), kinds)];\n if (!options?.byDocument) {\n return tarjan([...nodes.keys()], (id) => relevant(id).map((edge) => edge.to));\n }\n const ownerOf = (id: string): string => graph.owningDocument(id)?.id ?? id;\n const projected = new Map<string, Set<string>>();\n for (const node of nodes.values()) {\n for (const edge of relevant(node.id)) {\n const from = ownerOf(edge.from);\n const to = ownerOf(edge.to);\n // A relation that stays inside one document is a self-reference, not\n // a cycle, and has a rule of its own.\n if (from === to) continue;\n const set = projected.get(from) ?? new Set<string>();\n set.add(to);\n projected.set(from, set);\n }\n }\n return tarjan(\n documents.map((document) => document.id),\n (id) => [...(projected.get(id) ?? [])],\n );\n },\n };\n\n return graph;\n}\n\nconst EMPTY_EDGES: readonly Edge[] = Object.freeze([]);\nconst EMPTY_ITEMS: readonly ItemNode[] = Object.freeze([]);\n\nfunction push<T>(map: Map<string, T[]>, key: string, value: T): void {\n const list = map.get(key);\n if (list) list.push(value);\n else map.set(key, [value]);\n}\n\n/* -------------------------------------------------------------------------- */\n/* Cycles */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Tarjan's strongly connected components, iterative.\n *\n * Iterative rather than recursive because a monorepo's reference graph can be\n * deep enough to blow the call stack, and a linter that crashes on the largest\n * repository in the company is a linter nobody trusts on the small ones either.\n *\n * Takes a successor function so the same search serves both the raw graph and\n * the document-level projection.\n */\nfunction tarjan(ids: readonly string[], successors: (id: string) => string[]): string[][] {\n const indexOf = new Map<string, number>();\n const lowLink = new Map<string, number>();\n const onStack = new Set<string>();\n // A component is popped down to its own root and no further, so nothing\n // beneath the first root pushed is ever popped: a stack that starts with\n // something in it is an equivalent mutant.\n const stack: string[] = [];\n const components: string[][] = [];\n let counter = 0;\n\n for (const root of ids) {\n if (indexOf.has(root)) continue;\n\n const work: { id: string; next: number; children: string[] }[] = [\n { id: root, next: 0, children: successors(root) },\n ];\n indexOf.set(root, counter);\n lowLink.set(root, counter);\n counter += 1;\n stack.push(root);\n onStack.add(root);\n\n while (work.length > 0) {\n const frame = work[work.length - 1]!;\n // `<=` reads one child past the end: `undefined`, a node with no\n // successors that is settled on its own at once and is in no cycle. That\n // mutant is equivalent.\n if (frame.next < frame.children.length) {\n const child = frame.children[frame.next] as string;\n frame.next += 1;\n if (!indexOf.has(child)) {\n indexOf.set(child, counter);\n lowLink.set(child, counter);\n counter += 1;\n stack.push(child);\n onStack.add(child);\n work.push({ id: child, next: 0, children: successors(child) });\n } else if (onStack.has(child)) {\n lowLink.set(frame.id, Math.min(lowLink.get(frame.id) as number, indexOf.get(child) as number));\n }\n continue;\n }\n\n work.pop();\n const parent = work[work.length - 1];\n if (parent) {\n lowLink.set(parent.id, Math.min(lowLink.get(parent.id) as number, lowLink.get(frame.id) as number));\n }\n\n if (lowLink.get(frame.id) === indexOf.get(frame.id)) {\n const component: string[] = [];\n for (;;) {\n const popped = stack.pop() as string;\n onStack.delete(popped);\n component.push(popped);\n if (popped === frame.id) break;\n }\n if (component.length > 1) components.push(component.reverse());\n else if (successors(frame.id).includes(frame.id)) components.push(component);\n }\n }\n }\n\n return components;\n}\n\n/* -------------------------------------------------------------------------- */\n/* Derived predicates */\n/* -------------------------------------------------------------------------- */\n\n/** Edge kinds that move an obligation from one document to another. */\nexport const OBLIGATION_EDGES: readonly EdgeKind[] = Object.freeze(\n (Object.keys(EDGE_TRAITS) as EdgeKind[]).filter((kind) => EDGE_TRAITS[kind].transfersObligation),\n);\n\n/** Edge kinds whose source depends on what the target says. */\nexport const LOAD_BEARING_EDGES: readonly EdgeKind[] = Object.freeze(\n (Object.keys(EDGE_TRAITS) as EdgeKind[]).filter((kind) => EDGE_TRAITS[kind].loadBearing),\n);\n"]}
|
package/dist/select.js
CHANGED
|
@@ -162,9 +162,10 @@ class Parser {
|
|
|
162
162
|
return out;
|
|
163
163
|
}
|
|
164
164
|
// The anchor decides nothing, since a starred class matches the empty
|
|
165
|
-
// string where the search starts; it says where the value begins.
|
|
166
|
-
|
|
167
|
-
|
|
165
|
+
// string where the search starts; it says where the value begins. For the
|
|
166
|
+
// same reason the search never misses, and there is nothing to fall back
|
|
167
|
+
// from.
|
|
168
|
+
const value = /^[^\]\s]*/.exec(this.source.slice(this.position))[0];
|
|
168
169
|
this.position += value.length;
|
|
169
170
|
return value;
|
|
170
171
|
}
|
package/dist/select.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"select.js","sourceRoot":"","sources":["../src/select.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The selector language.\n *\n * Rules and users ask the graph the same kinds of question, so they use the same\n * machinery. Every built-in diagnostic is a path query plus a message; anything\n * a rule can find, `spec-graph query` can find too, which means a team can\n * express a convention spec-graph never anticipated without writing a plugin.\n *\n * ```text\n * item[openness=open] -delegates-to-> document[phase=retired]\n * document[phase=active] -assumes,depends-on-> document[phase=retired]\n * document =supersedes=> document[phase=active]\n * item[state=obviated] <-assumes- *\n * *[path^=docs/adr] -blocked-by-> item[openness=open]\n * ```\n *\n * A query evaluates to **paths**, not endpoints. A rule that has the whole path\n * can say \"ADR-0004 line 31 delegates this to ADR-0002, which was retired in\n * March\" instead of naming two documents and leaving the reader to reconstruct\n * the relationship.\n */\n\nimport { receptivityOf } from './lifecycle.js';\nimport type { SpecGraph } from './graph.js';\nimport { EDGE_KINDS, type Edge, type EdgeKind, type NodeKind, type SpecNode } from './types.js';\nimport { compileRegex, RegexError, type RegexMatcher } from './vendor/spec-core/pattern/index.js';\n\n/* -------------------------------------------------------------------------- */\n/* Shapes */\n/* -------------------------------------------------------------------------- */\n\nexport type Operator = '=' | '!=' | '^=' | '$=' | '*=' | '~=' | 'exists';\n\nexport interface Predicate {\n readonly key: string;\n readonly operator: Operator;\n readonly value: string;\n}\n\nexport interface NodeMatcher {\n /** `null` matches both documents and items. */\n readonly kind: NodeKind | null;\n readonly predicates: readonly Predicate[];\n}\n\nexport interface StepSpec {\n readonly direction: 'out' | 'in';\n /** `null` matches any edge kind. */\n readonly kinds: readonly EdgeKind[] | null;\n /** Follow the relation transitively, taking the shortest path to each node. */\n readonly transitive: boolean;\n readonly node: NodeMatcher;\n}\n\nexport interface QuerySpec {\n readonly start: NodeMatcher;\n readonly steps: readonly StepSpec[];\n}\n\n/**\n * One path through the graph.\n *\n * `nodes` holds the start and the node each step matched; `edges` is the whole\n * path in order. A transitive step contributes one node and every edge it\n * walked, so the nodes it passed through are named only by those edges.\n */\nexport interface Match {\n readonly nodes: readonly SpecNode[];\n readonly edges: readonly Edge[];\n}\n\nexport class QueryError extends Error {\n /** Offset into the query string where the problem starts. */\n readonly offset: number;\n\n constructor(message: string, offset: number) {\n super(message);\n this.name = 'QueryError';\n this.offset = offset;\n }\n}\n\n/** Guards against a pathological query fanning out over a huge corpus. */\nexport const DEFAULT_MATCH_LIMIT = 10_000;\n\n/* -------------------------------------------------------------------------- */\n/* Parsing */\n/* -------------------------------------------------------------------------- */\n\n/**\n * The words that name a node type, and `null` for the ones that name any.\n *\n * A map, because a selector is typed by a person and an object answers to\n * more names than it was given: `constructor` was a node type no node has, so\n * `constructor[status=draft]` matched nothing where `construct[status=draft]`\n * was refused.\n */\nconst NODE_KINDS: ReadonlyMap<string, NodeKind | null> = new Map<string, NodeKind | null>([\n ['document', 'document'],\n ['documents', 'document'],\n ['doc', 'document'],\n ['docs', 'document'],\n ['item', 'item'],\n ['items', 'item'],\n ['node', null],\n ['nodes', null],\n ['any', null],\n ['*', null],\n]);\n\n/** Compiles a selector string into a {@link QuerySpec}. */\nexport function parseQuery(source: string): QuerySpec {\n const parser = new Parser(source);\n const start = parser.parseNodeMatcher();\n const steps: StepSpec[] = [];\n parser.skipSpace();\n while (!parser.atEnd()) {\n steps.push(parser.parseStep());\n parser.skipSpace();\n }\n return { start, steps };\n}\n\nclass Parser {\n private readonly source: string;\n private position = 0;\n\n constructor(source: string) {\n this.source = source;\n }\n\n atEnd(): boolean {\n return this.position >= this.source.length;\n }\n\n skipSpace(): void {\n // The bound decides nothing: past the end the character is `undefined`,\n // which `test` reads as the word \"undefined\" and rejects. It is kept so the\n // loop does not lean on that.\n while (this.position < this.source.length && /\\s/.test(this.source[this.position] as string)) this.position += 1;\n }\n\n parseNodeMatcher(): NodeMatcher {\n this.skipSpace();\n let kind: NodeKind | null = null;\n const word = /^[A-Za-z]+|^\\*/.exec(this.source.slice(this.position));\n if (word) {\n const text = (word[0] as string).toLowerCase();\n if (!NODE_KINDS.has(text)) {\n throw new QueryError(\n `unknown node type \"${word[0]}\", expected one of: document, item, * (any)`,\n this.position,\n );\n }\n kind = NODE_KINDS.get(text) as NodeKind | null;\n this.position += (word[0] as string).length;\n } else if (this.source[this.position] !== '[') {\n throw new QueryError('expected a node type (document, item or *) or a [predicate]', this.position);\n }\n\n const predicates: Predicate[] = [];\n while (this.source[this.position] === '[') predicates.push(this.parsePredicate());\n return { kind, predicates };\n }\n\n private parsePredicate(): Predicate {\n this.position += 1;\n const keyMatch = /^[A-Za-z_][A-Za-z0-9_.:-]*/.exec(this.source.slice(this.position));\n if (!keyMatch) throw new QueryError('expected an attribute name after \"[\"', this.position);\n const key = (keyMatch[0] as string).toLowerCase();\n this.position += (keyMatch[0] as string).length;\n\n if (this.source[this.position] === ']') {\n this.position += 1;\n return { key, operator: 'exists', value: '' };\n }\n\n const operatorMatch = /^(!=|\\^=|\\$=|\\*=|~=|=)/.exec(this.source.slice(this.position));\n if (!operatorMatch) {\n throw new QueryError(\n `expected an operator (=, !=, ^=, $=, *=, ~=) or \"]\" after \"${key}\"`,\n this.position,\n );\n }\n const operator = operatorMatch[0] as Operator;\n this.position += operator.length;\n\n const valueStart = this.position;\n const value = this.parseValue();\n if (this.source[this.position] !== ']') throw new QueryError('expected \"]\" to close the predicate', this.position);\n this.position += 1;\n // A pattern is checked here rather than where it runs, because here is the\n // only place that knows where in the selector it was written. It used to be\n // compiled on first use and an unparseable one silently matched nothing,\n // which is the same silence a misspelled relation would have produced if\n // this grammar tolerated one. See ADR-0017.\n if (operator === '~=') {\n try {\n pattern(value);\n } catch (error) {\n if (!(error instanceof RegexError)) throw error;\n throw new QueryError(error.message, valueStart + error.offset + (quoted(this.source[valueStart]) ? 1 : 0));\n }\n }\n return { key, operator, value };\n }\n\n private parseValue(): string {\n const quote = this.source[this.position];\n if (quote === '\"' || quote === \"'\") {\n this.position += 1;\n let out = '';\n while (this.position < this.source.length && this.source[this.position] !== quote) {\n if (this.source[this.position] === '\\\\') this.position += 1;\n // `?? ''` meets only a backslash at the very end, and the value it\n // builds then is thrown away with the unterminated quote below.\n out += this.source[this.position] ?? '';\n this.position += 1;\n }\n if (this.source[this.position] !== quote) throw new QueryError('unterminated quoted value', this.position);\n this.position += 1;\n return out;\n }\n // The anchor decides nothing, since a starred class matches the empty\n // string where the search starts; it says where the value begins.\n const match = /^[^\\]\\s]*/.exec(this.source.slice(this.position));\n const value = (match?.[0] ?? '') as string;\n this.position += value.length;\n return value;\n }\n\n parseStep(): StepSpec {\n const rest = this.source.slice(this.position);\n // The forward form is lazy because its terminator is two characters (`->`),\n // which cannot be confused with the hyphen inside `delegates-to`. The\n // backward terminator is a single `-`, so it must be greedy and backtrack:\n // matching lazily would read `<-delegates-to-` as the relation `delegates`.\n const forward = /^(-|=)([A-Za-z,*-]*?)(->|=>)/.exec(rest);\n const backward = /^(<-|<=)([A-Za-z,*-]*)(-|=)(?=\\s|$|[A-Za-z*[])/.exec(rest);\n\n // Both are anchored where the step starts and open with different\n // characters, so at most one of them matches.\n if (forward) {\n const transitive = (forward[1] as string) === '=';\n const closing = forward[3] as string;\n if ((closing === '=>') !== transitive) {\n throw new QueryError('mismatched arrow: use -kind-> for one hop or =kind=> for transitive', this.position);\n }\n const kinds = this.parseKinds(forward[2] as string, this.position + 1);\n this.position += (forward[0] as string).length;\n return { direction: 'out', kinds, transitive, node: this.parseNodeMatcher() };\n }\n\n if (backward) {\n const transitive = (backward[1] as string) === '<=';\n const closing = backward[3] as string;\n if ((closing === '=') !== transitive) {\n throw new QueryError('mismatched arrow: use <-kind- for one hop or <=kind= for transitive', this.position);\n }\n const kinds = this.parseKinds(backward[2] as string, this.position + 2);\n this.position += (backward[0] as string).length;\n return { direction: 'in', kinds, transitive, node: this.parseNodeMatcher() };\n }\n\n throw new QueryError(\n 'expected a relation step such as -delegates-to->, <-assumes- or =supersedes=>',\n this.position,\n );\n }\n\n /**\n * Reads the relation list between a step's arrows.\n *\n * Nothing is trimmed, because the step patterns admit no whitespace inside\n * an arrow. An empty list is not a special case either: it splits into one\n * empty name, which is skipped, and no names at all means any relation.\n */\n private parseKinds(raw: string, offset: number): readonly EdgeKind[] | null {\n if (raw === '*') return null;\n const kinds: EdgeKind[] = [];\n for (const part of raw.split(',')) {\n const name = part.toLowerCase();\n if (name.length === 0) continue;\n if (!(EDGE_KINDS as readonly string[]).includes(name)) {\n throw new QueryError(`unknown relation \"${name}\", expected one of: ${EDGE_KINDS.join(', ')}`, offset);\n }\n kinds.push(name as EdgeKind);\n }\n // `null` rather than an empty list, which the graph would read the same\n // way: the spec says \"any relation\" in the form its type documents.\n return kinds.length > 0 ? kinds : null;\n }\n}\n\n/* -------------------------------------------------------------------------- */\n/* Attributes */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Every attribute key a node can answer to, excluding the open `fm.` namespace.\n *\n * Selectors do not validate their keys - an unknown one simply matches nothing,\n * which is the forgiving reading a query typed at a prompt wants. A message\n * template is the opposite case: `{1.phse}` would render as an empty string in\n * a diagnostic somebody has to act on, silently and forever. So the list is\n * published here, next to the switch it mirrors, for the one caller that needs\n * to be strict. See ADR-0016.\n */\nexport const SELECTOR_KEYS: readonly string[] = Object.freeze([\n 'alias',\n 'body',\n 'conflicted',\n 'disposition',\n 'document',\n 'evidence',\n 'file',\n 'id',\n 'kind',\n 'line',\n 'openness',\n 'path',\n 'phase',\n 'receptivity',\n 'section',\n 'state',\n 'status',\n 'text',\n 'title',\n]);\n\n/**\n * The values a predicate key sees on a node.\n *\n * Multi-valued keys (`alias`, `section`) match when *any* value matches, which\n * is what makes `[section=Open Questions]` read the way people expect.\n */\nexport function attributesOf(node: SpecNode, key: string, graph?: SpecGraph): string[] {\n switch (key) {\n case 'id':\n return [node.id];\n case 'kind':\n return [node.kind];\n case 'title':\n return [node.title];\n case 'file':\n return [node.at.file];\n case 'line':\n return [String(node.at.span.start.line)];\n case 'document':\n return [node.kind === 'item' ? node.document : node.id];\n }\n\n if (node.kind === 'document') {\n switch (key) {\n case 'path':\n return [node.path];\n case 'phase':\n return [node.phase];\n case 'status':\n return node.rawStatus === null ? [] : [node.rawStatus];\n case 'receptivity':\n return [receptivityOf(node.phase)];\n case 'alias':\n return [...node.aliases];\n }\n if (key.startsWith('fm.')) {\n // Its own keys only: every object answers to `constructor`, and no\n // document's front matter said so.\n const name = key.slice(3);\n if (!Object.hasOwn(node.frontMatter, name)) return [];\n const value = node.frontMatter[name] as string | readonly string[];\n return typeof value === 'string' ? [value] : [...value];\n }\n return [];\n }\n\n // An item inherits its document's lifecycle. Without this, the two rules that\n // matter most could not be written as queries at all, because the question\n // they ask - \"is the document holding this obligation still open?\" - is about\n // the owner, not the item.\n if (key === 'phase' || key === 'receptivity' || key === 'status' || key === 'path' || key === 'alias') {\n const owner = graph?.owningDocument(node.id);\n if (owner) return attributesOf(owner, key, graph);\n return key === 'path' ? [node.at.file] : [];\n }\n\n switch (key) {\n case 'state':\n case 'disposition':\n return [node.disposition];\n case 'openness':\n return [node.openness];\n case 'section':\n return [...node.section];\n case 'text':\n return [node.text];\n case 'body':\n return [node.body];\n case 'evidence':\n return [node.evidence.source];\n case 'conflicted':\n return [node.conflicts.length > 0 ? 'true' : 'false'];\n default:\n return [];\n }\n}\n\nfunction testPredicate(node: SpecNode, predicate: Predicate, graph?: SpecGraph): boolean {\n const values = attributesOf(node, predicate.key, graph);\n const needle = predicate.value.toLowerCase();\n\n if (predicate.operator === 'exists') return values.some((value) => value.length > 0);\n if (predicate.operator === '!=') return !values.some((value) => value.toLowerCase() === needle);\n\n return values.some((raw) => {\n const value = raw.toLowerCase();\n switch (predicate.operator) {\n case '=':\n return value === needle;\n case '^=':\n return value.startsWith(needle);\n case '$=':\n return value.endsWith(needle);\n case '*=':\n return value.includes(needle);\n case '~=':\n return pattern(predicate.value).test(raw);\n default:\n // Unreachable: `exists` and `!=` returned above, and the type knows\n // no other operator. Narrowing does not reach into this callback.\n return false;\n }\n });\n}\n\nconst patterns = new Map<string, RegexMatcher>();\n\n/**\n * Compiles a `~=` pattern, once per distinct pattern.\n *\n * Cached because a rule runs its predicate against every node in the corpus,\n * and because compiling is the expensive half now that matching is linear.\n * The cache changes the cost and nothing else: a pattern compiled twice\n * matches what it matched once.\n */\nexport function pattern(source: string): RegexMatcher {\n const cached = patterns.get(source);\n if (cached) return cached;\n const compiled = compileRegex(source);\n patterns.set(source, compiled);\n return compiled;\n}\n\nfunction quoted(char: string | undefined): boolean {\n return char === '\"' || char === \"'\";\n}\n\n/** True when a node satisfies a matcher. */\nexport function matches(node: SpecNode, matcher: NodeMatcher, graph?: SpecGraph): boolean {\n if (matcher.kind !== null && node.kind !== matcher.kind) return false;\n return matcher.predicates.every((predicate) => testPredicate(node, predicate, graph));\n}\n\n/* -------------------------------------------------------------------------- */\n/* Execution */\n/* -------------------------------------------------------------------------- */\n\nexport interface ExecuteOptions {\n /**\n * Cap on the paths produced by each traversal step.\n *\n * It bounds *expansion*, not the initial selection: a query with no steps\n * returns every matching node. That asymmetry is deliberate. The limit exists\n * so a query across a dense graph cannot fan out unboundedly, and the rules\n * run through this engine - truncating the set of nodes a rule starts from\n * would silently drop findings, whereas truncating a runaway expansion only\n * ever drops paths that were already beyond reading.\n */\n readonly limit?: number | undefined;\n /**\n * Whether a step may stay inside one document.\n *\n * Off by default for reflexive edges: a document that links to itself is a\n * formatting quirk, not a relationship, and letting those through turns every\n * table of contents into a finding.\n */\n readonly allowReflexive?: boolean | undefined;\n}\n\n/** Runs a compiled query and returns every matching path. */\nexport function execute(graph: SpecGraph, spec: QuerySpec, options: ExecuteOptions = {}): Match[] {\n const limit = options.limit ?? DEFAULT_MATCH_LIMIT;\n const allowReflexive = options.allowReflexive ?? false;\n\n let frontier: Match[] = [];\n for (const node of graph.nodes.values()) {\n if (matches(node, spec.start, graph)) frontier.push({ nodes: [node], edges: [] });\n }\n\n for (const step of spec.steps) {\n const next: Match[] = [];\n const seen = new Set<string>();\n\n for (const match of frontier) {\n const tail = match.nodes[match.nodes.length - 1] as SpecNode;\n for (const { node, path } of expand(graph, tail, step, allowReflexive)) {\n if (!matches(node, step.node, graph)) continue;\n const key = `${match.nodes.map((n) => n.id).join('>')}>${node.id}`;\n if (seen.has(key)) continue;\n seen.add(key);\n next.push({ nodes: [...match.nodes, node], edges: [...match.edges, ...path] });\n if (next.length >= limit) break;\n }\n if (next.length >= limit) break;\n }\n\n frontier = next;\n // An empty frontier stays empty through every later step; this only stops\n // walking them.\n if (frontier.length === 0) break;\n }\n\n return frontier;\n}\n\ninterface Expansion {\n readonly node: SpecNode;\n readonly path: readonly Edge[];\n}\n\n// `buildGraph` drops every edge that names an unknown node, so the `if (node)`\n// guards below never skip anything in a graph it built. They stand for a\n// `SpecGraph` built some other way.\nfunction expand(graph: SpecGraph, from: SpecNode, step: StepSpec, allowReflexive: boolean): Expansion[] {\n const kinds = step.kinds ?? [];\n const out: Expansion[] = [];\n\n if (!step.transitive) {\n const edges = step.direction === 'out' ? graph.out(from.id, kinds) : graph.in(from.id, kinds);\n for (const edge of edges) {\n if (!allowReflexive && edge.reflexive) continue;\n const targetId = step.direction === 'out' ? edge.to : edge.from;\n const node = graph.node(targetId);\n if (node) out.push({ node, path: [edge] });\n }\n return out;\n }\n\n // Transitive steps take the shortest path to each reachable node, which keeps\n // the result deterministic and the reported evidence minimal.\n const reached =\n step.direction === 'out'\n ? graph.reach(from.id, kinds)\n : reachIncoming(graph, from.id, kinds);\n\n for (const [id, path] of reached) {\n if (!allowReflexive && path.every((edge) => edge.reflexive)) continue;\n const node = graph.node(id);\n if (node) out.push({ node, path });\n }\n return out;\n}\n\nfunction reachIncoming(graph: SpecGraph, id: string, kinds: readonly EdgeKind[]): Map<string, readonly Edge[]> {\n const paths = new Map<string, readonly Edge[]>();\n const pathTo = new Map<string, readonly Edge[]>([[id, []]]);\n const queue: string[] = [id];\n\n while (queue.length > 0) {\n const current = queue.shift() as string;\n const prefix = pathTo.get(current) as readonly Edge[];\n for (const edge of graph.in(current, kinds)) {\n if (pathTo.has(edge.from) && edge.from !== id) continue;\n const path = [...prefix, edge];\n if (edge.from === id) {\n if (!paths.has(id)) paths.set(id, path);\n continue;\n }\n pathTo.set(edge.from, path);\n paths.set(edge.from, path);\n queue.push(edge.from);\n }\n }\n return paths;\n}\n\n/** Parses and runs a selector in one call. */\nexport function query(graph: SpecGraph, selector: string, options?: ExecuteOptions): Match[] {\n return execute(graph, parseQuery(selector), options);\n}\n\n/**\n * Renders a match the way the selector reads, for `spec-graph query`.\n *\n * Every edge is written in the direction it was walked - `A -kind-> B`\n * forwards, `A <-kind- B` backwards - and names the node it arrives at, so a\n * transitive step shows each document it passed through. Reading the nodes off\n * `match.nodes` instead printed the end of a transitive path in its middle, and\n * a backward step as a relation pointing the other way.\n */\nexport function renderMatch(match: Match): string {\n let at = (match.nodes[0] as SpecNode).id;\n const parts: string[] = [at];\n for (const edge of match.edges) {\n const forwards = edge.from === at;\n at = forwards ? edge.to : edge.from;\n parts.push(forwards ? `-${edge.kind}->` : `<-${edge.kind}-`, at);\n }\n return parts.join(' ');\n}\n"]}
|
|
1
|
+
{"version":3,"file":"select.js","sourceRoot":"","sources":["../src/select.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The selector language.\n *\n * Rules and users ask the graph the same kinds of question, so they use the same\n * machinery. Every built-in diagnostic is a path query plus a message; anything\n * a rule can find, `spec-graph query` can find too, which means a team can\n * express a convention spec-graph never anticipated without writing a plugin.\n *\n * ```text\n * item[openness=open] -delegates-to-> document[phase=retired]\n * document[phase=active] -assumes,depends-on-> document[phase=retired]\n * document =supersedes=> document[phase=active]\n * item[state=obviated] <-assumes- *\n * *[path^=docs/adr] -blocked-by-> item[openness=open]\n * ```\n *\n * A query evaluates to **paths**, not endpoints. A rule that has the whole path\n * can say \"ADR-0004 line 31 delegates this to ADR-0002, which was retired in\n * March\" instead of naming two documents and leaving the reader to reconstruct\n * the relationship.\n */\n\nimport { receptivityOf } from './lifecycle.js';\nimport type { SpecGraph } from './graph.js';\nimport { EDGE_KINDS, type Edge, type EdgeKind, type NodeKind, type SpecNode } from './types.js';\nimport { compileRegex, RegexError, type RegexMatcher } from './vendor/spec-core/pattern/index.js';\n\n/* -------------------------------------------------------------------------- */\n/* Shapes */\n/* -------------------------------------------------------------------------- */\n\nexport type Operator = '=' | '!=' | '^=' | '$=' | '*=' | '~=' | 'exists';\n\nexport interface Predicate {\n readonly key: string;\n readonly operator: Operator;\n readonly value: string;\n}\n\nexport interface NodeMatcher {\n /** `null` matches both documents and items. */\n readonly kind: NodeKind | null;\n readonly predicates: readonly Predicate[];\n}\n\nexport interface StepSpec {\n readonly direction: 'out' | 'in';\n /** `null` matches any edge kind. */\n readonly kinds: readonly EdgeKind[] | null;\n /** Follow the relation transitively, taking the shortest path to each node. */\n readonly transitive: boolean;\n readonly node: NodeMatcher;\n}\n\nexport interface QuerySpec {\n readonly start: NodeMatcher;\n readonly steps: readonly StepSpec[];\n}\n\n/**\n * One path through the graph.\n *\n * `nodes` holds the start and the node each step matched; `edges` is the whole\n * path in order. A transitive step contributes one node and every edge it\n * walked, so the nodes it passed through are named only by those edges.\n */\nexport interface Match {\n readonly nodes: readonly SpecNode[];\n readonly edges: readonly Edge[];\n}\n\nexport class QueryError extends Error {\n /** Offset into the query string where the problem starts. */\n readonly offset: number;\n\n constructor(message: string, offset: number) {\n super(message);\n this.name = 'QueryError';\n this.offset = offset;\n }\n}\n\n/** Guards against a pathological query fanning out over a huge corpus. */\nexport const DEFAULT_MATCH_LIMIT = 10_000;\n\n/* -------------------------------------------------------------------------- */\n/* Parsing */\n/* -------------------------------------------------------------------------- */\n\n/**\n * The words that name a node type, and `null` for the ones that name any.\n *\n * A map, because a selector is typed by a person and an object answers to\n * more names than it was given: `constructor` was a node type no node has, so\n * `constructor[status=draft]` matched nothing where `construct[status=draft]`\n * was refused.\n */\nconst NODE_KINDS: ReadonlyMap<string, NodeKind | null> = new Map<string, NodeKind | null>([\n ['document', 'document'],\n ['documents', 'document'],\n ['doc', 'document'],\n ['docs', 'document'],\n ['item', 'item'],\n ['items', 'item'],\n ['node', null],\n ['nodes', null],\n ['any', null],\n ['*', null],\n]);\n\n/** Compiles a selector string into a {@link QuerySpec}. */\nexport function parseQuery(source: string): QuerySpec {\n const parser = new Parser(source);\n const start = parser.parseNodeMatcher();\n const steps: StepSpec[] = [];\n parser.skipSpace();\n while (!parser.atEnd()) {\n steps.push(parser.parseStep());\n parser.skipSpace();\n }\n return { start, steps };\n}\n\nclass Parser {\n private readonly source: string;\n private position = 0;\n\n constructor(source: string) {\n this.source = source;\n }\n\n atEnd(): boolean {\n return this.position >= this.source.length;\n }\n\n skipSpace(): void {\n // The bound decides nothing: past the end the character is `undefined`,\n // which `test` reads as the word \"undefined\" and rejects. It is kept so the\n // loop does not lean on that.\n while (this.position < this.source.length && /\\s/.test(this.source[this.position] as string)) this.position += 1;\n }\n\n parseNodeMatcher(): NodeMatcher {\n this.skipSpace();\n let kind: NodeKind | null = null;\n const word = /^[A-Za-z]+|^\\*/.exec(this.source.slice(this.position));\n if (word) {\n const text = (word[0] as string).toLowerCase();\n if (!NODE_KINDS.has(text)) {\n throw new QueryError(\n `unknown node type \"${word[0]}\", expected one of: document, item, * (any)`,\n this.position,\n );\n }\n kind = NODE_KINDS.get(text) as NodeKind | null;\n this.position += (word[0] as string).length;\n } else if (this.source[this.position] !== '[') {\n throw new QueryError('expected a node type (document, item or *) or a [predicate]', this.position);\n }\n\n const predicates: Predicate[] = [];\n while (this.source[this.position] === '[') predicates.push(this.parsePredicate());\n return { kind, predicates };\n }\n\n private parsePredicate(): Predicate {\n this.position += 1;\n const keyMatch = /^[A-Za-z_][A-Za-z0-9_.:-]*/.exec(this.source.slice(this.position));\n if (!keyMatch) throw new QueryError('expected an attribute name after \"[\"', this.position);\n const key = (keyMatch[0] as string).toLowerCase();\n this.position += (keyMatch[0] as string).length;\n\n if (this.source[this.position] === ']') {\n this.position += 1;\n return { key, operator: 'exists', value: '' };\n }\n\n const operatorMatch = /^(!=|\\^=|\\$=|\\*=|~=|=)/.exec(this.source.slice(this.position));\n if (!operatorMatch) {\n throw new QueryError(\n `expected an operator (=, !=, ^=, $=, *=, ~=) or \"]\" after \"${key}\"`,\n this.position,\n );\n }\n const operator = operatorMatch[0] as Operator;\n this.position += operator.length;\n\n const valueStart = this.position;\n const value = this.parseValue();\n if (this.source[this.position] !== ']') throw new QueryError('expected \"]\" to close the predicate', this.position);\n this.position += 1;\n // A pattern is checked here rather than where it runs, because here is the\n // only place that knows where in the selector it was written. It used to be\n // compiled on first use and an unparseable one silently matched nothing,\n // which is the same silence a misspelled relation would have produced if\n // this grammar tolerated one. See ADR-0017.\n if (operator === '~=') {\n try {\n pattern(value);\n } catch (error) {\n if (!(error instanceof RegexError)) throw error;\n throw new QueryError(error.message, valueStart + error.offset + (quoted(this.source[valueStart]) ? 1 : 0));\n }\n }\n return { key, operator, value };\n }\n\n private parseValue(): string {\n const quote = this.source[this.position];\n if (quote === '\"' || quote === \"'\") {\n this.position += 1;\n let out = '';\n while (this.position < this.source.length && this.source[this.position] !== quote) {\n if (this.source[this.position] === '\\\\') this.position += 1;\n // `?? ''` meets only a backslash at the very end, and the value it\n // builds then is thrown away with the unterminated quote below.\n out += this.source[this.position] ?? '';\n this.position += 1;\n }\n if (this.source[this.position] !== quote) throw new QueryError('unterminated quoted value', this.position);\n this.position += 1;\n return out;\n }\n // The anchor decides nothing, since a starred class matches the empty\n // string where the search starts; it says where the value begins. For the\n // same reason the search never misses, and there is nothing to fall back\n // from.\n const value = /^[^\\]\\s]*/.exec(this.source.slice(this.position))![0];\n this.position += value.length;\n return value;\n }\n\n parseStep(): StepSpec {\n const rest = this.source.slice(this.position);\n // The forward form is lazy because its terminator is two characters (`->`),\n // which cannot be confused with the hyphen inside `delegates-to`. The\n // backward terminator is a single `-`, so it must be greedy and backtrack:\n // matching lazily would read `<-delegates-to-` as the relation `delegates`.\n const forward = /^(-|=)([A-Za-z,*-]*?)(->|=>)/.exec(rest);\n const backward = /^(<-|<=)([A-Za-z,*-]*)(-|=)(?=\\s|$|[A-Za-z*[])/.exec(rest);\n\n // Both are anchored where the step starts and open with different\n // characters, so at most one of them matches.\n if (forward) {\n const transitive = (forward[1] as string) === '=';\n const closing = forward[3] as string;\n if ((closing === '=>') !== transitive) {\n throw new QueryError('mismatched arrow: use -kind-> for one hop or =kind=> for transitive', this.position);\n }\n const kinds = this.parseKinds(forward[2] as string, this.position + 1);\n this.position += (forward[0] as string).length;\n return { direction: 'out', kinds, transitive, node: this.parseNodeMatcher() };\n }\n\n if (backward) {\n const transitive = (backward[1] as string) === '<=';\n const closing = backward[3] as string;\n if ((closing === '=') !== transitive) {\n throw new QueryError('mismatched arrow: use <-kind- for one hop or <=kind= for transitive', this.position);\n }\n const kinds = this.parseKinds(backward[2] as string, this.position + 2);\n this.position += (backward[0] as string).length;\n return { direction: 'in', kinds, transitive, node: this.parseNodeMatcher() };\n }\n\n throw new QueryError(\n 'expected a relation step such as -delegates-to->, <-assumes- or =supersedes=>',\n this.position,\n );\n }\n\n /**\n * Reads the relation list between a step's arrows.\n *\n * Nothing is trimmed, because the step patterns admit no whitespace inside\n * an arrow. An empty list is not a special case either: it splits into one\n * empty name, which is skipped, and no names at all means any relation.\n */\n private parseKinds(raw: string, offset: number): readonly EdgeKind[] | null {\n if (raw === '*') return null;\n const kinds: EdgeKind[] = [];\n for (const part of raw.split(',')) {\n const name = part.toLowerCase();\n if (name.length === 0) continue;\n if (!(EDGE_KINDS as readonly string[]).includes(name)) {\n throw new QueryError(`unknown relation \"${name}\", expected one of: ${EDGE_KINDS.join(', ')}`, offset);\n }\n kinds.push(name as EdgeKind);\n }\n // `null` rather than an empty list, which the graph would read the same\n // way: the spec says \"any relation\" in the form its type documents.\n return kinds.length > 0 ? kinds : null;\n }\n}\n\n/* -------------------------------------------------------------------------- */\n/* Attributes */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Every attribute key a node can answer to, excluding the open `fm.` namespace.\n *\n * Selectors do not validate their keys - an unknown one simply matches nothing,\n * which is the forgiving reading a query typed at a prompt wants. A message\n * template is the opposite case: `{1.phse}` would render as an empty string in\n * a diagnostic somebody has to act on, silently and forever. So the list is\n * published here, next to the switch it mirrors, for the one caller that needs\n * to be strict. See ADR-0016.\n */\nexport const SELECTOR_KEYS: readonly string[] = Object.freeze([\n 'alias',\n 'body',\n 'conflicted',\n 'disposition',\n 'document',\n 'evidence',\n 'file',\n 'id',\n 'kind',\n 'line',\n 'openness',\n 'path',\n 'phase',\n 'receptivity',\n 'section',\n 'state',\n 'status',\n 'text',\n 'title',\n]);\n\n/**\n * The values a predicate key sees on a node.\n *\n * Multi-valued keys (`alias`, `section`) match when *any* value matches, which\n * is what makes `[section=Open Questions]` read the way people expect.\n */\nexport function attributesOf(node: SpecNode, key: string, graph?: SpecGraph): string[] {\n switch (key) {\n case 'id':\n return [node.id];\n case 'kind':\n return [node.kind];\n case 'title':\n return [node.title];\n case 'file':\n return [node.at.file];\n case 'line':\n return [String(node.at.span.start.line)];\n case 'document':\n return [node.kind === 'item' ? node.document : node.id];\n }\n\n if (node.kind === 'document') {\n switch (key) {\n case 'path':\n return [node.path];\n case 'phase':\n return [node.phase];\n case 'status':\n return node.rawStatus === null ? [] : [node.rawStatus];\n case 'receptivity':\n return [receptivityOf(node.phase)];\n case 'alias':\n return [...node.aliases];\n }\n if (key.startsWith('fm.')) {\n // Its own keys only: every object answers to `constructor`, and no\n // document's front matter said so.\n const name = key.slice(3);\n if (!Object.hasOwn(node.frontMatter, name)) return [];\n const value = node.frontMatter[name] as string | readonly string[];\n return typeof value === 'string' ? [value] : [...value];\n }\n return [];\n }\n\n // An item inherits its document's lifecycle. Without this, the two rules that\n // matter most could not be written as queries at all, because the question\n // they ask - \"is the document holding this obligation still open?\" - is about\n // the owner, not the item.\n if (key === 'phase' || key === 'receptivity' || key === 'status' || key === 'path' || key === 'alias') {\n const owner = graph?.owningDocument(node.id);\n if (owner) return attributesOf(owner, key, graph);\n return key === 'path' ? [node.at.file] : [];\n }\n\n switch (key) {\n case 'state':\n case 'disposition':\n return [node.disposition];\n case 'openness':\n return [node.openness];\n case 'section':\n return [...node.section];\n case 'text':\n return [node.text];\n case 'body':\n return [node.body];\n case 'evidence':\n return [node.evidence.source];\n case 'conflicted':\n return [node.conflicts.length > 0 ? 'true' : 'false'];\n default:\n return [];\n }\n}\n\nfunction testPredicate(node: SpecNode, predicate: Predicate, graph?: SpecGraph): boolean {\n const values = attributesOf(node, predicate.key, graph);\n const needle = predicate.value.toLowerCase();\n\n if (predicate.operator === 'exists') return values.some((value) => value.length > 0);\n if (predicate.operator === '!=') return !values.some((value) => value.toLowerCase() === needle);\n\n return values.some((raw) => {\n const value = raw.toLowerCase();\n switch (predicate.operator) {\n case '=':\n return value === needle;\n case '^=':\n return value.startsWith(needle);\n case '$=':\n return value.endsWith(needle);\n case '*=':\n return value.includes(needle);\n case '~=':\n return pattern(predicate.value).test(raw);\n default:\n // Unreachable: `exists` and `!=` returned above, and the type knows\n // no other operator. Narrowing does not reach into this callback.\n return false;\n }\n });\n}\n\nconst patterns = new Map<string, RegexMatcher>();\n\n/**\n * Compiles a `~=` pattern, once per distinct pattern.\n *\n * Cached because a rule runs its predicate against every node in the corpus,\n * and because compiling is the expensive half now that matching is linear.\n * The cache changes the cost and nothing else: a pattern compiled twice\n * matches what it matched once.\n */\nexport function pattern(source: string): RegexMatcher {\n const cached = patterns.get(source);\n if (cached) return cached;\n const compiled = compileRegex(source);\n patterns.set(source, compiled);\n return compiled;\n}\n\nfunction quoted(char: string | undefined): boolean {\n return char === '\"' || char === \"'\";\n}\n\n/** True when a node satisfies a matcher. */\nexport function matches(node: SpecNode, matcher: NodeMatcher, graph?: SpecGraph): boolean {\n if (matcher.kind !== null && node.kind !== matcher.kind) return false;\n return matcher.predicates.every((predicate) => testPredicate(node, predicate, graph));\n}\n\n/* -------------------------------------------------------------------------- */\n/* Execution */\n/* -------------------------------------------------------------------------- */\n\nexport interface ExecuteOptions {\n /**\n * Cap on the paths produced by each traversal step.\n *\n * It bounds *expansion*, not the initial selection: a query with no steps\n * returns every matching node. That asymmetry is deliberate. The limit exists\n * so a query across a dense graph cannot fan out unboundedly, and the rules\n * run through this engine - truncating the set of nodes a rule starts from\n * would silently drop findings, whereas truncating a runaway expansion only\n * ever drops paths that were already beyond reading.\n */\n readonly limit?: number | undefined;\n /**\n * Whether a step may stay inside one document.\n *\n * Off by default for reflexive edges: a document that links to itself is a\n * formatting quirk, not a relationship, and letting those through turns every\n * table of contents into a finding.\n */\n readonly allowReflexive?: boolean | undefined;\n}\n\n/** Runs a compiled query and returns every matching path. */\nexport function execute(graph: SpecGraph, spec: QuerySpec, options: ExecuteOptions = {}): Match[] {\n const limit = options.limit ?? DEFAULT_MATCH_LIMIT;\n const allowReflexive = options.allowReflexive ?? false;\n\n let frontier: Match[] = [];\n for (const node of graph.nodes.values()) {\n if (matches(node, spec.start, graph)) frontier.push({ nodes: [node], edges: [] });\n }\n\n for (const step of spec.steps) {\n const next: Match[] = [];\n const seen = new Set<string>();\n\n for (const match of frontier) {\n const tail = match.nodes[match.nodes.length - 1]!;\n for (const { node, path } of expand(graph, tail, step, allowReflexive)) {\n if (!matches(node, step.node, graph)) continue;\n const key = `${match.nodes.map((n) => n.id).join('>')}>${node.id}`;\n if (seen.has(key)) continue;\n seen.add(key);\n next.push({ nodes: [...match.nodes, node], edges: [...match.edges, ...path] });\n if (next.length >= limit) break;\n }\n if (next.length >= limit) break;\n }\n\n frontier = next;\n // An empty frontier stays empty through every later step; this only stops\n // walking them.\n if (frontier.length === 0) break;\n }\n\n return frontier;\n}\n\ninterface Expansion {\n readonly node: SpecNode;\n readonly path: readonly Edge[];\n}\n\n// `buildGraph` drops every edge that names an unknown node, so the `if (node)`\n// guards below never skip anything in a graph it built. They stand for a\n// `SpecGraph` built some other way.\nfunction expand(graph: SpecGraph, from: SpecNode, step: StepSpec, allowReflexive: boolean): Expansion[] {\n const kinds = step.kinds ?? [];\n const out: Expansion[] = [];\n\n if (!step.transitive) {\n const edges = step.direction === 'out' ? graph.out(from.id, kinds) : graph.in(from.id, kinds);\n for (const edge of edges) {\n if (!allowReflexive && edge.reflexive) continue;\n const targetId = step.direction === 'out' ? edge.to : edge.from;\n const node = graph.node(targetId);\n if (node) out.push({ node, path: [edge] });\n }\n return out;\n }\n\n // Transitive steps take the shortest path to each reachable node, which keeps\n // the result deterministic and the reported evidence minimal.\n const reached =\n step.direction === 'out'\n ? graph.reach(from.id, kinds)\n : reachIncoming(graph, from.id, kinds);\n\n for (const [id, path] of reached) {\n if (!allowReflexive && path.every((edge) => edge.reflexive)) continue;\n const node = graph.node(id);\n if (node) out.push({ node, path });\n }\n return out;\n}\n\nfunction reachIncoming(graph: SpecGraph, id: string, kinds: readonly EdgeKind[]): Map<string, readonly Edge[]> {\n const paths = new Map<string, readonly Edge[]>();\n const pathTo = new Map<string, readonly Edge[]>([[id, []]]);\n const queue: string[] = [id];\n\n while (queue.length > 0) {\n const current = queue.shift() as string;\n const prefix = pathTo.get(current) as readonly Edge[];\n for (const edge of graph.in(current, kinds)) {\n if (pathTo.has(edge.from) && edge.from !== id) continue;\n const path = [...prefix, edge];\n if (edge.from === id) {\n if (!paths.has(id)) paths.set(id, path);\n continue;\n }\n pathTo.set(edge.from, path);\n paths.set(edge.from, path);\n queue.push(edge.from);\n }\n }\n return paths;\n}\n\n/** Parses and runs a selector in one call. */\nexport function query(graph: SpecGraph, selector: string, options?: ExecuteOptions): Match[] {\n return execute(graph, parseQuery(selector), options);\n}\n\n/**\n * Renders a match the way the selector reads, for `spec-graph query`.\n *\n * Every edge is written in the direction it was walked - `A -kind-> B`\n * forwards, `A <-kind- B` backwards - and names the node it arrives at, so a\n * transitive step shows each document it passed through. Reading the nodes off\n * `match.nodes` instead printed the end of a transitive path in its middle, and\n * a backward step as a relation pointing the other way.\n */\nexport function renderMatch(match: Match): string {\n let at = (match.nodes[0] as SpecNode).id;\n const parts: string[] = [at];\n for (const edge of match.edges) {\n const forwards = edge.from === at;\n at = forwards ? edge.to : edge.from;\n parts.push(forwards ? `-${edge.kind}->` : `<-${edge.kind}-`, at);\n }\n return parts.join(' ');\n}\n"]}
|
package/package.json
CHANGED