parseman 0.58.0 → 0.58.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/version.d.ts CHANGED
@@ -13,5 +13,5 @@
13
13
  * Kept in sync with `package.json` by `test/unit/version-sync.test.ts`, which fails
14
14
  * the build if this constant drifts from the published version.
15
15
  */
16
- export declare const PARSEMAN_VERSION = "0.58.0";
16
+ export declare const PARSEMAN_VERSION = "0.58.2";
17
17
  //# sourceMappingURL=version.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "parseman",
3
- "version": "0.58.0",
3
+ "version": "0.58.2",
4
4
  "packageManager": "pnpm@10.15.1",
5
5
  "engines": {
6
6
  "node": "^20.19.0 || >=22.13.0"
@@ -95,6 +95,7 @@
95
95
  "perf:guard": "node --import tsx/esm bench/perf-guard.ts",
96
96
  "perf:guard:grammars": "node --import tsx/esm bench/grammar-perf-guard.ts",
97
97
  "perf:xproc": "node --import tsx/esm bench/xproc-ab.ts",
98
+ "perf:xproc:gate": "node --import tsx/esm bench/xproc-gate.ts",
98
99
  "prepare": "git config core.hooksPath scripts/git-hooks || true; node scripts/build.mjs",
99
100
  "prepublishOnly": "node scripts/check-changelog.mjs --publish",
100
101
  "check:changelog": "node scripts/check-changelog.mjs",
package/src/cli/index.ts CHANGED
@@ -44,7 +44,7 @@
44
44
  import { readFileSync, writeFileSync, readdirSync, statSync } from 'node:fs'
45
45
  import { resolve, relative, join, extname } from 'node:path'
46
46
  import { pathToFileURL } from 'node:url'
47
- import { register } from 'node:module'
47
+ import * as nodeModule from 'node:module'
48
48
  import { diagnoseGrammar, examinedNothing, type GrammarDiagnosis } from '../analysis/diagnose.ts'
49
49
  import { renderDiagnosis } from '../analysis/diagnose-render.ts'
50
50
  import { DEFAULT_WIDTH } from '../analysis/terminal.ts'
@@ -147,6 +147,11 @@ async function registerTsIfNeeded(path: string): Promise<void> {
147
147
  *
148
148
  * Source is not rewritten: the attribute is removed from the load/resolve CONTEXT, so
149
149
  * nothing depends on parsing the importer's text.
150
+ *
151
+ * The hooks return whatever the next hook returns, without awaiting it, so the same
152
+ * module serves both hook APIs: `registerHooks()` runs it in-thread, where `next*`
153
+ * returns a result, and `register()` runs it on the hooks thread, where it returns a
154
+ * promise.
150
155
  */
151
156
  const MACRO_ATTR_HOOK = `
152
157
  const strip = (context) => {
@@ -156,18 +161,25 @@ const strip = (context) => {
156
161
  delete rest.type
157
162
  return { ...context, importAttributes: rest }
158
163
  }
159
- export async function resolve(specifier, context, nextResolve) {
164
+ export function resolve(specifier, context, nextResolve) {
160
165
  return nextResolve(specifier, strip(context))
161
166
  }
162
- export async function load(url, context, nextLoad) {
167
+ export function load(url, context, nextLoad) {
163
168
  return nextLoad(url, strip(context))
164
169
  }
165
170
  `
166
171
  let macroAttrRegistered = false
167
- function registerMacroAttributeHook(): void {
172
+ async function registerMacroAttributeHook(): Promise<void> {
168
173
  if (macroAttrRegistered) return
169
174
  macroAttrRegistered = true
170
- register(`data:text/javascript,${encodeURIComponent(MACRO_ATTR_HOOK)}`)
175
+ const url = `data:text/javascript,${encodeURIComponent(MACRO_ATTR_HOOK)}`
176
+ // `register()` is deprecated from Node 26 (DEP0205) and prints a warning into the
177
+ // CLI's stderr. `registerHooks()` replaces it but only exists from 22.15 / 23.5, so
178
+ // the 20.x and early-22.x lines in `engines` keep the old API.
179
+ if (typeof nodeModule.registerHooks === 'function') {
180
+ nodeModule.registerHooks(await import(url) as nodeModule.RegisterHooksOptions)
181
+ }
182
+ else nodeModule.register(url)
171
183
  }
172
184
 
173
185
  async function loadGrammar(path: string, exportName: string | undefined): Promise<unknown> {
@@ -176,7 +188,7 @@ async function loadGrammar(path: string, exportName: string | undefined): Promis
176
188
  catch { throw new CliError(`no such grammar module: ${path}`) }
177
189
  await registerTsIfNeeded(abs)
178
190
  // AFTER the TS loader, so this hook is outermost and `nextLoad` still runs it.
179
- registerMacroAttributeHook()
191
+ await registerMacroAttributeHook()
180
192
  let mod: Record<string, unknown>
181
193
  try { mod = await import(pathToFileURL(abs).href) as Record<string, unknown> }
182
194
  catch (e) {
package/src/run/index.ts CHANGED
@@ -25,6 +25,11 @@
25
25
  * const result = run(myGrammar, source, { trivia })
26
26
  */
27
27
  export { buildRootTriviaIndex } from '../cst/trivia-entries.ts'
28
+ // Line/column lookup for the spans and errors `run()` returns. `line-index.ts` is
29
+ // already in the driver's closure (recovery annotates errors with it), so exposing
30
+ // it here costs no module — a caller reporting positions need not import the main entry.
31
+ export { buildLineIndex, offsetToLineCol } from '../line-index.ts'
32
+ export type { LineIndex } from '../line-index.ts'
28
33
  export { run } from '../functional/run.ts'
29
34
  export type { RootTriviaCapture, Runnable, RunOptions, RunResult } from '../functional/run.ts'
30
35
  export type { RootTriviaGap, RootTriviaIndex, TriviaEntriesView } from '../cst/trivia-entries.ts'
@@ -983,17 +983,20 @@ class Encoder {
983
983
  const rr = this.refResolver()
984
984
  const { next, boundary } = follow
985
985
  if (matchesEmpty(next, new Set(), rr) || mayCommitFailure(next, rr, this.commitFailureMemo)) return undefined
986
- // A miss reports `deriveExpected(next)`, a static set. Only a terminal or a
987
- // label fails with exactly that set: a sequence over an `optional` prefix
988
- // reports the prefix's labels statically but not when it runs, and a choice
989
- // whose arms share an opener reports that opener once statically, once per
990
- // arm when it runs.
991
- const nextTag = (next._def as ParserDef).tag
992
- if (nextTag !== 'literal' && nextTag !== 'regex' && nextTag !== 'keywords' && nextTag !== 'label') return undefined
986
+ // A miss reports the set `next` fails with at its start, so only a row with
987
+ // one such set is gated: a terminal, which fails with its own spelling
988
+ // (`directTerminalFailureExpected` — `keywords()` and `word()` say `keyword`,
989
+ // not each word as `deriveExpected` lists them), or a label, which fails with
990
+ // its name. A sequence over an `optional` prefix reports the prefix's labels
991
+ // statically but not when it runs, and a choice whose arms share an opener
992
+ // reports that opener once statically, once per arm when it runs.
993
+ const nextDef = next._def as ParserDef
994
+ if (nextDef.tag !== 'literal' && nextDef.tag !== 'regex' && nextDef.tag !== 'keywords' && nextDef.tag !== 'label') return undefined
993
995
  const first = firstSetOf(next, new Set(), rr, boundary)
994
996
  const cls = this.charClass(boundary === undefined ? first : union(first, firstSetOf(boundary, new Set(), rr)))
995
997
  if (cls < 0) return undefined
996
- return { cls, fx: this.expected(deriveExpected(next)) }
998
+ const miss = nextDef.tag === 'label' ? deriveExpected(next) : directTerminalFailureExpected(nextDef)
999
+ return { cls, fx: this.expected(miss) }
997
1000
  }
998
1001
 
999
1002
  node(p: Combinator<unknown>): Emitted {
package/src/version.ts CHANGED
@@ -13,4 +13,4 @@
13
13
  * Kept in sync with `package.json` by `test/unit/version-sync.test.ts`, which fails
14
14
  * the build if this constant drifts from the published version.
15
15
  */
16
- export const PARSEMAN_VERSION = '0.58.0'
16
+ export const PARSEMAN_VERSION = '0.58.2'