UNPKG

css-selector-parser

Version:
297 lines (296 loc) 11.8 kB
/** * CSS Selector AST root. * Contains list of CSS rules (separated by a comma in the input CSS selector string). * Generated by {@link AstFactory.selector ast.selector}. */ export interface AstSelector { type: 'Selector'; /** * List of CSS rules. Every rule contains conditions. Selector is considered matched once at least one rule matches. */ rules: AstRule[]; } /** * A single CSS rule that contains match conditions. * Can nest another rule with or without a combinator (i.e. `"div > span"`). * Generated by {@link AstFactory.rule ast.rule}. */ export interface AstRule { type: 'Rule'; /** Items of a CSS rule. Can be tag, ids, class names, pseudo-classes and pseudo-elements. */ items: (AstTagName | AstWildcardTag | AstId | AstClassName | AstAttribute | AstPseudoClass | AstPseudoElement | AstNestingSelector)[]; /** Rule combinator which was used to nest this rule (i.e. `">"` in case of `"div > span"` if the current rule is `"span"`). */ combinator?: string; /** Nested rule if specified (i.e. `"div > span"`). */ nestedRule?: AstRule; } /** * Named tag, i.e. `"div"`. Part of CSS Qualified Names. * Generated by {@link AstFactory.tagName ast.tagName}. * @see https://developer.mozilla.org/en-US/docs/Web/CSS/Type_selectors * @see https://drafts.csswg.org/css-namespaces-3/#css-qnames */ export interface AstTagName { type: 'TagName'; /** Tag name, i.e. `"div"`. */ name: string; /** Namespace according to https://www.w3.org/TR/css3-namespace/. */ namespace?: AstNamespaceName | AstWildcardNamespace | AstNoNamespace; } /** * ID condition. Matches by id attribute value. * Generated by {@link AstFactory.id ast.id}. * https://developer.mozilla.org/en-US/docs/Web/CSS/ID_selectors * @example "#root" */ export interface AstId { type: 'Id'; /** ID name. I.e. `#root` -> `"root"`. */ name: string; } /** * Class name condition. Matches by class attribute value. * Generated by {@link AstFactory.className ast.className}. * https://developer.mozilla.org/en-US/docs/Web/CSS/ID_selectors * @example ".user" */ export interface AstClassName { type: 'ClassName'; /** ID name. I.e. `.user` -> `"user"`. */ name: string; } /** * Wildcard tag (universal selector): `*`. * Generated by {@link AstFactory.wildcardTag ast.wildcardTag}. * @see https://developer.mozilla.org/en-US/docs/Web/CSS/Universal_selectors * @see https://drafts.csswg.org/css-namespaces-3/#css-qnames */ export interface AstWildcardTag { type: 'WildcardTag'; /** Namespace according to https://www.w3.org/TR/css3-namespace/. */ namespace?: AstNamespaceName | AstWildcardNamespace | AstNoNamespace; } /** * Named namespace declaration (i.e. `ns|div`). * Generated by {@link AstFactory.namespaceName ast.namespaceName}. * @see https://drafts.csswg.org/css-namespaces-3/#css-qnames */ export interface AstNamespaceName { type: 'NamespaceName'; /** Namespace name (i.e. `"ns"` in case of `"ns|div"`). "*/ name: string; } /** * Wildcard namespace (universal selector): `*`. * Generated by {@link AstFactory.wildcardNamespace ast.wildcardNamespace}. * @see https://developer.mozilla.org/en-US/docs/Web/CSS/Universal_selectors * @see https://drafts.csswg.org/css-namespaces-3/#css-qnames */ export interface AstWildcardNamespace { type: 'WildcardNamespace'; } /** * Explicit no-namespace declaration (i.e. `|div`). * Generated by {@link AstFactory.noNamespace ast.noNamespace}. * @see https://drafts.csswg.org/css-namespaces-3/#css-qnames */ export interface AstNoNamespace { type: 'NoNamespace'; } /** * Attribute selector. * Generated by {@link AstFactory.attribute ast.attribute}. * @example "[role='button' i]" */ export interface AstAttribute { type: 'Attribute'; /** Attribute name (i.e. `"href"` in case if `"[href]"`). */ name: string; /** Namespace according to https://drafts.csswg.org/selectors/#attrnmsp. */ namespace?: AstNamespaceName | AstWildcardNamespace | AstNoNamespace; /** Comparison operator (i.e. `"|="` in case if `"[role|=button]"`). */ operator?: string; /** Comparison value (i.e. `"button"` in case if `"[role=button]"`). */ value?: AstString | AstSubstitution; /** Comparison case sensitivity modifier (i.e. `"i"` in case if `"[role='button' i]"`). */ caseSensitivityModifier?: string; } /** * Pseudo-class selector. * Generated by {@link AstFactory.pseudoClass ast.pseudoClass}. * @see https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements * @example ":lang(en)" */ export interface AstPseudoClass { type: 'PseudoClass'; /** Pseudo-class name (i.e. `"hover"` in case of `":hover"`). */ name: string; /** Pseudo-class value (i.e. `"en"` in case of `":lang(en)"`). */ argument?: AstSubstitution | AstSelector | AstString | AstFormula | AstFormulaOfSelector; } /** * Pseudo-class selector. * Generated by {@link AstFactory.pseudoElement ast.pseudoElement}. * @see https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Selectors/Pseudo-classes_and_pseudo-elements * @example "::before" */ export interface AstPseudoElement { type: 'PseudoElement'; /** Pseudo-element name (i.e. `"before"` in case of `"::before"`). */ name: string; /** Pseudo-element value (i.e. `"foo"` in case of `"::part(foo)"`). */ argument?: AstSubstitution | AstString | AstSelector; } /** * String value. Can be used as attribute value of pseudo-class string value. * For instance `:lang(en)` -> `{type: 'AstPseudoClass'..., argument: {type: 'String', value: 'en'}}`. * Generated by {@link AstFactory.string ast.string}. */ export interface AstString { type: 'String'; /** The actual string value. */ value: string; } /** * Pseudo-class formula value. `a` is multiplier of `n` and `b` us added on top. Formula: `an + b`. * For instance `:nth-child(2n + 1)` -> `{type: 'AstPseudoClass'..., argument: {type: 'Formula', a: 2, b: 1}}`. * Generated by {@link AstFactory.formula ast.formula}. * @see https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-child#functional_notation */ export interface AstFormula { type: 'Formula'; /** Multiplier of `n`. */ a: number; /** Constant added to `a*n`. */ b: number; } /** * Pseudo-class formula of selector value. `a` is multiplier of `n` and `b` us added on top. Formula: `an + b`. * Formula is followed by `of` keyword and then goes a CSS selector. * For instance `:nth-child(2n + 1 of div)` -> * `{type: 'AstPseudoClass'..., argument: {type: 'FormulaOfSelector', a: 2, b: 1, selector: {type: 'Selector', rules: [{type: 'Rule', items: [{type: 'TagName', name: 'div'}]}]}}}`. * Generated by {@link AstFactory.formulaOfSelector ast.formulaOfSelector}. * @see https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-child#functional_notation */ export interface AstFormulaOfSelector { type: 'FormulaOfSelector'; /** Multiplier of `n`. */ a: number; /** Constant added to `a*n`. */ b: number; /** Selector that goes after formula (i.e. `"div -> span"` in case of `":nth-child(2n + 1 of div > span)"` */ selector: AstRule; } /** * CSS Nesting Selector: `&`. * Represents the parent selector in nested CSS. * Generated by {@link AstFactory.nestingSelector ast.nestingSelector}. * @see https://www.w3.org/TR/css-nesting-1/#nest-selector * @example "&:hover" */ export interface AstNestingSelector { type: 'NestingSelector'; } /** * Substitution is not part of CSS spec, but rather a useful extension on top of CSS if you need to pass variables. * Generated by {@link AstFactory.substitution ast.substitution}. */ export interface AstSubstitution { type: 'Substitution'; /** Substitution name (i.e. "var" in case of `"[role=$var]"` or `":lang($var)"`). */ name: string; } /** One of pseudo-class argument types. */ export type AstPseudoClassArgument = AstSubstitution | AstSelector | AstString | AstFormula | AstFormulaOfSelector; /** One of pseudo-element argument types. */ export type AstPseudoElementArgument = AstSubstitution | AstString | AstSelector; /** One of CSS AST entity types. */ export type AstEntity = AstSelector | AstRule | AstTagName | AstWildcardTag | AstId | AstClassName | AstNamespaceName | AstWildcardNamespace | AstNoNamespace | AstNestingSelector | AstSubstitution | AstString | AstFormula | AstFormulaOfSelector | AstPseudoClass | AstAttribute | AstPseudoElement; type UnionToIntersection<T> = (T extends any ? (x: T) => any : never) extends (x: infer R) => any ? R : never; type ToAstFactory<T> = UnionToIntersection<T extends { type: infer Type; } ? Type extends string ? { [K in Uncapitalize<Type>]: {} extends Omit<T, 'type'> ? (props?: { [PK in keyof Omit<T, 'type'>]: Omit<T, 'type'>[PK]; }) => T : (props: { [PK in keyof Omit<T, 'type'>]: Omit<T, 'type'>[PK]; }) => T; } & { [K in `is${Type}`]: (entity: unknown) => entity is T; } : never : never>; /** @internal */ type AstFactoryBase = { [K in keyof ToAstFactory<AstEntity>]: ToAstFactory<AstEntity>[K]; }; /** * AST structure generators and matchers. * For instance, `ast.selector({rules: [...]})` creates AstSelector and `ast.isSelector(...)` checks if * AstSelector was specified. * * @example * * // Represents CSS selector: ns|div#user-34.user.user-active[role="button"]:lang(en)::before > * * const selector = ast.selector({ * rules: [ * ast.rule({ * items: [ * ast.tagName({name: 'div', namespace: ast.namespaceName({name: 'ns'})}), * ast.id({name: 'user-34'}), * ast.className({name: 'user'}), * ast.className({name: 'user-active'}), * ast.attribute({ * name: 'role', * operator: '=', * value: ast.string({value: 'button'}) * }), * ast.pseudoClass({ * name: 'lang', * argument: ast.string({value: 'en'}) * }), * ast.pseudoElement({name: 'before'}) * ], * nestedRule: ast.rule({combinator: '>', items: [ast.wildcardTag()]}) * }) * ] * }); * console.log(ast.isSelector(selector)); // prints true * console.log(ast.isRule(selector)); // prints false */ export interface AstFactory extends AstFactoryBase { } /** * AST structure generators and matchers. * For instance, `ast.selector({rules: [...]})` creates AstSelector and `ast.isSelector(...)` checks if * AstSelector was specified. * * @example * * // Represents CSS selector: ns|div#user-34.user.user-active[role="button"]:lang(en)::before > * * const selector = ast.selector({ * rules: [ * ast.rule({ * items: [ * ast.tagName({name: 'div', namespace: ast.namespaceName({name: 'ns'})}), * ast.id({name: 'user-34'}), * ast.className({name: 'user'}), * ast.className({name: 'user-active'}), * ast.attribute({ * name: 'role', * operator: '=', * value: ast.string({value: 'button'}) * }), * ast.pseudoClass({ * name: 'lang', * argument: ast.string({value: 'en'}) * }), * ast.pseudoElement({name: 'before'}) * ], * nestedRule: ast.rule({combinator: '>', items: [ast.wildcardTag()]}) * }) * ] * }); * console.log(ast.isSelector(selector)); // prints true * console.log(ast.isRule(selector)); // prints false */ export declare const ast: AstFactory; export {};