@codeque/core
Version:
Multiline code search for every language. Structural code search for JavaScript, TypeScript, HTML and CSS
167 lines (155 loc) • 4.69 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.parseCode = parseCode;
exports.parserModule = void 0;
var _treeSitterUtils = require("../../treeSitterUtils");
const defineRawValueForNodeTypes = ['identifier', 'number', 'string_content'];
const postProcessNodes = {
function_declaration: node => {
/**
* Global scope function declaration without name should be same as anonymous function definition passed as argument
*/
if (node.name?.rawValue === '') {
node.nodeType = 'function_definition';
node.name = null;
return node;
}
return node;
},
function_definition: node => {
/**
* Anonymous function definition should have null name field to be compared with `function_declaration` changed into `function_definition`
* We could use delete operator on `function_declaration`, but it's slow.
*/
if (node.name === undefined) {
node.name = null;
}
return node;
},
binary_expression: (node, codeText) => {
const leftNodeLocationLoc = node.left.loc;
const leftNodeLocationEndIndex = leftNodeLocationLoc.end.index;
const rightNodeLocationLoc = node.right.loc;
const rightNodeLocationStartIndex = rightNodeLocationLoc.start.index;
const operator = codeText.substring(leftNodeLocationEndIndex, rightNodeLocationStartIndex);
const operatorNode = {
nodeType: '__codeque__operator',
rawValue: operator.trim(),
loc: {
/**
* We could adjust location to be without spaces, but it does not matter actually
*/
start: leftNodeLocationLoc.end,
end: rightNodeLocationLoc.start
}
};
node.operator = operatorNode;
return node;
},
function_call: node => {
if (node.name.rawValue === '') {
const actualContent = node.arguments.children[0];
return {
nodeType: 'expression_list',
loc: node.loc,
children: [actualContent]
};
}
return node;
},
parenthesized_expression: node => {
const children = node.children; // Remove empty identifiers from parenthesized_expression
if (children.length === 1 && children[0]?.rawValue === '') {
return { ...node,
children: []
};
}
return node;
}
};
const parserModule = (0, _treeSitterUtils.treeSitterParserModuleFactory)({
treeSitterParserName: 'tree-sitter-lua',
postProcessNodes,
defineRawValueForNodeTypes
});
exports.parserModule = parserModule;
const isRawString = code => {
const trimmedCode = code.trim();
return !trimmedCode.includes('\n') && (trimmedCode.startsWith("'") && trimmedCode.endsWith("'") || trimmedCode.startsWith('"') && trimmedCode.endsWith('"'));
};
function parseCode(code) {
const trimmedCode = code.trim();
if (isRawString(trimmedCode)) {
/**
* Just string literal query is strangely parsed, so we parse it manually
*/
const loc = {
start: {
line: 1,
column: 0,
index: 0
},
end: {
line: 1,
column: trimmedCode.length,
index: trimmedCode.length
}
};
return {
nodeType: 'chunk',
loc,
children: [{
nodeType: 'expression_list',
loc,
children: [{
nodeType: 'string',
loc,
content: {
nodeType: 'string_content',
loc: {
start: {
line: 1,
column: loc.start.column + 1,
index: loc.start.index + 1
},
end: {
line: 1,
column: loc.end.column - 1,
index: loc.end.index - 1
}
},
children: [],
rawValue: trimmedCode.substring(1, trimmedCode.length - 1)
},
end: null,
start: null
}]
}]
};
}
try {
return parserModule.parse(code);
} catch (originalCodeParserError) {
/**
* Lua does not support standalone expressions in the code.
*
* To workaround that, when parser error occurs, we create variable assignment to extract expression_list
*
* we throw original error if that extraction fails, because our changes might produce also broken code.
*/
try {
const modifiedCode = `__codeque = ${trimmedCode}`;
const modifiedCodeAst = parserModule.parse(modifiedCode);
const expression_list = modifiedCodeAst?.children?.[0]?.children?.[1];
return {
nodeType: 'chunk',
loc: expression_list.loc,
children: [expression_list]
};
} catch (e) {
throw originalCodeParserError;
}
}
}