@codeque/core
Version:
Multiline code search for every language. Structural code search for JavaScript, TypeScript, HTML and CSS
293 lines (238 loc) • 8.6 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = exports.cssTree = void 0;
var _cssTree = require("css-tree");
var _utils = require("../../utils");
var _common = require("./common");
var _traverseAndMatch = require("../../searchStages/traverseAndMatch");
var _beforeWildcardsComparators = require("./beforeWildcardsComparators");
var _afterWildcardsComparators = require("./afterWildcardsComparators");
const supportedExtensions = ['css'];
const getProgramNodeFromRootNode = rootNode => rootNode; // root node is program node
const getProgramBodyFromRootNode = fileNode => {
return fileNode.children;
};
const unwrapExpressionStatement = node => {
return node;
};
const createBlockStatementNode = (children, position) => ({
type: 'Block',
children,
...position
});
const isNode = maybeNode => {
return typeof maybeNode?.type === 'string';
};
const astPropsToSkip = ['loc'];
const parseCode = code => {
const sharedOptions = {
parseAtrulePrelude: true,
parseRulePrelude: true,
parseValue: true,
positions: true
};
if (code.includes('{')) {
return (0, _cssTree.toPlainObject)((0, _cssTree.parse)(code, { ...sharedOptions,
context: 'stylesheet'
}));
} else {
return (0, _cssTree.toPlainObject)((0, _cssTree.parse)(code, { ...sharedOptions,
context: 'declarationList'
}));
}
};
const nodeValuesSanitizers = {
['Raw']: {
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 === 'WhiteSpace') {
return false;
}
if (node.type === 'Raw') {
const value = getSanitizedNodeValue('Raw', '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 stringLikeNodeTypes = ['TypeSelector', 'Raw', 'ClassSelector', 'Identifier', 'IdSelector', 'Url'];
const stringLikeLiteralUtils = {
// Raw is only pure string node
isStringLikeLiteralNode: node => stringLikeNodeTypes.includes(node.type),
getStringLikeLiteralValue: node => {
return node?.value || node?.name;
}
};
const pureNumericNodes = ['Percentage', 'Number', 'Hash'];
const numericLiteralUtils = {
isNumericLiteralNode: node => pureNumericNodes.includes(node.type),
getNumericLiteralValue: node => node.value
};
const programNodeAndBlockNodeUtils = {
isProgramNode: node => node.type === 'StyleSheet',
isBlockNode: node => node.type === 'Block',
programNodeBodyKey: 'children',
blockNodeBodyKey: 'children'
};
const getNodePosition = node => {
const location = node.loc;
return {
start: location?.start?.offset ?? 0,
end: location?.end?.offset ?? 0,
loc: {
start: {
line: location.start.line,
column: location.start.column - 1 // We need 0-based, parser return 1-based
},
end: {
line: location.end.line,
column: location.end.column - 1 // We need 0-based, parser return 1-based
}
}
};
};
const getParseErrorLocation = e => ({
line: e.loc?.line ?? 0,
column: e.loc?.column ?? 0
});
const alternativeNodeTypes = {
Identifier: _common.identifierNodeTypes
};
/**
* To support wildcards in caa we have to
* - encode wildcard, do it in query text before parsing $$ => a_a_x
* - decode wildcard, traverse parsed query and: a_a_x => $$
* - Same for numeric wildcard 0x0 -> 00000000 // 0{8}
* `$$` is invalid tag name start in all html parsers
*/
const encodedStringWildcardSequence = 'a_a_a';
const encodedNodesTreeWildcardSequence = 'z_z_z';
const encodedNumericWildcardSequence = '00000000';
const preprocessQueryCode = code => {
const queryCode = code.replace(/(\$\$\$)/g, () => encodedNodesTreeWildcardSequence).replace(/(\$\$)/g, () => encodedStringWildcardSequence).replace(/0x0/g, encodedNumericWildcardSequence);
return queryCode;
};
const replaceEncodedWildcards = value => value.replace(/a_a_a/g, () => '$$').replace(/z_z_z/g, () => '$$$').replace(/0{8}/g, '0x0');
const stringNodeTypes = {
withName: ['Identifier', 'IdSelector', 'MediaFeature', 'ClassSelector', 'PseudoClassSelector', 'PseudoElementSelector', 'TypeSelector', 'Function', 'Combinator'],
withValue: ['String', 'Url'],
withProperty: ['Declaration']
};
const postprocessQueryNodeWithName = node => {
const name = node.name;
if (name.includes(encodedStringWildcardSequence) || name.includes(encodedNodesTreeWildcardSequence)) {
node.name = replaceEncodedWildcards(name);
}
};
const postprocessQueryNodeWithValue = node => {
const value = node.value;
if (value.includes(encodedStringWildcardSequence) || value.includes(encodedNodesTreeWildcardSequence) || value.includes(encodedNumericWildcardSequence)) {
node.value = replaceEncodedWildcards(value);
}
};
const postprocessQueryNodeWithProperty = node => {
const property = node.property;
if (property.includes(encodedStringWildcardSequence) || property.includes(encodedNodesTreeWildcardSequence)) {
node.property = replaceEncodedWildcards(property);
}
};
const createVisitorsForNodeTypes = (types, visitorFn) => types.reduce((visitorsMap, nodeType) => ({ ...visitorsMap,
[nodeType]: visitorFn
}), {});
const postprocessVisitors = { ...createVisitorsForNodeTypes(stringNodeTypes.withName, postprocessQueryNodeWithName),
...createVisitorsForNodeTypes(stringNodeTypes.withProperty, postprocessQueryNodeWithProperty),
...createVisitorsForNodeTypes([...stringNodeTypes.withValue, ...pureNumericNodes], postprocessQueryNodeWithValue),
Dimension: node => {
const unit = node.unit;
const value = node.value;
if (unit.includes(encodedStringWildcardSequence)) {
node.unit = replaceEncodedWildcards(unit);
}
if (value === encodedNumericWildcardSequence) {
node.value = replaceEncodedWildcards(value);
}
}
};
const postprocessQueryNode = queryNode => {
(0, _traverseAndMatch.traverseAst)(queryNode, isNode, getNodeType, postprocessVisitors);
return queryNode;
};
const compareNodesBeforeWildcardsComparison = (...nodeComparatorParams) => {
return (0, _utils.runNodesComparators)(_beforeWildcardsComparators.beforeWildcardsComparators, nodeComparatorParams);
};
const compareNodesAfterWildcardsComparison = (...nodeComparatorParams) => {
return (0, _utils.runNodesComparators)(_afterWildcardsComparators.afterWildcardsComparators, nodeComparatorParams);
};
const getUniqueTokensFromStringOrIdentifierNode = ({
queryNode,
caseInsensitive,
parserSettings
}) => {
const MIN_TOKEN_LEN = 2;
const {
anyStringWildcardRegExp
} = parserSettings.wildcardUtils;
const tokens = [];
const valuesToProcess = [];
if (stringNodeTypes.withName.includes(queryNode.type)) {
valuesToProcess.push(queryNode.name);
}
if (stringNodeTypes.withProperty.includes(queryNode.type)) {
valuesToProcess.push(queryNode.property);
}
if (stringNodeTypes.withValue.includes(queryNode.type)) {
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 cssTree = {
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,
identifierTypeAnnotationFieldName: 'typeAnnotation',
stringLikeLiteralUtils,
numericLiteralUtils,
programNodeAndBlockNodeUtils,
getNodePosition,
getParseErrorLocation,
alternativeNodeTypes,
postprocessQueryNode,
preprocessQueryCode,
getUniqueTokensFromStringOrIdentifierNode
};
exports.cssTree = cssTree;
var _default = cssTree;
exports.default = _default;
;