fast-check
Version:
Property based testing framework for JavaScript (like QuickCheck)
92 lines (91 loc) • 3.75 kB
JavaScript
import { stringify } from '../../../utils/stringify.js';
function raiseUnsupportedASTNode(astNode) {
return new Error(`Unsupported AST node! Received: ${stringify(astNode)}`);
}
function addMissingDotStarTraversalAddMissing(astNode, isFirst, isLast) {
if (!isFirst && !isLast) {
return astNode;
}
const traversalResults = { hasStart: false, hasEnd: false };
const revampedNode = addMissingDotStarTraversal(astNode, isFirst, isLast, traversalResults);
const missingStart = isFirst && !traversalResults.hasStart;
const missingEnd = isLast && !traversalResults.hasEnd;
if (!missingStart && !missingEnd) {
return revampedNode;
}
const expressions = [];
if (missingStart) {
expressions.push({ type: 'Assertion', kind: '^' });
expressions.push({
type: 'Repetition',
quantifier: { type: 'Quantifier', kind: '*', greedy: true },
expression: { type: 'Char', kind: 'meta', symbol: '.', value: '.', codePoint: Number.NaN },
});
}
expressions.push(revampedNode);
if (missingEnd) {
expressions.push({
type: 'Repetition',
quantifier: { type: 'Quantifier', kind: '*', greedy: true },
expression: { type: 'Char', kind: 'meta', symbol: '.', value: '.', codePoint: Number.NaN },
});
expressions.push({ type: 'Assertion', kind: '$' });
}
return { type: 'Group', capturing: false, expression: { type: 'Alternative', expressions } };
}
function addMissingDotStarTraversal(astNode, isFirst, isLast, traversalResults) {
switch (astNode.type) {
case 'Char':
return astNode;
case 'Repetition':
return astNode;
case 'Quantifier':
throw new Error(`Wrongly defined AST tree, Quantifier nodes not supposed to be scanned!`);
case 'Alternative':
traversalResults.hasStart = true;
traversalResults.hasEnd = true;
return {
...astNode,
expressions: astNode.expressions.map((node, index) => addMissingDotStarTraversalAddMissing(node, isFirst && index === 0, isLast && index === astNode.expressions.length - 1)),
};
case 'CharacterClass':
return astNode;
case 'ClassRange':
return astNode;
case 'Group': {
return {
...astNode,
expression: addMissingDotStarTraversal(astNode.expression, isFirst, isLast, traversalResults),
};
}
case 'Disjunction': {
traversalResults.hasStart = true;
traversalResults.hasEnd = true;
return {
...astNode,
left: astNode.left !== null ? addMissingDotStarTraversalAddMissing(astNode.left, isFirst, isLast) : null,
right: astNode.right !== null ? addMissingDotStarTraversalAddMissing(astNode.right, isFirst, isLast) : null,
};
}
case 'Assertion': {
if (astNode.kind === '^' || astNode.kind === 'Lookahead') {
traversalResults.hasStart = true;
return astNode;
}
else if (astNode.kind === '$' || astNode.kind === 'Lookbehind') {
traversalResults.hasEnd = true;
return astNode;
}
else {
throw new Error(`Assertions of kind ${astNode.kind} not implemented yet!`);
}
}
case 'Backreference':
return astNode;
default:
throw raiseUnsupportedASTNode(astNode);
}
}
export function addMissingDotStar(astNode) {
return addMissingDotStarTraversalAddMissing(astNode, true, true);
}