Skip to content

Commit 3a8f8bd

Browse files
committed
fix: [createTokenizer] moveOnBreak logic at end-of-file
Signed-off-by: Lexus Drumgold <unicornware@flexdevelopment.llc>
1 parent 1dbef66 commit 3a8f8bd

File tree

10 files changed

+144
-90
lines changed

10 files changed

+144
-90
lines changed

__fixtures__/constructs/cli.mts

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

66
import codes from '#enums/codes'
7+
import eof from '#fixtures/constructs/eof'
78
import longFlag from '#fixtures/constructs/flag-long'
89
import operand from '#fixtures/constructs/operand'
910
import type { ConstructRecord } from '@flex-development/vfile-tokenizer'
@@ -13,6 +14,6 @@ import type { ConstructRecord } from '@flex-development/vfile-tokenizer'
1314
*
1415
* @const {ConstructRecord} cli
1516
*/
16-
const cli: ConstructRecord = { [codes.hyphen]: longFlag, null: operand }
17+
const cli: ConstructRecord = { [codes.hyphen]: longFlag, null: [operand, eof] }
1718

1819
export default cli

__fixtures__/constructs/eof.mts

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import codes from '#enums/codes'
77
import tt from '#fixtures/tt'
8+
import eos from '#utils/eof'
89
import type {
910
Code,
1011
Construct,
@@ -21,26 +22,12 @@ import { ok as assert } from 'devlop'
2122
*/
2223
const eof: Construct = {
2324
name: tt.eof,
24-
test: testEOF,
25+
test: eos,
2526
tokenize: tokenizeEOF
2627
}
2728

2829
export default eof
2930

30-
/**
31-
* Check if the current character `code` can start the end of file construct.
32-
*
33-
* @this {TokenizeContext}
34-
*
35-
* @param {Code} code
36-
* The current character code
37-
* @return {boolean}
38-
* `true` if `code` can start construct
39-
*/
40-
function testEOF(this: TokenizeContext, code: Code): boolean {
41-
return code === codes.eof
42-
}
43-
4431
/**
4532
* Tokenize the end of file.
4633
*

src/__snapshots__/tokenize.integration.snap

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,46 @@ exports[`integration:tokenize > should work with constructs (1) 1`] = `
179179
"value": "",
180180
},
181181
],
182+
[
183+
"enter",
184+
{
185+
"end": {
186+
"_bufferIndex": -1,
187+
"_index": 2,
188+
"column": 14,
189+
"line": 1,
190+
"offset": 13,
191+
},
192+
"start": {
193+
"_bufferIndex": -1,
194+
"_index": 1,
195+
"column": 14,
196+
"line": 1,
197+
"offset": 13,
198+
},
199+
"type": "eof",
200+
},
201+
],
202+
[
203+
"exit",
204+
{
205+
"end": {
206+
"_bufferIndex": -1,
207+
"_index": 2,
208+
"column": 14,
209+
"line": 1,
210+
"offset": 13,
211+
},
212+
"start": {
213+
"_bufferIndex": -1,
214+
"_index": 1,
215+
"column": 14,
216+
"line": 1,
217+
"offset": 13,
218+
},
219+
"type": "eof",
220+
},
221+
],
182222
]
183223
`;
184224

@@ -316,6 +356,46 @@ exports[`integration:tokenize > should work with constructs (2) 1`] = `
316356
"value": "3",
317357
},
318358
],
359+
[
360+
"enter",
361+
{
362+
"end": {
363+
"_bufferIndex": -1,
364+
"_index": 3,
365+
"column": 18,
366+
"line": 1,
367+
"offset": 17,
368+
},
369+
"start": {
370+
"_bufferIndex": -1,
371+
"_index": 2,
372+
"column": 18,
373+
"line": 1,
374+
"offset": 17,
375+
},
376+
"type": "eof",
377+
},
378+
],
379+
[
380+
"exit",
381+
{
382+
"end": {
383+
"_bufferIndex": -1,
384+
"_index": 3,
385+
"column": 18,
386+
"line": 1,
387+
"offset": 17,
388+
},
389+
"start": {
390+
"_bufferIndex": -1,
391+
"_index": 2,
392+
"column": 18,
393+
"line": 1,
394+
"offset": 17,
395+
},
396+
"type": "eof",
397+
},
398+
],
319399
]
320400
`;
321401

@@ -546,6 +626,46 @@ exports[`integration:tokenize > should work with constructs (4) 1`] = `
546626
"value": "@flex-development/vfile-tokenizer",
547627
},
548628
],
629+
[
630+
"enter",
631+
{
632+
"end": {
633+
"_bufferIndex": -1,
634+
"_index": 3,
635+
"column": 43,
636+
"line": 1,
637+
"offset": 42,
638+
},
639+
"start": {
640+
"_bufferIndex": -1,
641+
"_index": 2,
642+
"column": 43,
643+
"line": 1,
644+
"offset": 42,
645+
},
646+
"type": "eof",
647+
},
648+
],
649+
[
650+
"exit",
651+
{
652+
"end": {
653+
"_bufferIndex": -1,
654+
"_index": 3,
655+
"column": 43,
656+
"line": 1,
657+
"offset": 42,
658+
},
659+
"start": {
660+
"_bufferIndex": -1,
661+
"_index": 2,
662+
"column": 43,
663+
"line": 1,
664+
"offset": 42,
665+
},
666+
"type": "eof",
667+
},
668+
],
549669
]
550670
`;
551671

src/__tests__/tokenize.integration.spec.mts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ import type {
2222
EventType,
2323
FileLike,
2424
List,
25+
Options,
2526
Token,
26-
TokenizeOptions,
2727
Value
2828
} from '@flex-development/vfile-tokenizer'
2929
import pkg from '@flex-development/vfile-tokenizer/package.json'
@@ -54,7 +54,7 @@ describe('integration:tokenize', () => {
5454

5555
it.each<[
5656
value: FileLike | List<FileLike | Value> | Value | null | undefined,
57-
options?: Partial<TokenizeOptions> | null | undefined
57+
options?: Partial<Options> | null | undefined
5858
]>([
5959
[['hello', 'world']],
6060
[read('__fixtures__/markdown/code-fenced.md'), { tabSize: 2 }]

src/create-tokenizer.mts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,10 @@ function createTokenizer(this: void, options: Options): TokenizeContext {
400400
if (context.code === codes.break && peek() !== codes.break) {
401401
context.previous = context.code
402402
context.code = code
403-
if (options.moveOnBreak) move(context.previous)
403+
404+
if (options.moveOnBreak && context.code !== codes.eof) {
405+
move(context.previous)
406+
}
404407
}
405408

406409
/**
@@ -769,8 +772,7 @@ function createTokenizer(this: void, options: Options): TokenizeContext {
769772
if (!Array.isArray(chunk)) { // not in buffer chunk.
770773
assert(place._bufferIndex < 0, 'expected negative `_bufferIndex`')
771774
code = chunk
772-
} else { // in buffer chunk.
773-
assert(place._bufferIndex >= 0, 'expected non-negative `_bufferIndex`')
775+
} else { // in or at end of buffer chunk.
774776
code = chunk[place._bufferIndex]
775777
}
776778
}

src/enums/codes.mts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ const codes = {
9090
digit7: 55, // 7
9191
digit8: 56, // 8
9292
digit9: 57, // 9
93-
colon: 58, // =
93+
colon: 58, // :
9494
semicolon: 59, // ;
9595
leftAngleBracket: 60, // <
9696
lt: 60, // <

src/interfaces/__tests__/options-tokenize.spec-d.mts

Lines changed: 0 additions & 28 deletions
This file was deleted.

src/interfaces/index.mts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ export type { default as Options } from '#interfaces/options'
1111
export type {
1212
default as PreprocessOptions
1313
} from '#interfaces/options-preprocess'
14-
export type { default as TokenizeOptions } from '#interfaces/options-tokenize'
1514
export type { default as Place } from '#interfaces/place'
1615
export type { default as Position } from '#interfaces/position'
1716
export type { default as Preprocess } from '#interfaces/preprocess'

src/interfaces/options-tokenize.mts

Lines changed: 0 additions & 30 deletions
This file was deleted.

src/tokenize.mts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import type {
1010
Event,
1111
FileLike,
1212
List,
13+
Options,
1314
TokenizeContext,
14-
TokenizeOptions,
1515
Value
1616
} from '@flex-development/vfile-tokenizer'
1717

@@ -21,34 +21,37 @@ import type {
2121
* @see {@linkcode Event}
2222
* @see {@linkcode FileLike}
2323
* @see {@linkcode List}
24-
* @see {@linkcode TokenizeOptions}
24+
* @see {@linkcode Options}
25+
* @see {@linkcode TokenizeContext}
2526
* @see {@linkcode Value}
2627
*
2728
* @this {void}
2829
*
2930
* @param {FileLike | List<FileLike | Value> | Value | null | undefined} value
3031
* The file, value, or list of files and/or values to tokenize
31-
* @param {TokenizeOptions} options
32-
* Configuration options
32+
* @param {Options | TokenizeContext} options
33+
* Configuration options or the tokenizer to use
3334
* @return {Event[]}
3435
* List of events
3536
*/
3637
function tokenize(
3738
this: void,
3839
value: FileLike | List<FileLike | Value> | Value | null | undefined,
39-
options: TokenizeOptions
40+
options: Options | TokenizeContext
4041
): Event[] {
4142
/**
4243
* Tokenize context.
4344
*
44-
* @const {TokenizeContext} context
45+
* @var {TokenizeContext} context
4546
*/
46-
const context: TokenizeContext = options.tokenizer ?? createTokenizer(options)
47+
let context: TokenizeContext = options as TokenizeContext
48+
49+
// create tokenizer.
50+
if (!('write' in options)) context = createTokenizer(options)
4751

4852
// write chunks to stream.
4953
if (value !== null && value !== undefined) {
50-
for (const chunk of toList(value)) context.write(chunk)
51-
context.write(codes.eof)
54+
for (const chunk of [...toList(value), codes.eof]) context.write(chunk)
5255
}
5356

5457
return [...context.events]

0 commit comments

Comments
 (0)