@codeque/core
Version:
Multiline code search for every language. Structural code search for JavaScript, TypeScript, HTML and CSS
226 lines (185 loc) • 6.26 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.angularEslintTemplateParser = void 0;
var _templateParser = require("@angular-eslint/template-parser");
var _utils = require("../../utils");
var _common = require("./common");
var _traverseAndMatch = require("../../searchStages/traverseAndMatch");
var _beforeWildcardsComparators = require("./beforeWildcardsComparators");
const supportedExtensions = ['html', 'htm'];
const getProgramNodeFromRootNode = rootNode => rootNode; // root node is program node
const getProgramBodyFromRootNode = fileNode => {
return fileNode.templateNodes;
};
const unwrapExpressionStatement = node => {
return node;
};
const createBlockStatementNode = (templateNodes, position) => ({
type: 'Program',
templateNodes,
...position
});
const isNode = maybeNode => {
return typeof maybeNode?.type === 'string';
};
const astPropsToSkip = ['range', 'sourceSpan', 'startSourceSpan', 'endSourceSpan', 'valueSpan', 'keySpan', 'loc', 'start', 'end', 'extra', 'trailingComments', 'leadingComments', 'innerComments', 'comments', 'tail' // Support for partial matching of template literals
];
const parseCode = (code, filePath = '') => {
return (0, _templateParser.parseForESLint)(code, {
filePath,
range: true,
loc: true
}).ast;
};
const nodeValuesSanitizers = {
['Text$3']: {
value: _utils.normalizeText
}
};
const getSanitizedNodeValue = (nodeType, valueKey, value) => {
const valueSanitizer = nodeValuesSanitizers?.[nodeType]?.[valueKey];
if (valueSanitizer) {
return valueSanitizer(value);
}
return value;
};
const shouldCompareNode = node => {
if (node.type === 'Text$3') {
const value = getSanitizedNodeValue('Text$3', 'value', node.value);
const shouldCompare = value.length > 0;
return shouldCompare;
}
return true;
};
const getNodeType = node => node.type;
const isIdentifierNode = node => _common.identifierNodeTypes.includes(getNodeType(node));
const stringLikeLiteralUtils = {
// Text$3 is only pure string node
isStringLikeLiteralNode: node => node.type === 'Text$3',
getStringLikeLiteralValue: node => {
return node?.value;
}
};
const numericLiteralUtils = {
isNumericLiteralNode: node => node.type === 'NumericLiteral',
getNumericLiteralValue: node => node.extra.raw
};
const programNodeAndBlockNodeUtils = {
isProgramNode: node => node.type === 'Program',
isBlockNode: node => node.type === 'Program',
programNodeBodyKey: 'templateNodes',
blockNodeBodyKey: 'templateNodes'
};
const getNodePosition = node => ({
start: node?.sourceSpan?.start?.offset ?? 0,
end: node?.sourceSpan?.end?.offset ?? 0,
loc: node.loc
});
const getParseErrorLocation = e => ({
line: e.loc?.line ?? 0,
column: e.loc?.column ?? 0
});
const alternativeNodeTypes = {
Identifier: _common.identifierNodeTypes
};
/**
* To support wildcards in html we have to
* - encode wildcard, do it in query text before parsing $$ => a_a_$$
* - decode wildcard, traverse parsed query and: a_a_$$ => $$
* `$$` is invalid tag name start in all html parsers
*/
const encodedWildcardSequence = 'a_$$_x';
const preprocessQueryCode = code => {
const queryCode = code.replace(/(\$\$)/g, () => encodedWildcardSequence);
return queryCode;
};
const replaceEncodedWildcards = value => value.replace(/a_\$\$_x/g, () => '$$');
const postprocessQueryNode = queryNode => {
(0, _traverseAndMatch.traverseAst)(queryNode, isNode, getNodeType, {
Element$1: node => {
const nodeName = node.name;
if (nodeName.includes(encodedWildcardSequence)) {
node.name = replaceEncodedWildcards(nodeName);
}
},
TextAttribute: node => {
const nodeValue = node.value;
if (nodeValue.includes(encodedWildcardSequence)) {
node.value = replaceEncodedWildcards(nodeValue);
}
},
Text$3: node => {
const nodeValue = node.value;
if (nodeValue.includes(encodedWildcardSequence)) {
node.value = replaceEncodedWildcards(nodeValue);
}
}
});
return queryNode;
};
const compareNodesBeforeWildcardsComparison = (...nodeComparatorParams) => {
return (0, _utils.runNodesComparators)(_beforeWildcardsComparators.beforeWildcardsComparators, nodeComparatorParams);
};
const getUniqueTokensFromStringOrIdentifierNode = ({
queryNode,
caseInsensitive,
parserSettings
}) => {
const MIN_TOKEN_LEN = 2;
const {
anyStringWildcardRegExp
} = parserSettings.wildcardUtils;
const tokens = [];
const valuesToProcess = [];
if (queryNode.type === 'TextAttribute') {
valuesToProcess.push(queryNode.name);
valuesToProcess.push(queryNode.value);
}
if (queryNode.type === 'Element$1') {
valuesToProcess.push(queryNode.name);
}
if (queryNode.type === 'Text$3') {
valuesToProcess.push(queryNode.value);
}
valuesToProcess.map(val => parserSettings.wildcardUtils.removeWildcardAliasesFromStringLiteral(val)).map(val => (0, _utils.decomposeString)(val, anyStringWildcardRegExp)).flat(1).forEach(part => {
if (part.length >= MIN_TOKEN_LEN) {
tokens.push(caseInsensitive ? part.toLocaleLowerCase() : part);
}
});
return tokens;
};
const angularEslintTemplateParser = {
supportedExtensions,
parseCode,
isNode,
isIdentifierNode,
astPropsToSkip,
getProgramBodyFromRootNode,
getProgramNodeFromRootNode,
getIdentifierNodeName: _common.getIdentifierNodeName,
getNodeType,
unwrapExpressionStatement,
createBlockStatementNode,
getSanitizedNodeValue,
identifierNodeTypes: _common.identifierNodeTypes,
setIdentifierNodeName: _common.setIdentifierNodeName,
shouldCompareNode,
wildcardUtils: _common.wildcardUtils,
compareNodesBeforeWildcardsComparison,
compareNodesAfterWildcardsComparison: () => undefined,
identifierTypeAnnotationFieldName: 'typeAnnotation',
stringLikeLiteralUtils,
numericLiteralUtils,
programNodeAndBlockNodeUtils,
getNodePosition,
getParseErrorLocation,
alternativeNodeTypes,
postprocessQueryNode,
preprocessQueryCode,
getUniqueTokensFromStringOrIdentifierNode
};
exports.angularEslintTemplateParser = angularEslintTemplateParser;
var _default = angularEslintTemplateParser;
exports.default = _default;
;