chore(web): add and apply eslint formatting
This commit is contained in:
parent
5f63074057
commit
96a440af35
11 changed files with 622 additions and 569 deletions
22
lib/binding_web/.eslintrc.js
Normal file
22
lib/binding_web/.eslintrc.js
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
module.exports = {
|
||||
'env': {
|
||||
'commonjs': true,
|
||||
'es2021': true,
|
||||
},
|
||||
'extends': 'google',
|
||||
'overrides': [
|
||||
],
|
||||
'parserOptions': {
|
||||
'ecmaVersion': 'latest',
|
||||
'sourceType': 'module',
|
||||
},
|
||||
'rules': {
|
||||
'indent': ['error', 2, {'SwitchCase': 1}],
|
||||
'max-len': [
|
||||
'error',
|
||||
{'code': 120, 'ignoreComments': true, 'ignoreUrls': true, 'ignoreStrings': true, 'ignoreTemplateLiterals': true},
|
||||
],
|
||||
'require-jsdoc': 0,
|
||||
'new-cap': 0,
|
||||
},
|
||||
};
|
||||
|
|
@ -13,12 +13,14 @@ const PREDICATE_STEP_TYPE_STRING = 2;
|
|||
|
||||
const LANGUAGE_FUNCTION_REGEX = /^_?tree_sitter_\w+/;
|
||||
|
||||
var VERSION;
|
||||
var MIN_COMPATIBLE_VERSION;
|
||||
var TRANSFER_BUFFER;
|
||||
var currentParseCallback;
|
||||
var currentLogCallback;
|
||||
let VERSION;
|
||||
let MIN_COMPATIBLE_VERSION;
|
||||
let TRANSFER_BUFFER;
|
||||
let currentParseCallback;
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
let currentLogCallback;
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
class ParserImpl {
|
||||
static init() {
|
||||
TRANSFER_BUFFER = C._ts_init();
|
||||
|
|
@ -50,7 +52,7 @@ class ParserImpl {
|
|||
if (version < MIN_COMPATIBLE_VERSION || VERSION < version) {
|
||||
throw new Error(
|
||||
`Incompatible language version ${version}. ` +
|
||||
`Compatibility range ${MIN_COMPATIBLE_VERSION} through ${VERSION}.`
|
||||
`Compatibility range ${MIN_COMPATIBLE_VERSION} through ${VERSION}.`,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -62,7 +64,7 @@ class ParserImpl {
|
|||
}
|
||||
|
||||
getLanguage() {
|
||||
return this.language
|
||||
return this.language;
|
||||
}
|
||||
|
||||
parse(callback, oldTree, options) {
|
||||
|
|
@ -71,7 +73,7 @@ class ParserImpl {
|
|||
} else if (typeof callback === 'function') {
|
||||
currentParseCallback = callback;
|
||||
} else {
|
||||
throw new Error("Argument must be a string or a function");
|
||||
throw new Error('Argument must be a string or a function');
|
||||
}
|
||||
|
||||
if (this.logCallback) {
|
||||
|
|
@ -99,7 +101,7 @@ class ParserImpl {
|
|||
this[1],
|
||||
oldTree ? oldTree[0] : 0,
|
||||
rangeAddress,
|
||||
rangeCount
|
||||
rangeCount,
|
||||
);
|
||||
|
||||
if (!treeAddress) {
|
||||
|
|
@ -129,8 +131,8 @@ class ParserImpl {
|
|||
setLogger(callback) {
|
||||
if (!callback) {
|
||||
callback = null;
|
||||
} else if (typeof callback !== "function") {
|
||||
throw new Error("Logger callback must be a function");
|
||||
} else if (typeof callback !== 'function') {
|
||||
throw new Error('Logger callback must be a function');
|
||||
}
|
||||
this.logCallback = callback;
|
||||
return this;
|
||||
|
|
@ -403,7 +405,7 @@ class Node {
|
|||
startPosition.row,
|
||||
startPosition.column,
|
||||
endPosition.row,
|
||||
endPosition.column
|
||||
endPosition.column,
|
||||
);
|
||||
|
||||
// Instantiate the nodes based on the data returned.
|
||||
|
|
@ -460,7 +462,7 @@ class Node {
|
|||
}
|
||||
|
||||
marshalNode(this);
|
||||
let address = TRANSFER_BUFFER + SIZE_OF_NODE;
|
||||
const address = TRANSFER_BUFFER + SIZE_OF_NODE;
|
||||
setValue(address, start, 'i32');
|
||||
setValue(address + SIZE_OF_INT, end, 'i32');
|
||||
C._ts_node_descendant_for_index_wasm(this.tree[0]);
|
||||
|
|
@ -473,7 +475,7 @@ class Node {
|
|||
}
|
||||
|
||||
marshalNode(this);
|
||||
let address = TRANSFER_BUFFER + SIZE_OF_NODE;
|
||||
const address = TRANSFER_BUFFER + SIZE_OF_NODE;
|
||||
setValue(address, start, 'i32');
|
||||
setValue(address + SIZE_OF_INT, end, 'i32');
|
||||
C._ts_node_named_descendant_for_index_wasm(this.tree[0]);
|
||||
|
|
@ -486,7 +488,7 @@ class Node {
|
|||
}
|
||||
|
||||
marshalNode(this);
|
||||
let address = TRANSFER_BUFFER + SIZE_OF_NODE;
|
||||
const address = TRANSFER_BUFFER + SIZE_OF_NODE;
|
||||
marshalPoint(address, start);
|
||||
marshalPoint(address + SIZE_OF_POINT, end);
|
||||
C._ts_node_descendant_for_position_wasm(this.tree[0]);
|
||||
|
|
@ -499,7 +501,7 @@ class Node {
|
|||
}
|
||||
|
||||
marshalNode(this);
|
||||
let address = TRANSFER_BUFFER + SIZE_OF_NODE;
|
||||
const address = TRANSFER_BUFFER + SIZE_OF_NODE;
|
||||
marshalPoint(address, start);
|
||||
marshalPoint(address + SIZE_OF_POINT, end);
|
||||
C._ts_node_named_descendant_for_position_wasm(this.tree[0]);
|
||||
|
|
@ -747,7 +749,7 @@ class Language {
|
|||
sourceAddress,
|
||||
sourceLength,
|
||||
TRANSFER_BUFFER,
|
||||
TRANSFER_BUFFER + SIZE_OF_INT
|
||||
TRANSFER_BUFFER + SIZE_OF_INT,
|
||||
);
|
||||
|
||||
if (!address) {
|
||||
|
|
@ -769,11 +771,11 @@ class Language {
|
|||
break;
|
||||
case 5:
|
||||
error = new TypeError(`Bad pattern structure at offset ${errorIndex}: '${suffix}'...`);
|
||||
word = "";
|
||||
word = '';
|
||||
break;
|
||||
default:
|
||||
error = new SyntaxError(`Bad syntax at offset ${errorIndex}: '${suffix}'...`);
|
||||
word = "";
|
||||
word = '';
|
||||
break;
|
||||
}
|
||||
error.index = errorIndex;
|
||||
|
|
@ -792,7 +794,7 @@ class Language {
|
|||
const nameAddress = C._ts_query_capture_name_for_id(
|
||||
address,
|
||||
i,
|
||||
TRANSFER_BUFFER
|
||||
TRANSFER_BUFFER,
|
||||
);
|
||||
const nameLength = getValue(TRANSFER_BUFFER, 'i32');
|
||||
captureNames[i] = UTF8ToString(nameAddress, nameLength);
|
||||
|
|
@ -802,7 +804,7 @@ class Language {
|
|||
const valueAddress = C._ts_query_string_value_for_id(
|
||||
address,
|
||||
i,
|
||||
TRANSFER_BUFFER
|
||||
TRANSFER_BUFFER,
|
||||
);
|
||||
const nameLength = getValue(TRANSFER_BUFFER, 'i32');
|
||||
stringValues[i] = UTF8ToString(valueAddress, nameLength);
|
||||
|
|
@ -817,7 +819,7 @@ class Language {
|
|||
const predicatesAddress = C._ts_query_predicates_for_pattern(
|
||||
address,
|
||||
i,
|
||||
TRANSFER_BUFFER
|
||||
TRANSFER_BUFFER,
|
||||
);
|
||||
const stepCount = getValue(TRANSFER_BUFFER, 'i32');
|
||||
|
||||
|
|
@ -849,103 +851,121 @@ class Language {
|
|||
isPositive = false;
|
||||
case 'any-eq?':
|
||||
case 'eq?':
|
||||
if (steps.length !== 3) throw new Error(
|
||||
`Wrong number of arguments to \`#${operator}\` predicate. Expected 2, got ${steps.length - 1}`
|
||||
);
|
||||
if (steps[1].type !== 'capture') throw new Error(
|
||||
`First argument of \`#${operator}\` predicate must be a capture. Got "${steps[1].value}"`
|
||||
);
|
||||
if (steps.length !== 3) {
|
||||
throw new Error(
|
||||
`Wrong number of arguments to \`#${operator}\` predicate. Expected 2, got ${steps.length - 1}`,
|
||||
);
|
||||
}
|
||||
if (steps[1].type !== 'capture') {
|
||||
throw new Error(
|
||||
`First argument of \`#${operator}\` predicate must be a capture. Got "${steps[1].value}"`,
|
||||
);
|
||||
}
|
||||
matchAll = !operator.startsWith('any-');
|
||||
if (steps[2].type === 'capture') {
|
||||
const captureName1 = steps[1].name;
|
||||
const captureName2 = steps[2].name;
|
||||
textPredicates[i].push(function (captures) {
|
||||
let nodes_1 = [];
|
||||
let nodes_2 = [];
|
||||
textPredicates[i].push(function(captures) {
|
||||
const nodes1 = [];
|
||||
const nodes2 = [];
|
||||
for (const c of captures) {
|
||||
if (c.name === captureName1) nodes_1.push(c.node);
|
||||
if (c.name === captureName2) nodes_2.push(c.node);
|
||||
if (c.name === captureName1) nodes1.push(c.node);
|
||||
if (c.name === captureName2) nodes2.push(c.node);
|
||||
}
|
||||
let compare = (n1, n2, positive) => {
|
||||
const compare = (n1, n2, positive) => {
|
||||
return positive ?
|
||||
n1.text === n2.text :
|
||||
n1.text !== n2.text;
|
||||
};
|
||||
return matchAll
|
||||
? nodes_1.every(n1 => nodes_2.some(n2 => compare(n1, n2, isPositive)))
|
||||
: nodes_1.some(n1 => nodes_2.some(n2 => compare(n1, n2, isPositive)));
|
||||
return matchAll ?
|
||||
nodes1.every((n1) => nodes2.some((n2) => compare(n1, n2, isPositive))) :
|
||||
nodes1.some((n1) => nodes2.some((n2) => compare(n1, n2, isPositive)));
|
||||
});
|
||||
} else {
|
||||
captureName = steps[1].name;
|
||||
const stringValue = steps[2].value;
|
||||
let matches = (n) => n.text === stringValue;
|
||||
let doesNotMatch = (n) => n.text !== stringValue;
|
||||
textPredicates[i].push(function (captures) {
|
||||
let nodes = [];
|
||||
const matches = (n) => n.text === stringValue;
|
||||
const doesNotMatch = (n) => n.text !== stringValue;
|
||||
textPredicates[i].push(function(captures) {
|
||||
const nodes = [];
|
||||
for (const c of captures) {
|
||||
if (c.name === captureName) nodes.push(c.node);
|
||||
}
|
||||
let test = isPositive ? matches : doesNotMatch;
|
||||
return matchAll
|
||||
? nodes.every(test)
|
||||
: nodes.some(test);
|
||||
const test = isPositive ? matches : doesNotMatch;
|
||||
return matchAll ?
|
||||
nodes.every(test) :
|
||||
nodes.some(test);
|
||||
});
|
||||
}
|
||||
break;
|
||||
|
||||
case "any-not-match?":
|
||||
case "not-match?":
|
||||
isPositive = false;
|
||||
case "any-match?":
|
||||
case "match?":
|
||||
if (steps.length !== 3) throw new Error(
|
||||
`Wrong number of arguments to \`#${operator}\` predicate. Expected 2, got ${steps.length - 1}.`
|
||||
);
|
||||
if (steps[1].type !== 'capture') throw new Error(
|
||||
`First argument of \`#${operator}\` predicate must be a capture. Got "${steps[1].value}".`
|
||||
);
|
||||
if (steps[2].type !== 'string') throw new Error(
|
||||
`Second argument of \`#${operator}\` predicate must be a string. Got @${steps[2].value}.`
|
||||
);
|
||||
case 'any-not-match?':
|
||||
case 'not-match?':
|
||||
isPositive = false;
|
||||
case 'any-match?':
|
||||
case 'match?':
|
||||
if (steps.length !== 3) {
|
||||
throw new Error(
|
||||
`Wrong number of arguments to \`#${operator}\` predicate. Expected 2, got ${steps.length - 1}.`,
|
||||
);
|
||||
}
|
||||
if (steps[1].type !== 'capture') {
|
||||
throw new Error(
|
||||
`First argument of \`#${operator}\` predicate must be a capture. Got "${steps[1].value}".`,
|
||||
);
|
||||
}
|
||||
if (steps[2].type !== 'string') {
|
||||
throw new Error(
|
||||
`Second argument of \`#${operator}\` predicate must be a string. Got @${steps[2].value}.`,
|
||||
);
|
||||
}
|
||||
captureName = steps[1].name;
|
||||
const regex = new RegExp(steps[2].value);
|
||||
matchAll = !operator.startsWith('any-');
|
||||
textPredicates[i].push(function (captures) {
|
||||
textPredicates[i].push(function(captures) {
|
||||
const nodes = [];
|
||||
for (const c of captures) {
|
||||
if (c.name === captureName) nodes.push(c.node.text);
|
||||
}
|
||||
let test = (text, positive) => {
|
||||
const test = (text, positive) => {
|
||||
return positive ?
|
||||
regex.test(text) :
|
||||
!regex.test(text);
|
||||
};
|
||||
if (nodes.length === 0) return !isPositive;
|
||||
return matchAll
|
||||
? nodes.every(text => test(text, isPositive))
|
||||
: nodes.some(text => test(text, isPositive))
|
||||
return matchAll ?
|
||||
nodes.every((text) => test(text, isPositive)) :
|
||||
nodes.some((text) => test(text, isPositive));
|
||||
});
|
||||
break;
|
||||
|
||||
case 'set!':
|
||||
if (steps.length < 2 || steps.length > 3) throw new Error(
|
||||
`Wrong number of arguments to \`#set!\` predicate. Expected 1 or 2. Got ${steps.length - 1}.`
|
||||
);
|
||||
if (steps.some(s => s.type !== 'string')) throw new Error(
|
||||
`Arguments to \`#set!\` predicate must be a strings.".`
|
||||
);
|
||||
if (steps.length < 2 || steps.length > 3) {
|
||||
throw new Error(
|
||||
`Wrong number of arguments to \`#set!\` predicate. Expected 1 or 2. Got ${steps.length - 1}.`,
|
||||
);
|
||||
}
|
||||
if (steps.some((s) => s.type !== 'string')) {
|
||||
throw new Error(
|
||||
`Arguments to \`#set!\` predicate must be a strings.".`,
|
||||
);
|
||||
}
|
||||
if (!setProperties[i]) setProperties[i] = {};
|
||||
setProperties[i][steps[1].value] = steps[2] ? steps[2].value : null;
|
||||
break;
|
||||
|
||||
case 'is?':
|
||||
case 'is-not?':
|
||||
if (steps.length < 2 || steps.length > 3) throw new Error(
|
||||
`Wrong number of arguments to \`#${operator}\` predicate. Expected 1 or 2. Got ${steps.length - 1}.`
|
||||
);
|
||||
if (steps.some(s => s.type !== 'string')) throw new Error(
|
||||
`Arguments to \`#${operator}\` predicate must be a strings.".`
|
||||
);
|
||||
if (steps.length < 2 || steps.length > 3) {
|
||||
throw new Error(
|
||||
`Wrong number of arguments to \`#${operator}\` predicate. Expected 1 or 2. Got ${steps.length - 1}.`,
|
||||
);
|
||||
}
|
||||
if (steps.some((s) => s.type !== 'string')) {
|
||||
throw new Error(
|
||||
`Arguments to \`#${operator}\` predicate must be a strings.".`,
|
||||
);
|
||||
}
|
||||
const properties = operator === 'is?' ? assertedProperties : refutedProperties;
|
||||
if (!properties[i]) properties[i] = {};
|
||||
properties[i][steps[1].value] = steps[2] ? steps[2].value : null;
|
||||
|
|
@ -954,26 +974,32 @@ class Language {
|
|||
case 'not-any-of?':
|
||||
isPositive = false;
|
||||
case 'any-of?':
|
||||
if (steps.length < 2) throw new Error(
|
||||
`Wrong number of arguments to \`#${operator}\` predicate. Expected at least 1. Got ${steps.length - 1}.`
|
||||
);
|
||||
if (steps[1].type !== 'capture') throw new Error(
|
||||
`First argument of \`#${operator}\` predicate must be a capture. Got "${steps[1].value}".`
|
||||
);
|
||||
for (let i = 2; i < steps.length; i++) {
|
||||
if (steps[i].type !== 'string') throw new Error(
|
||||
`Arguments to \`#${operator}\` predicate must be a strings.".`
|
||||
if (steps.length < 2) {
|
||||
throw new Error(
|
||||
`Wrong number of arguments to \`#${operator}\` predicate. Expected at least 1. Got ${steps.length - 1}.`,
|
||||
);
|
||||
}
|
||||
if (steps[1].type !== 'capture') {
|
||||
throw new Error(
|
||||
`First argument of \`#${operator}\` predicate must be a capture. Got "${steps[1].value}".`,
|
||||
);
|
||||
}
|
||||
for (let i = 2; i < steps.length; i++) {
|
||||
if (steps[i].type !== 'string') {
|
||||
throw new Error(
|
||||
`Arguments to \`#${operator}\` predicate must be a strings.".`,
|
||||
);
|
||||
}
|
||||
}
|
||||
captureName = steps[1].name;
|
||||
const values = steps.slice(2).map(s => s.value);
|
||||
textPredicates[i].push(function (captures) {
|
||||
const values = steps.slice(2).map((s) => s.value);
|
||||
textPredicates[i].push(function(captures) {
|
||||
const nodes = [];
|
||||
for (const c of captures) {
|
||||
if (c.name === captureName) nodes.push(c.node.text);
|
||||
}
|
||||
if (nodes.length === 0) return !isPositive;
|
||||
return nodes.every(text => values.includes(text)) === isPositive;
|
||||
return nodes.every((text) => values.includes(text)) === isPositive;
|
||||
});
|
||||
break;
|
||||
|
||||
|
|
@ -999,7 +1025,7 @@ class Language {
|
|||
predicates,
|
||||
Object.freeze(setProperties),
|
||||
Object.freeze(assertedProperties),
|
||||
Object.freeze(refutedProperties)
|
||||
Object.freeze(refutedProperties),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -1018,28 +1044,28 @@ class Language {
|
|||
bytes = Promise.resolve(fs.readFileSync(url));
|
||||
} else {
|
||||
bytes = fetch(url)
|
||||
.then(response => response.arrayBuffer()
|
||||
.then(buffer => {
|
||||
.then((response) => response.arrayBuffer()
|
||||
.then((buffer) => {
|
||||
if (response.ok) {
|
||||
return new Uint8Array(buffer);
|
||||
} else {
|
||||
const body = new TextDecoder('utf-8').decode(buffer);
|
||||
throw new Error(`Language.load failed with status ${response.status}.\n\n${body}`)
|
||||
throw new Error(`Language.load failed with status ${response.status}.\n\n${body}`);
|
||||
}
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
return bytes
|
||||
.then(bytes => loadWebAssemblyModule(bytes, {loadAsync: true}))
|
||||
.then(mod => {
|
||||
const symbolNames = Object.keys(mod)
|
||||
const functionName = symbolNames.find(key =>
|
||||
.then((bytes) => loadWebAssemblyModule(bytes, {loadAsync: true}))
|
||||
.then((mod) => {
|
||||
const symbolNames = Object.keys(mod);
|
||||
const functionName = symbolNames.find((key) =>
|
||||
LANGUAGE_FUNCTION_REGEX.test(key) &&
|
||||
!key.includes("external_scanner_")
|
||||
!key.includes('external_scanner_'),
|
||||
);
|
||||
if (!functionName) {
|
||||
console.log(`Couldn't find language function in WASM file. Symbols:\n${JSON.stringify(symbolNames, null, 2)}`)
|
||||
console.log(`Couldn't find language function in WASM file. Symbols:\n${JSON.stringify(symbolNames, null, 2)}`);
|
||||
}
|
||||
const languageAddress = mod[functionName]();
|
||||
return new Language(INTERNAL, languageAddress);
|
||||
|
|
@ -1059,7 +1085,7 @@ class LookaheadIterable {
|
|||
}
|
||||
|
||||
get currentType() {
|
||||
return this.language.types[this.currentTypeId] || 'ERROR'
|
||||
return this.language.types[this.currentTypeId] || 'ERROR';
|
||||
}
|
||||
|
||||
delete() {
|
||||
|
|
@ -1085,11 +1111,11 @@ class LookaheadIterable {
|
|||
return {
|
||||
next() {
|
||||
if (C._ts_lookahead_iterator_next(self[0])) {
|
||||
return { done: false, value: self.currentType };
|
||||
return {done: false, value: self.currentType};
|
||||
}
|
||||
|
||||
return { done: true, value: "" };
|
||||
}
|
||||
return {done: true, value: ''};
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -1097,7 +1123,7 @@ class LookaheadIterable {
|
|||
class Query {
|
||||
constructor(
|
||||
internal, address, captureNames, textPredicates, predicates,
|
||||
setProperties, assertedProperties, refutedProperties
|
||||
setProperties, assertedProperties, refutedProperties,
|
||||
) {
|
||||
assertInternal(internal);
|
||||
this[0] = address;
|
||||
|
|
@ -1136,7 +1162,7 @@ class Query {
|
|||
startPosition.column,
|
||||
endPosition.row,
|
||||
endPosition.column,
|
||||
matchLimit
|
||||
matchLimit,
|
||||
);
|
||||
|
||||
const rawCount = getValue(TRANSFER_BUFFER, 'i32');
|
||||
|
|
@ -1155,7 +1181,7 @@ class Query {
|
|||
|
||||
const captures = new Array(captureCount);
|
||||
address = unmarshalCaptures(this, node.tree, address, captures);
|
||||
if (this.textPredicates[pattern].every(p => p(captures))) {
|
||||
if (this.textPredicates[pattern].every((p) => p(captures))) {
|
||||
result[filteredCount++] = {pattern, captures};
|
||||
const setProperties = this.setProperties[pattern];
|
||||
if (setProperties) result[i].setProperties = setProperties;
|
||||
|
|
@ -1192,7 +1218,7 @@ class Query {
|
|||
startPosition.column,
|
||||
endPosition.row,
|
||||
endPosition.column,
|
||||
matchLimit
|
||||
matchLimit,
|
||||
);
|
||||
|
||||
const count = getValue(TRANSFER_BUFFER, 'i32');
|
||||
|
|
@ -1211,10 +1237,10 @@ class Query {
|
|||
const captureIndex = getValue(address, 'i32');
|
||||
address += SIZE_OF_INT;
|
||||
|
||||
captures.length = captureCount
|
||||
captures.length = captureCount;
|
||||
address = unmarshalCaptures(this, node.tree, address, captures);
|
||||
|
||||
if (this.textPredicates[pattern].every(p => p(captures))) {
|
||||
if (this.textPredicates[pattern].every((p) => p(captures))) {
|
||||
const capture = captures[captureIndex];
|
||||
const setProperties = this.setProperties[pattern];
|
||||
if (setProperties) capture.setProperties = setProperties;
|
||||
|
|
@ -1231,7 +1257,7 @@ class Query {
|
|||
}
|
||||
|
||||
predicatesForPattern(patternIndex) {
|
||||
return this.predicates[patternIndex]
|
||||
return this.predicates[patternIndex];
|
||||
}
|
||||
|
||||
didExceedMatchLimit() {
|
||||
|
|
@ -1270,7 +1296,7 @@ function unmarshalCaptures(query, tree, address, result) {
|
|||
}
|
||||
|
||||
function assertInternal(x) {
|
||||
if (x !== INTERNAL) throw new Error('Illegal constructor')
|
||||
if (x !== INTERNAL) throw new Error('Illegal constructor');
|
||||
}
|
||||
|
||||
function isPoint(point) {
|
||||
|
|
@ -1319,25 +1345,25 @@ function unmarshalNode(tree, address = TRANSFER_BUFFER) {
|
|||
function marshalTreeCursor(cursor, address = TRANSFER_BUFFER) {
|
||||
setValue(address + 0 * SIZE_OF_INT, cursor[0], 'i32'),
|
||||
setValue(address + 1 * SIZE_OF_INT, cursor[1], 'i32'),
|
||||
setValue(address + 2 * SIZE_OF_INT, cursor[2], 'i32')
|
||||
setValue(address + 2 * SIZE_OF_INT, cursor[2], 'i32');
|
||||
}
|
||||
|
||||
function unmarshalTreeCursor(cursor) {
|
||||
cursor[0] = getValue(TRANSFER_BUFFER + 0 * SIZE_OF_INT, 'i32'),
|
||||
cursor[1] = getValue(TRANSFER_BUFFER + 1 * SIZE_OF_INT, 'i32'),
|
||||
cursor[2] = getValue(TRANSFER_BUFFER + 2 * SIZE_OF_INT, 'i32')
|
||||
cursor[2] = getValue(TRANSFER_BUFFER + 2 * SIZE_OF_INT, 'i32');
|
||||
}
|
||||
|
||||
function marshalPoint(address, point) {
|
||||
setValue(address, point.row, 'i32')
|
||||
setValue(address + SIZE_OF_INT, point.column, 'i32')
|
||||
setValue(address, point.row, 'i32');
|
||||
setValue(address + SIZE_OF_INT, point.column, 'i32');
|
||||
}
|
||||
|
||||
function unmarshalPoint(address) {
|
||||
return {
|
||||
row: getValue(address, 'i32'),
|
||||
column: getValue(address + SIZE_OF_INT, 'i32')
|
||||
}
|
||||
column: getValue(address + SIZE_OF_INT, 'i32'),
|
||||
};
|
||||
}
|
||||
|
||||
function marshalRange(address, range) {
|
||||
|
|
|
|||
|
|
@ -1,19 +1,19 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const inputFiles = [
|
||||
"binding.c",
|
||||
"binding.js",
|
||||
"exports.txt",
|
||||
"imports.js",
|
||||
"prefix.js",
|
||||
...list("../include/tree_sitter"),
|
||||
...list("../src"),
|
||||
'binding.c',
|
||||
'binding.js',
|
||||
'exports.txt',
|
||||
'imports.js',
|
||||
'prefix.js',
|
||||
...list('../include/tree_sitter'),
|
||||
...list('../src'),
|
||||
];
|
||||
|
||||
const outputFiles = ["tree-sitter.js", "tree-sitter.wasm"];
|
||||
const outputFiles = ['tree-sitter.js', 'tree-sitter.wasm'];
|
||||
|
||||
const outputMtime = Math.min(...outputFiles.map(mtime));
|
||||
|
||||
|
|
@ -26,8 +26,8 @@ for (const inputFile of inputFiles) {
|
|||
|
||||
function list(dir) {
|
||||
return fs
|
||||
.readdirSync(path.join(__dirname, dir), "utf8")
|
||||
.filter((p) => !p.startsWith("."))
|
||||
.readdirSync(path.join(__dirname, dir), 'utf8')
|
||||
.filter((p) => !p.startsWith('.'))
|
||||
.map((p) => path.join(dir, p));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@ mergeInto(LibraryManager.library, {
|
|||
index,
|
||||
row,
|
||||
column,
|
||||
lengthAddress
|
||||
lengthAddress,
|
||||
) {
|
||||
var INPUT_BUFFER_SIZE = 10 * 1024;
|
||||
var string = currentParseCallback(index, {row: row, column: column});
|
||||
const INPUT_BUFFER_SIZE = 10 * 1024;
|
||||
const string = currentParseCallback(index, {row: row, column: column});
|
||||
if (typeof string === 'string') {
|
||||
setValue(lengthAddress, string.length, 'i32');
|
||||
stringToUTF16(string, inputBufferAddress, INPUT_BUFFER_SIZE);
|
||||
|
|
@ -21,5 +21,5 @@ mergeInto(LibraryManager.library, {
|
|||
const message = UTF8ToString(messageAddress);
|
||||
currentLogCallback(message, isLexMessage !== 0);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@
|
|||
"homepage": "https://github.com/tree-sitter/tree-sitter/tree/master/lib/binding_web",
|
||||
"devDependencies": {
|
||||
"chai": "^4.3.7",
|
||||
"eslint": ">=8.56.0",
|
||||
"eslint-config-google": "^0.14.0",
|
||||
"mocha": "^10.2.0",
|
||||
"terser": "^5.16.6"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,4 +20,4 @@
|
|||
|
||||
if (typeof exports === 'object') {
|
||||
module.exports = TreeSitter;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,56 +1,56 @@
|
|||
const { assert } = require("chai");
|
||||
const {assert} = require('chai');
|
||||
let JavaScript;
|
||||
|
||||
describe("Language", () => {
|
||||
before(async () => ({ JavaScript } = await require("./helper")));
|
||||
describe('Language', () => {
|
||||
before(async () => ({JavaScript} = await require('./helper')));
|
||||
|
||||
describe(".fieldIdForName, .fieldNameForId", () => {
|
||||
it("converts between the string and integer representations of fields", () => {
|
||||
const nameId = JavaScript.fieldIdForName("name");
|
||||
const bodyId = JavaScript.fieldIdForName("body");
|
||||
describe('.fieldIdForName, .fieldNameForId', () => {
|
||||
it('converts between the string and integer representations of fields', () => {
|
||||
const nameId = JavaScript.fieldIdForName('name');
|
||||
const bodyId = JavaScript.fieldIdForName('body');
|
||||
|
||||
assert.isBelow(nameId, JavaScript.fieldCount);
|
||||
assert.isBelow(bodyId, JavaScript.fieldCount);
|
||||
assert.equal("name", JavaScript.fieldNameForId(nameId));
|
||||
assert.equal("body", JavaScript.fieldNameForId(bodyId));
|
||||
assert.equal('name', JavaScript.fieldNameForId(nameId));
|
||||
assert.equal('body', JavaScript.fieldNameForId(bodyId));
|
||||
});
|
||||
|
||||
it("handles invalid inputs", () => {
|
||||
assert.equal(null, JavaScript.fieldIdForName("namezzz"));
|
||||
it('handles invalid inputs', () => {
|
||||
assert.equal(null, JavaScript.fieldIdForName('namezzz'));
|
||||
assert.equal(null, JavaScript.fieldNameForId(-1));
|
||||
assert.equal(null, JavaScript.fieldNameForId(10000));
|
||||
});
|
||||
});
|
||||
|
||||
describe(".idForNodeType, .nodeTypeForId, .nodeTypeIsNamed", () => {
|
||||
it("converts between the string and integer representations of a node type", () => {
|
||||
const exportStatementId = JavaScript.idForNodeType("export_statement", true);
|
||||
const starId = JavaScript.idForNodeType("*", false);
|
||||
describe('.idForNodeType, .nodeTypeForId, .nodeTypeIsNamed', () => {
|
||||
it('converts between the string and integer representations of a node type', () => {
|
||||
const exportStatementId = JavaScript.idForNodeType('export_statement', true);
|
||||
const starId = JavaScript.idForNodeType('*', false);
|
||||
|
||||
assert.isBelow(exportStatementId, JavaScript.nodeTypeCount);
|
||||
assert.isBelow(starId, JavaScript.nodeTypeCount);
|
||||
assert.equal(true, JavaScript.nodeTypeIsNamed(exportStatementId))
|
||||
assert.equal("export_statement", JavaScript.nodeTypeForId(exportStatementId))
|
||||
assert.equal(false, JavaScript.nodeTypeIsNamed(starId))
|
||||
assert.equal("*", JavaScript.nodeTypeForId(starId))
|
||||
assert.equal(true, JavaScript.nodeTypeIsNamed(exportStatementId));
|
||||
assert.equal('export_statement', JavaScript.nodeTypeForId(exportStatementId));
|
||||
assert.equal(false, JavaScript.nodeTypeIsNamed(starId));
|
||||
assert.equal('*', JavaScript.nodeTypeForId(starId));
|
||||
});
|
||||
|
||||
it("handles invalid inputs", () => {
|
||||
it('handles invalid inputs', () => {
|
||||
assert.equal(null, JavaScript.nodeTypeForId(-1));
|
||||
assert.equal(null, JavaScript.nodeTypeForId(10000));
|
||||
assert.equal(null, JavaScript.idForNodeType("export_statement", false));
|
||||
assert.equal(null, JavaScript.idForNodeType('export_statement', false));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("Lookahead iterator", () => {
|
||||
describe('Lookahead iterator', () => {
|
||||
let lookahead;
|
||||
let state;
|
||||
before(async () => {
|
||||
let Parser;
|
||||
({ JavaScript, Parser } = await require("./helper"));
|
||||
({JavaScript, Parser} = await require('./helper'));
|
||||
const parser = new Parser().setLanguage(JavaScript);
|
||||
const tree = parser.parse("function fn() {}");
|
||||
const tree = parser.parse('function fn() {}');
|
||||
parser.delete();
|
||||
const cursor = tree.walk();
|
||||
assert(cursor.gotoFirstChild());
|
||||
|
|
@ -64,21 +64,21 @@ describe("Lookahead iterator", () => {
|
|||
lookahead.delete();
|
||||
});
|
||||
|
||||
const expected = ["identifier", "comment", "html_comment", "(", "*", "formal_parameters", "ERROR"];
|
||||
it("should iterate over valid symbols in the state", () => {
|
||||
const expected = ['identifier', 'comment', 'html_comment', '(', '*', 'formal_parameters', 'ERROR'];
|
||||
it('should iterate over valid symbols in the state', () => {
|
||||
const symbols = Array.from(lookahead);
|
||||
assert.includeMembers(symbols, expected);
|
||||
assert.lengthOf(symbols, expected.length);
|
||||
});
|
||||
|
||||
it("should reset to the initial state", () => {
|
||||
it('should reset to the initial state', () => {
|
||||
assert(lookahead.resetState(state));
|
||||
const symbols = Array.from(lookahead);
|
||||
assert.includeMembers(symbols, expected);
|
||||
assert.lengthOf(symbols, expected.length);
|
||||
});
|
||||
|
||||
it("should reset", () => {
|
||||
it('should reset', () => {
|
||||
assert(lookahead.reset(JavaScript, state));
|
||||
const symbols = Array.from(lookahead);
|
||||
assert.includeMembers(symbols, expected);
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
const {assert} = require('chai');
|
||||
let Parser, JavaScript;
|
||||
let Parser; let JavaScript;
|
||||
|
||||
describe("Node", () => {
|
||||
let parser, tree;
|
||||
describe('Node', () => {
|
||||
let parser; let tree;
|
||||
|
||||
before(async () =>
|
||||
({Parser, JavaScript} = await require('./helper'))
|
||||
({Parser, JavaScript} = await require('./helper')),
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
@ -18,83 +18,83 @@ describe("Node", () => {
|
|||
tree.delete();
|
||||
});
|
||||
|
||||
describe(".children", () => {
|
||||
it("returns an array of child nodes", () => {
|
||||
tree = parser.parse("x10 + 1000");
|
||||
describe('.children', () => {
|
||||
it('returns an array of child nodes', () => {
|
||||
tree = parser.parse('x10 + 1000');
|
||||
assert.equal(1, tree.rootNode.children.length);
|
||||
const sumNode = tree.rootNode.firstChild.firstChild;
|
||||
assert.deepEqual(
|
||||
sumNode.children.map(child => child.type),
|
||||
["identifier", "+", "number"]
|
||||
sumNode.children.map((child) => child.type),
|
||||
['identifier', '+', 'number'],
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe(".namedChildren", () => {
|
||||
it("returns an array of named child nodes", () => {
|
||||
tree = parser.parse("x10 + 1000");
|
||||
describe('.namedChildren', () => {
|
||||
it('returns an array of named child nodes', () => {
|
||||
tree = parser.parse('x10 + 1000');
|
||||
const sumNode = tree.rootNode.firstChild.firstChild;
|
||||
assert.equal(1, tree.rootNode.namedChildren.length);
|
||||
assert.deepEqual(
|
||||
["identifier", "number"],
|
||||
sumNode.namedChildren.map(child => child.type)
|
||||
['identifier', 'number'],
|
||||
sumNode.namedChildren.map((child) => child.type),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe(".startIndex and .endIndex", () => {
|
||||
it("returns the character index where the node starts/ends in the text", () => {
|
||||
tree = parser.parse("a👍👎1 / b👎c👎");
|
||||
describe('.startIndex and .endIndex', () => {
|
||||
it('returns the character index where the node starts/ends in the text', () => {
|
||||
tree = parser.parse('a👍👎1 / b👎c👎');
|
||||
const quotientNode = tree.rootNode.firstChild.firstChild;
|
||||
|
||||
assert.equal(0, quotientNode.startIndex);
|
||||
assert.equal(15, quotientNode.endIndex);
|
||||
assert.deepEqual(
|
||||
[0, 7, 9],
|
||||
quotientNode.children.map(child => child.startIndex)
|
||||
quotientNode.children.map((child) => child.startIndex),
|
||||
);
|
||||
assert.deepEqual(
|
||||
[6, 8, 15],
|
||||
quotientNode.children.map(child => child.endIndex)
|
||||
quotientNode.children.map((child) => child.endIndex),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe(".startPosition and .endPosition", () => {
|
||||
it("returns the row and column where the node starts/ends in the text", () => {
|
||||
tree = parser.parse("x10 + 1000");
|
||||
describe('.startPosition and .endPosition', () => {
|
||||
it('returns the row and column where the node starts/ends in the text', () => {
|
||||
tree = parser.parse('x10 + 1000');
|
||||
const sumNode = tree.rootNode.firstChild.firstChild;
|
||||
assert.equal("binary_expression", sumNode.type);
|
||||
assert.equal('binary_expression', sumNode.type);
|
||||
|
||||
assert.deepEqual({ row: 0, column: 0 }, sumNode.startPosition);
|
||||
assert.deepEqual({ row: 0, column: 10 }, sumNode.endPosition);
|
||||
assert.deepEqual({row: 0, column: 0}, sumNode.startPosition);
|
||||
assert.deepEqual({row: 0, column: 10}, sumNode.endPosition);
|
||||
assert.deepEqual(
|
||||
[{ row: 0, column: 0 }, { row: 0, column: 4 }, { row: 0, column: 6 }],
|
||||
sumNode.children.map(child => child.startPosition)
|
||||
[{row: 0, column: 0}, {row: 0, column: 4}, {row: 0, column: 6}],
|
||||
sumNode.children.map((child) => child.startPosition),
|
||||
);
|
||||
assert.deepEqual(
|
||||
[{ row: 0, column: 3 }, { row: 0, column: 5 }, { row: 0, column: 10 }],
|
||||
sumNode.children.map(child => child.endPosition)
|
||||
[{row: 0, column: 3}, {row: 0, column: 5}, {row: 0, column: 10}],
|
||||
sumNode.children.map((child) => child.endPosition),
|
||||
);
|
||||
});
|
||||
|
||||
it("handles characters that occupy two UTF16 code units", () => {
|
||||
tree = parser.parse("a👍👎1 /\n b👎c👎");
|
||||
it('handles characters that occupy two UTF16 code units', () => {
|
||||
tree = parser.parse('a👍👎1 /\n b👎c👎');
|
||||
const sumNode = tree.rootNode.firstChild.firstChild;
|
||||
assert.deepEqual(
|
||||
[
|
||||
[{ row: 0, column: 0 }, { row: 0, column: 6 }],
|
||||
[{ row: 0, column: 7 }, { row: 0, column: 8 }],
|
||||
[{ row: 1, column: 1 }, { row: 1, column: 7 }]
|
||||
[{row: 0, column: 0}, {row: 0, column: 6}],
|
||||
[{row: 0, column: 7}, {row: 0, column: 8}],
|
||||
[{row: 1, column: 1}, {row: 1, column: 7}],
|
||||
],
|
||||
sumNode.children.map(child => [child.startPosition, child.endPosition])
|
||||
sumNode.children.map((child) => [child.startPosition, child.endPosition]),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe(".parent", () => {
|
||||
it("returns the node's parent", () => {
|
||||
tree = parser.parse("x10 + 1000");
|
||||
describe('.parent', () => {
|
||||
it('returns the node\'s parent', () => {
|
||||
tree = parser.parse('x10 + 1000');
|
||||
const sumNode = tree.rootNode.firstChild;
|
||||
const variableNode = sumNode.firstChild;
|
||||
assert.notEqual(sumNode.id, variableNode.id);
|
||||
|
|
@ -105,7 +105,7 @@ describe("Node", () => {
|
|||
|
||||
describe('.child(), .firstChild, .lastChild', () => {
|
||||
it('returns null when the node has no children', () => {
|
||||
tree = parser.parse("x10 + 1000");
|
||||
tree = parser.parse('x10 + 1000');
|
||||
const sumNode = tree.rootNode.firstChild.firstChild;
|
||||
const variableNode = sumNode.firstChild;
|
||||
assert.equal(variableNode.firstChild, null);
|
||||
|
|
@ -113,12 +113,12 @@ describe("Node", () => {
|
|||
assert.equal(variableNode.firstNamedChild, null);
|
||||
assert.equal(variableNode.lastNamedChild, null);
|
||||
assert.equal(variableNode.child(1), null);
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
describe('.childForFieldName()', () => {
|
||||
it('returns null when the node has no children', () => {
|
||||
tree = parser.parse("class A { b() {} }");
|
||||
tree = parser.parse('class A { b() {} }');
|
||||
|
||||
const classNode = tree.rootNode.firstChild;
|
||||
assert.equal(classNode.type, 'class_declaration');
|
||||
|
|
@ -145,119 +145,119 @@ describe("Node", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe(".nextSibling and .previousSibling", () => {
|
||||
it("returns the node's next and previous sibling", () => {
|
||||
tree = parser.parse("x10 + 1000");
|
||||
describe('.nextSibling and .previousSibling', () => {
|
||||
it('returns the node\'s next and previous sibling', () => {
|
||||
tree = parser.parse('x10 + 1000');
|
||||
const sumNode = tree.rootNode.firstChild.firstChild;
|
||||
assert.equal(sumNode.children[1].id, sumNode.children[0].nextSibling.id);
|
||||
assert.equal(sumNode.children[2].id, sumNode.children[1].nextSibling.id);
|
||||
assert.equal(
|
||||
sumNode.children[0].id,
|
||||
sumNode.children[1].previousSibling.id
|
||||
sumNode.children[1].previousSibling.id,
|
||||
);
|
||||
assert.equal(
|
||||
sumNode.children[1].id,
|
||||
sumNode.children[2].previousSibling.id
|
||||
sumNode.children[2].previousSibling.id,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe(".nextNamedSibling and .previousNamedSibling", () => {
|
||||
it("returns the node's next and previous named sibling", () => {
|
||||
tree = parser.parse("x10 + 1000");
|
||||
describe('.nextNamedSibling and .previousNamedSibling', () => {
|
||||
it('returns the node\'s next and previous named sibling', () => {
|
||||
tree = parser.parse('x10 + 1000');
|
||||
const sumNode = tree.rootNode.firstChild.firstChild;
|
||||
assert.equal(
|
||||
sumNode.namedChildren[1].id,
|
||||
sumNode.namedChildren[0].nextNamedSibling.id
|
||||
sumNode.namedChildren[0].nextNamedSibling.id,
|
||||
);
|
||||
assert.equal(
|
||||
sumNode.namedChildren[0].id,
|
||||
sumNode.namedChildren[1].previousNamedSibling.id
|
||||
sumNode.namedChildren[1].previousNamedSibling.id,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe(".descendantForIndex(min, max)", () => {
|
||||
it("returns the smallest node that spans the given range", () => {
|
||||
tree = parser.parse("x10 + 1000");
|
||||
describe('.descendantForIndex(min, max)', () => {
|
||||
it('returns the smallest node that spans the given range', () => {
|
||||
tree = parser.parse('x10 + 1000');
|
||||
const sumNode = tree.rootNode.firstChild.firstChild;
|
||||
assert.equal("identifier", sumNode.descendantForIndex(1, 2).type);
|
||||
assert.equal("+", sumNode.descendantForIndex(4, 4).type);
|
||||
assert.equal('identifier', sumNode.descendantForIndex(1, 2).type);
|
||||
assert.equal('+', sumNode.descendantForIndex(4, 4).type);
|
||||
|
||||
assert.throws(() => {
|
||||
sumNode.descendantForIndex(1, {});
|
||||
}, "Arguments must be numbers");
|
||||
}, 'Arguments must be numbers');
|
||||
|
||||
assert.throws(() => {
|
||||
sumNode.descendantForIndex();
|
||||
}, "Arguments must be numbers");
|
||||
}, 'Arguments must be numbers');
|
||||
});
|
||||
});
|
||||
|
||||
describe(".namedDescendantForIndex", () => {
|
||||
it("returns the smallest node that spans the given range", () => {
|
||||
tree = parser.parse("x10 + 1000");
|
||||
describe('.namedDescendantForIndex', () => {
|
||||
it('returns the smallest node that spans the given range', () => {
|
||||
tree = parser.parse('x10 + 1000');
|
||||
const sumNode = tree.rootNode.firstChild;
|
||||
assert.equal("identifier", sumNode.descendantForIndex(1, 2).type);
|
||||
assert.equal("+", sumNode.descendantForIndex(4, 4).type);
|
||||
assert.equal('identifier', sumNode.descendantForIndex(1, 2).type);
|
||||
assert.equal('+', sumNode.descendantForIndex(4, 4).type);
|
||||
});
|
||||
});
|
||||
|
||||
describe(".descendantForPosition(min, max)", () => {
|
||||
it("returns the smallest node that spans the given range", () => {
|
||||
tree = parser.parse("x10 + 1000");
|
||||
describe('.descendantForPosition(min, max)', () => {
|
||||
it('returns the smallest node that spans the given range', () => {
|
||||
tree = parser.parse('x10 + 1000');
|
||||
const sumNode = tree.rootNode.firstChild;
|
||||
|
||||
assert.equal(
|
||||
"identifier",
|
||||
'identifier',
|
||||
sumNode.descendantForPosition(
|
||||
{ row: 0, column: 1 },
|
||||
{ row: 0, column: 2 }
|
||||
).type
|
||||
{row: 0, column: 1},
|
||||
{row: 0, column: 2},
|
||||
).type,
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
"+",
|
||||
sumNode.descendantForPosition({ row: 0, column: 4 }).type
|
||||
'+',
|
||||
sumNode.descendantForPosition({row: 0, column: 4}).type,
|
||||
);
|
||||
|
||||
assert.throws(() => {
|
||||
sumNode.descendantForPosition(1, {});
|
||||
}, "Arguments must be {row, column} objects");
|
||||
}, 'Arguments must be {row, column} objects');
|
||||
|
||||
assert.throws(() => {
|
||||
sumNode.descendantForPosition();
|
||||
}, "Arguments must be {row, column} objects");
|
||||
}, 'Arguments must be {row, column} objects');
|
||||
});
|
||||
});
|
||||
|
||||
describe(".namedDescendantForPosition(min, max)", () => {
|
||||
it("returns the smallest named node that spans the given range", () => {
|
||||
tree = parser.parse("x10 + 1000");
|
||||
describe('.namedDescendantForPosition(min, max)', () => {
|
||||
it('returns the smallest named node that spans the given range', () => {
|
||||
tree = parser.parse('x10 + 1000');
|
||||
const sumNode = tree.rootNode.firstChild;
|
||||
|
||||
assert.equal(
|
||||
sumNode.namedDescendantForPosition(
|
||||
{ row: 0, column: 1 },
|
||||
{ row: 0, column: 2 }
|
||||
{row: 0, column: 1},
|
||||
{row: 0, column: 2},
|
||||
).type,
|
||||
"identifier",
|
||||
'identifier',
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
sumNode.namedDescendantForPosition({ row: 0, column: 4 }).type,
|
||||
'binary_expression'
|
||||
sumNode.namedDescendantForPosition({row: 0, column: 4}).type,
|
||||
'binary_expression',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe(".hasError()", () => {
|
||||
it("returns true if the node contains an error", () => {
|
||||
tree = parser.parse("1 + 2 * * 3");
|
||||
describe('.hasError()', () => {
|
||||
it('returns true if the node contains an error', () => {
|
||||
tree = parser.parse('1 + 2 * * 3');
|
||||
const node = tree.rootNode;
|
||||
assert.equal(
|
||||
node.toString(),
|
||||
'(program (expression_statement (binary_expression left: (number) right: (binary_expression left: (number) (ERROR) right: (number)))))'
|
||||
'(program (expression_statement (binary_expression left: (number) right: (binary_expression left: (number) (ERROR) right: (number)))))',
|
||||
);
|
||||
|
||||
const sum = node.firstChild.firstChild;
|
||||
|
|
@ -268,13 +268,13 @@ describe("Node", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe(".isError()", () => {
|
||||
it("returns true if the node is an error", () => {
|
||||
tree = parser.parse("2 * * 3");
|
||||
describe('.isError()', () => {
|
||||
it('returns true if the node is an error', () => {
|
||||
tree = parser.parse('2 * * 3');
|
||||
const node = tree.rootNode;
|
||||
assert.equal(
|
||||
node.toString(),
|
||||
'(program (expression_statement (binary_expression left: (number) (ERROR) right: (number))))'
|
||||
'(program (expression_statement (binary_expression left: (number) (ERROR) right: (number))))',
|
||||
);
|
||||
|
||||
const multi = node.firstChild.firstChild;
|
||||
|
|
@ -286,17 +286,17 @@ describe("Node", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe(".isMissing()", () => {
|
||||
it("returns true if the node is missing from the source and was inserted via error recovery", () => {
|
||||
tree = parser.parse("(2 ||)");
|
||||
describe('.isMissing()', () => {
|
||||
it('returns true if the node is missing from the source and was inserted via error recovery', () => {
|
||||
tree = parser.parse('(2 ||)');
|
||||
const node = tree.rootNode;
|
||||
assert.equal(
|
||||
node.toString(),
|
||||
"(program (expression_statement (parenthesized_expression (binary_expression left: (number) right: (MISSING identifier)))))"
|
||||
'(program (expression_statement (parenthesized_expression (binary_expression left: (number) right: (MISSING identifier)))))',
|
||||
);
|
||||
|
||||
const sum = node.firstChild.firstChild.firstNamedChild;
|
||||
assert.equal(sum.type, 'binary_expression')
|
||||
assert.equal(sum.type, 'binary_expression');
|
||||
assert(sum.hasError());
|
||||
assert(!sum.children[0].isMissing());
|
||||
assert(!sum.children[1].isMissing());
|
||||
|
|
@ -304,33 +304,33 @@ describe("Node", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe(".text", () => {
|
||||
const text = "α0 / b👎c👎";
|
||||
describe('.text', () => {
|
||||
const text = 'α0 / b👎c👎';
|
||||
|
||||
Object.entries({
|
||||
'.parse(String)': text,
|
||||
'.parse(Function)': offset => text.substr(offset, 4)
|
||||
'.parse(Function)': (offset) => text.substr(offset, 4),
|
||||
}).forEach(([method, parse]) =>
|
||||
it(`returns the text of a node generated by ${method}`, async () => {
|
||||
const [numeratorSrc, denominatorSrc] = text.split(/\s*\/\s+/)
|
||||
tree = await parser.parse(text)
|
||||
const [numeratorSrc, denominatorSrc] = text.split(/\s*\/\s+/);
|
||||
tree = await parser.parse(text);
|
||||
const quotientNode = tree.rootNode.firstChild.firstChild;
|
||||
const [numerator, slash, denominator] = quotientNode.children;
|
||||
|
||||
assert.equal(text, tree.rootNode.text, 'root node text');
|
||||
assert.equal(text, tree.rootNode.text, 'root node text');
|
||||
assert.equal(denominatorSrc, denominator.text, 'denominator text');
|
||||
assert.equal(text, quotientNode.text, 'quotient text');
|
||||
assert.equal(numeratorSrc, numerator.text, 'numerator text');
|
||||
assert.equal('/', slash.text, '"/" text');
|
||||
})
|
||||
assert.equal(text, quotientNode.text, 'quotient text');
|
||||
assert.equal(numeratorSrc, numerator.text, 'numerator text');
|
||||
assert.equal('/', slash.text, '"/" text');
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
describe(".parseState, .nextParseState", () => {
|
||||
const text = "10 / 5";
|
||||
describe('.parseState, .nextParseState', () => {
|
||||
const text = '10 / 5';
|
||||
|
||||
it("returns node parse state ids", async () => {
|
||||
tree = await parser.parse(text)
|
||||
it('returns node parse state ids', async () => {
|
||||
tree = await parser.parse(text);
|
||||
const quotientNode = tree.rootNode.firstChild.firstChild;
|
||||
const [numerator, slash, denominator] = quotientNode.children;
|
||||
|
||||
|
|
@ -340,15 +340,15 @@ describe("Node", () => {
|
|||
assert.isAbove(numerator.parseState, 0);
|
||||
assert.isAbove(slash.parseState, 0);
|
||||
assert.isAbove(denominator.parseState, 0);
|
||||
})
|
||||
});
|
||||
|
||||
it("returns next parse state equal to the language", async () => {
|
||||
it('returns next parse state equal to the language', async () => {
|
||||
tree = await parser.parse(text);
|
||||
const quotientNode = tree.rootNode.firstChild.firstChild;
|
||||
quotientNode.children.forEach(node => {
|
||||
quotientNode.children.forEach((node) => {
|
||||
assert.equal(
|
||||
node.nextParseState,
|
||||
JavaScript.nextState(node.parseState, node.grammarId)
|
||||
JavaScript.nextState(node.parseState, node.grammarId),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -356,82 +356,82 @@ describe("Node", () => {
|
|||
|
||||
describe('.descendantsOfType(type, min, max)', () => {
|
||||
it('finds all of the descendants of the given type in the given range', () => {
|
||||
tree = parser.parse("a + 1 * b * 2 + c + 3");
|
||||
tree = parser.parse('a + 1 * b * 2 + c + 3');
|
||||
const outerSum = tree.rootNode.firstChild.firstChild;
|
||||
let descendants = outerSum.descendantsOfType('number', {row: 0, column: 2}, {row: 0, column: 15})
|
||||
let descendants = outerSum.descendantsOfType('number', {row: 0, column: 2}, {row: 0, column: 15});
|
||||
assert.deepEqual(
|
||||
descendants.map(node => node.startIndex),
|
||||
[4, 12]
|
||||
descendants.map((node) => node.startIndex),
|
||||
[4, 12],
|
||||
);
|
||||
assert.deepEqual(
|
||||
descendants.map(node => node.endPosition),
|
||||
[{row: 0, column: 5}, {row: 0, column: 13}]
|
||||
descendants.map((node) => node.endPosition),
|
||||
[{row: 0, column: 5}, {row: 0, column: 13}],
|
||||
);
|
||||
|
||||
descendants = outerSum.descendantsOfType('identifier', {row: 0, column: 2}, {row: 0, column: 15})
|
||||
descendants = outerSum.descendantsOfType('identifier', {row: 0, column: 2}, {row: 0, column: 15});
|
||||
assert.deepEqual(
|
||||
descendants.map(node => node.startIndex),
|
||||
[8]
|
||||
descendants.map((node) => node.startIndex),
|
||||
[8],
|
||||
);
|
||||
|
||||
descendants = outerSum.descendantsOfType('identifier', {row: 0, column: 0}, {row: 0, column: 30})
|
||||
descendants = outerSum.descendantsOfType('identifier', {row: 0, column: 0}, {row: 0, column: 30});
|
||||
assert.deepEqual(
|
||||
descendants.map(node => node.startIndex),
|
||||
[0, 8, 16]
|
||||
descendants.map((node) => node.startIndex),
|
||||
[0, 8, 16],
|
||||
);
|
||||
|
||||
descendants = outerSum.descendantsOfType('number', {row: 0, column: 0}, {row: 0, column: 30})
|
||||
descendants = outerSum.descendantsOfType('number', {row: 0, column: 0}, {row: 0, column: 30});
|
||||
assert.deepEqual(
|
||||
descendants.map(node => node.startIndex),
|
||||
[4, 12, 20]
|
||||
descendants.map((node) => node.startIndex),
|
||||
[4, 12, 20],
|
||||
);
|
||||
|
||||
descendants = outerSum.descendantsOfType(
|
||||
['identifier', 'number'],
|
||||
{row: 0, column: 0},
|
||||
{row: 0, column: 30}
|
||||
)
|
||||
{row: 0, column: 30},
|
||||
);
|
||||
assert.deepEqual(
|
||||
descendants.map(node => node.startIndex),
|
||||
[0, 4, 8, 12, 16, 20]
|
||||
descendants.map((node) => node.startIndex),
|
||||
[0, 4, 8, 12, 16, 20],
|
||||
);
|
||||
|
||||
descendants = outerSum.descendantsOfType('number')
|
||||
descendants = outerSum.descendantsOfType('number');
|
||||
assert.deepEqual(
|
||||
descendants.map(node => node.startIndex),
|
||||
[4, 12, 20]
|
||||
descendants.map((node) => node.startIndex),
|
||||
[4, 12, 20],
|
||||
);
|
||||
|
||||
descendants = outerSum.firstChild.descendantsOfType('number', {row: 0, column: 0}, {row: 0, column: 30})
|
||||
descendants = outerSum.firstChild.descendantsOfType('number', {row: 0, column: 0}, {row: 0, column: 30});
|
||||
assert.deepEqual(
|
||||
descendants.map(node => node.startIndex),
|
||||
[4, 12]
|
||||
descendants.map((node) => node.startIndex),
|
||||
[4, 12],
|
||||
);
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
describe.skip('.closest(type)', () => {
|
||||
it('returns the closest ancestor of the given type', () => {
|
||||
tree = parser.parse("a(b + -d.e)");
|
||||
const property = tree.rootNode.descendantForIndex("a(b + -d.".length);
|
||||
tree = parser.parse('a(b + -d.e)');
|
||||
const property = tree.rootNode.descendantForIndex('a(b + -d.'.length);
|
||||
assert.equal(property.type, 'property_identifier');
|
||||
|
||||
const unary = property.closest('unary_expression')
|
||||
assert.equal(unary.type, 'unary_expression')
|
||||
assert.equal(unary.startIndex, 'a(b + '.length)
|
||||
assert.equal(unary.endIndex, 'a(b + -d.e'.length)
|
||||
const unary = property.closest('unary_expression');
|
||||
assert.equal(unary.type, 'unary_expression');
|
||||
assert.equal(unary.startIndex, 'a(b + '.length);
|
||||
assert.equal(unary.endIndex, 'a(b + -d.e'.length);
|
||||
|
||||
const sum = property.closest(['binary_expression', 'call_expression'])
|
||||
assert.equal(sum.type, 'binary_expression')
|
||||
assert.equal(sum.startIndex, 2)
|
||||
assert.equal(sum.endIndex, 'a(b + -d.e'.length)
|
||||
const sum = property.closest(['binary_expression', 'call_expression']);
|
||||
assert.equal(sum.type, 'binary_expression');
|
||||
assert.equal(sum.startIndex, 2);
|
||||
assert.equal(sum.endIndex, 'a(b + -d.e'.length);
|
||||
});
|
||||
|
||||
it('throws an exception when an invalid argument is given', () => {
|
||||
tree = parser.parse("a + 1 * b * 2 + c + 3");
|
||||
const number = tree.rootNode.descendantForIndex(4)
|
||||
tree = parser.parse('a + 1 * b * 2 + c + 3');
|
||||
const number = tree.rootNode.descendantForIndex(4);
|
||||
|
||||
assert.throws(() => number.closest({a: 1}), /Argument must be a string or array of strings/)
|
||||
assert.throws(() => number.closest({a: 1}), /Argument must be a string or array of strings/);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
const {assert} = require('chai');
|
||||
let Parser, JavaScript, languageURL;
|
||||
let Parser; let JavaScript; let languageURL;
|
||||
|
||||
describe("Parser", () => {
|
||||
describe('Parser', () => {
|
||||
let parser;
|
||||
|
||||
before(async () =>
|
||||
({Parser, JavaScript, languageURL} = await require('./helper'))
|
||||
({Parser, JavaScript, languageURL} = await require('./helper')),
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
@ -13,11 +13,11 @@ describe("Parser", () => {
|
|||
});
|
||||
|
||||
afterEach(() => {
|
||||
parser.delete()
|
||||
parser.delete();
|
||||
});
|
||||
|
||||
describe(".setLanguage", () => {
|
||||
it("allows setting the language to null", () => {
|
||||
describe('.setLanguage', () => {
|
||||
it('allows setting the language to null', () => {
|
||||
assert.equal(parser.getLanguage(), null);
|
||||
parser.setLanguage(JavaScript);
|
||||
assert.equal(parser.getLanguage(), JavaScript);
|
||||
|
|
@ -25,112 +25,114 @@ describe("Parser", () => {
|
|||
assert.equal(parser.getLanguage(), null);
|
||||
});
|
||||
|
||||
it("throws an exception when the given object is not a tree-sitter language", () => {
|
||||
it('throws an exception when the given object is not a tree-sitter language', () => {
|
||||
assert.throws(() => parser.setLanguage({}), /Argument must be a Language/);
|
||||
assert.throws(() => parser.setLanguage(1), /Argument must be a Language/);
|
||||
});
|
||||
});
|
||||
|
||||
describe(".setLogger", () => {
|
||||
describe('.setLogger', () => {
|
||||
beforeEach(() => {
|
||||
parser.setLanguage(JavaScript)
|
||||
parser.setLanguage(JavaScript);
|
||||
});
|
||||
|
||||
it("calls the given callback for each parse event", () => {
|
||||
it('calls the given callback for each parse event', () => {
|
||||
const debugMessages = [];
|
||||
parser.setLogger((message) => debugMessages.push(message));
|
||||
parser.parse("a + b + c");
|
||||
parser.parse('a + b + c');
|
||||
assert.includeMembers(debugMessages, [
|
||||
"skip character:' '",
|
||||
"consume character:'b'",
|
||||
"reduce sym:program, child_count:1",
|
||||
"accept"
|
||||
'skip character:\' \'',
|
||||
'consume character:\'b\'',
|
||||
'reduce sym:program, child_count:1',
|
||||
'accept',
|
||||
]);
|
||||
});
|
||||
|
||||
it("allows the callback to be retrieved later", () => {
|
||||
const callback = () => {}
|
||||
it('allows the callback to be retrieved later', () => {
|
||||
const callback = () => {};
|
||||
parser.setLogger(callback);
|
||||
assert.equal(parser.getLogger(), callback);
|
||||
parser.setLogger(false);
|
||||
assert.equal(parser.getLogger(), null);
|
||||
});
|
||||
|
||||
it("disables debugging when given a falsy value", () => {
|
||||
it('disables debugging when given a falsy value', () => {
|
||||
const debugMessages = [];
|
||||
parser.setLogger((message) => debugMessages.push(message));
|
||||
parser.setLogger(false);
|
||||
parser.parse("a + b * c");
|
||||
parser.parse('a + b * c');
|
||||
assert.equal(debugMessages.length, 0);
|
||||
});
|
||||
|
||||
it("throws an error when given a truthy value that isn't a function ", () => {
|
||||
it('throws an error when given a truthy value that isn\'t a function ', () => {
|
||||
assert.throws(
|
||||
() => parser.setLogger("5"),
|
||||
"Logger callback must be a function"
|
||||
() => parser.setLogger('5'),
|
||||
'Logger callback must be a function',
|
||||
);
|
||||
});
|
||||
|
||||
it("rethrows errors thrown by the logging callback", () => {
|
||||
const error = new Error("The error message");
|
||||
parser.setLogger((msg, params) => { throw error; });
|
||||
it('rethrows errors thrown by the logging callback', () => {
|
||||
const error = new Error('The error message');
|
||||
parser.setLogger((msg, params) => {
|
||||
throw error;
|
||||
});
|
||||
assert.throws(
|
||||
() => parser.parse("ok;"),
|
||||
"The error message"
|
||||
() => parser.parse('ok;'),
|
||||
'The error message',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe(".parse", () => {
|
||||
describe('.parse', () => {
|
||||
let tree;
|
||||
|
||||
beforeEach(() => {
|
||||
tree = null;
|
||||
parser.setLanguage(JavaScript)
|
||||
parser.setLanguage(JavaScript);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
if (tree) tree.delete();
|
||||
});
|
||||
|
||||
it("reads from the given input", () => {
|
||||
const parts = ["first", "_", "second", "_", "third"];
|
||||
it('reads from the given input', () => {
|
||||
const parts = ['first', '_', 'second', '_', 'third'];
|
||||
tree = parser.parse(() => parts.shift());
|
||||
assert.equal(tree.rootNode.toString(), "(program (expression_statement (identifier)))");
|
||||
assert.equal(tree.rootNode.toString(), '(program (expression_statement (identifier)))');
|
||||
});
|
||||
|
||||
it("stops reading when the input callback return something that's not a string", () => {
|
||||
const parts = ["abc", "def", "ghi", {}, {}, {}, "second-word", " "];
|
||||
it('stops reading when the input callback return something that\'s not a string', () => {
|
||||
const parts = ['abc', 'def', 'ghi', {}, {}, {}, 'second-word', ' '];
|
||||
tree = parser.parse(() => parts.shift());
|
||||
assert.equal(
|
||||
tree.rootNode.toString(),
|
||||
"(program (expression_statement (identifier)))"
|
||||
'(program (expression_statement (identifier)))',
|
||||
);
|
||||
assert.equal(tree.rootNode.endIndex, 9);
|
||||
assert.equal(parts.length, 2);
|
||||
});
|
||||
|
||||
it("throws an exception when the given input is not a function", () => {
|
||||
assert.throws(() => parser.parse(null), "Argument must be a string or a function");
|
||||
assert.throws(() => parser.parse(5), "Argument must be a string or a function");
|
||||
assert.throws(() => parser.parse({}), "Argument must be a string or a function");
|
||||
it('throws an exception when the given input is not a function', () => {
|
||||
assert.throws(() => parser.parse(null), 'Argument must be a string or a function');
|
||||
assert.throws(() => parser.parse(5), 'Argument must be a string or a function');
|
||||
assert.throws(() => parser.parse({}), 'Argument must be a string or a function');
|
||||
});
|
||||
|
||||
it("handles long input strings", () => {
|
||||
it('handles long input strings', () => {
|
||||
const repeatCount = 10000;
|
||||
const inputString = "[" + "0,".repeat(repeatCount) + "]";
|
||||
const inputString = '[' + '0,'.repeat(repeatCount) + ']';
|
||||
|
||||
tree = parser.parse(inputString);
|
||||
assert.equal(tree.rootNode.type, "program");
|
||||
assert.equal(tree.rootNode.type, 'program');
|
||||
assert.equal(tree.rootNode.firstChild.firstChild.namedChildCount, repeatCount);
|
||||
}).timeout(5000);
|
||||
|
||||
it("can use the bash parser", async () => {
|
||||
it('can use the bash parser', async () => {
|
||||
parser.setLanguage(await Parser.Language.load(languageURL('bash')));
|
||||
tree = parser.parse("FOO=bar echo <<EOF 2> err.txt > hello.txt \nhello${FOO}\nEOF");
|
||||
tree = parser.parse('FOO=bar echo <<EOF 2> err.txt > hello.txt \nhello${FOO}\nEOF');
|
||||
assert.equal(
|
||||
tree.rootNode.toString(),
|
||||
'(program ' +
|
||||
'(program ' +
|
||||
'(redirected_statement ' +
|
||||
'body: (command ' +
|
||||
'(variable_assignment name: (variable_name) value: (word)) ' +
|
||||
|
|
@ -139,13 +141,13 @@ describe("Parser", () => {
|
|||
'redirect: (file_redirect descriptor: (file_descriptor) destination: (word)) ' +
|
||||
'redirect: (file_redirect destination: (word)) ' +
|
||||
'(heredoc_body ' +
|
||||
'(expansion (variable_name)) (heredoc_content)) (heredoc_end))))'
|
||||
'(expansion (variable_name)) (heredoc_content)) (heredoc_end))))',
|
||||
);
|
||||
}).timeout(5000);
|
||||
|
||||
it("can use the c++ parser", async () => {
|
||||
it('can use the c++ parser', async () => {
|
||||
parser.setLanguage(await Parser.Language.load(languageURL('cpp')));
|
||||
tree = parser.parse("const char *s = R\"EOF(HELLO WORLD)EOF\";");
|
||||
tree = parser.parse('const char *s = R"EOF(HELLO WORLD)EOF";');
|
||||
assert.equal(
|
||||
tree.rootNode.toString(),
|
||||
'(translation_unit (declaration ' +
|
||||
|
|
@ -153,22 +155,22 @@ describe("Parser", () => {
|
|||
'type: (primitive_type) ' +
|
||||
'declarator: (init_declarator ' +
|
||||
'declarator: (pointer_declarator declarator: (identifier)) ' +
|
||||
'value: (raw_string_literal delimiter: (raw_string_delimiter) (raw_string_content) (raw_string_delimiter)))))'
|
||||
'value: (raw_string_literal delimiter: (raw_string_delimiter) (raw_string_content) (raw_string_delimiter)))))',
|
||||
);
|
||||
}).timeout(5000);
|
||||
|
||||
it("can use the HTML parser", async () => {
|
||||
it('can use the HTML parser', async () => {
|
||||
parser.setLanguage(await Parser.Language.load(languageURL('html')));
|
||||
tree = parser.parse("<div><span><custom></custom></span></div>");
|
||||
tree = parser.parse('<div><span><custom></custom></span></div>');
|
||||
assert.equal(
|
||||
tree.rootNode.toString(),
|
||||
'(fragment (element (start_tag (tag_name)) (element (start_tag (tag_name)) (element (start_tag (tag_name)) (end_tag (tag_name))) (end_tag (tag_name))) (end_tag (tag_name))))'
|
||||
'(fragment (element (start_tag (tag_name)) (element (start_tag (tag_name)) (element (start_tag (tag_name)) (end_tag (tag_name))) (end_tag (tag_name))) (end_tag (tag_name))))',
|
||||
);
|
||||
}).timeout(5000);
|
||||
|
||||
it("can use the python parser", async () => {
|
||||
it('can use the python parser', async () => {
|
||||
parser.setLanguage(await Parser.Language.load(languageURL('python')));
|
||||
tree = parser.parse("class A:\n def b():\n c()");
|
||||
tree = parser.parse('class A:\n def b():\n c()');
|
||||
assert.equal(
|
||||
tree.rootNode.toString(),
|
||||
'(module (class_definition ' +
|
||||
|
|
@ -179,25 +181,25 @@ describe("Parser", () => {
|
|||
'parameters: (parameters) ' +
|
||||
'body: (block (expression_statement (call ' +
|
||||
'function: (identifier) ' +
|
||||
'arguments: (argument_list))))))))'
|
||||
'arguments: (argument_list))))))))',
|
||||
);
|
||||
}).timeout(5000);
|
||||
|
||||
it("can use the rust parser", async () => {
|
||||
it('can use the rust parser', async () => {
|
||||
parser.setLanguage(await Parser.Language.load(languageURL('rust')));
|
||||
tree = parser.parse("const x: &'static str = r###\"hello\"###;");
|
||||
tree = parser.parse('const x: &\'static str = r###"hello"###;');
|
||||
assert.equal(
|
||||
tree.rootNode.toString(),
|
||||
'(source_file (const_item ' +
|
||||
'name: (identifier) ' +
|
||||
'type: (reference_type (lifetime (identifier)) type: (primitive_type)) ' +
|
||||
'value: (raw_string_literal)))'
|
||||
'value: (raw_string_literal)))',
|
||||
);
|
||||
}).timeout(5000);
|
||||
|
||||
it("can use the typescript parser", async () => {
|
||||
it('can use the typescript parser', async () => {
|
||||
parser.setLanguage(await Parser.Language.load(languageURL('typescript')));
|
||||
tree = parser.parse("a()\nb()\n[c]");
|
||||
tree = parser.parse('a()\nb()\n[c]');
|
||||
assert.equal(
|
||||
tree.rootNode.toString(),
|
||||
'(program ' +
|
||||
|
|
@ -206,13 +208,13 @@ describe("Parser", () => {
|
|||
'object: (call_expression ' +
|
||||
'function: (identifier) ' +
|
||||
'arguments: (arguments)) ' +
|
||||
'index: (identifier))))'
|
||||
'index: (identifier))))',
|
||||
);
|
||||
}).timeout(5000);
|
||||
|
||||
it("can use the tsx parser", async () => {
|
||||
it('can use the tsx parser', async () => {
|
||||
parser.setLanguage(await Parser.Language.load(languageURL('tsx')));
|
||||
tree = parser.parse("a()\nb()\n[c]");
|
||||
tree = parser.parse('a()\nb()\n[c]');
|
||||
assert.equal(
|
||||
tree.rootNode.toString(),
|
||||
'(program ' +
|
||||
|
|
@ -221,17 +223,17 @@ describe("Parser", () => {
|
|||
'object: (call_expression ' +
|
||||
'function: (identifier) ' +
|
||||
'arguments: (arguments)) ' +
|
||||
'index: (identifier))))'
|
||||
'index: (identifier))))',
|
||||
);
|
||||
}).timeout(5000);
|
||||
|
||||
it('parses only the text within the `includedRanges` if they are specified', () => {
|
||||
const sourceCode = "<% foo() %> <% bar %>";
|
||||
const sourceCode = '<% foo() %> <% bar %>';
|
||||
|
||||
const start1 = sourceCode.indexOf('foo');
|
||||
const end1 = start1 + 5
|
||||
const end1 = start1 + 5;
|
||||
const start2 = sourceCode.indexOf('bar');
|
||||
const end2 = start2 + 3
|
||||
const end2 = start2 + 3;
|
||||
|
||||
const tree = parser.parse(sourceCode, null, {
|
||||
includedRanges: [
|
||||
|
|
@ -239,20 +241,21 @@ describe("Parser", () => {
|
|||
startIndex: start1,
|
||||
endIndex: end1,
|
||||
startPosition: {row: 0, column: start1},
|
||||
endPosition: {row: 0, column: end1}
|
||||
endPosition: {row: 0, column: end1},
|
||||
},
|
||||
{
|
||||
startIndex: start2,
|
||||
endIndex: end2,
|
||||
startPosition: {row: 0, column: start2},
|
||||
endPosition: {row: 0, column: end2}
|
||||
endPosition: {row: 0, column: end2},
|
||||
},
|
||||
]
|
||||
],
|
||||
});
|
||||
|
||||
assert.equal(
|
||||
tree.rootNode.toString(),
|
||||
'(program (expression_statement (call_expression function: (identifier) arguments: (arguments))) (expression_statement (identifier)))'
|
||||
'(program (expression_statement (call_expression function: (identifier) arguments: (arguments))) (expression_statement (identifier)))',
|
||||
);
|
||||
})
|
||||
});});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
const { assert } = require("chai");
|
||||
let Parser, JavaScript;
|
||||
const {assert} = require('chai');
|
||||
let Parser; let JavaScript;
|
||||
|
||||
describe("Query", () => {
|
||||
let parser, tree, query;
|
||||
describe('Query', () => {
|
||||
let parser; let tree; let query;
|
||||
|
||||
before(async () => ({ Parser, JavaScript } = await require("./helper")));
|
||||
before(async () => ({Parser, JavaScript} = await require('./helper')));
|
||||
|
||||
beforeEach(() => {
|
||||
parser = new Parser().setLanguage(JavaScript);
|
||||
|
|
@ -16,73 +16,73 @@ describe("Query", () => {
|
|||
if (query) query.delete();
|
||||
});
|
||||
|
||||
describe("construction", () => {
|
||||
it("throws an error on invalid patterns", () => {
|
||||
describe('construction', () => {
|
||||
it('throws an error on invalid patterns', () => {
|
||||
assert.throws(() => {
|
||||
JavaScript.query("(function_declaration wat)");
|
||||
}, "Bad syntax at offset 22: 'wat)'...");
|
||||
JavaScript.query('(function_declaration wat)');
|
||||
}, 'Bad syntax at offset 22: \'wat)\'...');
|
||||
assert.throws(() => {
|
||||
JavaScript.query("(non_existent)");
|
||||
}, "Bad node name 'non_existent'");
|
||||
JavaScript.query('(non_existent)');
|
||||
}, 'Bad node name \'non_existent\'');
|
||||
assert.throws(() => {
|
||||
JavaScript.query("(a)");
|
||||
}, "Bad node name 'a'");
|
||||
JavaScript.query('(a)');
|
||||
}, 'Bad node name \'a\'');
|
||||
assert.throws(() => {
|
||||
JavaScript.query("(function_declaration non_existent:(identifier))");
|
||||
}, "Bad field name 'non_existent'");
|
||||
JavaScript.query('(function_declaration non_existent:(identifier))');
|
||||
}, 'Bad field name \'non_existent\'');
|
||||
assert.throws(() => {
|
||||
JavaScript.query("(function_declaration name:(statement_block))");
|
||||
}, "Bad pattern structure at offset 22: 'name:(statement_block))'");
|
||||
JavaScript.query('(function_declaration name:(statement_block))');
|
||||
}, 'Bad pattern structure at offset 22: \'name:(statement_block))\'');
|
||||
});
|
||||
|
||||
it("throws an error on invalid predicates", () => {
|
||||
it('throws an error on invalid predicates', () => {
|
||||
assert.throws(() => {
|
||||
JavaScript.query("((identifier) @abc (#eq? @ab hi))");
|
||||
}, "Bad capture name @ab");
|
||||
JavaScript.query('((identifier) @abc (#eq? @ab hi))');
|
||||
}, 'Bad capture name @ab');
|
||||
assert.throws(() => {
|
||||
JavaScript.query("((identifier) @abc (#eq? @ab hi))");
|
||||
}, "Bad capture name @ab");
|
||||
JavaScript.query('((identifier) @abc (#eq? @ab hi))');
|
||||
}, 'Bad capture name @ab');
|
||||
assert.throws(() => {
|
||||
JavaScript.query("((identifier) @abc (#eq?))");
|
||||
}, "Wrong number of arguments to `#eq?` predicate. Expected 2, got 0");
|
||||
JavaScript.query('((identifier) @abc (#eq?))');
|
||||
}, 'Wrong number of arguments to `#eq?` predicate. Expected 2, got 0');
|
||||
assert.throws(() => {
|
||||
JavaScript.query("((identifier) @a (eq? @a @a @a))");
|
||||
}, "Wrong number of arguments to `#eq?` predicate. Expected 2, got 3");
|
||||
JavaScript.query('((identifier) @a (eq? @a @a @a))');
|
||||
}, 'Wrong number of arguments to `#eq?` predicate. Expected 2, got 3');
|
||||
});
|
||||
});
|
||||
|
||||
describe(".matches", () => {
|
||||
it("returns all of the matches for the given query", () => {
|
||||
tree = parser.parse("function one() { two(); function three() {} }");
|
||||
describe('.matches', () => {
|
||||
it('returns all of the matches for the given query', () => {
|
||||
tree = parser.parse('function one() { two(); function three() {} }');
|
||||
query = JavaScript.query(`
|
||||
(function_declaration name: (identifier) @fn-def)
|
||||
(call_expression function: (identifier) @fn-ref)
|
||||
`);
|
||||
const matches = query.matches(tree.rootNode);
|
||||
assert.deepEqual(formatMatches(matches), [
|
||||
{ pattern: 0, captures: [{ name: "fn-def", text: "one" }] },
|
||||
{ pattern: 1, captures: [{ name: "fn-ref", text: "two" }] },
|
||||
{ pattern: 0, captures: [{ name: "fn-def", text: "three" }] },
|
||||
{pattern: 0, captures: [{name: 'fn-def', text: 'one'}]},
|
||||
{pattern: 1, captures: [{name: 'fn-ref', text: 'two'}]},
|
||||
{pattern: 0, captures: [{name: 'fn-def', text: 'three'}]},
|
||||
]);
|
||||
});
|
||||
|
||||
it("can search in a specified ranges", () => {
|
||||
tree = parser.parse("[a, b,\nc, d,\ne, f,\ng, h]");
|
||||
query = JavaScript.query("(identifier) @element");
|
||||
it('can search in a specified ranges', () => {
|
||||
tree = parser.parse('[a, b,\nc, d,\ne, f,\ng, h]');
|
||||
query = JavaScript.query('(identifier) @element');
|
||||
const matches = query.matches(
|
||||
tree.rootNode,
|
||||
{ row: 1, column: 1 },
|
||||
{ row: 3, column: 1 }
|
||||
{row: 1, column: 1},
|
||||
{row: 3, column: 1},
|
||||
);
|
||||
assert.deepEqual(formatMatches(matches), [
|
||||
{ pattern: 0, captures: [{ name: "element", text: "d" }] },
|
||||
{ pattern: 0, captures: [{ name: "element", text: "e" }] },
|
||||
{ pattern: 0, captures: [{ name: "element", text: "f" }] },
|
||||
{ pattern: 0, captures: [{ name: "element", text: "g" }] },
|
||||
{pattern: 0, captures: [{name: 'element', text: 'd'}]},
|
||||
{pattern: 0, captures: [{name: 'element', text: 'e'}]},
|
||||
{pattern: 0, captures: [{name: 'element', text: 'f'}]},
|
||||
{pattern: 0, captures: [{name: 'element', text: 'g'}]},
|
||||
]);
|
||||
});
|
||||
|
||||
it("handles predicates that compare the text of capture to literal strings", () => {
|
||||
it('handles predicates that compare the text of capture to literal strings', () => {
|
||||
tree = parser.parse(`
|
||||
giraffe(1, 2, []);
|
||||
helment([false]);
|
||||
|
|
@ -103,14 +103,14 @@ describe("Query", () => {
|
|||
|
||||
const matches = query.matches(tree.rootNode);
|
||||
assert.deepEqual(formatMatches(matches), [
|
||||
{ pattern: 0, captures: [{ name: "name", text: "giraffe" }] },
|
||||
{ pattern: 0, captures: [{ name: "name", text: "gross" }] },
|
||||
{pattern: 0, captures: [{name: 'name', text: 'giraffe'}]},
|
||||
{pattern: 0, captures: [{name: 'name', text: 'gross'}]},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe(".captures", () => {
|
||||
it("returns all of the captures for the given query, in order", () => {
|
||||
describe('.captures', () => {
|
||||
it('returns all of the captures for the given query, in order', () => {
|
||||
tree = parser.parse(`
|
||||
a({
|
||||
bc: function de() {
|
||||
|
|
@ -138,22 +138,22 @@ describe("Query", () => {
|
|||
|
||||
const captures = query.captures(tree.rootNode);
|
||||
assert.deepEqual(formatCaptures(captures), [
|
||||
{ name: "method.def", text: "bc" },
|
||||
{ name: "delimiter", text: ":" },
|
||||
{ name: "method.alias", text: "de" },
|
||||
{ name: "function.def", text: "fg" },
|
||||
{ name: "operator", text: "=" },
|
||||
{ name: "function.alias", text: "hi" },
|
||||
{ name: "method.def", text: "jk" },
|
||||
{ name: "delimiter", text: ":" },
|
||||
{ name: "method.alias", text: "lm" },
|
||||
{ name: "function.def", text: "no" },
|
||||
{ name: "operator", text: "=" },
|
||||
{ name: "function.alias", text: "pq" },
|
||||
{name: 'method.def', text: 'bc'},
|
||||
{name: 'delimiter', text: ':'},
|
||||
{name: 'method.alias', text: 'de'},
|
||||
{name: 'function.def', text: 'fg'},
|
||||
{name: 'operator', text: '='},
|
||||
{name: 'function.alias', text: 'hi'},
|
||||
{name: 'method.def', text: 'jk'},
|
||||
{name: 'delimiter', text: ':'},
|
||||
{name: 'method.alias', text: 'lm'},
|
||||
{name: 'function.def', text: 'no'},
|
||||
{name: 'operator', text: '='},
|
||||
{name: 'function.alias', text: 'pq'},
|
||||
]);
|
||||
});
|
||||
|
||||
it("handles conditions that compare the text of capture to literal strings", () => {
|
||||
it('handles conditions that compare the text of capture to literal strings', () => {
|
||||
tree = parser.parse(`
|
||||
lambda
|
||||
panda
|
||||
|
|
@ -179,20 +179,20 @@ describe("Query", () => {
|
|||
|
||||
const captures = query.captures(tree.rootNode);
|
||||
assert.deepEqual(formatCaptures(captures), [
|
||||
{ name: "variable", text: "panda" },
|
||||
{ name: "variable", text: "toad" },
|
||||
{ name: "variable", text: "ab" },
|
||||
{ name: "variable", text: "require" },
|
||||
{ name: "function.builtin", text: "require" },
|
||||
{ name: "variable", text: "Cd" },
|
||||
{ name: "constructor", text: "Cd" },
|
||||
{ name: "variable", text: "EF" },
|
||||
{ name: "constructor", text: "EF" },
|
||||
{ name: "constant", text: "EF" },
|
||||
{name: 'variable', text: 'panda'},
|
||||
{name: 'variable', text: 'toad'},
|
||||
{name: 'variable', text: 'ab'},
|
||||
{name: 'variable', text: 'require'},
|
||||
{name: 'function.builtin', text: 'require'},
|
||||
{name: 'variable', text: 'Cd'},
|
||||
{name: 'constructor', text: 'Cd'},
|
||||
{name: 'variable', text: 'EF'},
|
||||
{name: 'constructor', text: 'EF'},
|
||||
{name: 'constant', text: 'EF'},
|
||||
]);
|
||||
});
|
||||
|
||||
it("handles conditions that compare the text of capture to each other", () => {
|
||||
it('handles conditions that compare the text of capture to each other', () => {
|
||||
tree = parser.parse(`
|
||||
ab = abc + 1;
|
||||
def = de + 1;
|
||||
|
|
@ -211,12 +211,12 @@ describe("Query", () => {
|
|||
|
||||
const captures = query.captures(tree.rootNode);
|
||||
assert.deepEqual(formatCaptures(captures), [
|
||||
{ name: "id1", text: "ghi" },
|
||||
{ name: "id2", text: "ghi" },
|
||||
{name: 'id1', text: 'ghi'},
|
||||
{name: 'id2', text: 'ghi'},
|
||||
]);
|
||||
});
|
||||
|
||||
it("handles patterns with properties", () => {
|
||||
it('handles patterns with properties', () => {
|
||||
tree = parser.parse(`a(b.c);`);
|
||||
query = JavaScript.query(`
|
||||
((call_expression (identifier) @func)
|
||||
|
|
@ -230,18 +230,18 @@ describe("Query", () => {
|
|||
|
||||
const captures = query.captures(tree.rootNode);
|
||||
assert.deepEqual(formatCaptures(captures), [
|
||||
{ name: "func", text: "a", setProperties: { foo: null, bar: "baz" } },
|
||||
{name: 'func', text: 'a', setProperties: {foo: null, bar: 'baz'}},
|
||||
{
|
||||
name: "prop",
|
||||
text: "c",
|
||||
assertedProperties: { foo: null },
|
||||
refutedProperties: { bar: "baz" },
|
||||
name: 'prop',
|
||||
text: 'c',
|
||||
assertedProperties: {foo: null},
|
||||
refutedProperties: {bar: 'baz'},
|
||||
},
|
||||
]);
|
||||
assert.ok(!query.didExceedMatchLimit());
|
||||
});
|
||||
|
||||
it("detects queries with too many permutations to track", () => {
|
||||
it('detects queries with too many permutations to track', () => {
|
||||
tree = parser.parse(`
|
||||
[
|
||||
hello, hello, hello, hello, hello, hello, hello, hello, hello, hello,
|
||||
|
|
@ -256,11 +256,11 @@ describe("Query", () => {
|
|||
(array (identifier) @pre (identifier) @post)
|
||||
`);
|
||||
|
||||
const captures = query.captures(tree.rootNode, null, null, { matchLimit: 32 });
|
||||
query.captures(tree.rootNode, null, null, {matchLimit: 32});
|
||||
assert.ok(query.didExceedMatchLimit());
|
||||
});
|
||||
|
||||
it("handles quantified captures properly", () => {
|
||||
it('handles quantified captures properly', () => {
|
||||
let captures;
|
||||
|
||||
tree = parser.parse(`
|
||||
|
|
@ -276,7 +276,7 @@ describe("Query", () => {
|
|||
)
|
||||
`);
|
||||
|
||||
let expectCount = (tree, queryText, expectedCount) => {
|
||||
const expectCount = (tree, queryText, expectedCount) => {
|
||||
query = JavaScript.query(queryText);
|
||||
captures = query.captures(tree.rootNode, null, null);
|
||||
assert.equal(captures.length, expectedCount);
|
||||
|
|
@ -284,68 +284,68 @@ describe("Query", () => {
|
|||
|
||||
expectCount(
|
||||
tree,
|
||||
` ( (comment)+ @foo (#any-eq? @foo "/// foo") ) `,
|
||||
3
|
||||
`((comment)+ @foo (#any-eq? @foo "/// foo"))`,
|
||||
3,
|
||||
);
|
||||
|
||||
expectCount(
|
||||
tree,
|
||||
` ( (comment)+ @foo (#eq? @foo "/// foo") ) `,
|
||||
0
|
||||
`((comment)+ @foo (#eq? @foo "/// foo"))`,
|
||||
0,
|
||||
);
|
||||
|
||||
expectCount(
|
||||
tree,
|
||||
` ( (comment)+ @foo (#any-not-eq? @foo "/// foo") ) `,
|
||||
3
|
||||
`((comment)+ @foo (#any-not-eq? @foo "/// foo"))`,
|
||||
3,
|
||||
);
|
||||
|
||||
expectCount(
|
||||
tree,
|
||||
` ( (comment)+ @foo (#not-eq? @foo "/// foo") ) `,
|
||||
0
|
||||
`((comment)+ @foo (#not-eq? @foo "/// foo"))`,
|
||||
0,
|
||||
);
|
||||
|
||||
expectCount(
|
||||
tree,
|
||||
` ( (comment)+ @foo (#match? @foo "^/// foo") ) `,
|
||||
0
|
||||
`((comment)+ @foo (#match? @foo "^/// foo"))`,
|
||||
0,
|
||||
);
|
||||
|
||||
expectCount(
|
||||
tree,
|
||||
` ( (comment)+ @foo (#any-match? @foo "^/// foo") ) `,
|
||||
3
|
||||
`((comment)+ @foo (#any-match? @foo "^/// foo"))`,
|
||||
3,
|
||||
);
|
||||
|
||||
expectCount(
|
||||
tree,
|
||||
` ( (comment)+ @foo (#not-match? @foo "^/// foo") ) `,
|
||||
0
|
||||
`((comment)+ @foo (#not-match? @foo "^/// foo"))`,
|
||||
0,
|
||||
);
|
||||
|
||||
expectCount(
|
||||
tree,
|
||||
` ( (comment)+ @foo (#not-match? @foo "fsdfsdafdfs") ) `,
|
||||
3
|
||||
`((comment)+ @foo (#not-match? @foo "fsdfsdafdfs"))`,
|
||||
3,
|
||||
);
|
||||
|
||||
expectCount(
|
||||
tree,
|
||||
` ( (comment)+ @foo (#any-not-match? @foo "^///") ) `,
|
||||
0
|
||||
`((comment)+ @foo (#any-not-match? @foo "^///"))`,
|
||||
0,
|
||||
);
|
||||
|
||||
expectCount(
|
||||
tree,
|
||||
` ( (comment)+ @foo (#any-not-match? @foo "^/// foo") ) `,
|
||||
3
|
||||
`((comment)+ @foo (#any-not-match? @foo "^/// foo"))`,
|
||||
3,
|
||||
);
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
describe(".predicatesForPattern(index)", () => {
|
||||
it("returns all of the predicates as objects", () => {
|
||||
describe('.predicatesForPattern(index)', () => {
|
||||
it('returns all of the predicates as objects', () => {
|
||||
query = JavaScript.query(`
|
||||
(
|
||||
(binary_expression
|
||||
|
|
@ -364,26 +364,26 @@ describe("Query", () => {
|
|||
|
||||
assert.deepEqual(query.predicatesForPattern(0), [
|
||||
{
|
||||
operator: "something?",
|
||||
operator: 'something?',
|
||||
operands: [
|
||||
{ type: "capture", name: "a" },
|
||||
{ type: "capture", name: "b" },
|
||||
{type: 'capture', name: 'a'},
|
||||
{type: 'capture', name: 'b'},
|
||||
],
|
||||
},
|
||||
{
|
||||
operator: "something-else?",
|
||||
operator: 'something-else?',
|
||||
operands: [
|
||||
{ type: "capture", name: "a" },
|
||||
{ type: "string", value: "A" },
|
||||
{ type: "capture", name: "b" },
|
||||
{ type: "string", value: "B" },
|
||||
{type: 'capture', name: 'a'},
|
||||
{type: 'string', value: 'A'},
|
||||
{type: 'capture', name: 'b'},
|
||||
{type: 'string', value: 'B'},
|
||||
],
|
||||
},
|
||||
]);
|
||||
assert.deepEqual(query.predicatesForPattern(1), [
|
||||
{
|
||||
operator: "hello!",
|
||||
operands: [{ type: "capture", name: "c" }],
|
||||
operator: 'hello!',
|
||||
operands: [{type: 'capture', name: 'c'}],
|
||||
},
|
||||
]);
|
||||
assert.deepEqual(query.predicatesForPattern(2), []);
|
||||
|
|
@ -392,7 +392,7 @@ describe("Query", () => {
|
|||
});
|
||||
|
||||
function formatMatches(matches) {
|
||||
return matches.map(({ pattern, captures }) => ({
|
||||
return matches.map(({pattern, captures}) => ({
|
||||
pattern,
|
||||
captures: formatCaptures(captures),
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
const {assert} = require('chai');
|
||||
let Parser, JavaScript;
|
||||
let Parser; let JavaScript;
|
||||
|
||||
describe("Tree", () => {
|
||||
let parser, tree;
|
||||
describe('Tree', () => {
|
||||
let parser; let tree;
|
||||
|
||||
before(async () =>
|
||||
({Parser, JavaScript} = await require('./helper'))
|
||||
({Parser, JavaScript} = await require('./helper')),
|
||||
);
|
||||
|
||||
beforeEach(() => {
|
||||
|
|
@ -18,14 +18,14 @@ describe("Tree", () => {
|
|||
});
|
||||
|
||||
describe('.edit', () => {
|
||||
let input, edit
|
||||
let input; let edit;
|
||||
|
||||
it('updates the positions of nodes', () => {
|
||||
input = 'abc + cde';
|
||||
tree = parser.parse(input);
|
||||
assert.equal(
|
||||
tree.rootNode.toString(),
|
||||
"(program (expression_statement (binary_expression left: (identifier) right: (identifier))))"
|
||||
'(program (expression_statement (binary_expression left: (identifier) right: (identifier))))',
|
||||
);
|
||||
|
||||
let sumNode = tree.rootNode.firstChild.firstChild;
|
||||
|
|
@ -51,17 +51,17 @@ describe("Tree", () => {
|
|||
tree = parser.parse(input, tree);
|
||||
assert.equal(
|
||||
tree.rootNode.toString(),
|
||||
"(program (expression_statement (binary_expression left: (binary_expression left: (identifier) right: (identifier)) right: (identifier))))"
|
||||
'(program (expression_statement (binary_expression left: (binary_expression left: (identifier) right: (identifier)) right: (identifier))))',
|
||||
);
|
||||
});
|
||||
|
||||
it("handles non-ascii characters", () => {
|
||||
it('handles non-ascii characters', () => {
|
||||
input = 'αβδ + cde';
|
||||
|
||||
tree = parser.parse(input);
|
||||
assert.equal(
|
||||
tree.rootNode.toString(),
|
||||
"(program (expression_statement (binary_expression left: (identifier) right: (identifier))))"
|
||||
'(program (expression_statement (binary_expression left: (identifier) right: (identifier))))',
|
||||
);
|
||||
|
||||
let variableNode = tree.rootNode.firstChild.firstChild.lastChild;
|
||||
|
|
@ -76,65 +76,65 @@ describe("Tree", () => {
|
|||
tree = parser.parse(input, tree);
|
||||
assert.equal(
|
||||
tree.rootNode.toString(),
|
||||
"(program (expression_statement (binary_expression left: (binary_expression left: (identifier) right: (identifier)) right: (identifier))))"
|
||||
'(program (expression_statement (binary_expression left: (binary_expression left: (identifier) right: (identifier)) right: (identifier))))',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe(".getChangedRanges(previous)", () => {
|
||||
it("reports the ranges of text whose syntactic meaning has changed", () => {
|
||||
let sourceCode = "abcdefg + hij";
|
||||
describe('.getChangedRanges(previous)', () => {
|
||||
it('reports the ranges of text whose syntactic meaning has changed', () => {
|
||||
let sourceCode = 'abcdefg + hij';
|
||||
tree = parser.parse(sourceCode);
|
||||
|
||||
assert.equal(
|
||||
tree.rootNode.toString(),
|
||||
"(program (expression_statement (binary_expression left: (identifier) right: (identifier))))"
|
||||
'(program (expression_statement (binary_expression left: (identifier) right: (identifier))))',
|
||||
);
|
||||
|
||||
sourceCode = "abc + defg + hij";
|
||||
sourceCode = 'abc + defg + hij';
|
||||
tree.edit({
|
||||
startIndex: 2,
|
||||
oldEndIndex: 2,
|
||||
newEndIndex: 5,
|
||||
startPosition: { row: 0, column: 2 },
|
||||
oldEndPosition: { row: 0, column: 2 },
|
||||
newEndPosition: { row: 0, column: 5 }
|
||||
startPosition: {row: 0, column: 2},
|
||||
oldEndPosition: {row: 0, column: 2},
|
||||
newEndPosition: {row: 0, column: 5},
|
||||
});
|
||||
|
||||
const tree2 = parser.parse(sourceCode, tree);
|
||||
assert.equal(
|
||||
tree2.rootNode.toString(),
|
||||
"(program (expression_statement (binary_expression left: (binary_expression left: (identifier) right: (identifier)) right: (identifier))))"
|
||||
'(program (expression_statement (binary_expression left: (binary_expression left: (identifier) right: (identifier)) right: (identifier))))',
|
||||
);
|
||||
|
||||
const ranges = tree.getChangedRanges(tree2);
|
||||
assert.deepEqual(ranges, [
|
||||
{
|
||||
startIndex: 0,
|
||||
endIndex: "abc + defg".length,
|
||||
startPosition: { row: 0, column: 0 },
|
||||
endPosition: { row: 0, column: "abc + defg".length }
|
||||
}
|
||||
endIndex: 'abc + defg'.length,
|
||||
startPosition: {row: 0, column: 0},
|
||||
endPosition: {row: 0, column: 'abc + defg'.length},
|
||||
},
|
||||
]);
|
||||
|
||||
tree2.delete();
|
||||
});
|
||||
|
||||
it('throws an exception if the argument is not a tree', () => {
|
||||
tree = parser.parse("abcdefg + hij");
|
||||
tree = parser.parse('abcdefg + hij');
|
||||
|
||||
assert.throws(() => {
|
||||
tree.getChangedRanges({});
|
||||
}, /Argument must be a Tree/);
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
describe(".walk()", () => {
|
||||
let cursor
|
||||
describe('.walk()', () => {
|
||||
let cursor;
|
||||
|
||||
afterEach(() => {
|
||||
cursor.delete();
|
||||
})
|
||||
});
|
||||
|
||||
it('returns a cursor that can be used to walk the tree', () => {
|
||||
tree = parser.parse('a * b + c / d');
|
||||
|
|
@ -146,7 +146,7 @@ describe("Tree", () => {
|
|||
startPosition: {row: 0, column: 0},
|
||||
endPosition: {row: 0, column: 13},
|
||||
startIndex: 0,
|
||||
endIndex: 13
|
||||
endIndex: 13,
|
||||
});
|
||||
|
||||
assert(cursor.gotoFirstChild());
|
||||
|
|
@ -156,7 +156,7 @@ describe("Tree", () => {
|
|||
startPosition: {row: 0, column: 0},
|
||||
endPosition: {row: 0, column: 13},
|
||||
startIndex: 0,
|
||||
endIndex: 13
|
||||
endIndex: 13,
|
||||
});
|
||||
|
||||
assert(cursor.gotoFirstChild());
|
||||
|
|
@ -166,7 +166,7 @@ describe("Tree", () => {
|
|||
startPosition: {row: 0, column: 0},
|
||||
endPosition: {row: 0, column: 13},
|
||||
startIndex: 0,
|
||||
endIndex: 13
|
||||
endIndex: 13,
|
||||
});
|
||||
|
||||
assert(cursor.gotoFirstChild());
|
||||
|
|
@ -176,7 +176,7 @@ describe("Tree", () => {
|
|||
startPosition: {row: 0, column: 0},
|
||||
endPosition: {row: 0, column: 5},
|
||||
startIndex: 0,
|
||||
endIndex: 5
|
||||
endIndex: 5,
|
||||
});
|
||||
|
||||
assert(cursor.gotoFirstChild());
|
||||
|
|
@ -187,10 +187,10 @@ describe("Tree", () => {
|
|||
startPosition: {row: 0, column: 0},
|
||||
endPosition: {row: 0, column: 1},
|
||||
startIndex: 0,
|
||||
endIndex: 1
|
||||
endIndex: 1,
|
||||
});
|
||||
|
||||
assert(!cursor.gotoFirstChild())
|
||||
assert(!cursor.gotoFirstChild());
|
||||
assert(cursor.gotoNextSibling());
|
||||
assert.equal(cursor.nodeText, '*');
|
||||
assertCursorState(cursor, {
|
||||
|
|
@ -199,7 +199,7 @@ describe("Tree", () => {
|
|||
startPosition: {row: 0, column: 2},
|
||||
endPosition: {row: 0, column: 3},
|
||||
startIndex: 2,
|
||||
endIndex: 3
|
||||
endIndex: 3,
|
||||
});
|
||||
|
||||
assert(cursor.gotoNextSibling());
|
||||
|
|
@ -210,7 +210,7 @@ describe("Tree", () => {
|
|||
startPosition: {row: 0, column: 4},
|
||||
endPosition: {row: 0, column: 5},
|
||||
startIndex: 4,
|
||||
endIndex: 5
|
||||
endIndex: 5,
|
||||
});
|
||||
|
||||
assert(!cursor.gotoNextSibling());
|
||||
|
|
@ -221,7 +221,7 @@ describe("Tree", () => {
|
|||
startPosition: {row: 0, column: 0},
|
||||
endPosition: {row: 0, column: 5},
|
||||
startIndex: 0,
|
||||
endIndex: 5
|
||||
endIndex: 5,
|
||||
});
|
||||
|
||||
assert(cursor.gotoNextSibling());
|
||||
|
|
@ -231,7 +231,7 @@ describe("Tree", () => {
|
|||
startPosition: {row: 0, column: 6},
|
||||
endPosition: {row: 0, column: 7},
|
||||
startIndex: 6,
|
||||
endIndex: 7
|
||||
endIndex: 7,
|
||||
});
|
||||
|
||||
assert(cursor.gotoNextSibling());
|
||||
|
|
@ -241,7 +241,7 @@ describe("Tree", () => {
|
|||
startPosition: {row: 0, column: 8},
|
||||
endPosition: {row: 0, column: 13},
|
||||
startIndex: 8,
|
||||
endIndex: 13
|
||||
endIndex: 13,
|
||||
});
|
||||
|
||||
{
|
||||
|
|
@ -255,7 +255,7 @@ describe("Tree", () => {
|
|||
startPosition: {row: 0, column: 6},
|
||||
endPosition: {row: 0, column: 7},
|
||||
startIndex: 6,
|
||||
endIndex: 7
|
||||
endIndex: 7,
|
||||
});
|
||||
|
||||
assert(copy.gotoPreviousSibling());
|
||||
|
|
@ -265,28 +265,28 @@ describe("Tree", () => {
|
|||
startPosition: {row: 0, column: 0},
|
||||
endPosition: {row: 0, column: 5},
|
||||
startIndex: 0,
|
||||
endIndex: 5
|
||||
endIndex: 5,
|
||||
});
|
||||
|
||||
assert(copy.gotoLastChild());
|
||||
assertCursorState(copy, {
|
||||
nodeType: "identifier",
|
||||
nodeType: 'identifier',
|
||||
nodeIsNamed: true,
|
||||
startPosition: {row: 0, column: 4},
|
||||
endPosition: {row: 0, column: 5},
|
||||
startIndex: 4,
|
||||
endIndex: 5
|
||||
})
|
||||
endIndex: 5,
|
||||
});
|
||||
|
||||
assert(copy.gotoParent());
|
||||
assert(copy.gotoParent());
|
||||
assert.equal(copy.nodeType, 'binary_expression')
|
||||
assert.equal(copy.nodeType, 'binary_expression');
|
||||
assert(copy.gotoParent());
|
||||
assert.equal(copy.nodeType, 'expression_statement')
|
||||
assert.equal(copy.nodeType, 'expression_statement');
|
||||
assert(copy.gotoParent());
|
||||
assert.equal(copy.nodeType, 'program')
|
||||
assert.equal(copy.nodeType, 'program');
|
||||
assert(!copy.gotoParent());
|
||||
}
|
||||
}
|
||||
|
||||
// const childIndex = cursor.gotoFirstChildForIndex(12);
|
||||
// assertCursorState(cursor, {
|
||||
|
|
@ -302,11 +302,11 @@ describe("Tree", () => {
|
|||
// assert(cursor.gotoParent());
|
||||
|
||||
assert(cursor.gotoParent());
|
||||
assert.equal(cursor.nodeType, 'binary_expression')
|
||||
assert.equal(cursor.nodeType, 'binary_expression');
|
||||
assert(cursor.gotoParent());
|
||||
assert.equal(cursor.nodeType, 'expression_statement')
|
||||
assert.equal(cursor.nodeType, 'expression_statement');
|
||||
assert(cursor.gotoParent());
|
||||
assert.equal(cursor.nodeType, 'program')
|
||||
assert.equal(cursor.nodeType, 'program');
|
||||
assert(!cursor.gotoParent());
|
||||
});
|
||||
|
||||
|
|
@ -350,31 +350,31 @@ describe("Tree", () => {
|
|||
startPosition: {row: 0, column: 0},
|
||||
endPosition: {row: 0, column: 5},
|
||||
startIndex: 0,
|
||||
endIndex: 5
|
||||
endIndex: 5,
|
||||
});
|
||||
|
||||
cursor.gotoFirstChild()
|
||||
cursor.gotoFirstChild();
|
||||
assertCursorState(cursor, {
|
||||
nodeType: 'identifier',
|
||||
nodeIsNamed: true,
|
||||
startPosition: {row: 0, column: 0},
|
||||
endPosition: {row: 0, column: 1},
|
||||
startIndex: 0,
|
||||
endIndex: 1
|
||||
endIndex: 1,
|
||||
});
|
||||
|
||||
assert(cursor.gotoParent());
|
||||
assert(!cursor.gotoParent());
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
describe(".copy", () => {
|
||||
it("creates another tree that remains stable if the original tree is edited", () => {
|
||||
describe('.copy', () => {
|
||||
it('creates another tree that remains stable if the original tree is edited', () => {
|
||||
input = 'abc + cde';
|
||||
tree = parser.parse(input);
|
||||
assert.equal(
|
||||
tree.rootNode.toString(),
|
||||
"(program (expression_statement (binary_expression left: (identifier) right: (identifier))))"
|
||||
'(program (expression_statement (binary_expression left: (identifier) right: (identifier))))',
|
||||
);
|
||||
|
||||
const tree2 = tree.copy();
|
||||
|
|
@ -386,10 +386,10 @@ describe("Tree", () => {
|
|||
const leftNode2 = tree2.rootNode.firstChild.firstChild.firstChild;
|
||||
const rightNode = tree.rootNode.firstChild.firstChild.lastChild;
|
||||
const rightNode2 = tree2.rootNode.firstChild.firstChild.lastChild;
|
||||
assert.equal(leftNode.endIndex, 6)
|
||||
assert.equal(leftNode2.endIndex, 3)
|
||||
assert.equal(rightNode.startIndex, 9)
|
||||
assert.equal(rightNode2.startIndex, 6)
|
||||
assert.equal(leftNode.endIndex, 6);
|
||||
assert.equal(leftNode2.endIndex, 3);
|
||||
assert.equal(rightNode.startIndex, 9);
|
||||
assert.equal(rightNode2.startIndex, 6);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -406,16 +406,16 @@ function spliceInput(input, startIndex, lengthRemoved, newText) {
|
|||
{
|
||||
startIndex, startPosition,
|
||||
oldEndIndex, oldEndPosition,
|
||||
newEndIndex, newEndPosition
|
||||
}
|
||||
newEndIndex, newEndPosition,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
function getExtent(text) {
|
||||
let row = 0
|
||||
let row = 0;
|
||||
let index;
|
||||
for (index = 0; index != -1; index = text.indexOf('\n', index)) {
|
||||
index++
|
||||
index++;
|
||||
row++;
|
||||
}
|
||||
return {row, column: text.length - index};
|
||||
|
|
@ -429,7 +429,7 @@ function assertCursorState(cursor, params) {
|
|||
assert.deepEqual(cursor.startIndex, params.startIndex);
|
||||
assert.deepEqual(cursor.endIndex, params.endIndex);
|
||||
|
||||
const node = cursor.currentNode()
|
||||
const node = cursor.currentNode();
|
||||
assert.equal(node.type, params.nodeType);
|
||||
assert.equal(node.isNamed(), params.nodeIsNamed);
|
||||
assert.deepEqual(node.startPosition, params.startPosition);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue