@descent-vtt/spec-graph 0.9.9 → 0.10.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.
Files changed (43) hide show
  1. package/CHANGELOG.md +132 -2
  2. package/README.md +523 -308
  3. package/dist/cli.d.ts +2 -2
  4. package/dist/cli.js +112 -67
  5. package/dist/cli.js.map +1 -1
  6. package/dist/extract.d.ts +14 -1
  7. package/dist/extract.js +114 -10
  8. package/dist/extract.js.map +1 -1
  9. package/dist/glob.d.ts +17 -2
  10. package/dist/glob.js +137 -34
  11. package/dist/glob.js.map +1 -1
  12. package/dist/index.d.ts +1 -1
  13. package/dist/index.js +1 -1
  14. package/dist/index.js.map +1 -1
  15. package/dist/lifecycle.d.ts +11 -1
  16. package/dist/lifecycle.js +187 -28
  17. package/dist/lifecycle.js.map +1 -1
  18. package/dist/report.d.ts +22 -0
  19. package/dist/report.js +50 -3
  20. package/dist/report.js.map +1 -1
  21. package/dist/sections.d.ts +7 -1
  22. package/dist/sections.js +10 -2
  23. package/dist/sections.js.map +1 -1
  24. package/dist/state.js +19 -3
  25. package/dist/state.js.map +1 -1
  26. package/dist/vendor/spec-core/markdown/frontmatter.d.ts +11 -1
  27. package/dist/vendor/spec-core/markdown/frontmatter.js +20 -3
  28. package/dist/vendor/spec-core/markdown/frontmatter.js.map +1 -1
  29. package/dist/vendor/spec-core/pattern/glob.d.ts +88 -2
  30. package/dist/vendor/spec-core/pattern/glob.js +234 -32
  31. package/dist/vendor/spec-core/pattern/glob.js.map +1 -1
  32. package/dist/vendor/spec-core/pattern/index.d.ts +2 -2
  33. package/dist/vendor/spec-core/pattern/index.js +1 -1
  34. package/dist/vendor/spec-core/pattern/index.js.map +1 -1
  35. package/dist/vendor/spec-core/text/index.d.ts +1 -0
  36. package/dist/vendor/spec-core/text/index.js +1 -0
  37. package/dist/vendor/spec-core/text/index.js.map +1 -1
  38. package/dist/vendor/spec-core/text/width.d.ts +30 -0
  39. package/dist/vendor/spec-core/text/width.js +113 -0
  40. package/dist/vendor/spec-core/text/width.js.map +1 -0
  41. package/dist/yaml.js +6 -2
  42. package/dist/yaml.js.map +1 -1
  43. package/package.json +1 -1
package/dist/glob.js CHANGED
@@ -8,9 +8,9 @@
8
8
  * how a list with `!` entries in it reads, which directories a walk never
9
9
  * enters, and how a reference target - which is not a path - is matched.
10
10
  */
11
- import { readdir, stat } from 'node:fs/promises';
11
+ import { readdir, realpath, stat } from 'node:fs/promises';
12
12
  import { isAbsolutePath, joinPosix, toPosix } from './paths.js';
13
- import { compileGlob as compileFamilyGlob, GlobError, isGlobSyntax, parseGlob, parseGlobList, } from './vendor/spec-core/pattern/index.js';
13
+ import { compileGlob as compileFamilyGlob, GlobError, isGlobSyntax, parseGlob, parseGlobList, rebaseGlob, } from './vendor/spec-core/pattern/index.js';
14
14
  /** Directories skipped unless a pattern explicitly names them. */
