Skip to content

Commit ca3aace

Browse files
committed
feat: parser start point
Signed-off-by: Lexus Drumgold <[email protected]>
1 parent 0c6f1ee commit ca3aace

File tree

9 files changed

+268
-114
lines changed

9 files changed

+268
-114
lines changed

README.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -340,13 +340,16 @@ Configuration options (TypeScript type).
340340

341341
#### Properties
342342

343-
- `codeblocks` (`OneOrMany<RegExp | string>`, optional) &mdash; block tag node names and tags, or regular
344-
expressions, matching block tags that should have their text converted to [`Code`][mdast-code] when parsed as markdown
343+
- `codeblocks` (`OneOrMany<RegExp | string>`, optional) &mdash; block tag names, or regular expressions, matching block
344+
tags that should have their text converted to [`Code`][mdast-code] when parsed as markdown
345345
- **default**: `'example'`
346-
- `mdastExtensions` ([`MdastExtension[]`][mdast-util-extension], optional) &mdash; markdown extensions to change how
346+
- `from` ([`docast.Point`][docast-point], optional) &mdash; parser start point. node positions will be relative to this
347+
point
348+
- **default**: `{ column: 1, line: 1, offset: 0 }`
349+
- `mdastExtensions` ([`mdast.Extension[]`][mdast-extension], optional) &mdash; markdown extensions to change how
347350
micromark tokens are converted to nodes
348-
- `micromarkExtensions` ([`MicromarkExtension[]`][micromark-extension], optional) &mdash; micromark extensions to change
349-
how markdown is parsed
351+
- `micromarkExtensions` ([`micromark.Extension[]`][micromark-extension], optional) &mdash; micromark extensions to
352+
change how markdown is parsed
350353
- `transforms` ([`Transform[]`](#transform), optional) &mdash; tree transforms
351354

352355
### `Transform`
@@ -386,13 +389,14 @@ This package is fully typed with [TypeScript][typescript].
386389
See [`CONTRIBUTING.md`](CONTRIBUTING.md).
387390

388391
[docast-parse]: https://github.com/flex-development/docast-parse
392+
[docast-point]: https://github.com/flex-development/docast#point
389393
[docast-tree]: https://github.com/flex-development/docast#root
390394
[docast]: https://github.com/flex-development/docast
391395
[docblock]: https://github.com/flex-development/docast#docblock-comment
392396
[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
393397
[esmsh]: https://esm.sh/
394398
[mdast-code]: https://github.com/syntax-tree/mdast#code
395-
[mdast-util-extension]: https://github.com/syntax-tree/mdast-util-from-markdown#extension
399+
[mdast-extension]: https://github.com/syntax-tree/mdast-util-from-markdown#extension
396400
[mdast-util-from-markdown]: https://github.com/syntax-tree/mdast-util-from-markdown
397401
[micromark-extension]: https://github.com/micromark/micromark#extensions
398402
[micromark]: https://github.com/micromark/micromark

src/__snapshots__/util.integration.snap

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -592,3 +592,112 @@ root[14]
592592
├─3 text "-th character or " (190:29-190:46, 4727-4744)
593593
└─4 inlineCode "null" (190:46-190:52, 4744-4750)
594594
`;
595+
596+
exports[`integration:fromDocs > non-empty snippet > snippet sample 0 1`] = `
597+
root[1]
598+
└─0 comment[7] (110:3-138:6, 2388-3460)
599+
code: null
600+
├─0 description[12] (111:6-128:42, 2397-3216)
601+
│ ├─0 paragraph[5] (111:6-111:53, 2397-2444)
602+
│ │ ├─0 text "Get a " (111:6-111:12, 2397-2403)
603+
│ │ ├─1 linkReference[1] (111:12-111:24, 2403-2415)
604+
│ │ │ │ label: "1"
605+
│ │ │ │ identifier: "1"
606+
│ │ │ │ referenceType: "full"
607+
│ │ │ └─0 emphasis[1] (111:13-111:20, 2404-2411)
608+
│ │ │ └─0 text "point" (111:14-111:19, 2405-2410)
609+
│ │ ├─2 text " in the document by " (111:24-111:44, 2415-2435)
610+
│ │ ├─3 inlineCode "offset" (111:44-111:52, 2435-2443)
611+
│ │ └─4 text "." (111:52-111:53, 2443-2444)
612+
│ ├─1 break (111:53-112:1, 2444-2445)
613+
│ ├─2 break (112:5-113:1, 2449-2450)
614+
│ │ data: {"blank":true}
615+
│ ├─3 paragraph[13] (113:6-114:76, 2455-2606)
616+
│ │ ├─0 text "The given " (113:6-113:16, 2455-2465)
617+
│ │ ├─1 inlineCode "offset" (113:16-113:24, 2465-2473)
618+
│ │ ├─2 text " must be an integer in the range " (113:24-113:57, 2473-2506)
619+
│ │ ├─3 inlineCode "[0, document.length]" (113:57-113:79, 2506-2528)
620+
│ │ ├─4 text "." (113:79-113:80, 2528-2529)
621+
│ │ ├─5 break (113:80-113:81, 2529-2530)
622+
│ │ │ data: {"hard":true}
623+
│ │ ├─6 text "If invalid, " (114:6-114:18, 2536-2548)
624+
│ │ ├─7 inlineCode "point.column" (114:18-114:32, 2548-2562)
625+
│ │ ├─8 text " and " (114:32-114:37, 2562-2567)
626+
│ │ ├─9 inlineCode "point.line" (114:37-114:49, 2567-2579)
627+
│ │ ├─10 text " will have a value of " (114:49-114:71, 2579-2601)
628+
│ │ ├─11 inlineCode "-1" (114:71-114:75, 2601-2605)
629+
│ │ └─12 text "." (114:75-114:76, 2605-2606)
630+
│ ├─4 break (114:76-115:1, 2606-2607)
631+
│ ├─5 break (115:5-116:1, 2611-2612)
632+
│ │ data: {"blank":true}
633+
│ ├─6 blockquote[7] (116:6-124:35, 2617-3064)
634+
│ │ ├─0 paragraph[4] (116:8-116:63, 2619-2674)
635+
│ │ │ ├─0 strong[1] (116:8-116:17, 2619-2628)
636+
│ │ │ │ └─0 text "Point" (116:10-116:15, 2621-2626)
637+
│ │ │ ├─1 text " represents one place in a source " (116:17-116:51, 2628-2662)
638+
│ │ │ ├─2 linkReference[1] (116:51-116:62, 2662-2673)
639+
│ │ │ │ │ label: "2"
640+
│ │ │ │ │ identifier: "2"
641+
│ │ │ │ │ referenceType: "full"
642+
│ │ │ │ └─0 emphasis[1] (116:52-116:58, 2663-2669)
643+
│ │ │ │ └─0 text "file" (116:53-116:57, 2664-2668)
644+
│ │ │ └─3 text "." (116:62-116:63, 2673-2674)
645+
│ │ ├─1 break (116:63-117:1, 2674-2675)
646+
│ │ ├─2 break (117:7-118:1, 2681-2682)
647+
│ │ │ data: {"blank":true}
648+
│ │ ├─3 paragraph[13] (118:8-121:35, 2689-2945)
649+
│ │ │ ├─0 text "The " (118:8-118:12, 2689-2693)
650+
│ │ │ ├─1 inlineCode "line" (118:12-118:18, 2693-2699)
651+
│ │ │ ├─2 text " field (" (118:18-118:26, 2699-2707)
652+
│ │ │ ├─3 inlineCode "1" (118:26-118:29, 2707-2710)
653+
│ │ │ ├─4 text "-indexed integer) represents a line in a source file. The " (118:29-119:18, 2710-2775)
654+
│ │ │ ├─5 inlineCode "column" (119:18-119:26, 2775-2783)
655+
│ │ │ ├─6 text " field (" (119:26-119:34, 2783-2791)
656+
│ │ │ ├─7 inlineCode "1" (119:34-119:37, 2791-2794)
657+
│ │ │ ├─8 text "-indexed integer) represents a column in a source file. The " (119:37-120:25, 2794-2861)
658+
│ │ │ ├─9 inlineCode "offset" (120:25-120:33, 2861-2869)
659+
│ │ │ ├─10 text " field (" (120:33-120:41, 2869-2877)
660+
│ │ │ ├─11 inlineCode "0" (120:41-120:44, 2877-2880)
661+
│ │ │ └─12 text "-indexed integer) represents a character in a source file." (120:44-121:35, 2880-2945)
662+
│ │ ├─4 break (121:35-122:1, 2945-2946)
663+
│ │ ├─5 break (122:7-123:1, 2952-2953)
664+
│ │ │ data: {"blank":true}
665+
│ │ └─6 paragraph[3] (123:8-124:35, 2960-3064)
666+
│ │ ├─0 text "The term character means a (UTF-16) code unit which is defined in the " (123:8-124:1, 2960-3030)
667+
│ │ ├─1 linkReference[1] (124:8-124:20, 3037-3049)
668+
│ │ │ │ label: "3"
669+
│ │ │ │ identifier: "3"
670+
│ │ │ │ referenceType: "full"
671+
│ │ │ └─0 text "Web IDL" (124:9-124:16, 3038-3045)
672+
│ │ └─2 text " specification." (124:20-124:35, 3049-3064)
673+
│ ├─7 break (124:35-125:1, 3064-3065)
674+
│ ├─8 break (125:5-126:1, 3069-3070)
675+
│ │ data: {"blank":true}
676+
│ ├─9 definition (126:6-126:53, 3075-3122)
677+
│ │ identifier: "1"
678+
│ │ label: "1"
679+
│ │ title: null
680+
│ │ url: "https://github.com/syntax-tree/unist#point"
681+
│ ├─10 definition (127:6-127:52, 3128-3174)
682+
│ │ identifier: "2"
683+
│ │ label: "2"
684+
│ │ title: null
685+
│ │ url: "https://github.com/syntax-tree/unist#file"
686+
│ └─11 definition (128:6-128:42, 3180-3216)
687+
identifier: "3"
688+
label: "3"
689+
title: null
690+
url: "https://webidl.spec.whatwg.org/"
691+
├─1 blockTag<@see>[1] (130:6-130:28, 3227-3249)
692+
│ └─0 inlineTag<@linkcode> "Point" (130:11-130:28, 3232-3249)
693+
├─2 blockTag<@see>[1] (131:6-131:53, 3255-3302)
694+
│ └─0 text "https://github.com/syntax-tree/unist#point" (131:11-131:53, 3260-3302)
695+
├─3 blockTag<@public>[0] (133:6-133:13, 3313-3320)
696+
├─4 blockTag<@instance>[0] (134:6-134:15, 3326-3335)
697+
├─5 blockTag<@param>[2] (136:6-136:75, 3346-3415)
698+
│ ├─0 typeExpression "number?" (136:13-136:22, 3353-3362)
699+
│ └─1 text "[offset=this.index] - Index of character in document" (136:23-136:75, 3363-3415)
700+
└─6 blockTag<@return>[2] (137:6-137:39, 3421-3454)
701+
├─0 typeExpression "Point" (137:14-137:21, 3429-3436)
702+
└─1 text "Point in document" (137:22-137:39, 3437-3454)
703+
`;

src/__tests__/util.integration.spec.ts

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
* @module docast-util-from-docs/tests/util/integration
44
*/
55

6-
import { constant } from '@flex-development/tutils'
6+
import type { Point } from '@flex-development/docast'
7+
import { constant, type Assign } from '@flex-development/tutils'
78
import { directiveFromMarkdown } from 'mdast-util-directive'
89
import { directive } from 'micromark-extension-directive'
910
import { read } from 'to-vfile'
@@ -14,20 +15,20 @@ import type { Options } from '../interfaces'
1415
import testSubject from '../util'
1516

1617
describe('integration:fromDocs', () => {
18+
beforeEach((ctx: TestContext): void => {
19+
ctx.expect.addSnapshotSerializer({
20+
print: (val: unknown): string => inspectNoColor(val),
21+
test: constant(true)
22+
})
23+
})
24+
1725
describe('empty document', () => {
1826
it('should parse empty document', () => {
1927
expect(testSubject('')).to.eql({ children: [], type: 'root' })
2028
})
2129
})
2230

2331
describe('non-empty document', async () => {
24-
beforeEach((ctx: TestContext): void => {
25-
ctx.expect.addSnapshotSerializer({
26-
print: (val: unknown): string => inspectNoColor(val),
27-
test: constant(true)
28-
})
29-
})
30-
3132
it.each<[VFile, Options?]>([
3233
[await read('__fixtures__/validate-url-string.ts'), { codeblocks: null }],
3334
[await read('__fixtures__/detect-syntax.ts'), { codeblocks: /@example/ }],
@@ -41,4 +42,19 @@ describe('integration:fromDocs', () => {
4142
expect(testSubject(file, options)).toMatchSnapshot()
4243
})
4344
})
45+
46+
describe('non-empty snippet', async () => {
47+
it.each<[VFile, Assign<Options, { end: number; from: Point }>]>([
48+
[await read('__fixtures__/reader.ts'), {
49+
end: 3461,
50+
from: { column: 3, line: 110, offset: 2388 }
51+
}]
52+
])('snippet sample %#', (file, { end, from }) => {
53+
// Arrange
54+
const snippet: string = String(file).slice(from.offset, end)
55+
56+
// Act + Expect
57+
expect(testSubject(snippet, { from })).toMatchSnapshot()
58+
})
59+
})
4460
})

src/interfaces/__tests__/options.spec-d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55

66
import type { Transform } from '#src/types'
7+
import type { Point } from '@flex-development/docast'
78
import type { Nilable, OneOrMany } from '@flex-development/tutils'
89
import type { Extension as MdastExtension } from 'mdast-util-from-markdown'
910
import type { Extension as MicromarkExtension } from 'micromark-util-types'
@@ -16,6 +17,12 @@ describe('unit-d:interfaces/Options', () => {
1617
.toEqualTypeOf<Nilable<OneOrMany<RegExp | string>>>()
1718
})
1819

20+
it('should match [from?: Nilable<Point>]', () => {
21+
expectTypeOf<TestSubject>()
22+
.toHaveProperty('from')
23+
.toEqualTypeOf<Nilable<Point>>()
24+
})
25+
1926
it('should match [mdastExtensions?: Nilable<MdastExtension[]>]', () => {
2027
expectTypeOf<TestSubject>()
2128
.toHaveProperty('mdastExtensions')

src/interfaces/options.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55

66
import type { Transform } from '#src/types'
7+
import type { Point } from '@flex-development/docast'
78
import type { Nilable, OneOrMany } from '@flex-development/tutils'
89
import type { Code } from 'mdast'
910
import type { Extension as MdastExtension } from 'mdast-util-from-markdown'
@@ -21,6 +22,15 @@ interface Options {
2122
*/
2223
codeblocks?: Nilable<OneOrMany<RegExp | string>>
2324

25+
/**
26+
* Parser start point.
27+
*
28+
* Node positions will be relative to this point.
29+
*
30+
* @see {@linkcode Point}
31+
*/
32+
from?: Nilable<Point>
33+
2434
/**
2535
* Markdown extensions to change how micromark tokens are converted to nodes.
2636
*

src/lexer.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
*/
55

66
import type { Point } from '@flex-development/docast'
7-
import type { Optional } from '@flex-development/tutils'
7+
import type { Nilable, Optional } from '@flex-development/tutils'
88
import debug from 'debug'
99
import { ok } from 'devlop'
1010
import type { VFile } from 'vfile'
@@ -94,11 +94,12 @@ class Lexer {
9494
* @see {@linkcode VFile}
9595
*
9696
* @param {VFile | string} source - Source document or file
97+
* @param {Nilable<Point>?} [from] - Point before first character in `source`
9798
*/
98-
constructor(source: VFile | string) {
99+
constructor(source: VFile | string, from?: Nilable<Point>) {
99100
this.comment = false
100101
this.debug = debug('docast-util-from-docs:lexer')
101-
this.reader = new Reader(source)
102+
this.reader = new Reader(source, from)
102103
this.tokens = []
103104

104105
this.head = this.tokenize()
@@ -305,7 +306,7 @@ class Lexer {
305306
* @return {Point} Current point in document
306307
*/
307308
protected now(): Point {
308-
return this.reader.point(this.reader.index)
309+
return this.reader.point(this.reader.from.offset + this.reader.index)
309310
}
310311

311312
/**

0 commit comments

Comments
 (0)