For writing tests, cursornext provides you with the caret syntax.
import { t } from 'cursornext'
const { cursor, target } = t
.capture('-----🌵(cursor)1992🌵(target)------12---86---')
.toMap()
In cursornext, there are two syntax styles:
- Inline style
- Block style
In inline style syntax, the cursor name is wrapped inside parentheses and prefixed with the 🌵
symbol (which is Alt + 127797
on Windows).
-----🌵(cursor)1992🌵(target)------12---86---
To generate test case from the inline syntax, you can use inline()
method:
const { cursor, target } = t
.inline('----🌵(cursor)1992🌵(target)------12---86---')
.toMap()
In block style syntax, lines from document are marked with line numbers. Lines without line numbers are used to describe cursors positions.
1 | -----1992------12---86---
| ^ ^
| | target
| cursor
To generate test case from the block syntax, we can use the block()
method:
const { cursor, target } = t
.block(
`
1 | -----1992------12---86---
| ^ ^
| | target
| cursor
`
)
.toMap()
The following function takes a cursor as an input, parse an integer and returns the corresponding token. If the input string does not match, it returns null
:
function parseInteger(cursor: Cursor) {
const marker = cursor.clone()
if (!cursor.exec(/^[0-9]/)) {
return null
}
while (cursor.exec(/^[0-9]/)) {
cursor.next(1)
}
const value = parseInt(marker.takeUntil(cursor))
return {
type: 'Integer',
value,
}
}
Given the following caret syntax:
1 | -----1992------12---86---
| ^ ^
| | target
| cursor
After running parseInteger
, the cursor is expected to be at the target position, a token is returned.
1 | -----1992------12---86---
| ^
| target
| cursor
The equivalent test case would be:
const { cursor, target } = t
.block(
`
1 | -----1992------12---86---
| ^ ^
| | target
| cursor
`
)
.toMap()
const token = parseInteger(cursor)
t.assert(cursor.isAt(target))
t.deepEqual(token, {
type: 'Integer',
value: 1992,
})
Returns a map of cursors with each key is a respective label.
const { cursor, target } = t
.inline('-----🌵(cursor)1992🌵(target)------12---86---')
.toMap()
Returns an array of captured cursors.
const [cursor, target] = t
.inline('-----🌵(cursor)1992🌵(target)------12---86---')
.toArray()
Returns an iterator, which can be used to iterate over the list of captured cursors in order.
const iter = t
.inline('-----🌵1992🌵------🌵12🌵---🌵86🌵---')
.toIter()
for (const value in [1992, 12, 86]) {
const cursor = iter.next()
const target = iter.next()
const token = parseInteger(cursor)
t.is(token, null)
t.is(token.type, 'Interger')
t.is(token.value, value)
}
For people who prefer to work with iterator, we can explicitly omit the labeled cursors by setting noLabel
option to true
.
const iter = t
.inline('-----🌵1992🌵------🌵12🌵---🌵86🌵---', {
noLabel: true,
})
.toIter()
Returns captured cursors by pairs. To use toPairs()
, cursor label should be renamed to contains start
and end
keywords. The pair labels are named using the inner cursor labels.
const pairs = t
.block(
`
1 | {
2 | "type": "Integer",
| ^ ^ ^ ^
| | | | end(value)
| | | | end(field)
| | | start(value)
| | end(key)
| start(key)
| start(field)
|
3 | "value": 1992
4 | }
5 |
`
)
.toPairs()
t.is(pairs.length, 3)
for (const { label, start, end } of pairs) {
const value = start.takeUntil(end)
switch (label) {
case 'key':
t.is(value, '"type"')
break
case 'value':
t.is(value, '"Integer"')
break
case 'field':
t.is(value, '"type": "Integer"')
break
default:
break
}
}
There are three ways we can change the configuration of the test object:
- Change the configuration per test case.
- Change the global configuration.
- Create a custom test object.
You can config the test object per test case by passing config options as the second parameter:
t.capture('-----🔥1992🔥------12---86---', {
prefix: '🔥',
noLabel: true,
})
The global configuration can be changed by using config()
:
t.config({
prefix: '🔥',
noLabel: true,
})
In caret syntax, empty labels are named none
by default.
const captureResult = t.capture(
'🌵()function 🌵()() 🌵(){ console.log("Ok!") }🌵()'
)
The above code would be rendered as:
1 | function () { console.log("Ok!") }
| ^ ^ ^ ^
| | | | none
| | | none
| | none
| none
t.is(captureResult.toArray().length, 4)
The symbol
label is used not to generate a new cursor but to insert the prefix symbol 🌵
to the document instead. It is often used in inline syntax where prefix symbol are often escaped. The following syntax:
Hello, cactus! 🌵(symbol)
Would be rendered as:
1 | Hello, cactus! 🌵