15
15
  export const DEFAULT_IGNORED_DIRECTORIES = Object.freeze([
16
16
  '.git',
@@ -161,6 +161,66 @@ export function createGlobMatcher(patterns) {
161
161
  const list = pathList(patterns);
162
162
  return (path) => list.match(path);
163
163
  }
164
+ /**
165
+ * A list entry typed in `directory`, below the root, rewritten to read from the
166
+ * root, or refused naming the entry as it was typed (ADR-0018).
167
+ *
168
+ * Each brace alternative is rebased as that text written alone would be, so
169
+ * `{/docs,x}` typed in `sub` is `{/docs,sub/x}`: a leading `/` roots it
170
+ * wherever it was typed. A leading `..` climbs out of `directory`, and one past
171
+ * the root is refused, as is a directory whose name a pattern would read as
172
+ * syntax.
173
+ */
174
+ export function rebasePattern(entry, directory) {
175
+ const rebased = rebaseGlob(entry, directory, PATH);
176
+ if (!rebased.ok)
177
+ throw new GlobError(entry, rebased.error);
178
+ return rebased.pattern;
179
+ }
180
+ /**
181
+ * Each dot in a reference pattern that may begin a segment, which is escaped:
182
+ * a `.` or `..` segment then reads as the name it is, one or two dots, where
183
+ * the dialect would drop the one and refuse the other.
184
+ *
185
+ * Braces expand before segments are read, so a dot written beside a brace or a
186
+ * comma may begin a segment of an alternative: `docs/{.,x}` is `docs/.` or
187
+ * `docs/x`, `.{/gone.md,x}` is `./gone.md` or `.x`, and `{docs/,x/}.` ends in a
188
+ * segment `.` either way. An escaped dot is the same character as a dot in a
189
+ * name, so escaping one that begins `.x`, or the braces leave inside a name as
190
+ * in `a{.,b}`, reads the same, and nothing needs to tell those apart:
191
+ * escaping each whole `.` or `..` segment instead reads each of 43,069
192
+ * generated patterns the same, refusals included (ADR-0022).
193
+ */
194
+ const SEGMENT_DOT = /(?<=^|[/{,}])\./g;
195
+ /**
196
+ * How a reference target is matched. Every option is spelled out, though the
197
+ * dialect reads `{}` the same way today: its defaults are spec-core's to
198
+ * change, and this reading is spec-graph's to keep. A mutant that drops one,
199
+ * or all of them, is equivalent until then.
200
+ */
201
+ const TARGET = { dialect: 'path', caseSensitive: false, literal: 'file' };
202
+ /**
203
+ * A refusal of a reference pattern in the words it was typed in.
204
+ *
205
+ * The dialect writes its advice for a `**` inside a name from the text it was
206
+ * given, and that text held a `\` before each dot {@link SEGMENT_DOT} escaped:
207
+ * `../notes/**.md` was told `\.\./notes/**\/*.md`. Given the pattern again with
208
+ * a character it does not hold in place of each of those dots, the dialect
209
+ * refuses it for the same reason, since both are one literal character and
210
+ * neither is a direction, and each stand-in is read back as the dot it was.
211
+ * Counting down from U+E000 would find a stand-in as well, among the
212
+ * surrogates, so that mutant is equivalent.
213
+ */
214
+ function asTyped(typed, reason) {
215
+ let point = 0xe000;
216
+ while (typed.includes(String.fromCodePoint(point)))
217
+ point += 1;
218
+ const stand = String.fromCodePoint(point);
219
+ const again = parseGlob(typed.replace(SEGMENT_DOT, stand), TARGET);
220
+ // Stand-ins and escaped dots compile or fail alike, so `again` never
221
+ // compiles here, and a mutant that reads it as compiled is equivalent.
222
+ return again.ok ? reason : again.error.replaceAll(stand, '.');
223
+ }
164
224
  /**
165
225
  * Builds a predicate over reference *targets*, not paths.
166
226
  *
@@ -180,32 +240,18 @@ export function createGlobMatcher(patterns) {
180
240
  * separator to allow for. And a `.` or `..` segment is text, in a brace
181
241
  * alternative as anywhere else: in a path the dialect drops the one and
182
242
  * refuses the other as climbing out of the root, but `../../notes/gone.md` is
183
- * a link somebody wrote and may want left alone.
243
+ * a link somebody wrote and may want left alone. A pattern that is refused is
244
+ * named, and advised, as it was typed.
184
245
  */
185
246
  export function createReferenceFilter(patterns) {
186
247
  // A blank pattern reaches the dialect, which refuses it, as every pattern
187
248
  // spec-graph reads is refused when it names nothing. It used to be dropped,
188
249
  // so an unset variable in `--ignore-ref "$TAGS"` went unnoticed.
189
250
  const globs = patterns.map((pattern) => {
190
- // Each `.` or `..` that may stand as a segment is escaped, and the dialect
191
- // reads an escaped dot as text. Braces expand before segments are read, so
192
- // one written beside a brace or a comma may be a segment of an
193
- // alternative: `docs/{.,x}` is `docs/.` or `docs/x`, `.{/gone.md,x}` is
194
- // `./gone.md` or `.x`, and `{docs/,x/}.` ends in a segment `.` either way.
195
- // Escaping one the braces leave inside a name, as in `.x` or `a{.,b}`, or
196
- // beside a `,` or `}` that is itself text outside braces, reads as the same
197
- // character, so nothing needs to tell those apart. No other dot is
198
- // escaped: the advice for a `**` inside a name is written from the
199
- // pattern, and `.github/**.md` is told `.github/**/*.md`. A mutant that
200
- // counts dots from none matches the empty run between two boundaries too,
201
- // and writes nothing for it: equivalent.
202
- const literalDots = pattern.trim().replace(/(?<=^|[/{,}])\.{1,2}(?=$|[/{,}])/g, (dots) => '\\.'.repeat(dots.length));
203
- // Every option spelled out, though the dialect reads `{}` the same way
204
- // today: its defaults are spec-core's to change, and this reading is
205
- // spec-graph's to keep. A mutant that drops one is equivalent until then.
206
- const parsed = parseGlob(literalDots, { dialect: 'path', caseSensitive: false, literal: 'file' });
251
+ const typed = pattern.trim();
252
+ const parsed = parseGlob(typed.replace(SEGMENT_DOT, '\\.'), TARGET);
207
253
  if (!parsed.ok)
208
- throw new GlobError(pattern, parsed.error);
254
+ throw new GlobError(pattern, asTyped(typed, parsed.error));
209
255
  return parsed.glob;
210
256
  });
211
257
  return (target) => {
@@ -249,10 +295,18 @@ export function globBase(pattern) {
249
295
  * `docs/linked/*.md` was read through the link `docs/linked`, which the walk
250
296
  * from the root passes over. Asking each parent for the entry says which it
251
297
  * is, and a base beyond a link is left as silently as the walk leaves the link.
298
+ *
299
+ * Where links are followed, the answer is the real path of each directory
300
+ * above the base, the root included, for the walk to tell a cycle by; a base
301
+ * beyond a link back into one of them is one the walk from the root never
302
+ * reaches, and is left the same way. Where they are not, it is empty and never
303
+ * read, so a mutant that fills it anyway is equivalent. `null` is a base the
304
+ * walk does not start at.
252
305
  */
253
306
  async function reachable(root, base, followSymlinks) {
307
+ const above = new Set();
254
308
  if (base.length === 0)
255
- return true;
309
+ return above;
256
310
  let directory = root;
257
311
  for (const segment of base.split('/')) {
258
312
  let entries;
@@ -260,17 +314,26 @@ async function reachable(root, base, followSymlinks) {
260
314
  entries = await readdir(directory, { withFileTypes: true });
261
315
  }
262
316
  catch {
263
- // Answering `true` here would change nothing a test can see: the walk
317
+ // Answering a set here would change nothing a test can see: the walk
264
318
  // would then read a directory beneath this one, fail the same way, and
265
319
  // find nothing.
266
- return false;
320
+ return null;
267
321
  }
268
322
  const entry = entries.find((candidate) => candidate.name === segment);
269
323
  if (entry === undefined || (entry.isSymbolicLink() && !followSymlinks))
270
- return false;
324
+ return null;
325
+ if (followSymlinks) {
326
+ // The directory was just listed, so asking for its real path fails only
327
+ // where it went in between, and the walk would find nothing there: a
328
+ // mutant that answers otherwise is equivalent.
329
+ const real = await realpath(directory).catch(() => null);
330
+ if (real === null || above.has(real))
331
+ return null;
332
+ above.add(real);
333
+ }
271
334
  directory = `${directory}/${segment}`;
272
335
  }
273
- return true;
336
+ return above;
274
337
  }
275
338
  /**
276
339
  * Walks the tree and returns every file matching the patterns.
@@ -293,8 +356,19 @@ export async function walkFiles(options) {
293
356
  // The empty pattern is no directory's name, so it goes to the dialect, which
294
357
  // refuses it as it refuses an empty include: a pattern that names nothing is
295
358
  // a typo or an unset variable, and was an ignore that ignored nothing.
296
- const bare = (pattern) => pattern.length > 0 && !isGlob(pattern) && !pattern.includes('/');
297
- const named = new Set(ignores.filter(bare));
359
+ const plainName = (pattern) => pattern.length > 0 && !isGlob(pattern) && !pattern.includes('/') && !pattern.startsWith('!');
360
+ // A `!` before a name gives the name back, as a `.gitignore` line does, and
361
+ // the last bare entry to name a directory decides whether it is pruned. It
362
+ // was read as a directory called `!docs`, so `--ignore docs --ignore "!docs"`
363
+ // pruned `docs` and said nothing. The default list is a list of names too,
364
+ // and gives way to one: `--ignore "!vendor"` reads every `vendor`. A `!` alone
365
+ // or before another is no name, and goes to the dialect, which refuses both.
366
+ const bare = (pattern) => plainName(pattern) || (pattern.startsWith('!') && plainName(pattern.slice(1)));
367
+ const named = new Map();
368
+ for (const pattern of ignores.filter(bare)) {
369
+ const negated = pattern.startsWith('!');
370
+ named.set(negated ? pattern.slice(1) : pattern, !negated);
371
+ }
298
372
  const skippedByDefault = new Set(DEFAULT_IGNORED_DIRECTORIES);
299
373
  const ignoreList = pathList(ignores.filter((pattern) => !bare(pattern)));
300
374
  const excluded = (path) => ignoreList.match(path);
@@ -348,7 +422,7 @@ export async function walkFiles(options) {
348
422
  if (base.length === 0)
349
423
  return true;
350
424
  const segments = base.split('/');
351
- return !segments.some((segment, i) => named.has(segment) || excluded(segments.slice(0, i + 1).join('/')));
425
+ return !segments.some((segment, i) => named.get(segment) === true || excluded(segments.slice(0, i + 1).join('/')));
352
426
  };
353
427
  // Whether the walk leaves a directory it meets, asked of a followed link to
354
428
  // one as well: a link called `node_modules`, which pnpm writes, or one an
@@ -356,18 +430,43 @@ export async function walkFiles(options) {
356
430
  // and was entered whatever they were. Pruning a whole subtree is an
357
431
  // optimisation; a pattern that only matches the files inside it is still
358
432
  // honoured when they are filtered. A bare `--ignore` name prunes a directory
359
- // a pattern names as well: only the default list gives way.
360
- const pruned = (name, path) => named.has(name) || (skippedByDefault.has(name) && !literals.has(path)) || excluded(path);
433
+ // a pattern names as well: only the default list gives way, to a pattern and
434
+ // to a `!` before its name.
435
+ const pruned = (name, path) => (named.get(name) ?? (skippedByDefault.has(name) && !literals.has(path))) || excluded(path);
361
436
  const out = new Map();
362
437
  // Where two walks overlap, whichever reaches a directory first reads it and
363
438
  // the other stops there. Reading it twice would find the same files under
364
439
  // the same keys, so the two mutants that drop this are equivalent.
365
440
  const visited = new Set();
441
+ // Where links are followed, the real path of each directory from the root to
442
+ // the one being read. A link whose real path is among them leads back into a
443
+ // directory the walk is inside, and following it read the same files again
444
+ // under a longer path each time round, until the host refused the path: on
445
+ // Windows, 64 copies of each. It is passed over as silently as a link is
446
+ // when links are not followed. A link to anywhere else is followed, one to a
447
+ // directory the walk has already read beside this one included, since only
448
+ // a directory on the way here can make a cycle. The walks run one at a time,
449
+ // so one set serves them all. Only a followed link can make a cycle, so with
450
+ // links not followed no real path is asked for, and a mutant that asks finds
451
+ // none: equivalent.
452
+ let inside = new Set();
366
453
  const walk = async (relative) => {
367
454
  const absolute = relative.length === 0 ? root : `${root}/${relative}`;
368
455
  if (visited.has(absolute))
369
456
  return;
370
457
  visited.add(absolute);
458
+ if (!options.followSymlinks)
459
+ return read(relative, absolute);
460
+ // A directory with no real path is one that cannot be listed either, so
461
+ // a mutant that reads it rather than returning reads nothing more.
462
+ const real = await realpath(absolute).catch(() => null);
463
+ if (real === null || inside.has(real))
464
+ return;
465
+ inside.add(real);
466
+ await read(relative, absolute);
467
+ inside.delete(real);
468
+ };
469
+ const read = async (relative, absolute) => {
371
470
  let entries;
372
471
  try {
373
472
  entries = await readdir(absolute, { withFileTypes: true });
@@ -417,9 +516,13 @@ export async function walkFiles(options) {
417
516
  }
418
517
  }
419
518
  };
420
- for (const base of bases)
421
- if (startable(base) && (await reachable(root, base, options.followSymlinks)))
422
- await walk(base);
519
+ for (const base of bases) {
520
+ const above = startable(base) ? await reachable(root, base, options.followSymlinks) : null;
521
+ if (above === null)
522
+ continue;
523
+ inside = above;
524
+ await walk(base);
525
+ }
423
526
  // No two paths are equal, since they are the keys of `out`, so the order
424
527
  // needs only `<`, and `<=` would read the same.
425
528
  return [...out.values()].sort((a, b) => (a.path < b.path ? -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, 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 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 /** Follow directory symlinks. Off by default: cycles are real. */\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 * 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.\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 // Each `.` or `..` that may stand as a segment is escaped, and the dialect\n // reads an escaped dot as text. Braces expand before segments are read, so\n // one written beside a brace or a comma may be a segment of an\n // alternative: `docs/{.,x}` is `docs/.` or `docs/x`, `.{/gone.md,x}` is\n // `./gone.md` or `.x`, and `{docs/,x/}.` ends in a segment `.` either way.\n // Escaping one the braces leave inside a name, as in `.x` or `a{.,b}`, or\n // beside a `,` or `}` that is itself text outside braces, reads as the same\n // character, so nothing needs to tell those apart. No other dot is\n // escaped: the advice for a `**` inside a name is written from the\n // pattern, and `.github/**.md` is told `.github/**/*.md`. A mutant that\n // counts dots from none matches the empty run between two boundaries too,\n // and writes nothing for it: equivalent.\n const literalDots = pattern.trim().replace(/(?<=^|[/{,}])\\.{1,2}(?=$|[/{,}])/g, (dots) => '\\\\.'.repeat(dots.length));\n // Every option spelled out, though the dialect reads `{}` the same way\n // today: its defaults are spec-core's to change, and this reading is\n // spec-graph's to keep. A mutant that drops one is equivalent until then.\n const parsed = parseGlob(literalDots, { dialect: 'path', caseSensitive: false, literal: 'file' });\n if (!parsed.ok) throw new GlobError(pattern, 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 */\nasync function reachable(root: string, base: string, followSymlinks: boolean | undefined): Promise<boolean> {\n if (base.length === 0) return true;\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 `true` 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 false;\n }\n const entry = entries.find((candidate) => candidate.name === segment);\n if (entry === undefined || (entry.isSymbolicLink() && !followSymlinks)) return false;\n directory = `${directory}/${segment}`;\n }\n return true;\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.\n const bare = (pattern: string): boolean => pattern.length > 0 && !isGlob(pattern) && !pattern.includes('/');\n const named = new Set(ignores.filter(bare));\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.has(segment) || 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.\n const pruned = (name: string, path: string): boolean =>\n named.has(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\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\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) if (startable(base) && (await reachable(root, base, options.followSymlinks))) await walk(base);\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":"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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.\n const plainName = (pattern: string): boolean =>\n pattern.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/index.d.ts CHANGED
@@ -39,7 +39,7 @@ export { resolveStrict, runRules, sortDiagnostics, DEFAULT_SEVERITIES, RULE_DECI
39
39
  export type { RuleOptions } from './rules.js';
40
40
  export { compileProjectRules, renderTemplate } from './project-rules.js';
41
41
  export type { CompiledProjectRules, ProjectRule } from './project-rules.js';
42
- export { createPainter, formatGitlab, formatGraph, formatJson, formatMarkdown, formatReport, formatSarif, shouldUseAscii, shouldUseColor, } from './report.js';
42
+ export { createPainter, formatGithub, formatGitlab, formatGraph, formatJson, formatMarkdown, formatReport, formatSarif, shouldUseAscii, shouldUseColor, } from './report.js';
43
43
  export type { ColorEnvironment, GraphExportOptions, GraphFormat, Painter, ReporterOptions } from './report.js';
44
44
  export { extractDocument, extractSpecifications, classifyReference, inheritableFrontMatter, sectionPathAt, } from './extract.js';
45
45
  export { findSpecificationRegions, readRegionStatus, regionAt } from './sections.js';
package/dist/index.js CHANGED
@@ -32,7 +32,7 @@ export { attributesOf, execute, matches, parseQuery, pattern, query, renderMatch
32
32
  export { compileRegex as compilePattern, RegexError as PatternError } from './vendor/spec-core/pattern/index.js';
33
33
  export { resolveStrict, runRules, sortDiagnostics, DEFAULT_SEVERITIES, RULE_DECISIONS, RULE_DESCRIPTIONS, RULE_IDS, RULE_QUERIES, } from './rules.js';
34
34
  export { compileProjectRules, renderTemplate } from './project-rules.js';
35
- export { createPainter, formatGitlab, formatGraph, formatJson, formatMarkdown, formatReport, formatSarif, shouldUseAscii, shouldUseColor, } from './report.js';
35
+ export { createPainter, formatGithub, formatGitlab, formatGraph, formatJson, formatMarkdown, formatReport, formatSarif, shouldUseAscii, shouldUseColor, } from './report.js';
36
36
  export { extractDocument, extractSpecifications, classifyReference, inheritableFrontMatter, sectionPathAt, } from './extract.js';
37
37
  export { findSpecificationRegions, readRegionStatus, regionAt } from './sections.js';
38
38
  export { resolveCorpus, documentOf } from './resolve.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Programmatic API.\n *\n * The CLI is a shell over `analyse`; anything the CLI can do, a build script, a\n * custom reporter or an editor extension can do too.\n *\n * ```ts\n * import { analyse, formatReport } from '@descent-vtt/spec-graph';\n *\n * const result = await analyse({ root: process.cwd(), patterns: ['docs/**\\/*.md'] });\n * if (!result.ok) console.error(formatReport(result, { color: true }));\n * ```\n *\n * For a corpus that is already in memory - a monorepo tool, a language server,\n * a test - skip the filesystem entirely:\n *\n * ```ts\n * import { analyseSources, query } from '@descent-vtt/spec-graph';\n *\n * const { graph } = analyseSources([{ path: 'adr/0001.md', text: '...' }]);\n * const ghosts = query(graph, 'item[openness=open] -delegates-to-> document[phase=retired]');\n * ```\n */\n\nexport {\n applyBaseline,\n formatBaseline,\n fingerprintOf,\n parseBaseline,\n BASELINE_VERSION,\n EMPTY_BASELINE,\n} from './baseline.js';\nexport type { Baseline, BaselineEntry, BaselineOutcome, ParsedBaseline, StaleEntry } from './baseline.js';\n\nexport { discoverConfig, loadConfig, parseConfig, CONFIG_FILES, CONFIG_PACKAGE_KEY } from './config.js';\nexport type { DiscoveredConfig, DiscoveryIO, LoadedConfig, SpecGraphConfig } from './config.js';\n\nexport { main, parseArgs, HELP, UsageError, EXIT_OK, EXIT_FAILED, EXIT_ERROR } from './cli.js';\nexport type { CliIO, CliOptions, Command } from './cli.js';\n\nexport {\n analyse,\n analyseSources,\n createFamilyFilter,\n createHistoryMatcher,\n withDiagnostics,\n DEFAULT_CONCURRENCY,\n DEFAULT_PATTERNS,\n} from './runner.js';\nexport type { AnalyseOptions, AnalyseSourcesOptions, AnalysisResult, Source } from './runner.js';\n\nexport { buildGraph, LOAD_BEARING_EDGES, OBLIGATION_EDGES } from './graph.js';\nexport type { SpecGraph } from './graph.js';\n\nexport {\n attributesOf,\n execute,\n matches,\n parseQuery,\n pattern,\n query,\n renderMatch,\n QueryError,\n DEFAULT_MATCH_LIMIT,\n SELECTOR_KEYS,\n} from './select.js';\n\n// The matcher behind `~=` lives in spec-core now (ADR-0017), and keeps the\n// names it was published under here.\nexport { compileRegex as compilePattern, RegexError as PatternError } from './vendor/spec-core/pattern/index.js';\nexport type { RegexMatcher as Matcher, RegexOptions as PatternOptions } from './vendor/spec-core/pattern/index.js';\nexport type {\n ExecuteOptions,\n Match,\n NodeMatcher,\n Operator,\n Predicate,\n QuerySpec,\n StepSpec,\n} from './select.js';\n\nexport {\n resolveStrict,\n runRules,\n sortDiagnostics,\n DEFAULT_SEVERITIES,\n RULE_DECISIONS,\n RULE_DESCRIPTIONS,\n RULE_IDS,\n RULE_QUERIES,\n} from './rules.js';\nexport type { RuleOptions } from './rules.js';\n\nexport { compileProjectRules, renderTemplate } from './project-rules.js';\nexport type { CompiledProjectRules, ProjectRule } from './project-rules.js';\n\nexport {\n createPainter,\n formatGitlab,\n formatGraph,\n formatJson,\n formatMarkdown,\n formatReport,\n formatSarif,\n shouldUseAscii,\n shouldUseColor,\n} from './report.js';\nexport type { ColorEnvironment, GraphExportOptions, GraphFormat, Painter, ReporterOptions } from './report.js';\n\nexport {\n extractDocument,\n extractSpecifications,\n classifyReference,\n inheritableFrontMatter,\n sectionPathAt,\n} from './extract.js';\nexport { findSpecificationRegions, readRegionStatus, regionAt } from './sections.js';\nexport type { RegionStatus, SpecificationRegion } from './sections.js';\nexport type { Classification, ExtractedDocument, ExtractInput, ReferenceCandidate } from './extract.js';\n\nexport { resolveCorpus, documentOf } from './resolve.js';\nexport type { ResolvedCorpus, ResolveOptions } from './resolve.js';\n\nexport { scanMarkdown, slugify } from './markdown.js';\nexport type {\n FrontMatter,\n Heading,\n HtmlComment,\n Link,\n LinkForm,\n ListItem,\n Range,\n ScannedDocument,\n ScannedLine,\n} from './markdown.js';\n\nexport { parseDirectives, attr, attrList, bindItemDirectives, directiveFor } from './directives.js';\nexport type { Attribute, Directive, DirectiveName } from './directives.js';\n\nexport { parseFrontMatter, toRecord, valuesOf } from './yaml.js';\nexport type { YamlEntry } from './yaml.js';\n\nexport {\n isRetired,\n isStatusHeading,\n normaliseStatus,\n phaseFromPath,\n phaseOf,\n receptivityOf,\n supersessionTargetsIn,\n STATUS_KEYS,\n} from './lifecycle.js';\n\nexport { resolveItemState, KNOWN_STATE_WORDS } from './state.js';\nexport type { ResolvedState, StateInput } from './state.js';\n\nexport {\n familyFromPath,\n identify,\n isDocumentTarget,\n isExternal,\n looksLikePath,\n normaliseRef,\n parseBareRef,\n parsePrefixedRef,\n splitAnchor,\n ID_KEYS,\n} from './identity.js';\nexport type { DocumentIdentity, IdentityInput } from './identity.js';\n\nexport {\n compileGlob,\n createGlobMatcher,\n createReferenceFilter,\n globBase,\n globToRegExp,\n isGlob,\n walkFiles,\n DEFAULT_IGNORED_DIRECTORIES,\n MAX_FILE_SIZE,\n} from './glob.js';\nexport type { GlobMatcher, GlobOptions, WalkedFile, WalkOptions } from './glob.js';\n\nexport { compareRefs, createLineIndex, formatRef, refOf, spanOf } from './source.js';\nexport type { LineIndex } from './source.js';\n\nexport {\n basenamePosix,\n dirnamePosix,\n extnamePosix,\n isAbsolutePath,\n joinPosix,\n normalisePosix,\n resolveFrom,\n toPosix,\n} from './paths.js';\n\nexport { isProjectRule, DISPOSITIONS, EDGE_KINDS, EDGE_TRAITS, OPENNESS_OF, PROJECT_RULE_PREFIX } from './types.js';\nexport type {\n AnalysisSummary,\n AnyRuleId,\n DanglingReason,\n DanglingRef,\n Diagnostic,\n Disposition,\n DocumentNode,\n Edge,\n EdgeKind,\n EdgeOrigin,\n EdgeTraits,\n ItemNode,\n MisreadKey,\n NodeKind,\n Openness,\n ParseProblem,\n Phase,\n Position,\n Receptivity,\n ProjectRuleId,\n RelatedLocation,\n RuleId,\n Severity,\n SourceRef,\n Span,\n SpecNode,\n StateSignal,\n SuppressedRef,\n} from './types.js';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EACL,aAAa,EACb,cAAc,EACd,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,cAAc,GACf,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAGxG,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAG/F,OAAO,EACL,OAAO,EACP,cAAc,EACd,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,EACf,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,UAAU,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAG9E,OAAO,EACL,YAAY,EACZ,OAAO,EACP,OAAO,EACP,UAAU,EACV,OAAO,EACP,KAAK,EACL,WAAW,EACX,UAAU,EACV,mBAAmB,EACnB,aAAa,GACd,MAAM,aAAa,CAAC;AAErB,2EAA2E;AAC3E,qCAAqC;AACrC,OAAO,EAAE,YAAY,IAAI,cAAc,EAAE,UAAU,IAAI,YAAY,EAAE,MAAM,qCAAqC,CAAC;AAYjH,OAAO,EACL,aAAa,EACb,QAAQ,EACR,eAAe,EACf,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,QAAQ,EACR,YAAY,GACb,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAGzE,OAAO,EACL,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,WAAW,EACX,UAAU,EACV,cAAc,EACd,YAAY,EACZ,WAAW,EACX,cAAc,EACd,cAAc,GACf,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,iBAAiB,EACjB,sBAAsB,EACtB,aAAa,GACd,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,wBAAwB,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAIrF,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAGzD,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAatD,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,QAAQ,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAGpG,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAGjE,OAAO,EACL,SAAS,EACT,eAAe,EACf,eAAe,EACf,aAAa,EACb,OAAO,EACP,aAAa,EACb,qBAAqB,EACrB,WAAW,GACZ,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAGjE,OAAO,EACL,cAAc,EACd,QAAQ,EACR,gBAAgB,EAChB,UAAU,EACV,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,OAAO,GACR,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,qBAAqB,EACrB,QAAQ,EACR,YAAY,EACZ,MAAM,EACN,SAAS,EACT,2BAA2B,EAC3B,aAAa,GACd,MAAM,WAAW,CAAC;AAGnB,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrF,OAAO,EACL,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,cAAc,EACd,SAAS,EACT,cAAc,EACd,WAAW,EACX,OAAO,GACR,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC","sourcesContent":["/**\n * Programmatic API.\n *\n * The CLI is a shell over `analyse`; anything the CLI can do, a build script, a\n * custom reporter or an editor extension can do too.\n *\n * ```ts\n * import { analyse, formatReport } from '@descent-vtt/spec-graph';\n *\n * const result = await analyse({ root: process.cwd(), patterns: ['docs/**\\/*.md'] });\n * if (!result.ok) console.error(formatReport(result, { color: true }));\n * ```\n *\n * For a corpus that is already in memory - a monorepo tool, a language server,\n * a test - skip the filesystem entirely:\n *\n * ```ts\n * import { analyseSources, query } from '@descent-vtt/spec-graph';\n *\n * const { graph } = analyseSources([{ path: 'adr/0001.md', text: '...' }]);\n * const ghosts = query(graph, 'item[openness=open] -delegates-to-> document[phase=retired]');\n * ```\n */\n\nexport {\n applyBaseline,\n formatBaseline,\n fingerprintOf,\n parseBaseline,\n BASELINE_VERSION,\n EMPTY_BASELINE,\n} from './baseline.js';\nexport type { Baseline, BaselineEntry, BaselineOutcome, ParsedBaseline, StaleEntry } from './baseline.js';\n\nexport { discoverConfig, loadConfig, parseConfig, CONFIG_FILES, CONFIG_PACKAGE_KEY } from './config.js';\nexport type { DiscoveredConfig, DiscoveryIO, LoadedConfig, SpecGraphConfig } from './config.js';\n\nexport { main, parseArgs, HELP, UsageError, EXIT_OK, EXIT_FAILED, EXIT_ERROR } from './cli.js';\nexport type { CliIO, CliOptions, Command } from './cli.js';\n\nexport {\n analyse,\n analyseSources,\n createFamilyFilter,\n createHistoryMatcher,\n withDiagnostics,\n DEFAULT_CONCURRENCY,\n DEFAULT_PATTERNS,\n} from './runner.js';\nexport type { AnalyseOptions, AnalyseSourcesOptions, AnalysisResult, Source } from './runner.js';\n\nexport { buildGraph, LOAD_BEARING_EDGES, OBLIGATION_EDGES } from './graph.js';\nexport type { SpecGraph } from './graph.js';\n\nexport {\n attributesOf,\n execute,\n matches,\n parseQuery,\n pattern,\n query,\n renderMatch,\n QueryError,\n DEFAULT_MATCH_LIMIT,\n SELECTOR_KEYS,\n} from './select.js';\n\n// The matcher behind `~=` lives in spec-core now (ADR-0017), and keeps the\n// names it was published under here.\nexport { compileRegex as compilePattern, RegexError as PatternError } from './vendor/spec-core/pattern/index.js';\nexport type { RegexMatcher as Matcher, RegexOptions as PatternOptions } from './vendor/spec-core/pattern/index.js';\nexport type {\n ExecuteOptions,\n Match,\n NodeMatcher,\n Operator,\n Predicate,\n QuerySpec,\n StepSpec,\n} from './select.js';\n\nexport {\n resolveStrict,\n runRules,\n sortDiagnostics,\n DEFAULT_SEVERITIES,\n RULE_DECISIONS,\n RULE_DESCRIPTIONS,\n RULE_IDS,\n RULE_QUERIES,\n} from './rules.js';\nexport type { RuleOptions } from './rules.js';\n\nexport { compileProjectRules, renderTemplate } from './project-rules.js';\nexport type { CompiledProjectRules, ProjectRule } from './project-rules.js';\n\nexport {\n createPainter,\n formatGithub,\n formatGitlab,\n formatGraph,\n formatJson,\n formatMarkdown,\n formatReport,\n formatSarif,\n shouldUseAscii,\n shouldUseColor,\n} from './report.js';\nexport type { ColorEnvironment, GraphExportOptions, GraphFormat, Painter, ReporterOptions } from './report.js';\n\nexport {\n extractDocument,\n extractSpecifications,\n classifyReference,\n inheritableFrontMatter,\n sectionPathAt,\n} from './extract.js';\nexport { findSpecificationRegions, readRegionStatus, regionAt } from './sections.js';\nexport type { RegionStatus, SpecificationRegion } from './sections.js';\nexport type { Classification, ExtractedDocument, ExtractInput, ReferenceCandidate } from './extract.js';\n\nexport { resolveCorpus, documentOf } from './resolve.js';\nexport type { ResolvedCorpus, ResolveOptions } from './resolve.js';\n\nexport { scanMarkdown, slugify } from './markdown.js';\nexport type {\n FrontMatter,\n Heading,\n HtmlComment,\n Link,\n LinkForm,\n ListItem,\n Range,\n ScannedDocument,\n ScannedLine,\n} from './markdown.js';\n\nexport { parseDirectives, attr, attrList, bindItemDirectives, directiveFor } from './directives.js';\nexport type { Attribute, Directive, DirectiveName } from './directives.js';\n\nexport { parseFrontMatter, toRecord, valuesOf } from './yaml.js';\nexport type { YamlEntry } from './yaml.js';\n\nexport {\n isRetired,\n isStatusHeading,\n normaliseStatus,\n phaseFromPath,\n phaseOf,\n receptivityOf,\n supersessionTargetsIn,\n STATUS_KEYS,\n} from './lifecycle.js';\n\nexport { resolveItemState, KNOWN_STATE_WORDS } from './state.js';\nexport type { ResolvedState, StateInput } from './state.js';\n\nexport {\n familyFromPath,\n identify,\n isDocumentTarget,\n isExternal,\n looksLikePath,\n normaliseRef,\n parseBareRef,\n parsePrefixedRef,\n splitAnchor,\n ID_KEYS,\n} from './identity.js';\nexport type { DocumentIdentity, IdentityInput } from './identity.js';\n\nexport {\n compileGlob,\n createGlobMatcher,\n createReferenceFilter,\n globBase,\n globToRegExp,\n isGlob,\n walkFiles,\n DEFAULT_IGNORED_DIRECTORIES,\n MAX_FILE_SIZE,\n} from './glob.js';\nexport type { GlobMatcher, GlobOptions, WalkedFile, WalkOptions } from './glob.js';\n\nexport { compareRefs, createLineIndex, formatRef, refOf, spanOf } from './source.js';\nexport type { LineIndex } from './source.js';\n\nexport {\n basenamePosix,\n dirnamePosix,\n extnamePosix,\n isAbsolutePath,\n joinPosix,\n normalisePosix,\n resolveFrom,\n toPosix,\n} from './paths.js';\n\nexport { isProjectRule, DISPOSITIONS, EDGE_KINDS, EDGE_TRAITS, OPENNESS_OF, PROJECT_RULE_PREFIX } from './types.js';\nexport type {\n AnalysisSummary,\n AnyRuleId,\n DanglingReason,\n DanglingRef,\n Diagnostic,\n Disposition,\n DocumentNode,\n Edge,\n EdgeKind,\n EdgeOrigin,\n EdgeTraits,\n ItemNode,\n MisreadKey,\n NodeKind,\n Openness,\n ParseProblem,\n Phase,\n Position,\n Receptivity,\n ProjectRuleId,\n RelatedLocation,\n RuleId,\n Severity,\n SourceRef,\n Span,\n SpecNode,\n StateSignal,\n SuppressedRef,\n} from './types.js';\n"]}
@@ -13,7 +13,10 @@
13
13
  * rule change.
14
14
  */
15
15
  import type { Phase, Receptivity } from './types.js';
16
- /** Front-matter keys that may carry a status, in order of preference. */
16
+ /**
17
+ * Front-matter keys that may carry a status, in order of preference. The
18
+ * Chinese key is the English one it translates, so it ranks beside it.
19
+ */
17
20
  export declare const STATUS_KEYS: readonly string[];
18
21
  /**
19
22
  * Reduces a status string to lookup form.
@@ -23,6 +26,8 @@ export declare const STATUS_KEYS: readonly string[];
23
26
  * same token.
24
27
  */
25
28
  export declare function normaliseStatus(raw: string): string;
29
+ /** Whether a Chinese negation stands directly before the offset. */
30
+ export declare function negatedAt(text: string, offset: number): boolean;
26
31
  /**
27
32
  * Maps a raw status string onto a lifecycle phase.
28
33
  *
@@ -53,5 +58,10 @@ export declare function phaseFromPath(posixPath: string): Phase;
53
58
  * recorded, and it is written in the status field rather than as a link. Reading
54
59
  * it here means the relation reaches the graph even in repositories that never
55
60
  * adopted an explicit field for it.
61
+ *
62
+ * In Chinese the successor stands between `被` and the verb: `已被 ADR-0003
63
+ * 取代`. Left unread, a document that said so and one that said it supersedes
64
+ * this one disagreed, and `unreciprocated-supersession` asked for a
65
+ * `superseded-by` key the status had already given.
56
66
  */
57
67
  export declare function supersessionTargetsIn(raw: string): string[];