@descent-vtt/spec-graph 0.9.6 → 0.9.8

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.
@@ -1 +1 @@
1
- {"version":3,"file":"tables.js","sourceRoot":"","sources":["../../../../src/vendor/spec-core/markdown/tables.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * GFM pipe tables, with an offset for every cell.\n *\n * Cell offsets are the point: a register kept as a table needs findings that\n * name the cell declaring a relation, not the row and not the file. Rows are\n * split on the structure mask, so a pipe inside a code span or a comment\n * cannot invent a column, and the text of each cell comes from the original.\n *\n * Reading one line past the last, or one character past a line's end, finds\n * no row and no pipe, so mutants that move those bounds are equivalent.\n */\n\nimport { isMarkdown, leadOffset, type Layout } from './layout.js';\nimport type { Heading, ScannedLine, Table, TableCell, TableRow } from './types.js';\n\nconst PIPE = 124;\nconst BACKSLASH = 92;\nconst DELIMITER_CELL = /^:?-+:?$/;\n\n/**\n * A header line, a delimiter row with as many cells, and the rows under them\n * up to a line that is blank, holds no pipe, or is not Markdown.\n */\nexport function findTables(layout: Layout, atx: readonly Pick<Heading, 'line'>[]): Table[] {\n const { lines } = layout;\n const heading = new Set(atx.map((h) => h.line));\n // A line starting in a comment is not a row, and neither is one that\n // continues a code span or comment from the line above.\n const row = (i: number): ScannedLine | null => {\n const line = lines[i];\n if (line === undefined || !isMarkdown(line) || line.blank || line.comment) return null;\n return layout.covered.has(line.line) || heading.has(line.line) ? null : line;\n };\n\n const out: Table[] = [];\n for (let i = 0; i + 1 < lines.length; i += 1) {\n const header = row(i);\n const delimiter = row(i + 1);\n if (header === null || delimiter === null) continue;\n const headers = splitRow(layout, header);\n if (headers.length === 0) continue;\n const marks = splitRow(layout, delimiter);\n if (marks.length !== headers.length || !marks.every((cell) => DELIMITER_CELL.test(cell.text))) continue;\n\n const rows: TableRow[] = [];\n let last = delimiter;\n for (let line = row(i + 2); line !== null; line = row(line.line)) {\n const cells = splitRow(layout, line);\n if (cells.length === 0) break;\n rows.push({ cells, start: line.contentStart, end: line.end, line: line.line });\n last = line;\n }\n out.push({ start: header.contentStart, end: last.end, line: header.line, endLine: last.line, headers, rows });\n i = last.line - 1;\n }\n return out;\n}\n\n/** Splits a row into cells, keeping each cell's offsets. A row without a pipe has none. */\nfunction splitRow(layout: Layout, line: ScannedLine): TableCell[] {\n const { text, structure } = layout;\n const bounds: number[] = [];\n for (let at = line.contentStart; at < line.end; at += 1) {\n // A pipe escaped with a backslash is content, not a column edge.\n if (structure.charCodeAt(at) === PIPE && text.charCodeAt(at - 1) !== BACKSLASH) bounds.push(at);\n }\n if (bounds.length === 0) return [];\n\n const cells: TableCell[] = [];\n // A pipe opening the row is a border, not the edge of an empty first cell.\n let cursor = bounds[0] === leadOffset(line) ? (bounds.shift() as number) + 1 : line.contentStart;\n for (const bound of bounds) {\n cells.push(cell(text, cursor, bound));\n cursor = bound + 1;\n }\n // What follows the last pipe is a cell unless the row ended with a border.\n if (text.slice(cursor, line.end).trim().length > 0) cells.push(cell(text, cursor, line.end));\n return cells;\n}\n\nfunction cell(text: string, start: number, end: number): TableCell {\n const raw = text.slice(start, end);\n const leading = raw.length - raw.trimStart().length;\n const trimmed = raw.trim();\n return { text: trimmed, start: start + leading, end: start + leading + trimmed.length };\n}\n"]}
1
+ {"version":3,"file":"tables.js","sourceRoot":"","sources":["../../../../src/vendor/spec-core/markdown/tables.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * GFM pipe tables, with an offset for every cell.\n *\n * Cell offsets are the point: a register kept as a table needs findings that\n * name the cell declaring a relation, not the row and not the file. Rows are\n * split on the structure mask, so a pipe inside a code span or a comment\n * cannot invent a column, and the text of each cell comes from the original.\n *\n * Reading one line past the last, or one character past a line's end, finds\n * no row and no pipe, so mutants that move those bounds are equivalent.\n */\n\nimport { isMarkdown, leadOffset, type Layout } from './layout.js';\nimport type { Heading, ScannedLine, Table, TableCell, TableRow } from './types.js';\n\nconst PIPE = 124;\nconst BACKSLASH = 92;\nconst DELIMITER_CELL = /^:?-+:?$/;\n\n/**\n * A header line, a delimiter row with as many cells, and the rows under them\n * up to a line that is blank, holds no pipe, or is not Markdown.\n */\nexport function findTables(layout: Layout, atx: readonly Pick<Heading, 'line'>[]): Table[] {\n const { lines } = layout;\n const heading = new Set(atx.map((h) => h.line));\n // A line starting in a comment is not a row, and neither is one that\n // continues a code span or comment from the line above.\n const row = (i: number): ScannedLine | null => {\n const line = lines[i];\n if (line === undefined || !isMarkdown(line) || line.blank || line.comment) return null;\n return layout.covered.has(line.line) || heading.has(line.line) ? null : line;\n };\n\n const out: Table[] = [];\n // A header needs a line under it. `row` answers null for a line past the\n // last, so a bound that lets `i` reach one or two further finds the same\n // tables.\n for (let i = 0; i + 1 < lines.length; i += 1) {\n const header = row(i);\n const delimiter = row(i + 1);\n if (header === null || delimiter === null) continue;\n const headers = splitRow(layout, header);\n if (headers.length === 0) continue;\n const marks = splitRow(layout, delimiter);\n if (marks.length !== headers.length || !marks.every((cell) => DELIMITER_CELL.test(cell.text))) continue;\n\n const rows: TableRow[] = [];\n let last = delimiter;\n for (let line = row(i + 2); line !== null; line = row(line.line)) {\n const cells = splitRow(layout, line);\n if (cells.length === 0) break;\n rows.push({ cells, start: line.contentStart, end: line.end, line: line.line });\n last = line;\n }\n out.push({ start: header.contentStart, end: last.end, line: header.line, endLine: last.line, headers, rows });\n i = last.line - 1;\n }\n return out;\n}\n\n/** Splits a row into cells, keeping each cell's offsets. A row without a pipe has none. */\nfunction splitRow(layout: Layout, line: ScannedLine): TableCell[] {\n const { text, structure } = layout;\n const bounds: number[] = [];\n for (let at = line.contentStart; at < line.end; at += 1) {\n // A pipe escaped with a backslash is content, not a column edge.\n if (structure.charCodeAt(at) === PIPE && text.charCodeAt(at - 1) !== BACKSLASH) bounds.push(at);\n }\n if (bounds.length === 0) return [];\n\n const cells: TableCell[] = [];\n // A pipe opening the row is a border, not the edge of an empty first cell.\n let cursor = bounds[0] === leadOffset(line) ? (bounds.shift() as number) + 1 : line.contentStart;\n for (const bound of bounds) {\n cells.push(cell(text, cursor, bound));\n cursor = bound + 1;\n }\n // What follows the last pipe is a cell unless the row ended with a border.\n if (text.slice(cursor, line.end).trim().length > 0) cells.push(cell(text, cursor, line.end));\n return cells;\n}\n\nfunction cell(text: string, start: number, end: number): TableCell {\n const raw = text.slice(start, end);\n const leading = raw.length - raw.trimStart().length;\n const trimmed = raw.trim();\n return { text: trimmed, start: start + leading, end: start + leading + trimmed.length };\n}\n"]}
@@ -46,10 +46,22 @@ interface Hole {
46
46
  * matched slowly.
47
47
  */
48
48
  export declare const MAX_STATES = 65536;
49
+ /**
50
+ * Thrown by the builder past {@link MAX_STATES}. `parseGlob` answers it as a
51
+ * refusal and `compileGlob` as a `GlobError`, so no function the pattern
52
+ * module exports lets it out; it stays exported for callers written when
53
+ * `parseGlob` did.
54
+ */
49
55
  export declare class AutomatonTooLarge extends Error {
50
56
  constructor();
51
57
  }
52
- /** Thompson's construction, one fragment at a time. */
58
+ /**
59
+ * Thompson's construction, one fragment at a time.
60
+ *
61
+ * An arrow written as -1 is a hole that `patch` aims before `finish` returns,
62
+ * or one nothing follows: a CHAR's second and both of a MATCH's. What it
63
+ * starts as is never read, so any other start gives the same automaton.
64
+ */
53
65
  export declare class Builder {
54
66
  private readonly kinds;
55
67
  private readonly first;
@@ -78,7 +90,8 @@ export declare class Builder {
78
90
  * A reusable matcher over one automaton.
79
91
  *
80
92
  * Holds its buffers between subjects; it is not reentrant, and nothing needs
81
- * it to be - matching calls out to nothing.
93
+ * it to be - matching calls out to nothing. `test` empties each buffer before
94
+ * it reads one, so what a buffer starts with is never read.
82
95
  */
83
96
  export declare class Matcher {
84
97
  private readonly automaton;
@@ -29,13 +29,25 @@ const MATCH = 3;
29
29
  * matched slowly.
30
30
  */
31
31
  export const MAX_STATES = 65_536;
32
+ /**
33
+ * Thrown by the builder past {@link MAX_STATES}. `parseGlob` answers it as a
34
+ * refusal and `compileGlob` as a `GlobError`, so no function the pattern
35
+ * module exports lets it out; it stays exported for callers written when
36
+ * `parseGlob` did.
37
+ */
32
38
  export class AutomatonTooLarge extends Error {
33
39
  constructor() {
34
40
  super(`the pattern compiles to more than ${MAX_STATES} states`);
35
41
  this.name = 'AutomatonTooLarge';
36
42
  }
37
43
  }
38
- /** Thompson's construction, one fragment at a time. */
44
+ /**
45
+ * Thompson's construction, one fragment at a time.
46
+ *
47
+ * An arrow written as -1 is a hole that `patch` aims before `finish` returns,
48
+ * or one nothing follows: a CHAR's second and both of a MATCH's. What it
49
+ * starts as is never read, so any other start gives the same automaton.
50
+ */
39
51
  export class Builder {
40
52
  kinds = [];
41
53
  first = [];
@@ -70,6 +82,10 @@ export class Builder {
70
82
  }
71
83
  /** Each fragment after the one before it. */
72
84
  sequence(parts) {
85
+ // A glob never asks for an empty sequence, nor below for an empty
86
+ // alternation: a segment holds a token, a pattern an alternative. The two
87
+ // guards change no answer the module gives; they meet a misuse where it
88
+ // happens rather than in whatever reads the fragment next.
73
89
  if (parts.length === 0)
74
90
  return this.empty();
75
91
  let current = parts[0];
@@ -151,7 +167,8 @@ function close(automaton, stack, visited, stamp, into) {
151
167
  * A reusable matcher over one automaton.
152
168
  *
153
169
  * Holds its buffers between subjects; it is not reentrant, and nothing needs
154
- * it to be - matching calls out to nothing.
170
+ * it to be - matching calls out to nothing. `test` empties each buffer before
171
+ * it reads one, so what a buffer starts with is never read.
155
172
  */
156
173
  export class Matcher {
157
174
  automaton;
@@ -187,6 +204,8 @@ export class Matcher {
187
204
  this.stack.push(automaton.first[state]);
188
205
  close(automaton, this.stack, this.visited, this.stamp, this.next);
189
206
  }
207
+ // With no live state the rest of the subject changes nothing, and the
208
+ // answer is false either way; this only stops early.
190
209
  if (this.next.length === 0)
191
210
  return false;
192
211
  const spent = this.live;
@@ -1 +1 @@
1
- {"version":3,"file":"automaton.js","sourceRoot":"","sources":["../../../../src/vendor/spec-core/pattern/automaton.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Non-deterministic finite automata over code points: built by Thompson's\n * construction, run by keeping a set of live states, and searched for a\n * shortest string several of them accept and several others refuse.\n *\n * Why an automaton rather than a `RegExp`: a glob such as `*-*-*-*-*-*x`\n * handed to a backtracking engine tries every way of dividing a long name\n * between its stars, and one spec-* tool measured 28 seconds for one path. A\n * set of live states visits each state at most once per character, so a match\n * costs at most the pattern's size times the path's length, whatever the\n * pattern says.\n *\n * Why the same automaton for the witness: whether two scopes can name the same\n * file, and whether one lies wholly inside another, are questions about the\n * languages the patterns accept. Asked of the automata that do the matching,\n * the answers cannot drift from what matching does.\n */\n\nimport { accepts, acceptsIgnoringCase, boundaryPoints, DOT, SLASH, type CharSet } from './charset.js';\n\nconst CHAR = 0;\nconst SPLIT = 1;\nconst JUMP = 2;\nconst MATCH = 3;\n\n/** A compiled automaton. Immutable once built, and safe to share. */\nexport interface Automaton {\n readonly kinds: Uint8Array;\n /** A CHAR's next state, a SPLIT's first branch, a JUMP's target. */\n readonly first: Int32Array;\n /** A SPLIT's second branch. */\n readonly second: Int32Array;\n /** A CHAR's set; unused for the others. */\n readonly sets: readonly (CharSet | null)[];\n readonly start: number;\n readonly caseSensitive: boolean;\n}\n\n/** A piece of an automaton under construction: where it starts, and the arrows still unaimed. */\nexport interface Fragment {\n readonly start: number;\n readonly holes: readonly Hole[];\n}\n\ninterface Hole {\n readonly state: number;\n readonly slot: 1 | 2;\n}\n\n/**\n * Ceiling on the size of one automaton.\n *\n * Brace alternatives are compiled side by side, so a pattern's size is the\n * sum of its alternatives'. Far above anything a scope list says; it exists\n * so that a pathological pattern is refused while compiling rather than\n * matched slowly.\n */\nexport const MAX_STATES = 65_536;\n\nexport class AutomatonTooLarge extends Error {\n constructor() {\n super(`the pattern compiles to more than ${MAX_STATES} states`);\n this.name = 'AutomatonTooLarge';\n }\n}\n\n/** Thompson's construction, one fragment at a time. */\nexport class Builder {\n private readonly kinds: number[] = [];\n private readonly first: number[] = [];\n private readonly second: number[] = [];\n private readonly sets: (CharSet | null)[] = [];\n\n private add(kind: number, set: CharSet | null, first: number, second: number): number {\n if (this.kinds.length >= MAX_STATES) throw new AutomatonTooLarge();\n this.kinds.push(kind);\n this.first.push(first);\n this.second.push(second);\n this.sets.push(set);\n return this.kinds.length - 1;\n }\n\n private patch(holes: readonly Hole[], target: number): void {\n for (const hole of holes) {\n if (hole.slot === 1) this.first[hole.state] = target;\n else this.second[hole.state] = target;\n }\n }\n\n /** One character from a set. */\n char(set: CharSet): Fragment {\n const state = this.add(CHAR, set, -1, -1);\n return { start: state, holes: [{ state, slot: 1 }] };\n }\n\n /** The empty string. */\n empty(): Fragment {\n const state = this.add(JUMP, null, -1, -1);\n return { start: state, holes: [{ state, slot: 1 }] };\n }\n\n /** Each fragment after the one before it. */\n sequence(parts: readonly Fragment[]): Fragment {\n if (parts.length === 0) return this.empty();\n let current = parts[0] as Fragment;\n for (let i = 1; i < parts.length; i += 1) {\n const next = parts[i] as Fragment;\n this.patch(current.holes, next.start);\n current = { start: current.start, holes: next.holes };\n }\n return current;\n }\n\n /** Any one of the fragments. */\n either(options: readonly Fragment[]): Fragment {\n if (options.length === 0) throw new Error('an alternation needs at least one option');\n let current = options[options.length - 1] as Fragment;\n for (let i = options.length - 2; i >= 0; i -= 1) {\n const option = options[i] as Fragment;\n const split = this.add(SPLIT, null, option.start, current.start);\n current = { start: split, holes: [...option.holes, ...current.holes] };\n }\n return current;\n }\n\n /** Zero or more of a fragment. */\n star(body: Fragment): Fragment {\n const split = this.add(SPLIT, null, body.start, -1);\n this.patch(body.holes, split);\n return { start: split, holes: [{ state: split, slot: 2 }] };\n }\n\n /** One or more of a fragment. */\n plus(body: Fragment): Fragment {\n const split = this.add(SPLIT, null, body.start, -1);\n this.patch(body.holes, split);\n return { start: body.start, holes: [{ state: split, slot: 2 }] };\n }\n\n /** Zero or one of a fragment. */\n optional(body: Fragment): Fragment {\n const empty = this.empty();\n return this.either([body, empty]);\n }\n\n /** Closes the automaton: every unaimed arrow reaches acceptance. */\n finish(body: Fragment, caseSensitive: boolean): Automaton {\n const match = this.add(MATCH, null, -1, -1);\n this.patch(body.holes, match);\n return {\n kinds: Uint8Array.from(this.kinds),\n first: Int32Array.from(this.first),\n second: Int32Array.from(this.second),\n sets: [...this.sets],\n start: body.start,\n caseSensitive,\n };\n }\n}\n\n/**\n * Follows every empty arrow out of the states on a stack, appending each\n * CHAR or MATCH state reached to `into`. `visited[state] === stamp` marks a\n * state already taken this round, which is what bounds the work.\n */\nfunction close(\n automaton: Automaton,\n stack: number[],\n visited: Int32Array,\n stamp: number,\n into: number[],\n): void {\n const { kinds, first, second } = automaton;\n while (stack.length > 0) {\n const state = stack.pop() as number;\n if (visited[state] === stamp) continue;\n visited[state] = stamp;\n switch (kinds[state]) {\n case SPLIT:\n stack.push(second[state] as number, first[state] as number);\n break;\n case JUMP:\n stack.push(first[state] as number);\n break;\n default:\n into.push(state);\n }\n }\n}\n\n/**\n * A reusable matcher over one automaton.\n *\n * Holds its buffers between subjects; it is not reentrant, and nothing needs\n * it to be - matching calls out to nothing.\n */\nexport class Matcher {\n private readonly automaton: Automaton;\n private readonly visited: Int32Array;\n private stamp = 0;\n private readonly stack: number[] = [];\n private live: number[] = [];\n private next: number[] = [];\n\n constructor(automaton: Automaton) {\n this.automaton = automaton;\n this.visited = new Int32Array(automaton.kinds.length).fill(-1);\n }\n\n /** Whether the automaton accepts the whole of a subject. */\n test(subject: string): boolean {\n const { automaton } = this;\n const accept = automaton.caseSensitive ? accepts : acceptsIgnoringCase;\n this.live.length = 0;\n this.stack.length = 0;\n this.stack.push(automaton.start);\n this.stamp += 1;\n close(automaton, this.stack, this.visited, this.stamp, this.live);\n\n for (let i = 0; i < subject.length; i += 1) {\n const point = subject.codePointAt(i) as number;\n if (point > 0xffff) i += 1;\n this.next.length = 0;\n this.stamp += 1;\n for (const state of this.live) {\n if (automaton.kinds[state] !== CHAR) continue;\n if (!accept(automaton.sets[state] as CharSet, point)) continue;\n this.stack.push(automaton.first[state] as number);\n close(automaton, this.stack, this.visited, this.stamp, this.next);\n }\n if (this.next.length === 0) return false;\n const spent = this.live;\n this.live = this.next;\n this.next = spent;\n }\n return this.live.some((state) => automaton.kinds[state] === MATCH);\n }\n}\n\n/** The answer to a witness search. */\nexport type Witness =\n | { readonly kind: 'found'; readonly path: string }\n | { readonly kind: 'none' }\n /** The search met its budget before deciding. Rare, and never a guess either way. */\n | { readonly kind: 'undecided' };\n\n/**\n * How many distinct search states a witness search may visit. The search is\n * polynomial in the sizes of the automata it must satisfy and, for the ones\n * it must avoid, bounded by the subsets of their states it reaches; scope\n * patterns reach a handful. The bound turns a pathological input into an\n * `undecided` rather than a hang.\n */\nexport const WITNESS_BUDGET = 200_000;\n\n/**\n * Path validity as a four-state machine: at the start of a segment, inside a\n * segment reading `.` or `..` so far, or inside a segment that is a name. A\n * witness must end inside a name, and a `/` is only legal after one, so no\n * witness has an empty segment, a `.` or `..` segment, or a slash at either\n * end - which a pattern such as `a/*\\/b` would otherwise produce as `a//b`.\n * NUL is refused outright: no filesystem and no git tree holds a path with one.\n */\nconst SEGMENT_START = 0;\nconst ONE_DOT = 1;\nconst TWO_DOTS = 2;\nconst IN_NAME = 3;\nconst INVALID = -1;\nconst NUL = 0;\n\nfunction stepValidity(state: number, point: number): number {\n if (point === NUL) return INVALID;\n if (point === SLASH) return state === IN_NAME ? SEGMENT_START : INVALID;\n if (point === DOT) return state === SEGMENT_START ? ONE_DOT : state === ONE_DOT ? TWO_DOTS : IN_NAME;\n return IN_NAME;\n}\n\ninterface SearchNode {\n /** One live CHAR/MATCH state per automaton that must accept. */\n readonly positive: readonly number[];\n /** Every live state, sorted, per automaton that must refuse. */\n readonly negative: readonly (readonly number[])[];\n readonly validity: number;\n readonly parent: number;\n readonly point: number;\n}\n\nfunction closureOf(automaton: Automaton, seeds: readonly number[]): number[] {\n const visited = new Int32Array(automaton.kinds.length).fill(-1);\n const out: number[] = [];\n close(automaton, [...seeds], visited, 0, out);\n return out;\n}\n\nfunction stepSet(automaton: Automaton, states: readonly number[], point: number): number[] {\n const seeds: number[] = [];\n for (const state of states) {\n if (automaton.kinds[state] === CHAR && accepts(automaton.sets[state] as CharSet, point)) {\n seeds.push(automaton.first[state] as number);\n }\n }\n return closureOf(automaton, seeds).sort((a, b) => a - b);\n}\n\n/** Every way of choosing one element from each list. */\nfunction combinations(lists: readonly (readonly number[])[]): number[][] {\n let out: number[][] = [[]];\n for (const list of lists) {\n const grown: number[][] = [];\n for (const prefix of out) for (const state of list) grown.push([...prefix, state]);\n out = grown;\n }\n return out;\n}\n\nfunction isMatch(automaton: Automaton, state: number): boolean {\n return automaton.kinds[state] === MATCH;\n}\n\n/**\n * A shortest path every automaton in `include` accepts and none in `exclude`\n * does, spelled with readable characters where there is a choice.\n *\n * Breadth-first over the product of one live state per included automaton\n * (existential: some run of each must accept) and the whole live set per\n * excluded one (universal: no run of it may). Characters are tried at the\n * boundary points of every set in play, which meets every combination of\n * answers those sets can give, so the search is exact: `none` means no path\n * exists, not that none was found. The first path reached is a shortest one.\n *\n * Case-sensitive automata only. Every scope comparison in the family is\n * case-sensitive, and folding case exactly would need every set's closure\n * under case mapping.\n */\nexport function findWitness(\n include: readonly Automaton[],\n exclude: readonly Automaton[] = [],\n budget: number = WITNESS_BUDGET,\n): Witness {\n if (include.length === 0) throw new Error('a witness search needs at least one automaton to satisfy');\n for (const automaton of [...include, ...exclude]) {\n if (!automaton.caseSensitive) throw new Error('a witness search is defined for case-sensitive patterns only');\n }\n\n const startPositive = include.map((automaton) => closureOf(automaton, [automaton.start]));\n const startNegative = exclude.map((automaton) => closureOf(automaton, [automaton.start]).sort((a, b) => a - b));\n\n const nodes: SearchNode[] = [];\n const seen = new Set<string>();\n const key = (positive: readonly number[], negative: readonly (readonly number[])[], validity: number): string =>\n `${positive.join(',')}|${validity}|${negative.map((set) => set.join(',')).join('|')}`;\n\n const enqueue = (\n positive: readonly number[],\n negative: readonly (readonly number[])[],\n validity: number,\n parent: number,\n point: number,\n ): void => {\n const id = key(positive, negative, validity);\n if (seen.has(id)) return;\n seen.add(id);\n nodes.push({ positive, negative, validity, parent, point });\n };\n\n for (const positive of combinations(startPositive)) enqueue(positive, startNegative, SEGMENT_START, -1, 0);\n\n for (let cursor = 0; cursor < nodes.length; cursor += 1) {\n if (cursor >= budget) return { kind: 'undecided' };\n const node = nodes[cursor] as SearchNode;\n\n const accepted = node.positive.every((state, i) => isMatch(include[i] as Automaton, state));\n const refused = node.negative.every((set, i) => !set.some((state) => isMatch(exclude[i] as Automaton, state)));\n if (accepted && refused && node.validity === IN_NAME) return { kind: 'found', path: spell(nodes, cursor) };\n\n // A MATCH state reads nothing more: an included automaton sitting on one\n // can only accept here, so no longer path extends this node.\n if (node.positive.some((state, i) => (include[i] as Automaton).kinds[state] !== CHAR)) continue;\n\n const sets: CharSet[] = [];\n node.positive.forEach((state, i) => sets.push((include[i] as Automaton).sets[state] as CharSet));\n node.negative.forEach((set, i) => {\n const automaton = exclude[i] as Automaton;\n for (const state of set) if (automaton.kinds[state] === CHAR) sets.push(automaton.sets[state] as CharSet);\n });\n\n // Where each included automaton goes next does not depend on the\n // character, only whether it may go; what the excluded ones reach does.\n const successors = combinations(\n node.positive.map((state, i) => closureOf(include[i] as Automaton, [(include[i] as Automaton).first[state] as number])),\n );\n for (const point of boundaryPoints(sets)) {\n const validity = stepValidity(node.validity, point);\n if (validity === INVALID) continue;\n if (!node.positive.every((state, i) => accepts((include[i] as Automaton).sets[state] as CharSet, point))) {\n continue;\n }\n const negative = node.negative.map((set, i) => stepSet(exclude[i] as Automaton, set, point));\n for (const positive of successors) enqueue(positive, negative, validity, cursor, point);\n }\n }\n return { kind: 'none' };\n}\n\nfunction spell(nodes: readonly SearchNode[], index: number): string {\n const points: number[] = [];\n for (let i = index; (nodes[i] as SearchNode).parent >= 0; i = (nodes[i] as SearchNode).parent) {\n points.push((nodes[i] as SearchNode).point);\n }\n return String.fromCodePoint(...points.reverse());\n}\n"]}
1
+ {"version":3,"file":"automaton.js","sourceRoot":"","sources":["../../../../src/vendor/spec-core/pattern/automaton.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Non-deterministic finite automata over code points: built by Thompson's\n * construction, run by keeping a set of live states, and searched for a\n * shortest string several of them accept and several others refuse.\n *\n * Why an automaton rather than a `RegExp`: a glob such as `*-*-*-*-*-*x`\n * handed to a backtracking engine tries every way of dividing a long name\n * between its stars, and one spec-* tool measured 28 seconds for one path. A\n * set of live states visits each state at most once per character, so a match\n * costs at most the pattern's size times the path's length, whatever the\n * pattern says.\n *\n * Why the same automaton for the witness: whether two scopes can name the same\n * file, and whether one lies wholly inside another, are questions about the\n * languages the patterns accept. Asked of the automata that do the matching,\n * the answers cannot drift from what matching does.\n */\n\nimport { accepts, acceptsIgnoringCase, boundaryPoints, DOT, SLASH, type CharSet } from './charset.js';\n\nconst CHAR = 0;\nconst SPLIT = 1;\nconst JUMP = 2;\nconst MATCH = 3;\n\n/** A compiled automaton. Immutable once built, and safe to share. */\nexport interface Automaton {\n readonly kinds: Uint8Array;\n /** A CHAR's next state, a SPLIT's first branch, a JUMP's target. */\n readonly first: Int32Array;\n /** A SPLIT's second branch. */\n readonly second: Int32Array;\n /** A CHAR's set; unused for the others. */\n readonly sets: readonly (CharSet | null)[];\n readonly start: number;\n readonly caseSensitive: boolean;\n}\n\n/** A piece of an automaton under construction: where it starts, and the arrows still unaimed. */\nexport interface Fragment {\n readonly start: number;\n readonly holes: readonly Hole[];\n}\n\ninterface Hole {\n readonly state: number;\n readonly slot: 1 | 2;\n}\n\n/**\n * Ceiling on the size of one automaton.\n *\n * Brace alternatives are compiled side by side, so a pattern's size is the\n * sum of its alternatives'. Far above anything a scope list says; it exists\n * so that a pathological pattern is refused while compiling rather than\n * matched slowly.\n */\nexport const MAX_STATES = 65_536;\n\n/**\n * Thrown by the builder past {@link MAX_STATES}. `parseGlob` answers it as a\n * refusal and `compileGlob` as a `GlobError`, so no function the pattern\n * module exports lets it out; it stays exported for callers written when\n * `parseGlob` did.\n */\nexport class AutomatonTooLarge extends Error {\n constructor() {\n super(`the pattern compiles to more than ${MAX_STATES} states`);\n this.name = 'AutomatonTooLarge';\n }\n}\n\n/**\n * Thompson's construction, one fragment at a time.\n *\n * An arrow written as -1 is a hole that `patch` aims before `finish` returns,\n * or one nothing follows: a CHAR's second and both of a MATCH's. What it\n * starts as is never read, so any other start gives the same automaton.\n */\nexport class Builder {\n private readonly kinds: number[] = [];\n private readonly first: number[] = [];\n private readonly second: number[] = [];\n private readonly sets: (CharSet | null)[] = [];\n\n private add(kind: number, set: CharSet | null, first: number, second: number): number {\n if (this.kinds.length >= MAX_STATES) throw new AutomatonTooLarge();\n this.kinds.push(kind);\n this.first.push(first);\n this.second.push(second);\n this.sets.push(set);\n return this.kinds.length - 1;\n }\n\n private patch(holes: readonly Hole[], target: number): void {\n for (const hole of holes) {\n if (hole.slot === 1) this.first[hole.state] = target;\n else this.second[hole.state] = target;\n }\n }\n\n /** One character from a set. */\n char(set: CharSet): Fragment {\n const state = this.add(CHAR, set, -1, -1);\n return { start: state, holes: [{ state, slot: 1 }] };\n }\n\n /** The empty string. */\n empty(): Fragment {\n const state = this.add(JUMP, null, -1, -1);\n return { start: state, holes: [{ state, slot: 1 }] };\n }\n\n /** Each fragment after the one before it. */\n sequence(parts: readonly Fragment[]): Fragment {\n // A glob never asks for an empty sequence, nor below for an empty\n // alternation: a segment holds a token, a pattern an alternative. The two\n // guards change no answer the module gives; they meet a misuse where it\n // happens rather than in whatever reads the fragment next.\n if (parts.length === 0) return this.empty();\n let current = parts[0] as Fragment;\n for (let i = 1; i < parts.length; i += 1) {\n const next = parts[i] as Fragment;\n this.patch(current.holes, next.start);\n current = { start: current.start, holes: next.holes };\n }\n return current;\n }\n\n /** Any one of the fragments. */\n either(options: readonly Fragment[]): Fragment {\n if (options.length === 0) throw new Error('an alternation needs at least one option');\n let current = options[options.length - 1] as Fragment;\n for (let i = options.length - 2; i >= 0; i -= 1) {\n const option = options[i] as Fragment;\n const split = this.add(SPLIT, null, option.start, current.start);\n current = { start: split, holes: [...option.holes, ...current.holes] };\n }\n return current;\n }\n\n /** Zero or more of a fragment. */\n star(body: Fragment): Fragment {\n const split = this.add(SPLIT, null, body.start, -1);\n this.patch(body.holes, split);\n return { start: split, holes: [{ state: split, slot: 2 }] };\n }\n\n /** One or more of a fragment. */\n plus(body: Fragment): Fragment {\n const split = this.add(SPLIT, null, body.start, -1);\n this.patch(body.holes, split);\n return { start: body.start, holes: [{ state: split, slot: 2 }] };\n }\n\n /** Zero or one of a fragment. */\n optional(body: Fragment): Fragment {\n const empty = this.empty();\n return this.either([body, empty]);\n }\n\n /** Closes the automaton: every unaimed arrow reaches acceptance. */\n finish(body: Fragment, caseSensitive: boolean): Automaton {\n const match = this.add(MATCH, null, -1, -1);\n this.patch(body.holes, match);\n return {\n kinds: Uint8Array.from(this.kinds),\n first: Int32Array.from(this.first),\n second: Int32Array.from(this.second),\n sets: [...this.sets],\n start: body.start,\n caseSensitive,\n };\n }\n}\n\n/**\n * Follows every empty arrow out of the states on a stack, appending each\n * CHAR or MATCH state reached to `into`. `visited[state] === stamp` marks a\n * state already taken this round, which is what bounds the work.\n */\nfunction close(\n automaton: Automaton,\n stack: number[],\n visited: Int32Array,\n stamp: number,\n into: number[],\n): void {\n const { kinds, first, second } = automaton;\n while (stack.length > 0) {\n const state = stack.pop() as number;\n if (visited[state] === stamp) continue;\n visited[state] = stamp;\n switch (kinds[state]) {\n case SPLIT:\n stack.push(second[state] as number, first[state] as number);\n break;\n case JUMP:\n stack.push(first[state] as number);\n break;\n default:\n into.push(state);\n }\n }\n}\n\n/**\n * A reusable matcher over one automaton.\n *\n * Holds its buffers between subjects; it is not reentrant, and nothing needs\n * it to be - matching calls out to nothing. `test` empties each buffer before\n * it reads one, so what a buffer starts with is never read.\n */\nexport class Matcher {\n private readonly automaton: Automaton;\n private readonly visited: Int32Array;\n private stamp = 0;\n private readonly stack: number[] = [];\n private live: number[] = [];\n private next: number[] = [];\n\n constructor(automaton: Automaton) {\n this.automaton = automaton;\n this.visited = new Int32Array(automaton.kinds.length).fill(-1);\n }\n\n /** Whether the automaton accepts the whole of a subject. */\n test(subject: string): boolean {\n const { automaton } = this;\n const accept = automaton.caseSensitive ? accepts : acceptsIgnoringCase;\n this.live.length = 0;\n this.stack.length = 0;\n this.stack.push(automaton.start);\n this.stamp += 1;\n close(automaton, this.stack, this.visited, this.stamp, this.live);\n\n for (let i = 0; i < subject.length; i += 1) {\n const point = subject.codePointAt(i) as number;\n if (point > 0xffff) i += 1;\n this.next.length = 0;\n this.stamp += 1;\n for (const state of this.live) {\n if (automaton.kinds[state] !== CHAR) continue;\n if (!accept(automaton.sets[state] as CharSet, point)) continue;\n this.stack.push(automaton.first[state] as number);\n close(automaton, this.stack, this.visited, this.stamp, this.next);\n }\n // With no live state the rest of the subject changes nothing, and the\n // answer is false either way; this only stops early.\n if (this.next.length === 0) return false;\n const spent = this.live;\n this.live = this.next;\n this.next = spent;\n }\n return this.live.some((state) => automaton.kinds[state] === MATCH);\n }\n}\n\n/** The answer to a witness search. */\nexport type Witness =\n | { readonly kind: 'found'; readonly path: string }\n | { readonly kind: 'none' }\n /** The search met its budget before deciding. Rare, and never a guess either way. */\n | { readonly kind: 'undecided' };\n\n/**\n * How many distinct search states a witness search may visit. The search is\n * polynomial in the sizes of the automata it must satisfy and, for the ones\n * it must avoid, bounded by the subsets of their states it reaches; scope\n * patterns reach a handful. The bound turns a pathological input into an\n * `undecided` rather than a hang.\n */\nexport const WITNESS_BUDGET = 200_000;\n\n/**\n * Path validity as a four-state machine: at the start of a segment, inside a\n * segment reading `.` or `..` so far, or inside a segment that is a name. A\n * witness must end inside a name, and a `/` is only legal after one, so no\n * witness has an empty segment, a `.` or `..` segment, or a slash at either\n * end - which a pattern such as `a/*\\/b` would otherwise produce as `a//b`.\n * NUL is refused outright: no filesystem and no git tree holds a path with one.\n */\nconst SEGMENT_START = 0;\nconst ONE_DOT = 1;\nconst TWO_DOTS = 2;\nconst IN_NAME = 3;\nconst INVALID = -1;\nconst NUL = 0;\n\nfunction stepValidity(state: number, point: number): number {\n if (point === NUL) return INVALID;\n if (point === SLASH) return state === IN_NAME ? SEGMENT_START : INVALID;\n if (point === DOT) return state === SEGMENT_START ? ONE_DOT : state === ONE_DOT ? TWO_DOTS : IN_NAME;\n return IN_NAME;\n}\n\ninterface SearchNode {\n /** One live CHAR/MATCH state per automaton that must accept. */\n readonly positive: readonly number[];\n /** Every live state, sorted, per automaton that must refuse. */\n readonly negative: readonly (readonly number[])[];\n readonly validity: number;\n readonly parent: number;\n readonly point: number;\n}\n\nfunction closureOf(automaton: Automaton, seeds: readonly number[]): number[] {\n const visited = new Int32Array(automaton.kinds.length).fill(-1);\n const out: number[] = [];\n close(automaton, [...seeds], visited, 0, out);\n return out;\n}\n\nfunction stepSet(automaton: Automaton, states: readonly number[], point: number): number[] {\n const seeds: number[] = [];\n for (const state of states) {\n if (automaton.kinds[state] === CHAR && accepts(automaton.sets[state] as CharSet, point)) {\n seeds.push(automaton.first[state] as number);\n }\n }\n return closureOf(automaton, seeds).sort((a, b) => a - b);\n}\n\n/** Every way of choosing one element from each list. */\nfunction combinations(lists: readonly (readonly number[])[]): number[][] {\n let out: number[][] = [[]];\n for (const list of lists) {\n const grown: number[][] = [];\n for (const prefix of out) for (const state of list) grown.push([...prefix, state]);\n out = grown;\n }\n return out;\n}\n\nfunction isMatch(automaton: Automaton, state: number): boolean {\n return automaton.kinds[state] === MATCH;\n}\n\n/**\n * A shortest path every automaton in `include` accepts and none in `exclude`\n * does, spelled with readable characters where there is a choice.\n *\n * Breadth-first over the product of one live state per included automaton\n * (existential: some run of each must accept) and the whole live set per\n * excluded one (universal: no run of it may). Characters are tried at the\n * boundary points of every set in play, which meets every combination of\n * answers those sets can give, so the search is exact: `none` means no path\n * exists, not that none was found. The first path reached is a shortest one.\n *\n * Case-sensitive automata only. Every scope comparison in the family is\n * case-sensitive, and folding case exactly would need every set's closure\n * under case mapping.\n */\nexport function findWitness(\n include: readonly Automaton[],\n exclude: readonly Automaton[] = [],\n budget: number = WITNESS_BUDGET,\n): Witness {\n if (include.length === 0) throw new Error('a witness search needs at least one automaton to satisfy');\n for (const automaton of [...include, ...exclude]) {\n if (!automaton.caseSensitive) throw new Error('a witness search is defined for case-sensitive patterns only');\n }\n\n const startPositive = include.map((automaton) => closureOf(automaton, [automaton.start]));\n const startNegative = exclude.map((automaton) => closureOf(automaton, [automaton.start]).sort((a, b) => a - b));\n\n const nodes: SearchNode[] = [];\n const seen = new Set<string>();\n const key = (positive: readonly number[], negative: readonly (readonly number[])[], validity: number): string =>\n `${positive.join(',')}|${validity}|${negative.map((set) => set.join(',')).join('|')}`;\n\n const enqueue = (\n positive: readonly number[],\n negative: readonly (readonly number[])[],\n validity: number,\n parent: number,\n point: number,\n ): void => {\n const id = key(positive, negative, validity);\n if (seen.has(id)) return;\n seen.add(id);\n nodes.push({ positive, negative, validity, parent, point });\n };\n\n for (const positive of combinations(startPositive)) enqueue(positive, startNegative, SEGMENT_START, -1, 0);\n\n for (let cursor = 0; cursor < nodes.length; cursor += 1) {\n if (cursor >= budget) return { kind: 'undecided' };\n const node = nodes[cursor] as SearchNode;\n\n const accepted = node.positive.every((state, i) => isMatch(include[i] as Automaton, state));\n const refused = node.negative.every((set, i) => !set.some((state) => isMatch(exclude[i] as Automaton, state)));\n if (accepted && refused && node.validity === IN_NAME) return { kind: 'found', path: spell(nodes, cursor) };\n\n // A MATCH state reads nothing more: an included automaton sitting on one\n // can only accept here, so no longer path extends this node.\n if (node.positive.some((state, i) => (include[i] as Automaton).kinds[state] !== CHAR)) continue;\n\n const sets: CharSet[] = [];\n node.positive.forEach((state, i) => sets.push((include[i] as Automaton).sets[state] as CharSet));\n node.negative.forEach((set, i) => {\n const automaton = exclude[i] as Automaton;\n for (const state of set) if (automaton.kinds[state] === CHAR) sets.push(automaton.sets[state] as CharSet);\n });\n\n // Where each included automaton goes next does not depend on the\n // character, only whether it may go; what the excluded ones reach does.\n const successors = combinations(\n node.positive.map((state, i) => closureOf(include[i] as Automaton, [(include[i] as Automaton).first[state] as number])),\n );\n for (const point of boundaryPoints(sets)) {\n const validity = stepValidity(node.validity, point);\n if (validity === INVALID) continue;\n if (!node.positive.every((state, i) => accepts((include[i] as Automaton).sets[state] as CharSet, point))) {\n continue;\n }\n const negative = node.negative.map((set, i) => stepSet(exclude[i] as Automaton, set, point));\n for (const positive of successors) enqueue(positive, negative, validity, cursor, point);\n }\n }\n return { kind: 'none' };\n}\n\nfunction spell(nodes: readonly SearchNode[], index: number): string {\n const points: number[] = [];\n for (let i = index; (nodes[i] as SearchNode).parent >= 0; i = (nodes[i] as SearchNode).parent) {\n points.push((nodes[i] as SearchNode).point);\n }\n return String.fromCodePoint(...points.reverse());\n}\n"]}
@@ -21,7 +21,11 @@ export interface CharSet {
21
21
  export declare const SLASH = 47;
22
22
  export declare const DOT = 46;
23
23
  export declare const MAX_CODE_POINT = 1114111;
24
- /** The separator, and nothing else. */
24
+ /**
25
+ * The separator, and nothing else. `separator` is what `accepts` asks; the
26
+ * range is read only for the points a witness search tries, and `/` and `0`,
27
+ * the point after it, are tried whatever the sets hold.
28
+ */
25
29
  export declare const SEPARATOR: CharSet;
26
30
  /** Any character but the separator: `?`, and the body of `*`. */
27
31
  export declare const ANY: CharSet;
@@ -13,11 +13,18 @@
13
13
  export const SLASH = 0x2f;
14
14
  export const DOT = 0x2e;
15
15
  export const MAX_CODE_POINT = 0x10ffff;
16
- /** The separator, and nothing else. */
16
+ /**
17
+ * The separator, and nothing else. `separator` is what `accepts` asks; the
18
+ * range is read only for the points a witness search tries, and `/` and `0`,
19
+ * the point after it, are tried whatever the sets hold.
20
+ */
17
21
  export const SEPARATOR = { negated: false, ranges: [[SLASH, SLASH]], separator: true };
18
22
  /** Any character but the separator: `?`, and the body of `*`. */
19
23
  export const ANY = { negated: true, ranges: [], separator: false };
20
24
  export function literalSet(point) {
25
+ // A glob's literals are read from inside one segment, so none is `/` and
26
+ // `separator` is false for every one compiled; it is computed so the set
27
+ // holds true for any point it is given.
21
28
  return { negated: false, ranges: [[point, point]], separator: point === SLASH };
22
29
  }
23
30
  export function classSet(ranges, negated) {
@@ -1 +1 @@
1
- {"version":3,"file":"charset.js","sourceRoot":"","sources":["../../../../src/vendor/spec-core/pattern/charset.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Sets of characters a glob position accepts, over Unicode code points.\n *\n * A glob matches a path one character at a time, and a character is a code\n * point: `?` matches `é` whether it is stored as one UTF-16 unit or not, and an\n * emoji as one. That is what a person counting characters in a file name\n * expects, and it is the same on every host.\n *\n * No set but the separator's accepts `/`. A path is matched a segment at a\n * time, and a `*` or a `[!a]` that swallowed a slash would let one segment of\n * a pattern match two of a path.\n */\n\n/** An inclusive range of code points. */\nexport type CodeRange = readonly [number, number];\n\nexport interface CharSet {\n readonly negated: boolean;\n readonly ranges: readonly CodeRange[];\n /** True only for the path separator itself. */\n readonly separator: boolean;\n}\n\nexport const SLASH = 0x2f;\nexport const DOT = 0x2e;\nexport const MAX_CODE_POINT = 0x10ffff;\n\n/** The separator, and nothing else. */\nexport const SEPARATOR: CharSet = { negated: false, ranges: [[SLASH, SLASH]], separator: true };\n\n/** Any character but the separator: `?`, and the body of `*`. */\nexport const ANY: CharSet = { negated: true, ranges: [], separator: false };\n\nexport function literalSet(point: number): CharSet {\n return { negated: false, ranges: [[point, point]], separator: point === SLASH };\n}\n\nexport function classSet(ranges: readonly CodeRange[], negated: boolean): CharSet {\n return { negated, ranges, separator: false };\n}\n\nfunction within(ranges: readonly CodeRange[], point: number): boolean {\n for (let i = 0; i < ranges.length; i += 1) {\n const range = ranges[i] as CodeRange;\n if (point >= range[0] && point <= range[1]) return true;\n }\n return false;\n}\n\n/** Whether a set accepts a code point as written. */\nexport function accepts(set: CharSet, point: number): boolean {\n if (point === SLASH) return set.separator;\n return within(set.ranges, point) !== set.negated;\n}\n\n/**\n * The code points a code point is the same letter as, ignoring case: itself,\n * and its lower- and upper-case forms where each is a single code point.\n *\n * Simple case mapping, which is what `toLowerCase` and `toUpperCase` give one\n * character at a time. It is locale-free, so two hosts agree; `ß` has no single\n * upper-case code point and so matches only itself.\n */\nexport function caseVariants(point: number): readonly number[] {\n if (point < 0x80) {\n if (point >= 0x41 && point <= 0x5a) return [point, point + 32];\n if (point >= 0x61 && point <= 0x7a) return [point, point - 32];\n return [point];\n }\n const char = String.fromCodePoint(point);\n const out = [point];\n for (const variant of [char.toLowerCase(), char.toUpperCase()]) {\n const code = variant.codePointAt(0) as number;\n if (variant.length === String.fromCodePoint(code).length && !out.includes(code)) out.push(code);\n }\n return out;\n}\n\n/**\n * Whether a set accepts a code point with case ignored: whether it accepts\n * the point or one of its case variants. A negated set is negated over the\n * same question, so `[!a]` refuses `A` as well as `a`.\n */\nexport function acceptsIgnoringCase(set: CharSet, point: number): boolean {\n if (point === SLASH) return set.separator;\n const variants = caseVariants(point);\n let inside = false;\n for (let i = 0; i < variants.length && !inside; i += 1) inside = within(set.ranges, variants[i] as number);\n return inside !== set.negated;\n}\n\n/**\n * Characters a witness is spelled with when any of them will do, in order of\n * preference. A witness is read by a person deciding whether two scopes really\n * overlap, and `src/x.ts` reads better than `src/\\u0000.ts`.\n */\nconst READABLE = [0x78, 0x61, 0x62, 0x30, 0x5f, 0x2d, 0x7e, 0x21, DOT, SLASH] as const;\n\n/**\n * Every code point at which the answer \"which of these sets accept it\" can\n * change, readable ones first.\n *\n * Each set accepts a union of intervals, so the sets' memberships are constant\n * between consecutive interval ends. The start of each interval and the point\n * after its end therefore meet every distinct combination of answers, and\n * trying them all decides every question a witness search can ask of one\n * character. The separator and the dot are always included: path validity\n * turns on them.\n */\nexport function boundaryPoints(sets: readonly CharSet[]): number[] {\n // 1, not 0: no path holds a NUL, so the least character worth trying is the next.\n const points: number[] = [...READABLE, 1];\n for (const set of sets) {\n for (const [low, high] of set.ranges) {\n points.push(low);\n if (high < MAX_CODE_POINT) points.push(high + 1);\n }\n }\n const seen = new Set<number>();\n const out: number[] = [];\n for (const point of points) {\n if (seen.has(point)) continue;\n seen.add(point);\n out.push(point);\n }\n return out;\n}\n"]}
1
+ {"version":3,"file":"charset.js","sourceRoot":"","sources":["../../../../src/vendor/spec-core/pattern/charset.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Sets of characters a glob position accepts, over Unicode code points.\n *\n * A glob matches a path one character at a time, and a character is a code\n * point: `?` matches `é` whether it is stored as one UTF-16 unit or not, and an\n * emoji as one. That is what a person counting characters in a file name\n * expects, and it is the same on every host.\n *\n * No set but the separator's accepts `/`. A path is matched a segment at a\n * time, and a `*` or a `[!a]` that swallowed a slash would let one segment of\n * a pattern match two of a path.\n */\n\n/** An inclusive range of code points. */\nexport type CodeRange = readonly [number, number];\n\nexport interface CharSet {\n readonly negated: boolean;\n readonly ranges: readonly CodeRange[];\n /** True only for the path separator itself. */\n readonly separator: boolean;\n}\n\nexport const SLASH = 0x2f;\nexport const DOT = 0x2e;\nexport const MAX_CODE_POINT = 0x10ffff;\n\n/**\n * The separator, and nothing else. `separator` is what `accepts` asks; the\n * range is read only for the points a witness search tries, and `/` and `0`,\n * the point after it, are tried whatever the sets hold.\n */\nexport const SEPARATOR: CharSet = { negated: false, ranges: [[SLASH, SLASH]], separator: true };\n\n/** Any character but the separator: `?`, and the body of `*`. */\nexport const ANY: CharSet = { negated: true, ranges: [], separator: false };\n\nexport function literalSet(point: number): CharSet {\n // A glob's literals are read from inside one segment, so none is `/` and\n // `separator` is false for every one compiled; it is computed so the set\n // holds true for any point it is given.\n return { negated: false, ranges: [[point, point]], separator: point === SLASH };\n}\n\nexport function classSet(ranges: readonly CodeRange[], negated: boolean): CharSet {\n return { negated, ranges, separator: false };\n}\n\nfunction within(ranges: readonly CodeRange[], point: number): boolean {\n for (let i = 0; i < ranges.length; i += 1) {\n const range = ranges[i] as CodeRange;\n if (point >= range[0] && point <= range[1]) return true;\n }\n return false;\n}\n\n/** Whether a set accepts a code point as written. */\nexport function accepts(set: CharSet, point: number): boolean {\n if (point === SLASH) return set.separator;\n return within(set.ranges, point) !== set.negated;\n}\n\n/**\n * The code points a code point is the same letter as, ignoring case: itself,\n * and its lower- and upper-case forms where each is a single code point.\n *\n * Simple case mapping, which is what `toLowerCase` and `toUpperCase` give one\n * character at a time. It is locale-free, so two hosts agree; `ß` has no single\n * upper-case code point and so matches only itself.\n */\nexport function caseVariants(point: number): readonly number[] {\n if (point < 0x80) {\n if (point >= 0x41 && point <= 0x5a) return [point, point + 32];\n if (point >= 0x61 && point <= 0x7a) return [point, point - 32];\n return [point];\n }\n const char = String.fromCodePoint(point);\n const out = [point];\n for (const variant of [char.toLowerCase(), char.toUpperCase()]) {\n const code = variant.codePointAt(0) as number;\n if (variant.length === String.fromCodePoint(code).length && !out.includes(code)) out.push(code);\n }\n return out;\n}\n\n/**\n * Whether a set accepts a code point with case ignored: whether it accepts\n * the point or one of its case variants. A negated set is negated over the\n * same question, so `[!a]` refuses `A` as well as `a`.\n */\nexport function acceptsIgnoringCase(set: CharSet, point: number): boolean {\n if (point === SLASH) return set.separator;\n const variants = caseVariants(point);\n let inside = false;\n for (let i = 0; i < variants.length && !inside; i += 1) inside = within(set.ranges, variants[i] as number);\n return inside !== set.negated;\n}\n\n/**\n * Characters a witness is spelled with when any of them will do, in order of\n * preference. A witness is read by a person deciding whether two scopes really\n * overlap, and `src/x.ts` reads better than `src/\\u0000.ts`.\n */\nconst READABLE = [0x78, 0x61, 0x62, 0x30, 0x5f, 0x2d, 0x7e, 0x21, DOT, SLASH] as const;\n\n/**\n * Every code point at which the answer \"which of these sets accept it\" can\n * change, readable ones first.\n *\n * Each set accepts a union of intervals, so the sets' memberships are constant\n * between consecutive interval ends. The start of each interval and the point\n * after its end therefore meet every distinct combination of answers, and\n * trying them all decides every question a witness search can ask of one\n * character. The separator and the dot are always included: path validity\n * turns on them.\n */\nexport function boundaryPoints(sets: readonly CharSet[]): number[] {\n // 1, not 0: no path holds a NUL, so the least character worth trying is the next.\n const points: number[] = [...READABLE, 1];\n for (const set of sets) {\n for (const [low, high] of set.ranges) {\n points.push(low);\n if (high < MAX_CODE_POINT) points.push(high + 1);\n }\n }\n const seen = new Set<number>();\n const out: number[] = [];\n for (const point of points) {\n if (seen.has(point)) continue;\n seen.add(point);\n out.push(point);\n }\n return out;\n}\n"]}
@@ -26,6 +26,11 @@
26
26
  * tools read it three ways, and the quiet reading narrowed their scope. The
27
27
  * refusal writes the two patterns it may have meant from the one written.
28
28
  * - `*`, `?` and classes never match `/`, and `*` matches a leading dot.
29
+ * - Braces expand first, and each alternative reads as it would written on
30
+ * its own: `{src/,lib}` is `src/` or `lib`, and a trailing `/` means the
31
+ * directory's contents - in an exclusion, the directory and its contents.
32
+ * One that names no path, `{./,lib}` or `{,lib}`, is refused, as `./` and
33
+ * the empty pattern are.
29
34
  * - Case is the caller's decision, stated every time. A result must not
30
35
  * depend on the host it ran on.
31
36
  * - A malformed pattern is an error, never a literal. An unclosed `[` or `{`,
@@ -46,7 +51,8 @@ export interface GlobOptions {
46
51
  * `path` dialect only: how a pattern with no glob syntax is read - as a
47
52
  * file, as a directory and everything beneath it, or as either. A function
48
53
  * is asked per literal path, for a caller that knows the tree. `either` when
49
- * unset. A trailing `/` always means a directory.
54
+ * unset. A trailing `/`, on the pattern or on one of its brace alternatives,
55
+ * always means a directory's contents, and is never asked about.
50
56
  */
51
57
  readonly literal?: LiteralReading | ((path: string) => LiteralReading) | undefined;
52
58
  /**
@@ -85,9 +91,16 @@ export declare class GlobError extends Error {
85
91
  export declare const MAX_ALTERNATIVES = 256;
86
92
  /** Whether a string uses glob syntax at all. */
87
93
  export declare function isGlobSyntax(source: string): boolean;
88
- /** Parses and compiles a glob, or says why it cannot. */
94
+ /**
95
+ * Parses and compiles a glob, or says why it cannot: malformed, or too large
96
+ * to compile, past {@link MAX_ALTERNATIVES} alternatives or `MAX_STATES`
97
+ * states. It throws only what a `literal` function throws.
98
+ */
89
99
  export declare function parseGlob(source: string, options: GlobOptions): GlobParse;
90
- /** Parses and compiles a glob, throwing {@link GlobError} when it cannot. */
100
+ /**
101
+ * Parses and compiles a glob, throwing {@link GlobError} for every reason
102
+ * {@link parseGlob} gives, and what a `literal` function throws.
103
+ */
91
104
  export declare function compileGlob(source: string, options: GlobOptions): Glob;
92
105
  /**
93
106
  * A shortest path every glob in `include` matches and no glob in `exclude`
@@ -26,6 +26,11 @@
26
26
  * tools read it three ways, and the quiet reading narrowed their scope. The
27
27
  * refusal writes the two patterns it may have meant from the one written.
28
28
  * - `*`, `?` and classes never match `/`, and `*` matches a leading dot.
29
+ * - Braces expand first, and each alternative reads as it would written on
30
+ * its own: `{src/,lib}` is `src/` or `lib`, and a trailing `/` means the
31
+ * directory's contents - in an exclusion, the directory and its contents.
32
+ * One that names no path, `{./,lib}` or `{,lib}`, is refused, as `./` and
33
+ * the empty pattern are.
29
34
  * - Case is the caller's decision, stated every time. A result must not
30
35
  * depend on the host it ran on.
31
36
  * - A malformed pattern is an error, never a literal. An unclosed `[` or `{`,
@@ -34,7 +39,7 @@
34
39
  * glob is a group holding a `|`, `+(a|b)`: without one, `C++(notes).md` is
35
40
  * a name with parentheses in it, as ripgrep and `.gitignore` read it.
36
41
  */
37
- import { Builder, findWitness, Matcher, WITNESS_BUDGET, } from './automaton.js';
42
+ import { AutomatonTooLarge, Builder, findWitness, Matcher, WITNESS_BUDGET, } from './automaton.js';
38
43
  import { ANY, classSet, literalSet, SEPARATOR } from './charset.js';
39
44
  export class GlobError extends Error {
40
45
  source;
@@ -50,12 +55,19 @@ export const MAX_ALTERNATIVES = 256;
50
55
  export function isGlobSyntax(source) {
51
56
  return /[*?[\]{}]/.test(source);
52
57
  }
53
- /** Parses and compiles a glob, or says why it cannot. */
58
+ /**
59
+ * Parses and compiles a glob, or says why it cannot: malformed, or too large
60
+ * to compile, past {@link MAX_ALTERNATIVES} alternatives or `MAX_STATES`
61
+ * states. It throws only what a `literal` function throws.
62
+ */
54
63
  export function parseGlob(source, options) {
55
64
  const result = build(source, options);
56
65
  return typeof result === 'string' ? { ok: false, error: result } : { ok: true, glob: result };
57
66
  }
58
- /** Parses and compiles a glob, throwing {@link GlobError} when it cannot. */
67
+ /**
68
+ * Parses and compiles a glob, throwing {@link GlobError} for every reason
69
+ * {@link parseGlob} gives, and what a `literal` function throws.
70
+ */
59
71
  export function compileGlob(source, options) {
60
72
  const result = build(source, options);
61
73
  if (typeof result === 'string')
@@ -87,13 +99,6 @@ function build(source, options) {
87
99
  rooted = true;
88
100
  pattern = pattern.replace(/^\/+/, '');
89
101
  }
90
- // A trailing slash means a directory's contents, except in an exclusion,
91
- // where `build/` and `build` exclude the same things.
92
- if (pattern.endsWith('/')) {
93
- pattern = pattern.replace(/\/+$/, '');
94
- if (options.dialect !== 'gitignore')
95
- pattern = `${pattern}/**`;
96
- }
97
102
  if (pattern.length === 0)
98
103
  return 'the pattern names the root itself, not a path under it';
99
104
  const expanded = expandBraces(pattern, escapes);
@@ -101,7 +106,13 @@ function build(source, options) {
101
106
  return expanded;
102
107
  const alternatives = [];
103
108
  for (const text of expanded) {
104
- const parsed = parseAlternative(text, escapes);
109
+ // Refused before its trailing slash is read, which would make `./` the
110
+ // contents of `.`, every path: `{./,a}` is refused as `./` alone is.
111
+ // Each text the braces give is shorter than the pattern, so only a
112
+ // pattern without braces is its own text.
113
+ if (namesNoPath(text))
114
+ return text === pattern ? 'the pattern names no path' : bracesNamingNoPath(text);
115
+ const parsed = parseAlternative(trailingSlash(text, options.dialect), escapes);
105
116
  if (parsed === GLOBSTAR_IN_NAME)
106
117
  return `${GLOBSTAR_IN_NAME}: ${globstarAdvice(written)}`;
107
118
  if (typeof parsed === 'string')
@@ -111,12 +122,23 @@ function build(source, options) {
111
122
  const builder = new Builder();
112
123
  const fragments = [];
113
124
  const bases = [];
114
- for (const alternative of alternatives) {
115
- const compiled = compileAlternative(builder, alternative, options, rooted, anchored);
116
- fragments.push(compiled.fragment);
117
- bases.push(compiled.base);
125
+ let automaton;
126
+ try {
127
+ for (const alternative of alternatives) {
128
+ const compiled = compileAlternative(builder, alternative, options, rooted, anchored);
129
+ fragments.push(compiled.fragment);
130
+ bases.push(compiled.base);
131
+ }
132
+ automaton = builder.finish(builder.either(fragments), options.caseSensitive);
133
+ }
134
+ catch (error) {
135
+ // A pattern too large to compile is refused with a reason, as a malformed
136
+ // one is. Anything else - a caller's literal reading that throws - is the
137
+ // caller's failure, not the pattern's, and goes on up.
138
+ if (error instanceof AutomatonTooLarge)
139
+ return error.message;
140
+ throw error;
118
141
  }
119
- const automaton = builder.finish(builder.either(fragments), options.caseSensitive);
120
142
  let matcher = null;
121
143
  return {
122
144
  source,
@@ -138,6 +160,12 @@ function build(source, options) {
138
160
  * Classes and escapes are skipped while looking for braces and commas, so
139
161
  * `{[,]x,y}` is two alternatives, `[,]x` and `y`. A lone `}` is a literal: it
140
162
  * cannot be read as anything else. An unclosed `{` is an error.
163
+ *
164
+ * Here and in the two functions after it, a loop that reads one step past
165
+ * the end reads `''`, which none of them acts on, and `classEnd` answers -1
166
+ * or an index past the `[`, so `close > 0` and `close >= 0` read the same.
167
+ * `open` is set by the `{` that any `}` read here closes, so its first value
168
+ * is never read.
141
169
  */
142
170
  function expandBraces(pattern, escapes) {
143
171
  let depth = 0;
@@ -233,6 +261,40 @@ function classEnd(pattern, open, escapes) {
233
261
  return -1;
234
262
  }
235
263
  /* ---------------------------------------------------------------- segments */
264
+ /** Whether a pattern's text names no path: nothing in it but `/` and `.` segments. */
265
+ function namesNoPath(text) {
266
+ return text.split('/').every((part) => part === '' || part === '.');
267
+ }
268
+ /**
269
+ * The refusal of an alternative the braces give that names no path, naming
270
+ * it as it was expanded, so that `.{/,a}` is told `./`, the text refused.
271
+ */
272
+ function bracesNamingNoPath(text) {
273
+ return text === '' ? 'the braces expand to an empty pattern' : `the braces expand to "${text}", which names no path`;
274
+ }
275
+ /**
276
+ * What a trailing slash means, read on each alternative the braces give, so
277
+ * that `{src/,lib}` reads `src/` as `src/` alone reads: the directory's
278
+ * contents, `src/**`, and not a literal that may be the directory itself.
279
+ *
280
+ * In an exclusion `build/` excludes what `build` does. Git's rule is that a
281
+ * trailing slash matches only a directory, and a directory is excluded with
282
+ * everything in it; a matcher that sees only a path cannot tell a directory
283
+ * from a file, so the slash is dropped, and it anchors nothing.
284
+ *
285
+ * Only ever given a text that names a path, so a name is left. The whole run
286
+ * of slashes is taken, but one slash would read the same, since
287
+ * `parseAlternative` drops the empty segments the rest leave; and taken
288
+ * lazily it is the whole run all the same, since it ends the text.
289
+ */
290
+ function trailingSlash(text, dialect) {
291
+ const name = text.replace(/\/+$/, '');
292
+ return name === text || dialect === 'gitignore' ? name : `${name}/**`;
293
+ }
294
+ /**
295
+ * The segments of a text that names a path - `build` refuses one that does
296
+ * not - so at least one segment is left.
297
+ */
236
298
  function parseAlternative(text, escapes) {
237
299
  const segments = [];
238
300
  const raw = text.split('/');
@@ -251,8 +313,6 @@ function parseAlternative(text, escapes) {
251
313
  return tokens;
252
314
  segments.push({ kind: 'name', tokens });
253
315
  }
254
- if (segments.length === 0)
255
- return 'the pattern names no path';
256
316
  return { segments, slashed: raw.filter((part) => part !== '' && part !== '.').length > 1 };
257
317
  }
258
318
  const EXTGLOB = 'extended globs such as "+(a|b)" are not supported: write alternatives as "{a,b}", and a literal parenthesis as "[(]"';