Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@vltpkg/dss-parser

Package Overview
Dependencies
Maintainers
6
Versions
46
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@vltpkg/dss-parser - npm Package Compare versions

Comparing version
1.0.0-rc.23
to
1.0.0-rc.24
+15
dist/index.d.ts
import type { Root } from 'postcss-selector-parser';
export * from './types.ts';
/**
* Escapes forward slashes in specific patterns matching @scoped/name paths
* This will allow usage of unescaped forward slashes necessary for scoped
* package names in the id selector.
*/
export declare const escapeScopedNamesSlashes: (query: string) => string;
export declare const escapeDots: (query: string) => string;
export declare const unescapeDots: (query: string) => string;
/**
* Parses a CSS selector string into an AST
* Handles escaping of forward slashes in specific patterns
*/
export declare const parse: (query: string) => Root;
import postcssSelectorParser from 'postcss-selector-parser';
import { asSelectorNode, isCombinatorNode, isPseudoNode, isTagNode, } from "./types.js";
export * from "./types.js";
/**
* Escapes forward slashes in specific patterns matching @scoped/name paths
* This will allow usage of unescaped forward slashes necessary for scoped
* package names in the id selector.
*/
export const escapeScopedNamesSlashes = (query) => query.replace(/(#@(\w|-|\.)+)\//gm, (_, scope) => `${scope}\\/`);
export const escapeDots = (query) => query.replaceAll('.', '\\.');
export const unescapeDots = (query) => query.replaceAll('\\.', '.');
const pseudoCleanUpNeeded = new Set([
':published',
':score',
':malware',
':severity',
':sev',
':squat',
':semver',
':v',
]);
const hasParamsToEscape = (node) => pseudoCleanUpNeeded.has(node.value);
/**
* Parses a CSS selector string into an AST
* Handles escaping of forward slashes in specific patterns
*/
export const parse = (query) => {
const escapedQuery = escapeDots(escapeScopedNamesSlashes(query));
const transformAst = (root) => {
root.walk((node) => {
// clean up the escaped dots
if (node.value && typeof node.value === 'string') {
node.value = unescapeDots(node.value);
}
if (isPseudoNode(node) && hasParamsToEscape(node)) {
// these are pseudo nodes that should only take strings as
// parameters, so in this preparse step we clean up anything
// that was recognized as a postcss node and transform that
// into something that can be most likely parsed as a string
for (const n of node.nodes) {
// the parameters have a selector node that wraps them up
const selector = asSelectorNode(n);
selector.nodes.forEach((currentNode, index, arr) => {
// get the next node, we'll update it later
const nextNode = arr[index + 1];
// if the current node is a combinator node, we'll need to
// escape it, we do so by removing the node entirely and
// updating the contents of the next node with its value
if (isCombinatorNode(currentNode) &&
isTagNode(nextNode)) {
nextNode.value = `${currentNode.spaces.before}${currentNode.value}${currentNode.spaces.after}${nextNode.value}`;
// make sure to also update the source position
// references, those are used by the syntax highlighter
if (nextNode.source?.start?.line &&
currentNode.source?.start?.line) {
nextNode.source.start.line =
currentNode.source.start.line;
}
if (nextNode.source?.start?.column &&
currentNode.source?.start?.column) {
nextNode.source.start.column =
currentNode.source.start.column;
}
// removes the current node from the selector node
arr.splice(index, 1);
}
});
// after removing combinator nodes, if we end up with multiple
// tags in the selector node, we need to smush them together
selector.nodes.reduce((acc, currentNode) => {
if (currentNode === acc)
return acc;
acc.value = `${acc.value}${currentNode.spaces.before}${currentNode.value}${currentNode.spaces.after}`;
// make sure to also update the source position refs
if (currentNode.source?.end?.line &&
acc.source?.end?.line) {
acc.source.end.line = currentNode.source.end.line;
}
if (currentNode.source?.end?.column &&
acc.source?.end?.column) {
acc.source.end.column = currentNode.source.end.column;
}
return acc;
}, selector.first);
// the selector wrapper node should have a single node
selector.nodes.length = 1;
}
}
});
};
return postcssSelectorParser(transformAst).astSync(escapedQuery);
};
import type { Tag, String, Selector, Root, Pseudo, Nesting, Identifier, Comment, Combinator, ClassName, Attribute, Universal, tag, id, combinator, string, attribute, pseudo } from 'postcss-selector-parser';
export type PostcssNode = Tag | String | Selector | Root | Pseudo | Nesting | Identifier | Comment | Combinator | ClassName | Attribute | Universal;
export type PostCSSLeaf = ReturnType<typeof tag> | ReturnType<typeof id> | ReturnType<typeof attribute> | ReturnType<typeof combinator> | ReturnType<typeof pseudo> | ReturnType<typeof string>;
export type PostcssNodeWithChildren = Selector | Root | Pseudo;
export type ParsedSelectorToken = PostcssNode & {
token: string;
};
export declare const isPostcssNodeWithChildren: (node: any) => node is PostcssNodeWithChildren;
export declare const asPostcssNodeWithChildren: (node?: PostcssNode) => PostcssNodeWithChildren;
export declare const isAttributeNode: (node: unknown) => node is Attribute;
export declare const asAttributeNode: (node?: PostcssNode) => Attribute;
export declare const isCombinatorNode: (node: unknown) => node is Combinator;
export declare const asCombinatorNode: (node?: PostcssNode) => Combinator;
export declare const isIdentifierNode: (node: any) => node is Identifier;
export declare const asIdentifierNode: (node?: PostcssNode) => Identifier;
export declare const isSelectorNode: (node: any) => node is Selector;
export declare const asSelectorNode: (node?: PostcssNode) => Selector;
export declare const isPseudoNode: (node: unknown) => node is Pseudo;
export declare const asPseudoNode: (node?: PostcssNode) => Pseudo;
export declare const isTagNode: (node: unknown) => node is Tag;
export declare const asTagNode: (node?: PostcssNode) => Tag;
export declare const isStringNode: (node: unknown) => node is String;
export declare const asStringNode: (node?: PostcssNode) => String;
export declare const isCommentNode: (node: unknown) => node is Comment;
export declare const asCommentNode: (node?: PostcssNode) => Comment;
import { error } from '@vltpkg/error-cause';
export const isPostcssNodeWithChildren = (node) => 'type' in node && 'nodes' in node;
export const asPostcssNodeWithChildren = (node) => {
if (!node) {
throw error('Expected a query node');
}
if (!isPostcssNodeWithChildren(node)) {
throw error('Not a query selector node with children', {
found: node,
});
}
return node;
};
const isObj = (o) => !!o && typeof o === 'object';
export const isAttributeNode = (node) => isObj(node) && !!node.attribute && node.type === 'attribute';
export const asAttributeNode = (node) => {
if (!node) {
throw error('Expected a query node');
}
if (!isAttributeNode(node)) {
throw error('Mismatching query node', {
wanted: 'attribute',
found: node.type,
});
}
return node;
};
export const isCombinatorNode = (node) => isObj(node) && !!node.value && node.type === 'combinator';
export const asCombinatorNode = (node) => {
if (!node) {
throw error('Expected a query node');
}
if (!isCombinatorNode(node)) {
throw error('Mismatching query node', {
wanted: 'combinator',
found: node.type,
});
}
return node;
};
export const isIdentifierNode = (node) => isObj(node) && !!node.value && node.type === 'id';
export const asIdentifierNode = (node) => {
if (!node) {
throw error('Expected a query node');
}
if (!isIdentifierNode(node)) {
throw error('Mismatching query node', {
wanted: 'id',
found: node.type,
});
}
return node;
};
export const isSelectorNode = (node) => isPostcssNodeWithChildren(node) && node.type === 'selector';
export const asSelectorNode = (node) => {
if (!node) {
throw error('Expected a query node');
}
if (!isSelectorNode(node)) {
throw error('Mismatching query node', {
wanted: 'selector',
found: node.type,
});
}
return node;
};
export const isPseudoNode = (node) => isObj(node) && !!node.value && node.type === 'pseudo';
export const asPseudoNode = (node) => {
if (!node) {
throw error('Expected a query node');
}
if (!isPseudoNode(node)) {
throw error('Mismatching query node', {
wanted: 'pseudo',
found: node.type,
});
}
return node;
};
export const isTagNode = (node) => isObj(node) && !!node.value && node.type === 'tag';
export const asTagNode = (node) => {
if (!node) {
throw error('Expected a query node');
}
if (!isTagNode(node)) {
throw error('Mismatching query node', {
wanted: 'tag',
found: node.type,
});
}
return node;
};
export const isStringNode = (node) => isObj(node) && !!node.value && node.type === 'string';
export const asStringNode = (node) => {
if (!node) {
throw error('Expected a query node');
}
if (!isStringNode(node)) {
throw error('Mismatching query node', {
wanted: 'string',
found: node.type,
});
}
return node;
};
export const isCommentNode = (node) => isObj(node) && !!node.value && node.type === 'comment';
export const asCommentNode = (node) => {
if (!node) {
throw error('Expected a query node');
}
if (!isCommentNode(node)) {
throw error('Mismatching query node', {
wanted: 'comment',
found: node.type,
});
}
return node;
};
+2
-2
{
"name": "@vltpkg/dss-parser",
"description": "The Dependency Selector Syntax (DSS) parser",
"version": "1.0.0-rc.23",
"version": "1.0.0-rc.24",
"repository": {

@@ -15,3 +15,3 @@ "type": "git",

"dependencies": {
"@vltpkg/error-cause": "1.0.0-rc.23",
"@vltpkg/error-cause": "1.0.0-rc.24",
"postcss-selector-parser": "^7.1.1"

@@ -18,0 +18,0 @@ },