mirror of
https://github.com/webstudio-is/webstudio.git
synced 2026-10-23 03:27:27 +09:00
refactor: upgrade to csstree v3 (#5455)
The new version is aware of modern colors and other new css features.
This commit is contained in:
1 parent
1662637d92
commit
02ca084a0c
24 files changed
+1053
-335
No files matched your search
Vendored
+772
@@ -0,0 +1,772 @@
|
||||
// Minimal-yet-safe TypeScript typings for css-tree v3.x
|
||||
// Covers: AST node types, parse/generate, walk/find, List, lexer API,
|
||||
// value definition syntax helpers, and common utils used in this project.
|
||||
|
||||
declare module "css-tree" {
|
||||
// -------------------------------------------------
|
||||
// Common
|
||||
// -------------------------------------------------
|
||||
export interface SourceLocation {
|
||||
source: string;
|
||||
start: { offset: number; line: number; column: number };
|
||||
end: { offset: number; line: number; column: number };
|
||||
}
|
||||
|
||||
export interface BaseNode {
|
||||
type: string;
|
||||
loc: SourceLocation | null;
|
||||
}
|
||||
|
||||
// Doubly-linked list used by csstree
|
||||
export interface ListItem<T> {
|
||||
prev: ListItem<T> | null;
|
||||
next: ListItem<T> | null;
|
||||
data: T;
|
||||
}
|
||||
|
||||
export class List<T> implements Iterable<T> {
|
||||
static createItem<T>(data: T): ListItem<T>;
|
||||
|
||||
constructor();
|
||||
// iteration
|
||||
[Symbol.iterator](): IterableIterator<T>;
|
||||
// props
|
||||
readonly size: number;
|
||||
readonly isEmpty: boolean;
|
||||
readonly first: T | null;
|
||||
readonly last: T | null;
|
||||
// traversal helpers
|
||||
forEach(
|
||||
fn: (data: T, item: ListItem<T>, list: List<T>) => void,
|
||||
thisArg?: any
|
||||
): void;
|
||||
forEachRight(
|
||||
fn: (data: T, item: ListItem<T>, list: List<T>) => void,
|
||||
thisArg?: any
|
||||
): void;
|
||||
// conversion
|
||||
fromArray(items: T[]): this;
|
||||
toArray(): T[];
|
||||
toJSON(): T[];
|
||||
// mutation (minimal surface used by walkers)
|
||||
clear(): void;
|
||||
remove(item: ListItem<T>): ListItem<T>;
|
||||
insert(item: ListItem<T>, before?: ListItem<T> | null): void;
|
||||
insertData(data: T, before?: ListItem<T> | null): void;
|
||||
append(item: ListItem<T>): void;
|
||||
appendData(data: T): void;
|
||||
prepend(item: ListItem<T>): void;
|
||||
prependData(data: T): void;
|
||||
replace(oldItem: ListItem<T>, newItemOrList: ListItem<T> | List<T>): void;
|
||||
}
|
||||
|
||||
// -------------------------------------------------
|
||||
// AST Nodes (as per docs/ast.md)
|
||||
// -------------------------------------------------
|
||||
export interface AnPlusB extends BaseNode {
|
||||
type: "AnPlusB";
|
||||
a: string | null;
|
||||
b: string | null;
|
||||
}
|
||||
export interface Atrule extends BaseNode {
|
||||
type: "Atrule";
|
||||
name: string;
|
||||
prelude: AtrulePrelude | Raw | null;
|
||||
block: Block | null;
|
||||
}
|
||||
export interface AtrulePrelude extends BaseNode {
|
||||
type: "AtrulePrelude";
|
||||
children: List<CssNode>;
|
||||
}
|
||||
export interface AttributeSelector extends BaseNode {
|
||||
type: "AttributeSelector";
|
||||
name: Identifier;
|
||||
matcher: string | null;
|
||||
value: StringNode | Identifier | null;
|
||||
flags: string | null;
|
||||
}
|
||||
export interface Block extends BaseNode {
|
||||
type: "Block";
|
||||
children: List<Atrule | Rule | Declaration>;
|
||||
}
|
||||
export interface Brackets extends BaseNode {
|
||||
type: "Brackets";
|
||||
children: List<CssNode>;
|
||||
}
|
||||
export interface CDC extends BaseNode {
|
||||
type: "CDC";
|
||||
}
|
||||
export interface CDO extends BaseNode {
|
||||
type: "CDO";
|
||||
}
|
||||
export interface ClassSelector extends BaseNode {
|
||||
type: "ClassSelector";
|
||||
name: string;
|
||||
}
|
||||
export interface Combinator extends BaseNode {
|
||||
type: "Combinator";
|
||||
name: string;
|
||||
}
|
||||
export interface Comment extends BaseNode {
|
||||
type: "Comment";
|
||||
value: string;
|
||||
}
|
||||
export interface Condition extends BaseNode {
|
||||
type: "Condition";
|
||||
kind: string;
|
||||
children: List<
|
||||
| Identifier
|
||||
| Feature
|
||||
| FeatureFunction
|
||||
| FeatureRange
|
||||
| SupportsDeclaration
|
||||
>;
|
||||
}
|
||||
export interface Declaration extends BaseNode {
|
||||
type: "Declaration";
|
||||
important: boolean | string;
|
||||
property: string;
|
||||
value: Value | Raw;
|
||||
}
|
||||
export interface DeclarationList extends BaseNode {
|
||||
type: "DeclarationList";
|
||||
children: List<Declaration | Atrule | Rule>;
|
||||
}
|
||||
export interface Dimension extends BaseNode {
|
||||
type: "Dimension";
|
||||
value: string;
|
||||
unit: string;
|
||||
}
|
||||
export interface Feature extends BaseNode {
|
||||
type: "Feature";
|
||||
kind: string;
|
||||
name: string;
|
||||
value: Identifier | NumberNode | Dimension | Ratio | FunctionNode | null;
|
||||
}
|
||||
export interface FeatureFunction extends BaseNode {
|
||||
type: "FeatureFunction";
|
||||
kind: string;
|
||||
feature: string;
|
||||
value: Declaration | Selector;
|
||||
}
|
||||
export interface FeatureRange extends BaseNode {
|
||||
type: "FeatureRange";
|
||||
kind: string;
|
||||
left: Identifier | NumberNode | Dimension | Ratio | FunctionNode;
|
||||
leftComparison: string;
|
||||
middle: Identifier | NumberNode | Dimension | Ratio | FunctionNode;
|
||||
rightComparison: string | null;
|
||||
right: Identifier | NumberNode | Dimension | Ratio | FunctionNode | null;
|
||||
}
|
||||
export interface FunctionNode extends BaseNode {
|
||||
type: "Function";
|
||||
name: string;
|
||||
children: List<CssNode>;
|
||||
}
|
||||
export interface GeneralEnclosed extends BaseNode {
|
||||
type: "GeneralEnclosed";
|
||||
kind: string;
|
||||
function: string | null;
|
||||
children: List<CssNode>;
|
||||
}
|
||||
export interface Hash extends BaseNode {
|
||||
type: "Hash";
|
||||
value: string;
|
||||
}
|
||||
export interface IdSelector extends BaseNode {
|
||||
type: "IdSelector";
|
||||
name: string;
|
||||
}
|
||||
export interface Identifier extends BaseNode {
|
||||
type: "Identifier";
|
||||
name: string;
|
||||
}
|
||||
export interface Layer extends BaseNode {
|
||||
type: "Layer";
|
||||
name: string;
|
||||
}
|
||||
export interface LayerList extends BaseNode {
|
||||
type: "LayerList";
|
||||
children: List<Layer>;
|
||||
}
|
||||
export interface MediaQuery extends BaseNode {
|
||||
type: "MediaQuery";
|
||||
modifier: string | null;
|
||||
mediaType: string | null;
|
||||
condition: Condition | null;
|
||||
}
|
||||
export interface MediaQueryList extends BaseNode {
|
||||
type: "MediaQueryList";
|
||||
children: List<MediaQuery>;
|
||||
}
|
||||
export interface NestingSelector extends BaseNode {
|
||||
type: "NestingSelector";
|
||||
}
|
||||
export interface Nth extends BaseNode {
|
||||
type: "Nth";
|
||||
nth: AnPlusB | Identifier;
|
||||
selector: SelectorList | null;
|
||||
}
|
||||
export interface NumberNode extends BaseNode {
|
||||
type: "Number";
|
||||
value: string;
|
||||
}
|
||||
export interface Operator extends BaseNode {
|
||||
type: "Operator";
|
||||
value: string;
|
||||
}
|
||||
export interface Parentheses extends BaseNode {
|
||||
type: "Parentheses";
|
||||
children: List<CssNode>;
|
||||
}
|
||||
export interface Percentage extends BaseNode {
|
||||
type: "Percentage";
|
||||
value: string;
|
||||
}
|
||||
export interface PseudoClassSelector extends BaseNode {
|
||||
type: "PseudoClassSelector";
|
||||
name: string;
|
||||
children: List<Raw> | null;
|
||||
}
|
||||
export interface PseudoElementSelector extends BaseNode {
|
||||
type: "PseudoElementSelector";
|
||||
name: string;
|
||||
children: List<Raw> | null;
|
||||
}
|
||||
export interface Ratio extends BaseNode {
|
||||
type: "Ratio";
|
||||
left: NumberNode | FunctionNode;
|
||||
right: NumberNode | FunctionNode | null;
|
||||
}
|
||||
export interface Raw extends BaseNode {
|
||||
type: "Raw";
|
||||
value: string;
|
||||
}
|
||||
export interface Rule extends BaseNode {
|
||||
type: "Rule";
|
||||
prelude: SelectorList | Raw;
|
||||
block: Block;
|
||||
}
|
||||
export interface Scope extends BaseNode {
|
||||
type: "Scope";
|
||||
root: SelectorList | Raw | null;
|
||||
limit: SelectorList | Raw | null;
|
||||
}
|
||||
export interface Selector extends BaseNode {
|
||||
type: "Selector";
|
||||
children: List<
|
||||
| TypeSelector
|
||||
| IdSelector
|
||||
| ClassSelector
|
||||
| AttributeSelector
|
||||
| PseudoClassSelector
|
||||
| PseudoElementSelector
|
||||
| Combinator
|
||||
| NestingSelector
|
||||
>;
|
||||
}
|
||||
export interface SelectorList extends BaseNode {
|
||||
type: "SelectorList";
|
||||
children: List<Selector | Raw>;
|
||||
}
|
||||
export interface StringNode extends BaseNode {
|
||||
type: "String";
|
||||
value: string;
|
||||
}
|
||||
export interface StyleSheet extends BaseNode {
|
||||
type: "StyleSheet";
|
||||
children: List<Comment | CDO | CDC | Atrule | Rule | Raw>;
|
||||
}
|
||||
export interface SupportsDeclaration extends BaseNode {
|
||||
type: "SupportsDeclaration";
|
||||
declaration: Declaration;
|
||||
}
|
||||
export interface TypeSelector extends BaseNode {
|
||||
type: "TypeSelector";
|
||||
name: string;
|
||||
}
|
||||
export interface UnicodeRange extends BaseNode {
|
||||
type: "UnicodeRange";
|
||||
value: string;
|
||||
}
|
||||
export interface Url extends BaseNode {
|
||||
type: "Url";
|
||||
value: string;
|
||||
}
|
||||
export interface Value extends BaseNode {
|
||||
type: "Value";
|
||||
children: List<CssNode>;
|
||||
}
|
||||
export interface WhiteSpace extends BaseNode {
|
||||
type: "WhiteSpace";
|
||||
value: string;
|
||||
}
|
||||
|
||||
export type CssNode =
|
||||
| AnPlusB
|
||||
| Atrule
|
||||
| AtrulePrelude
|
||||
| AttributeSelector
|
||||
| Block
|
||||
| Brackets
|
||||
| CDC
|
||||
| CDO
|
||||
| ClassSelector
|
||||
| Combinator
|
||||
| Comment
|
||||
| Condition
|
||||
| Declaration
|
||||
| DeclarationList
|
||||
| Dimension
|
||||
| Feature
|
||||
| FeatureFunction
|
||||
| FeatureRange
|
||||
| FunctionNode
|
||||
| GeneralEnclosed
|
||||
| Hash
|
||||
| IdSelector
|
||||
| Identifier
|
||||
| Layer
|
||||
| LayerList
|
||||
| MediaQuery
|
||||
| MediaQueryList
|
||||
| NestingSelector
|
||||
| Nth
|
||||
| NumberNode
|
||||
| Operator
|
||||
| Parentheses
|
||||
| Percentage
|
||||
| PseudoClassSelector
|
||||
| PseudoElementSelector
|
||||
| Ratio
|
||||
| Raw
|
||||
| Rule
|
||||
| Scope
|
||||
| Selector
|
||||
| SelectorList
|
||||
| StringNode
|
||||
| StyleSheet
|
||||
| SupportsDeclaration
|
||||
| TypeSelector
|
||||
| UnicodeRange
|
||||
| Url
|
||||
| Value
|
||||
| WhiteSpace;
|
||||
|
||||
// A plain-object form where children are arrays (for JSON, etc.)
|
||||
export type CssNodePlain = Omit<CssNode, "children" | "loc"> & {
|
||||
children?: CssNodePlain[] | null;
|
||||
loc?: SourceLocation | null;
|
||||
};
|
||||
|
||||
// -------------------------------------------------
|
||||
// Parsing / Generation
|
||||
// -------------------------------------------------
|
||||
export type ParseContext =
|
||||
| "stylesheet"
|
||||
| "atrule"
|
||||
| "atrulePrelude"
|
||||
| "mediaQueryList"
|
||||
| "mediaQuery"
|
||||
| "rule"
|
||||
| "selectorList"
|
||||
| "selector"
|
||||
| "block"
|
||||
| "declarationList"
|
||||
| "declaration"
|
||||
| "value";
|
||||
|
||||
export interface ParseOptions {
|
||||
context?: ParseContext;
|
||||
atrule?: string | null;
|
||||
positions?: boolean;
|
||||
onParseError?: (error: any, fallbackNode?: Raw) => void;
|
||||
onComment?: (value: string, loc: SourceLocation | null) => void;
|
||||
onToken?:
|
||||
| ((type: number, start: number, end: number, index: number) => void)
|
||||
| Array<{ type: number; start: number; end: number }>
|
||||
| null;
|
||||
filename?: string;
|
||||
offset?: number;
|
||||
line?: number;
|
||||
column?: number;
|
||||
parseAtrulePrelude?: boolean;
|
||||
parseRulePrelude?: boolean;
|
||||
parseValue?: boolean;
|
||||
parseCustomProperty?: boolean;
|
||||
}
|
||||
|
||||
// Strict overloads by context
|
||||
export function parse(source: string): StyleSheet;
|
||||
export function parse(
|
||||
source: string,
|
||||
options: ParseOptions & { context?: "stylesheet" }
|
||||
): StyleSheet;
|
||||
export function parse(
|
||||
source: string,
|
||||
options: ParseOptions & { context: "atrule" }
|
||||
): Atrule;
|
||||
export function parse(
|
||||
source: string,
|
||||
options: ParseOptions & { context: "atrulePrelude" }
|
||||
): AtrulePrelude;
|
||||
export function parse(
|
||||
source: string,
|
||||
options: ParseOptions & { context: "mediaQueryList" }
|
||||
): MediaQueryList;
|
||||
export function parse(
|
||||
source: string,
|
||||
options: ParseOptions & { context: "mediaQuery" }
|
||||
): MediaQuery;
|
||||
export function parse(
|
||||
source: string,
|
||||
options: ParseOptions & { context: "rule" }
|
||||
): Rule;
|
||||
export function parse(
|
||||
source: string,
|
||||
options: ParseOptions & { context: "selectorList" }
|
||||
): SelectorList;
|
||||
export function parse(
|
||||
source: string,
|
||||
options: ParseOptions & { context: "selector" }
|
||||
): Selector;
|
||||
export function parse(
|
||||
source: string,
|
||||
options: ParseOptions & { context: "block" }
|
||||
): Block;
|
||||
export function parse(
|
||||
source: string,
|
||||
options: ParseOptions & { context: "declarationList" }
|
||||
): DeclarationList;
|
||||
export function parse(
|
||||
source: string,
|
||||
options: ParseOptions & { context: "declaration" }
|
||||
): Declaration;
|
||||
export function parse(
|
||||
source: string,
|
||||
options: ParseOptions & { context: "value" }
|
||||
): Value;
|
||||
// Fallback
|
||||
export function parse(source: string, options: ParseOptions): CssNode;
|
||||
|
||||
export function generate(
|
||||
ast: CssNode,
|
||||
options: {
|
||||
sourceMap: true;
|
||||
decorator?: (node: CssNode) => any;
|
||||
mode?: "spec" | "safe";
|
||||
}
|
||||
): { css: string; map: any };
|
||||
export function generate(
|
||||
ast: CssNode,
|
||||
options?: {
|
||||
sourceMap?: false;
|
||||
decorator?: (node: CssNode) => any;
|
||||
mode?: "spec" | "safe";
|
||||
}
|
||||
): string;
|
||||
|
||||
// -------------------------------------------------
|
||||
// Traversal helpers
|
||||
// -------------------------------------------------
|
||||
export type WalkHandler = (
|
||||
node: CssNode,
|
||||
item?: ListItem<CssNode>,
|
||||
list?: List<CssNode>
|
||||
) => any;
|
||||
export interface WalkOptions {
|
||||
enter?: WalkHandler;
|
||||
leave?: WalkHandler;
|
||||
visit?: CssNode["type"] | null;
|
||||
reverse?: boolean;
|
||||
}
|
||||
export function walk(ast: CssNode, options: WalkOptions | WalkHandler): void;
|
||||
export function find(ast: CssNode, fn: WalkHandler): CssNode | null;
|
||||
export function findLast(ast: CssNode, fn: WalkHandler): CssNode | null;
|
||||
export function findAll(ast: CssNode, fn: WalkHandler): CssNode[];
|
||||
|
||||
// -------------------------------------------------
|
||||
// Utils
|
||||
// -------------------------------------------------
|
||||
export function clone<T extends CssNode>(ast: T): T;
|
||||
export function fromPlainObject<T extends { children?: any }>(obj: T): T;
|
||||
export function toPlainObject<T extends { children?: any }>(ast: T): T;
|
||||
|
||||
export interface PropertyInfo {
|
||||
basename: string;
|
||||
name: string;
|
||||
hack: string;
|
||||
vendor: string;
|
||||
prefix: string;
|
||||
custom: boolean;
|
||||
}
|
||||
export function property(name: string): PropertyInfo;
|
||||
|
||||
export interface KeywordInfo {
|
||||
basename: string;
|
||||
name: string;
|
||||
vendor: string;
|
||||
prefix: string;
|
||||
custom: boolean;
|
||||
}
|
||||
export function keyword(name: string): KeywordInfo;
|
||||
|
||||
export namespace ident {
|
||||
function decode(value: string): string;
|
||||
function encode(value: string): string;
|
||||
}
|
||||
export namespace string {
|
||||
function decode(value: string): string;
|
||||
function encode(value: string, preferSingleQuotes?: boolean): string;
|
||||
}
|
||||
export namespace url {
|
||||
function decode(value: string): string;
|
||||
function encode(value: string): string;
|
||||
}
|
||||
|
||||
// -------------------------------------------------
|
||||
// Definition syntax (values) sub-API
|
||||
// -------------------------------------------------
|
||||
export namespace definitionSyntax {
|
||||
// AST nodes for definition syntax are intentionally minimal here
|
||||
interface Base {
|
||||
type: string;
|
||||
}
|
||||
interface Group extends Base {
|
||||
type: "Group";
|
||||
terms: Base[];
|
||||
combinator: " " | "|" | "||" | "&&";
|
||||
disallowEmpty: boolean;
|
||||
explicit: boolean;
|
||||
}
|
||||
interface Keyword extends Base {
|
||||
type: "Keyword";
|
||||
name: string;
|
||||
}
|
||||
interface Function extends Base {
|
||||
type: "Function";
|
||||
name: string;
|
||||
}
|
||||
interface String extends Base {
|
||||
type: "String";
|
||||
value: string;
|
||||
}
|
||||
interface Property extends Base {
|
||||
type: "Property";
|
||||
name: string;
|
||||
}
|
||||
interface Type extends Base {
|
||||
type: "Type";
|
||||
name: string;
|
||||
opts: Range | null;
|
||||
}
|
||||
interface Range extends Base {
|
||||
type: "Range";
|
||||
min: number | null;
|
||||
max: number | null;
|
||||
}
|
||||
interface Multiplier extends Base {
|
||||
type: "Multiplier";
|
||||
comma: boolean;
|
||||
min: number;
|
||||
max: number;
|
||||
term: Base;
|
||||
}
|
||||
|
||||
type Node =
|
||||
| Group
|
||||
| Keyword
|
||||
| Function
|
||||
| String
|
||||
| Property
|
||||
| Type
|
||||
| Range
|
||||
| Multiplier
|
||||
| Base;
|
||||
|
||||
function parse(source: string): Node;
|
||||
function walk(
|
||||
node: Node,
|
||||
options:
|
||||
| { enter?: (n: Node) => void; leave?: (n: Node) => void }
|
||||
| ((n: Node) => void),
|
||||
context?: any
|
||||
): void;
|
||||
function generate(
|
||||
node: Node,
|
||||
options?: {
|
||||
forceBraces?: boolean;
|
||||
compact?: boolean;
|
||||
decorate?: (content: string, node: Node) => string;
|
||||
}
|
||||
): string;
|
||||
}
|
||||
|
||||
// -------------------------------------------------
|
||||
// Lexer
|
||||
// -------------------------------------------------
|
||||
export interface AtruleSyntaxConfig {
|
||||
prelude?: string | definitionSyntax.Node | ((ref?: any) => any) | null;
|
||||
descriptors?: Record<
|
||||
string,
|
||||
string | definitionSyntax.Node | ((ref?: any) => any)
|
||||
> | null;
|
||||
}
|
||||
|
||||
export interface LexerConfig {
|
||||
generic?: boolean;
|
||||
cssWideKeywords?: string[];
|
||||
units?: Record<string, string[]>;
|
||||
types?: Record<
|
||||
string,
|
||||
string | definitionSyntax.Node | ((ref?: any) => any)
|
||||
>;
|
||||
atrules?: Record<string, AtruleSyntaxConfig>;
|
||||
properties?: Record<
|
||||
string,
|
||||
string | definitionSyntax.Node | ((ref?: any) => any)
|
||||
>;
|
||||
}
|
||||
|
||||
export interface MatchResult {
|
||||
matched: any;
|
||||
error: Error | null;
|
||||
iterations: number;
|
||||
isType(node: CssNode | null | undefined, name: string): boolean;
|
||||
getTrace(
|
||||
node: CssNode | null | undefined
|
||||
): Array<{ type: string; name: string }>;
|
||||
}
|
||||
|
||||
export interface FragmentResult {
|
||||
parent: List<CssNode>;
|
||||
nodes: List<CssNode>;
|
||||
}
|
||||
|
||||
export class Lexer {
|
||||
constructor(config?: LexerConfig, syntax?: any, structure?: any);
|
||||
|
||||
cssWideKeywords: string[];
|
||||
units: Record<string, string[]>;
|
||||
|
||||
checkStructure(
|
||||
ast: CssNode
|
||||
): false | Array<{ node: CssNode; message: string }>;
|
||||
|
||||
checkAtruleName(atruleName: string): Error | void;
|
||||
checkAtrulePrelude(
|
||||
atruleName: string,
|
||||
prelude?: string | CssNode | null
|
||||
): Error | void;
|
||||
checkAtruleDescriptorName(
|
||||
atruleName: string,
|
||||
descriptorName: string
|
||||
): Error | void;
|
||||
checkPropertyName(propertyName: string): Error | void;
|
||||
|
||||
matchAtrulePrelude(
|
||||
atruleName: string,
|
||||
prelude?: string | CssNode | null
|
||||
): MatchResult;
|
||||
matchAtruleDescriptor(
|
||||
atruleName: string,
|
||||
descriptorName: string,
|
||||
value: string | CssNode
|
||||
): MatchResult;
|
||||
matchDeclaration(node: CssNode): MatchResult;
|
||||
matchProperty(propertyName: string, value: string | CssNode): MatchResult;
|
||||
matchType(typeName: string, value: string | CssNode): MatchResult;
|
||||
match(
|
||||
syntax: string | definitionSyntax.Node,
|
||||
value: string | CssNode
|
||||
): MatchResult;
|
||||
|
||||
findValueFragments(
|
||||
propertyName: string,
|
||||
value: Value,
|
||||
type: string,
|
||||
name: string
|
||||
): FragmentResult[];
|
||||
findDeclarationValueFragments(
|
||||
declaration: Declaration,
|
||||
type: string,
|
||||
name: string
|
||||
): FragmentResult[];
|
||||
findAllFragments(
|
||||
ast: CssNode,
|
||||
type: string,
|
||||
name: string
|
||||
): FragmentResult[];
|
||||
|
||||
// descriptor getters
|
||||
getAtrule(atruleName: string, fallbackBasename?: boolean): any | null;
|
||||
getAtrulePrelude(
|
||||
atruleName: string,
|
||||
fallbackBasename?: boolean
|
||||
): any | null;
|
||||
getAtruleDescriptor(atruleName: string, name: string): any | null;
|
||||
getProperty(propertyName: string, fallbackBasename?: boolean): any | null;
|
||||
getType(name: string): any | null;
|
||||
|
||||
validate(): null | {
|
||||
errors: string[];
|
||||
types: string[];
|
||||
properties: string[];
|
||||
};
|
||||
dump(syntaxAsAst?: boolean, pretty?: boolean): any;
|
||||
toString(): string;
|
||||
}
|
||||
|
||||
export const lexer: Lexer;
|
||||
export function createLexer(config?: LexerConfig): Lexer;
|
||||
|
||||
// -------------------------------------------------
|
||||
// Tokenizer / misc exports (lightly typed)
|
||||
// -------------------------------------------------
|
||||
export const tokenTypes: Record<string, number>;
|
||||
export const tokenNames: string[];
|
||||
export function tokenize(input: string): IterableIterator<any>;
|
||||
|
||||
// Syntax factory and forking
|
||||
export function createSyntax(config: any): any;
|
||||
export function fork(ext?: any): any;
|
||||
}
|
||||
|
||||
// Optional subpath module shims to enable tree-shake-style imports
|
||||
declare module "css-tree/lexer" {
|
||||
export * from "css-tree";
|
||||
}
|
||||
declare module "css-tree/parser" {
|
||||
export type { ParseOptions, CssNode } from "css-tree";
|
||||
export { parse as default } from "css-tree";
|
||||
}
|
||||
declare module "css-tree/generator" {
|
||||
export { generate as default } from "css-tree";
|
||||
}
|
||||
declare module "css-tree/walker" {
|
||||
export {
|
||||
walk,
|
||||
find,
|
||||
findAll,
|
||||
findLast,
|
||||
WalkOptions,
|
||||
WalkHandler,
|
||||
} from "css-tree";
|
||||
}
|
||||
declare module "css-tree/definition-syntax" {
|
||||
export { definitionSyntax } from "css-tree";
|
||||
}
|
||||
declare module "css-tree/utils" {
|
||||
export {
|
||||
List,
|
||||
ListItem,
|
||||
clone,
|
||||
fromPlainObject,
|
||||
toPlainObject,
|
||||
property,
|
||||
keyword,
|
||||
ident,
|
||||
string,
|
||||
url,
|
||||
} from "css-tree";
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { generate, walk } from "css-tree";
|
||||
import { generate, walk, List, type CssNode } from "css-tree";
|
||||
import type { HtmlTags } from "html-tags";
|
||||
import {
|
||||
camelCaseProperty,
|
||||
@@ -294,13 +294,14 @@ const substituteVars = (
|
||||
enter(node, item, list) {
|
||||
if (node.type === "Function" && node.name === "var") {
|
||||
const varValue = parseCssVar(node);
|
||||
if (varValue) {
|
||||
if (varValue && item) {
|
||||
const newValue = mapper(varValue);
|
||||
list.replace(
|
||||
list?.replace(
|
||||
item,
|
||||
node.children.createItem({
|
||||
List.createItem<CssNode>({
|
||||
type: "Raw",
|
||||
value: toValue(newValue),
|
||||
loc: null,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
"change-case": "^5.4.4",
|
||||
"colord": "^2.9.3",
|
||||
"cookie": "^1.0.1",
|
||||
"css-tree": "^2.3.1",
|
||||
"css-tree": "^3.1.0",
|
||||
"debug": "^4.3.7",
|
||||
"downshift": "^6.1.7",
|
||||
"entrijs": "^0.0.11",
|
||||
|
||||
@@ -36,7 +36,6 @@
|
||||
"@storybook/addon-controls": "^8.6.4",
|
||||
"@storybook/react": "^8.6.4",
|
||||
"@storybook/react-vite": "^8.6.4",
|
||||
"@types/css-tree": "^2.3.1",
|
||||
"@types/node": "^22.13.10",
|
||||
"@types/react": "^18.2.70",
|
||||
"esbuild": "^0.25.3",
|
||||
@@ -85,8 +84,6 @@
|
||||
},
|
||||
"patchedDependencies": {
|
||||
"@stitches/react@1.3.1-1": "patches/@stitches__react@1.3.1-1.patch",
|
||||
"css-tree@2.3.1": "patches/css-tree@2.3.1.patch",
|
||||
"@types/css-tree@2.3.1": "patches/@types__css-tree@2.3.1.patch",
|
||||
"@radix-ui/react-scroll-area@1.0.5": "patches/@radix-ui__react-scroll-area@1.0.5.patch",
|
||||
"@remix-run/dev": "patches/@remix-run__dev.patch"
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
"css-to-ws": "./bin/css-to-ws.ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/css-tree": "^2.3.1",
|
||||
"@webstudio-is/tsconfig": "workspace:*",
|
||||
"html-tags": "^4.0.0",
|
||||
"mdn-data": "2.23.0",
|
||||
@@ -36,7 +35,7 @@
|
||||
"@webstudio-is/css-engine": "workspace:*",
|
||||
"change-case": "^5.4.4",
|
||||
"colord": "^2.9.3",
|
||||
"css-tree": "^2.3.1",
|
||||
"css-tree": "^3.1.0",
|
||||
"openai": "^3.2.1",
|
||||
"p-retry": "^6.2.1",
|
||||
"warn-once": "^0.1.1"
|
||||
|
||||
@@ -219,6 +219,7 @@ export const parseCssVar = (node: FunctionNode): undefined | VarValue => {
|
||||
const [name, _comma, ...fallback] = node.children;
|
||||
const fallbackString = generate({
|
||||
type: "Value",
|
||||
loc: null,
|
||||
children: new List<CssNode>().fromArray(fallback),
|
||||
}).trim();
|
||||
if (name.type === "Identifier") {
|
||||
@@ -380,7 +381,7 @@ const parseLiteral = (
|
||||
type: "function",
|
||||
args: parseShadow(
|
||||
node.children.toArray(),
|
||||
generate({ type: "Value", children: node.children })
|
||||
generate({ type: "Value", loc: null, children: node.children })
|
||||
),
|
||||
name: node.name,
|
||||
};
|
||||
@@ -469,6 +470,7 @@ export const parseCssValue = (
|
||||
value: splitRepeated(nodes).map((nodes) => {
|
||||
const value = generate({
|
||||
type: "Value",
|
||||
loc: null,
|
||||
children: new List<CssNode>().fromArray(nodes),
|
||||
});
|
||||
const parsed = parseCssValue(property, value, false) as LayerValueItem;
|
||||
@@ -506,6 +508,7 @@ export const parseCssValue = (
|
||||
}
|
||||
return generate({
|
||||
type: "Value",
|
||||
loc: null,
|
||||
children: new List<CssNode>().fromArray(nodes),
|
||||
});
|
||||
}),
|
||||
|
||||
+175
-145
@@ -102,163 +102,193 @@ export const parseCss = (css: string): ParsedStyleDecl[] => {
|
||||
return [];
|
||||
}
|
||||
|
||||
csstree.walk(ast, function (node) {
|
||||
// forbid nested at rules
|
||||
if (node.type === "Atrule" && this.atrule) {
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore https://github.com/csstree/csstree/blob/v2.3.1/docs/traversal.md
|
||||
return this.break;
|
||||
}
|
||||
if (node.type !== "Declaration" || this.rule?.prelude.type === undefined) {
|
||||
return;
|
||||
}
|
||||
// Track context as we traverse
|
||||
let currentAtrule: csstree.Atrule | undefined;
|
||||
let currentRule: csstree.Rule | undefined;
|
||||
let nestedAtruleDepth = 0;
|
||||
|
||||
if (this.atrule && this.atrule.name !== "media") {
|
||||
return;
|
||||
}
|
||||
const supportedMediaFeatures = ["min-width", "max-width"];
|
||||
const supportedUnits = ["px"];
|
||||
|
||||
const supportedMediaFeatures = ["min-width", "max-width"];
|
||||
const supportedUnits = ["px"];
|
||||
let breakpoint: undefined | string;
|
||||
let invalidBreakpoint = false;
|
||||
if (this.atrule?.prelude?.type === "AtrulePrelude") {
|
||||
csstree.walk(this.atrule.prelude, {
|
||||
enter: (node, item, list) => {
|
||||
if (node.type === "Identifier") {
|
||||
if (
|
||||
node.name === "screen" ||
|
||||
node.name === "all" ||
|
||||
node.name === "and"
|
||||
) {
|
||||
list.remove(item);
|
||||
csstree.walk(ast, {
|
||||
enter(node) {
|
||||
if (node.type === "Atrule") {
|
||||
if (currentAtrule) {
|
||||
nestedAtruleDepth++;
|
||||
}
|
||||
currentAtrule = node;
|
||||
} else if (node.type === "Rule") {
|
||||
currentRule = node;
|
||||
}
|
||||
},
|
||||
leave(node) {
|
||||
if (node.type === "Atrule") {
|
||||
if (nestedAtruleDepth > 0) {
|
||||
nestedAtruleDepth--;
|
||||
} else {
|
||||
currentAtrule = undefined;
|
||||
}
|
||||
} else if (node.type === "Rule") {
|
||||
currentRule = undefined;
|
||||
}
|
||||
|
||||
// Process declarations
|
||||
if (
|
||||
node.type !== "Declaration" ||
|
||||
!currentRule ||
|
||||
currentRule.prelude.type === undefined
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
// forbid nested at rules
|
||||
if (nestedAtruleDepth > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentAtrule && currentAtrule.name !== "media") {
|
||||
return;
|
||||
}
|
||||
|
||||
let breakpoint: undefined | string;
|
||||
let invalidBreakpoint = false;
|
||||
|
||||
if (currentAtrule?.prelude?.type === "AtrulePrelude") {
|
||||
csstree.walk(currentAtrule.prelude, {
|
||||
enter: (node) => {
|
||||
if (node.type === "MediaQuery") {
|
||||
if (node.mediaType === "screen" || node.mediaType === "all") {
|
||||
node.mediaType = null;
|
||||
}
|
||||
// prevent saving print styles
|
||||
if (node.mediaType === "print") {
|
||||
invalidBreakpoint = true;
|
||||
}
|
||||
}
|
||||
// prevent saving print styles
|
||||
if (node.name === "print") {
|
||||
if (
|
||||
node.type === "Feature" &&
|
||||
supportedMediaFeatures.includes(node.name) === false
|
||||
) {
|
||||
invalidBreakpoint = true;
|
||||
}
|
||||
}
|
||||
if (
|
||||
node.type === "MediaFeature" &&
|
||||
supportedMediaFeatures.includes(node.name) === false
|
||||
) {
|
||||
invalidBreakpoint = true;
|
||||
}
|
||||
if (
|
||||
node.type === "Dimension" &&
|
||||
supportedUnits.includes(node.unit) === false
|
||||
) {
|
||||
invalidBreakpoint = true;
|
||||
}
|
||||
},
|
||||
leave: (node) => {
|
||||
// complex media queries are not supported yet
|
||||
if (node.type === "MediaQuery" && node.children.size > 1) {
|
||||
invalidBreakpoint = true;
|
||||
}
|
||||
``;
|
||||
},
|
||||
});
|
||||
const generated = csstree.generate(this.atrule.prelude);
|
||||
if (generated) {
|
||||
breakpoint = generated;
|
||||
}
|
||||
}
|
||||
if (invalidBreakpoint || this.rule.prelude.type !== "SelectorList") {
|
||||
return;
|
||||
}
|
||||
|
||||
const selectors: Selector[] = [];
|
||||
|
||||
for (const node of this.rule.prelude.children) {
|
||||
if (node.type !== "Selector") {
|
||||
continue;
|
||||
}
|
||||
let selector: Selector | undefined = undefined;
|
||||
const children = node.children.toArray();
|
||||
// @ts-expect-error NestingSelector is not defined in type definitions
|
||||
const startsWithNesting = children[0]?.type === "NestingSelector";
|
||||
for (let index = 0; index < children.length; index += 1) {
|
||||
const childNode = children[index];
|
||||
let name: string = "";
|
||||
let state: string | undefined;
|
||||
switch (childNode.type) {
|
||||
case "TypeSelector":
|
||||
name = childNode.name;
|
||||
break;
|
||||
case "ClassSelector":
|
||||
name = `.${childNode.name}`;
|
||||
break;
|
||||
case "AttributeSelector":
|
||||
// for example &[data-state=active]
|
||||
if (startsWithNesting && index === 1 && children.length === 2) {
|
||||
state = csstree.generate(childNode);
|
||||
} else {
|
||||
name = csstree.generate(childNode);
|
||||
if (
|
||||
node.type === "Dimension" &&
|
||||
supportedUnits.includes(node.unit) === false
|
||||
) {
|
||||
invalidBreakpoint = true;
|
||||
}
|
||||
break;
|
||||
case "PseudoClassSelector": {
|
||||
// First pseudo selector is not a state but an element selector, e.g. :root
|
||||
if (selector) {
|
||||
state = `:${childNode.name}`;
|
||||
} else {
|
||||
name = `:${childNode.name}`;
|
||||
},
|
||||
leave: (node) => {
|
||||
// complex media queries are not supported yet
|
||||
if (node.type === "MediaQuery") {
|
||||
const children = node.condition?.children;
|
||||
if (children && children.size > 1) {
|
||||
invalidBreakpoint = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "PseudoElementSelector":
|
||||
state = `::${childNode.name}`;
|
||||
break;
|
||||
case "Combinator":
|
||||
// " " vs " > "
|
||||
name =
|
||||
childNode.name === " " ? childNode.name : ` ${childNode.name} `;
|
||||
break;
|
||||
},
|
||||
});
|
||||
const generated = csstree.generate(currentAtrule.prelude);
|
||||
if (generated) {
|
||||
breakpoint = generated;
|
||||
}
|
||||
}
|
||||
if (invalidBreakpoint || currentRule.prelude.type !== "SelectorList") {
|
||||
return;
|
||||
}
|
||||
|
||||
const selectors: Selector[] = [];
|
||||
|
||||
for (const node of currentRule.prelude.children) {
|
||||
if (node.type !== "Selector") {
|
||||
continue;
|
||||
}
|
||||
let selector: Selector | undefined = undefined;
|
||||
const children = node.children.toArray();
|
||||
const startsWithNesting = children[0]?.type === "NestingSelector";
|
||||
for (let index = 0; index < children.length; index += 1) {
|
||||
const childNode = children[index];
|
||||
let name: string = "";
|
||||
let state: string | undefined;
|
||||
switch (childNode.type) {
|
||||
case "TypeSelector":
|
||||
name = childNode.name;
|
||||
break;
|
||||
case "ClassSelector":
|
||||
name = `.${childNode.name}`;
|
||||
break;
|
||||
case "AttributeSelector":
|
||||
// for example &[data-state=active]
|
||||
if (startsWithNesting && index === 1 && children.length === 2) {
|
||||
state = csstree.generate(childNode);
|
||||
} else {
|
||||
name = csstree.generate(childNode);
|
||||
}
|
||||
break;
|
||||
case "PseudoClassSelector": {
|
||||
// First pseudo selector is not a state but an element selector, e.g. :root
|
||||
if (selector) {
|
||||
state = `:${childNode.name}`;
|
||||
} else {
|
||||
name = `:${childNode.name}`;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "PseudoElementSelector":
|
||||
state = `::${childNode.name}`;
|
||||
break;
|
||||
case "Combinator":
|
||||
// " " vs " > "
|
||||
name =
|
||||
childNode.name === " " ? childNode.name : ` ${childNode.name} `;
|
||||
break;
|
||||
}
|
||||
|
||||
if (selector) {
|
||||
selector.name += name;
|
||||
if (state) {
|
||||
selector.state = state;
|
||||
}
|
||||
} else {
|
||||
selector = { name, state };
|
||||
}
|
||||
}
|
||||
if (selector) {
|
||||
selector.name += name;
|
||||
if (state) {
|
||||
selector.state = state;
|
||||
selectors.push(selector);
|
||||
selector = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
const stringValue = csstree.generate(node.value);
|
||||
|
||||
const parsedCss = parseCssValue(
|
||||
normalizeProperty(node.property),
|
||||
stringValue
|
||||
);
|
||||
|
||||
for (const { name: selector, state } of selectors) {
|
||||
for (const [property, value] of parsedCss) {
|
||||
const normalizedProperty = normalizeProperty(property);
|
||||
const styleDecl: ParsedStyleDecl = {
|
||||
selector,
|
||||
property: normalizedProperty,
|
||||
value,
|
||||
};
|
||||
if (breakpoint) {
|
||||
styleDecl.breakpoint = breakpoint;
|
||||
}
|
||||
} else {
|
||||
selector = { name, state };
|
||||
if (state) {
|
||||
styleDecl.state = state;
|
||||
}
|
||||
|
||||
// deduplicate styles within selector and state by using map
|
||||
styles.set(
|
||||
`${breakpoint}:${selector}:${state}:${normalizedProperty}`,
|
||||
styleDecl
|
||||
);
|
||||
}
|
||||
}
|
||||
if (selector) {
|
||||
selectors.push(selector);
|
||||
selector = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
const stringValue = csstree.generate(node.value);
|
||||
|
||||
const parsedCss = parseCssValue(
|
||||
normalizeProperty(node.property),
|
||||
stringValue
|
||||
);
|
||||
|
||||
for (const { name: selector, state } of selectors) {
|
||||
for (const [property, value] of parsedCss) {
|
||||
const normalizedProperty = normalizeProperty(property);
|
||||
const styleDecl: ParsedStyleDecl = {
|
||||
selector,
|
||||
property: normalizedProperty,
|
||||
value,
|
||||
};
|
||||
if (breakpoint) {
|
||||
styleDecl.breakpoint = breakpoint;
|
||||
}
|
||||
if (state) {
|
||||
styleDecl.state = state;
|
||||
}
|
||||
|
||||
// deduplicate styles within selector and state by using map
|
||||
styles.set(
|
||||
`${breakpoint}:${selector}:${state}:${normalizedProperty}`,
|
||||
styleDecl
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return Array.from(styles.values());
|
||||
@@ -276,7 +306,7 @@ export const parseMediaQuery = (
|
||||
let property: undefined | "minWidth" | "maxWidth";
|
||||
let value: undefined | number;
|
||||
csstree.walk(ast, (node) => {
|
||||
if (node.type === "MediaFeature") {
|
||||
if (node.type === "Feature") {
|
||||
if (node.name === "min-width") {
|
||||
property = "minWidth";
|
||||
}
|
||||
|
||||
@@ -13,33 +13,52 @@ const cssWideKeywordsSyntax = Array.from(cssWideKeywords).join(" | ");
|
||||
|
||||
const createValueNode = (data?: CssNode[]): Value => ({
|
||||
type: "Value",
|
||||
loc: null,
|
||||
children: new List<CssNode>().fromArray(data ?? []),
|
||||
});
|
||||
|
||||
const createNumber = (value: string): Value => ({
|
||||
type: "Value",
|
||||
children: new List<CssNode>().appendData({
|
||||
const createNumber = (value: string): Value => {
|
||||
const list = new List<CssNode>();
|
||||
list.appendData({
|
||||
type: "Number",
|
||||
value,
|
||||
}),
|
||||
});
|
||||
loc: null,
|
||||
});
|
||||
return {
|
||||
type: "Value",
|
||||
loc: null,
|
||||
children: list,
|
||||
};
|
||||
};
|
||||
|
||||
const createDimension = (value: string, unit: string): Value => ({
|
||||
type: "Value",
|
||||
children: new List<CssNode>().appendData({
|
||||
const createDimension = (value: string, unit: string): Value => {
|
||||
const list = new List<CssNode>();
|
||||
list.appendData({
|
||||
type: "Dimension",
|
||||
value,
|
||||
unit,
|
||||
}),
|
||||
});
|
||||
loc: null,
|
||||
});
|
||||
return {
|
||||
type: "Value",
|
||||
loc: null,
|
||||
children: list,
|
||||
};
|
||||
};
|
||||
|
||||
const createIdentifier = (name: string): Value => ({
|
||||
type: "Value",
|
||||
children: new List<CssNode>().appendData({
|
||||
const createIdentifier = (name: string): Value => {
|
||||
const list = new List<CssNode>();
|
||||
list.appendData({
|
||||
type: "Identifier",
|
||||
name,
|
||||
}),
|
||||
});
|
||||
loc: null,
|
||||
});
|
||||
return {
|
||||
type: "Value",
|
||||
loc: null,
|
||||
children: list,
|
||||
};
|
||||
};
|
||||
|
||||
const createInitialNode = () => createIdentifier("initial");
|
||||
|
||||
@@ -67,7 +86,7 @@ const joinByOperator = (list: List<CssNode> | CssNode[], operator: string) => {
|
||||
const joined: CssNode[] = [];
|
||||
for (const node of list) {
|
||||
if (joined.length > 0) {
|
||||
joined.push({ type: "Operator", value: operator });
|
||||
joined.push({ type: "Operator", value: operator, loc: null });
|
||||
}
|
||||
joined.push(...getValueList(node));
|
||||
}
|
||||
@@ -298,7 +317,7 @@ const expandFont = function* (value: CssNode) {
|
||||
let fontFamily: CssNode = createInitialNode();
|
||||
if (config) {
|
||||
if (
|
||||
lexer.match("<'font-size'> / <'line-height'> <'font-family'>", config)
|
||||
lexer.match("<'font-size'> / <'line-height'> <'font-family'>#", config)
|
||||
.matched
|
||||
) {
|
||||
const [fontSizeNode, _slashNode, lineHeightNode, ...fontFamilyNodes] =
|
||||
@@ -595,8 +614,8 @@ const expandMask = function* (value: CssNode) {
|
||||
reference ?? createIdentifier("none"),
|
||||
position ??
|
||||
createValueNode([
|
||||
{ type: "Dimension", value: "0", unit: "%" },
|
||||
{ type: "Dimension", value: "0", unit: "%" },
|
||||
{ type: "Dimension", value: "0", unit: "%", loc: null },
|
||||
{ type: "Dimension", value: "0", unit: "%", loc: null },
|
||||
]),
|
||||
bgSize ?? createIdentifier("auto"),
|
||||
repeatStyle ?? createIdentifier("repeat"),
|
||||
@@ -802,7 +821,9 @@ const expandGrid = function* (value: CssNode) {
|
||||
if (autoFlowKeyword) {
|
||||
autoFlow = createIdentifier("row");
|
||||
if (denseKeyword) {
|
||||
autoFlow.children.appendList(denseKeyword.children);
|
||||
denseKeyword.children.forEach((item) => {
|
||||
autoFlow.children.appendData(item);
|
||||
});
|
||||
}
|
||||
}
|
||||
autoRows = config ?? createIdentifier("auto");
|
||||
@@ -819,7 +840,9 @@ const expandGrid = function* (value: CssNode) {
|
||||
if (autoFlowKeyword) {
|
||||
autoFlow = createIdentifier("column");
|
||||
if (denseKeyword) {
|
||||
autoFlow.children.appendList(denseKeyword.children);
|
||||
denseKeyword.children.forEach((item) => {
|
||||
autoFlow.children.appendData(item);
|
||||
});
|
||||
}
|
||||
}
|
||||
autoColumns = config ?? createIdentifier("auto");
|
||||
@@ -973,13 +996,13 @@ const expandBackground = function* (value: CssNode) {
|
||||
image ?? createIdentifier("none"),
|
||||
position ??
|
||||
createValueNode([
|
||||
{ type: "Dimension", value: "0", unit: "%" },
|
||||
{ type: "Dimension", value: "0", unit: "%" },
|
||||
{ type: "Dimension", value: "0", unit: "%", loc: null },
|
||||
{ type: "Dimension", value: "0", unit: "%", loc: null },
|
||||
]),
|
||||
size ??
|
||||
createValueNode([
|
||||
{ type: "Identifier", name: "auto" },
|
||||
{ type: "Identifier", name: "auto" },
|
||||
{ type: "Identifier", name: "auto", loc: null },
|
||||
{ type: "Identifier", name: "auto", loc: null },
|
||||
]),
|
||||
repeatStyle ?? createIdentifier("repeat"),
|
||||
attachment ?? createIdentifier("scroll"),
|
||||
@@ -1418,7 +1441,7 @@ const parseValue = function* (property: string, value: string) {
|
||||
ast.type === "Value" &&
|
||||
ast.children.isEmpty
|
||||
) {
|
||||
ast.children.appendData({ type: "Identifier", name: "unset" });
|
||||
ast.children.appendData({ type: "Identifier", name: "unset", loc: null });
|
||||
}
|
||||
yield [property, ast] as const;
|
||||
} catch {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"extends": "@webstudio-is/tsconfig/base.json",
|
||||
"include": ["**/*.ts", "**/*.tsx", "../../@types/**/*.d.ts"],
|
||||
"compilerOptions": {
|
||||
"isolatedDeclarations": true
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
{
|
||||
"extends": "@webstudio-is/tsconfig/base.json"
|
||||
"extends": "@webstudio-is/tsconfig/base.json",
|
||||
"include": ["**/*.ts", "**/*.tsx", "../../@types/**/*.d.ts"]
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
{
|
||||
"extends": "@webstudio-is/tsconfig/base.json"
|
||||
"extends": "@webstudio-is/tsconfig/base.json",
|
||||
"include": ["**/*.ts", "**/*.tsx", "../../@types/**/*.d.ts"]
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
{
|
||||
"extends": "@webstudio-is/tsconfig/base.json"
|
||||
"extends": "@webstudio-is/tsconfig/base.json",
|
||||
"include": ["**/*.ts", "**/*.tsx", "../../@types/**/*.d.ts"]
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
{
|
||||
"extends": "@webstudio-is/tsconfig/base.json"
|
||||
"extends": "@webstudio-is/tsconfig/base.json",
|
||||
"include": ["**/*.ts", "**/*.tsx", "../../@types/**/*.d.ts"]
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
{
|
||||
"extends": "@webstudio-is/tsconfig/base.json"
|
||||
"extends": "@webstudio-is/tsconfig/base.json",
|
||||
"include": ["**/*.ts", "**/*.tsx", "../../@types/**/*.d.ts"]
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
{
|
||||
"extends": "@webstudio-is/tsconfig/base.json"
|
||||
"extends": "@webstudio-is/tsconfig/base.json",
|
||||
"include": ["**/*.ts", "**/*.tsx", "../../@types/**/*.d.ts"]
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
{
|
||||
"extends": "@webstudio-is/tsconfig/base.json"
|
||||
"extends": "@webstudio-is/tsconfig/base.json",
|
||||
"include": ["**/*.ts", "**/*.tsx", "../../@types/**/*.d.ts"]
|
||||
}
|
||||
@@ -2,10 +2,9 @@
|
||||
"extends": "@webstudio-is/tsconfig/base.json",
|
||||
"include": [
|
||||
"src",
|
||||
"../../@types/**/scroll-timeline.d.ts",
|
||||
"private-src",
|
||||
"../sdk/src/schema/animation-schema.ts",
|
||||
"../../@types/navigator.d.ts"
|
||||
"../../@types/**/*.d.ts"
|
||||
],
|
||||
"exclude": ["private-src/perf/**/*"],
|
||||
"compilerOptions": {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
{
|
||||
"extends": "@webstudio-is/tsconfig/base.json"
|
||||
"extends": "@webstudio-is/tsconfig/base.json",
|
||||
"include": ["**/*.ts", "**/*.tsx", "../../@types/**/*.d.ts"]
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
{
|
||||
"extends": "@webstudio-is/tsconfig/base.json"
|
||||
"extends": "@webstudio-is/tsconfig/base.json",
|
||||
"include": ["**/*.ts", "**/*.tsx", "../../@types/**/*.d.ts"]
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
{
|
||||
"extends": "@webstudio-is/tsconfig/base.json"
|
||||
"extends": "@webstudio-is/tsconfig/base.json",
|
||||
"include": ["**/*.ts", "**/*.tsx", "../../@types/**/*.d.ts"]
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"extends": "@webstudio-is/tsconfig/base.json",
|
||||
"include": ["**/*.ts", "**/*.tsx", "../../@types/**/*.d.ts"],
|
||||
"compilerOptions": {
|
||||
"isolatedDeclarations": true
|
||||
}
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
diff --git a/index.d.ts b/index.d.ts
|
||||
index e6a09d2756a7d942d7dbf2d6b9437deb06e8eb31..46120815179b6176100a045a599b92ecaa6be89c 100755
|
||||
--- a/index.d.ts
|
||||
+++ b/index.d.ts
|
||||
@@ -546,48 +546,7 @@ export interface WalkOptionsVisit<NodeType extends CssNode = CssNode> {
|
||||
reverse?: boolean | undefined;
|
||||
}
|
||||
|
||||
-export type WalkOptions =
|
||||
- WalkOptionsVisit<AnPlusB>
|
||||
- | WalkOptionsVisit<Atrule>
|
||||
- | WalkOptionsVisit<AtrulePrelude>
|
||||
- | WalkOptionsVisit<AttributeSelector>
|
||||
- | WalkOptionsVisit<Block>
|
||||
- | WalkOptionsVisit<Brackets>
|
||||
- | WalkOptionsVisit<CDC>
|
||||
- | WalkOptionsVisit<CDO>
|
||||
- | WalkOptionsVisit<ClassSelector>
|
||||
- | WalkOptionsVisit<Combinator>
|
||||
- | WalkOptionsVisit<Comment>
|
||||
- | WalkOptionsVisit<Declaration>
|
||||
- | WalkOptionsVisit<DeclarationList>
|
||||
- | WalkOptionsVisit<Dimension>
|
||||
- | WalkOptionsVisit<FunctionNode>
|
||||
- | WalkOptionsVisit<Hash>
|
||||
- | WalkOptionsVisit<IdSelector>
|
||||
- | WalkOptionsVisit<Identifier>
|
||||
- | WalkOptionsVisit<MediaFeature>
|
||||
- | WalkOptionsVisit<MediaQuery>
|
||||
- | WalkOptionsVisit<MediaQueryList>
|
||||
- | WalkOptionsVisit<Nth>
|
||||
- | WalkOptionsVisit<NumberNode>
|
||||
- | WalkOptionsVisit<Operator>
|
||||
- | WalkOptionsVisit<Parentheses>
|
||||
- | WalkOptionsVisit<Percentage>
|
||||
- | WalkOptionsVisit<PseudoClassSelector>
|
||||
- | WalkOptionsVisit<PseudoElementSelector>
|
||||
- | WalkOptionsVisit<Ratio>
|
||||
- | WalkOptionsVisit<Raw>
|
||||
- | WalkOptionsVisit<Rule>
|
||||
- | WalkOptionsVisit<Selector>
|
||||
- | WalkOptionsVisit<SelectorList>
|
||||
- | WalkOptionsVisit<StringNode>
|
||||
- | WalkOptionsVisit<StyleSheet>
|
||||
- | WalkOptionsVisit<TypeSelector>
|
||||
- | WalkOptionsVisit<UnicodeRange>
|
||||
- | WalkOptionsVisit<Url>
|
||||
- | WalkOptionsVisit<Value>
|
||||
- | WalkOptionsVisit<WhiteSpace>
|
||||
- | WalkOptionsNoVisit;
|
||||
+export type WalkOptions = WalkOptionsNoVisit;
|
||||
|
||||
export function walk(ast: CssNode, options: EnterOrLeaveFn | WalkOptions): void;
|
||||
|
||||
@@ -851,9 +810,30 @@ export class SyntaxReferenceError extends SyntaxError {
|
||||
reference: string;
|
||||
}
|
||||
|
||||
-export interface LexerMatchResult {
|
||||
- error: Error | SyntaxMatchError | SyntaxReferenceError | null;
|
||||
-}
|
||||
+type Match =
|
||||
+ | {
|
||||
+ syntax: DSNodeProperty;
|
||||
+ match: Match[];
|
||||
+ }
|
||||
+ | {
|
||||
+ syntax: DSNodeType;
|
||||
+ match: Match[];
|
||||
+ }
|
||||
+ | {
|
||||
+ syntax: DSNodeKeyword;
|
||||
+ token: string;
|
||||
+ }
|
||||
+ | { syntax: null };
|
||||
+
|
||||
+export type LexerMatchResult =
|
||||
+ | {
|
||||
+ matched: null;
|
||||
+ error: Error | SyntaxMatchError | SyntaxReferenceError;
|
||||
+ }
|
||||
+ | {
|
||||
+ matched: Match;
|
||||
+ error: null;
|
||||
+ };
|
||||
|
||||
export class Lexer {
|
||||
matchAtruleDescriptor(atruleName: string, descriptorName: string, value: CssNode | string): LexerMatchResult;
|
||||
@@ -864,6 +844,8 @@ export class Lexer {
|
||||
match(syntax: DSNode | string, value: CssNode | string): LexerMatchResult;
|
||||
}
|
||||
|
||||
+export declare const lexer: Lexer;
|
||||
+
|
||||
export function fork(extension: {
|
||||
atrules?: Record<string, string> | undefined,
|
||||
properties?: Record<string, string> | undefined,
|
||||
@@ -1,18 +0,0 @@
|
||||
diff --git a/package.json b/package.json
|
||||
index 934e699f19c6f1a265c1ef29121c6dde92cd25ed..a54e28a44de8e1adcf775be9564c2ad8b15b5c98 100644
|
||||
--- a/package.json
|
||||
+++ b/package.json
|
||||
@@ -18,11 +18,11 @@
|
||||
"validation"
|
||||
],
|
||||
"type": "module",
|
||||
- "module": "./lib/index.js",
|
||||
+ "module": "./dist/csstree.esm.js",
|
||||
"main": "./cjs/index.cjs",
|
||||
"exports": {
|
||||
".": {
|
||||
- "import": "./lib/index.js",
|
||||
+ "import": "./dist/csstree.esm.js",
|
||||
"require": "./cjs/index.cjs"
|
||||
},
|
||||
"./dist/*": "./dist/*.js",
|
||||
Generated
+23
-26
@@ -20,12 +20,6 @@ patchedDependencies:
|
||||
'@stitches/react@1.3.1-1':
|
||||
hash: knml42mpr6mlzseo3d6gjljiq4
|
||||
path: patches/@stitches__react@1.3.1-1.patch
|
||||
'@types/css-tree@2.3.1':
|
||||
hash: ac22lciodhaj6xmoeignv36gyq
|
||||
path: patches/@types__css-tree@2.3.1.patch
|
||||
css-tree@2.3.1:
|
||||
hash: epgcmebti7rfrc2ej4odb3t4jy
|
||||
path: patches/css-tree@2.3.1.patch
|
||||
|
||||
importers:
|
||||
|
||||
@@ -61,9 +55,6 @@ importers:
|
||||
'@storybook/react-vite':
|
||||
specifier: ^8.6.4
|
||||
version: 8.6.4(react-dom@18.3.0-canary-14898b6a9-20240318(react@18.3.0-canary-14898b6a9-20240318))(react@18.3.0-canary-14898b6a9-20240318)(rollup@4.40.0)(storybook@8.6.4(prettier@3.5.3))(typescript@5.8.2)(vite@6.3.4(@types/node@22.13.10)(jiti@2.4.2)(tsx@4.19.3))
|
||||
'@types/css-tree':
|
||||
specifier: ^2.3.1
|
||||
version: 2.3.1(patch_hash=ac22lciodhaj6xmoeignv36gyq)
|
||||
'@types/node':
|
||||
specifier: ^22.13.10
|
||||
version: 22.13.10
|
||||
@@ -326,8 +317,8 @@ importers:
|
||||
specifier: ^1.0.1
|
||||
version: 1.0.1
|
||||
css-tree:
|
||||
specifier: ^2.3.1
|
||||
version: 2.3.1(patch_hash=epgcmebti7rfrc2ej4odb3t4jy)
|
||||
specifier: ^3.1.0
|
||||
version: 3.1.0
|
||||
debug:
|
||||
specifier: ^4.3.7
|
||||
version: 4.3.7
|
||||
@@ -1241,8 +1232,8 @@ importers:
|
||||
specifier: ^2.9.3
|
||||
version: 2.9.3
|
||||
css-tree:
|
||||
specifier: ^2.3.1
|
||||
version: 2.3.1(patch_hash=epgcmebti7rfrc2ej4odb3t4jy)
|
||||
specifier: ^3.1.0
|
||||
version: 3.1.0
|
||||
openai:
|
||||
specifier: ^3.2.1
|
||||
version: 3.2.1
|
||||
@@ -1253,9 +1244,6 @@ importers:
|
||||
specifier: ^0.1.1
|
||||
version: 0.1.1
|
||||
devDependencies:
|
||||
'@types/css-tree':
|
||||
specifier: ^2.3.1
|
||||
version: 2.3.1(patch_hash=ac22lciodhaj6xmoeignv36gyq)
|
||||
'@webstudio-is/tsconfig':
|
||||
specifier: workspace:*
|
||||
version: link:../tsconfig
|
||||
@@ -5375,9 +5363,6 @@ packages:
|
||||
'@types/cookie@0.6.0':
|
||||
resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
|
||||
|
||||
'@types/css-tree@2.3.1':
|
||||
resolution: {integrity: sha512-3m636Jz4d9d+lHVMp6FNLsUWQrfOx1xpm1SBxPbQYSNNgXMe+XswcsDeo1ldyULiuzYyWKk1kmvkLTgNq+215Q==}
|
||||
|
||||
'@types/debug@4.1.12':
|
||||
resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==}
|
||||
|
||||
@@ -6101,6 +6086,10 @@ packages:
|
||||
resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==}
|
||||
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
|
||||
|
||||
css-tree@3.1.0:
|
||||
resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==}
|
||||
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
|
||||
|
||||
css-what@6.1.0:
|
||||
resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==}
|
||||
engines: {node: '>= 6'}
|
||||
@@ -7313,6 +7302,9 @@ packages:
|
||||
mdn-data@2.0.30:
|
||||
resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==}
|
||||
|
||||
mdn-data@2.12.2:
|
||||
resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==}
|
||||
|
||||
mdn-data@2.23.0:
|
||||
resolution: {integrity: sha512-786vq1+4079JSeu2XdcDjrhi/Ry7BWtjDl9WtGPWLiIHb2T66GvIVflZTBoSNZ5JqTtJGYEVMuFA/lbQlMOyDQ==}
|
||||
|
||||
@@ -12591,7 +12583,7 @@ snapshots:
|
||||
|
||||
'@svgo/jsx@0.4.2':
|
||||
dependencies:
|
||||
css-tree: 2.3.1(patch_hash=epgcmebti7rfrc2ej4odb3t4jy)
|
||||
css-tree: 2.3.1
|
||||
svgo: 3.0.2
|
||||
|
||||
'@swc/helpers@0.5.15':
|
||||
@@ -12678,8 +12670,6 @@ snapshots:
|
||||
|
||||
'@types/cookie@0.6.0': {}
|
||||
|
||||
'@types/css-tree@2.3.1(patch_hash=ac22lciodhaj6xmoeignv36gyq)': {}
|
||||
|
||||
'@types/debug@4.1.12':
|
||||
dependencies:
|
||||
'@types/ms': 0.7.31
|
||||
@@ -13527,13 +13517,18 @@ snapshots:
|
||||
css-tree@2.2.1:
|
||||
dependencies:
|
||||
mdn-data: 2.0.28
|
||||
source-map-js: 1.2.0
|
||||
source-map-js: 1.2.1
|
||||
|
||||
css-tree@2.3.1(patch_hash=epgcmebti7rfrc2ej4odb3t4jy):
|
||||
css-tree@2.3.1:
|
||||
dependencies:
|
||||
mdn-data: 2.0.30
|
||||
source-map-js: 1.2.0
|
||||
|
||||
css-tree@3.1.0:
|
||||
dependencies:
|
||||
mdn-data: 2.12.2
|
||||
source-map-js: 1.2.1
|
||||
|
||||
css-what@6.1.0: {}
|
||||
|
||||
cssesc@3.0.0: {}
|
||||
@@ -14995,6 +14990,8 @@ snapshots:
|
||||
|
||||
mdn-data@2.0.30: {}
|
||||
|
||||
mdn-data@2.12.2: {}
|
||||
|
||||
mdn-data@2.23.0: {}
|
||||
|
||||
media-query-parser@2.0.2:
|
||||
@@ -16644,7 +16641,7 @@ snapshots:
|
||||
'@trysound/sax': 0.2.0
|
||||
commander: 7.2.0
|
||||
css-select: 5.1.0
|
||||
css-tree: 2.3.1(patch_hash=epgcmebti7rfrc2ej4odb3t4jy)
|
||||
css-tree: 2.3.1
|
||||
csso: 5.0.5
|
||||
picocolors: 1.1.1
|
||||
|
||||
@@ -16653,7 +16650,7 @@ snapshots:
|
||||
'@trysound/sax': 0.2.0
|
||||
commander: 7.2.0
|
||||
css-select: 5.1.0
|
||||
css-tree: 2.3.1(patch_hash=epgcmebti7rfrc2ej4odb3t4jy)
|
||||
css-tree: 2.3.1
|
||||
css-what: 6.1.0
|
||||
csso: 5.0.5
|
||||
picocolors: 1.1.1
|
||||
|
||||
Reference in new issue
Block a user