From 668a68460eb1e95cff74d3cb34a2d18030ade04d Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Fri, 4 May 2018 13:34:06 -0700 Subject: [PATCH 1/2] ideas for the API to rewrite for landing in postcss core. --- postcss-selector-parser-5.d.ts | 207 +++++++++++++++++++++++++++++++++ types-test.ts | 20 ++++ 2 files changed, 227 insertions(+) create mode 100644 postcss-selector-parser-5.d.ts create mode 100644 types-test.ts diff --git a/postcss-selector-parser-5.d.ts b/postcss-selector-parser-5.d.ts new file mode 100644 index 0000000..f7d9045 --- /dev/null +++ b/postcss-selector-parser-5.d.ts @@ -0,0 +1,207 @@ +// ====== Selector Nodes ====== + +enum KindOfNode { + Selector = "selector", + Value = "value", + Ignorable = "ignorable", +} +enum SelectorType { + List = "list", + Complex = "complex", + Relative = "relative", + Compound = "compound", + Simple = "simple", +} + +interface HasComplexSelectors { + selectors: Array; +} + +class SelectorNode extends Node { + kind: KindOfNode.Selector; + selectorType: SelectorType; +} + +// Rule would have an accessor to get a parsed selector list. +// This is the `Root` class right now. +class SelectorList extends SelectorNode, HasComplexSelectors { + selectorType: SelectorType.List; + selectors: Array; +} + +class ComplexSelector extends SelectorNode { + selectorType: SelectorType.Complex; + readonly firstSelector: CompoundSelector; // head of the linked list + keySelector: CompoundSelector; // The compound selector that matches the element receiving the styles. + selectors: Array; // random access into the linked list + combinators: Array; // random access into the linked list +} + +class Combinator extends Literal<" " | ">" | "~" | "+" | ">>>" | "" > { + +} + +// Sass and Less allow selectors to begin with a combinator, +// so does some new pseudo selectors +// https://drafts.csswg.org/selectors-4/#relative +class RelativeSelector extends ComplexSelector { + selectorType: SelectorType.Relative; + leadingCombinator: Combinator; +} + +// linked list where the next object has a combinator and the following selector. +class CompoundSelector extends SelectorNode { + selectorType: SelectorType.CompoundSelector; + selectors: Array + next?: { + combinator: Combinator; + selector?: CompoundSelector; + } +} + +type SimpleSelector = Identifier | ClassName | Attribute +| PseudoClass | PseudoElement | ParentReference +| Universal | Tag; + +enum SimpleSelectorType { + Identifier = "identifier", + ClassName = "class", + Attribute = "attribute", + PseudoClass = "pseudoclass", + PseudoElement = "pseudoelement", + ParentReference = "parentref", + Universal = "univeral", + Tag = "tag", +} +class Selector extends SelectorNode { + selectorType: SelectorType.Simple; + simpleType: SimpleSelectorType; + value: T; +} + +interface HasNamespace { + namespace?: Ident | Literal<"*">; +} + +class Attribute extends Selector, HasNamespace { + simpleType: SimpleSelectorType.Attribute; + name: Ident; + operator?: Literal<"=" | "|=" | "^=" | "$=" | "*=" | "~=">; + flags: Ident; // E.g. the i for case insensitivity +} + +// A proxy for reading/writing node attributes as strings +type Reader = { + [P in keyof T]: T[P] extends Value ? string : never; +} + +class Identifier extends Selector { + simpleType: SimpleSelectorType.Identifier; +} + +class ClassName extends Selector { + simpleType: SimpleSelectorType.ClassName; +} + +// classes and elements are the same node type right now and that's +// just weird. +class PseudoClass extends Selector, HasComplexSelectors { + simpleType: SimpleSelectorType.PseudoClass; + colon: ":"; +} + +class PseudoElement extends Selector { + simpleType: SimpleSelectorType.PseudoElement; + colon: ":" | "::"; +} + +class Universal extends Selector>, HasNamespace { + simpleType: SimpleSelectorType.Universal; +} + +class ParentReference extends Selector> { + simpleType: SimpleSelectorType.ParentReference; +} + +class Tag extends Selector, HasNamespace { + simpleType: SimpleSelectorType.Tag; +} + +// ====== Value Nodes ====== + +interface HasValue { + value: T; + raw: T extends string ? T : never | undefined; // only available when T is a string +} + +class Value extends Node implements HasValue { + kind: KindOfNode.Value; + value: T; + raw: T | undefined; +} + +enum IgnorableType { + comment = "comment", + whitespace = "whitespace", +} + +class Comment extends SourceNode implements HasValue { + kind: KindOfNode.Ignorable; + ignorableType: IgnorableType.comment; + value: string; + raw: string | undefined; + open: string; // usually set to "/*" but could be "//" for single-line comments + close: string | undefined; // single line comments and comments at the end of the file +} + +class Whitespace extends SourceNode implements HasValue { + kind: KindOfNode.Ignorable; + ignorableType: IgnorableType.whitespace; + value: string; + raw: string | undefined; +} + +type Ignorable = Comment | Whitespace; + +enum ValueType { + Ident = "ident", + String = "string", + Literal = "literal", +} + + +class Ident extends Value { + kind: KindOfNode.Value; + valueType = ValueType.Ident; +} + +class String extends Value { + valueType = ValueType.String; + quoteMark: "'" | '"'; +} + +class Literal extends Value { + valueType = ValueType.Literal; +} + +// ==== Common Node ====== + +interface Position { + line: number; + column: number; +} +interface Location { + start: Position; + end: Position; +} + +class SourceNode { + source: Location; + sourceIndex: number; + sourceLength: number; +} + +class Node extends SourceNode { + before: Array; + after: Array; +} \ No newline at end of file diff --git a/types-test.ts b/types-test.ts new file mode 100644 index 0000000..b3f2e3c --- /dev/null +++ b/types-test.ts @@ -0,0 +1,20 @@ +import * as parser from 'postcss-selector-parser'; + +const transform: parser.SyncProcessor = selectors => { + selectors.walk(selector => { + // do something with the selector + console.log(String(selector)) + }); +}; + +const transformAsync = selectors => { + return Promise.resolve().then(() => { + selectors.walk(selector => { + // do something with the selector + console.log(String(selector)) + }); + }) +}; +const p = parser(transformAsync); + +const transformed = p.processSync('h1, h2, h3'); \ No newline at end of file From ccc07da53c1fe8c27c96dca05513ea9909245186 Mon Sep 17 00:00:00 2001 From: Chris Eppstein Date: Tue, 8 May 2018 17:25:26 -0700 Subject: [PATCH 2/2] Update API concepts for the next major release. --- postcss-selector-parser-5.d.ts | 207 --------------------------- postcss-selector-parser-core.d.ts | 229 ++++++++++++++++++++++++++++++ 2 files changed, 229 insertions(+), 207 deletions(-) delete mode 100644 postcss-selector-parser-5.d.ts create mode 100644 postcss-selector-parser-core.d.ts diff --git a/postcss-selector-parser-5.d.ts b/postcss-selector-parser-5.d.ts deleted file mode 100644 index f7d9045..0000000 --- a/postcss-selector-parser-5.d.ts +++ /dev/null @@ -1,207 +0,0 @@ -// ====== Selector Nodes ====== - -enum KindOfNode { - Selector = "selector", - Value = "value", - Ignorable = "ignorable", -} -enum SelectorType { - List = "list", - Complex = "complex", - Relative = "relative", - Compound = "compound", - Simple = "simple", -} - -interface HasComplexSelectors { - selectors: Array; -} - -class SelectorNode extends Node { - kind: KindOfNode.Selector; - selectorType: SelectorType; -} - -// Rule would have an accessor to get a parsed selector list. -// This is the `Root` class right now. -class SelectorList extends SelectorNode, HasComplexSelectors { - selectorType: SelectorType.List; - selectors: Array; -} - -class ComplexSelector extends SelectorNode { - selectorType: SelectorType.Complex; - readonly firstSelector: CompoundSelector; // head of the linked list - keySelector: CompoundSelector; // The compound selector that matches the element receiving the styles. - selectors: Array; // random access into the linked list - combinators: Array; // random access into the linked list -} - -class Combinator extends Literal<" " | ">" | "~" | "+" | ">>>" | "" > { - -} - -// Sass and Less allow selectors to begin with a combinator, -// so does some new pseudo selectors -// https://drafts.csswg.org/selectors-4/#relative -class RelativeSelector extends ComplexSelector { - selectorType: SelectorType.Relative; - leadingCombinator: Combinator; -} - -// linked list where the next object has a combinator and the following selector. -class CompoundSelector extends SelectorNode { - selectorType: SelectorType.CompoundSelector; - selectors: Array - next?: { - combinator: Combinator; - selector?: CompoundSelector; - } -} - -type SimpleSelector = Identifier | ClassName | Attribute -| PseudoClass | PseudoElement | ParentReference -| Universal | Tag; - -enum SimpleSelectorType { - Identifier = "identifier", - ClassName = "class", - Attribute = "attribute", - PseudoClass = "pseudoclass", - PseudoElement = "pseudoelement", - ParentReference = "parentref", - Universal = "univeral", - Tag = "tag", -} -class Selector extends SelectorNode { - selectorType: SelectorType.Simple; - simpleType: SimpleSelectorType; - value: T; -} - -interface HasNamespace { - namespace?: Ident | Literal<"*">; -} - -class Attribute extends Selector, HasNamespace { - simpleType: SimpleSelectorType.Attribute; - name: Ident; - operator?: Literal<"=" | "|=" | "^=" | "$=" | "*=" | "~=">; - flags: Ident; // E.g. the i for case insensitivity -} - -// A proxy for reading/writing node attributes as strings -type Reader = { - [P in keyof T]: T[P] extends Value ? string : never; -} - -class Identifier extends Selector { - simpleType: SimpleSelectorType.Identifier; -} - -class ClassName extends Selector { - simpleType: SimpleSelectorType.ClassName; -} - -// classes and elements are the same node type right now and that's -// just weird. -class PseudoClass extends Selector, HasComplexSelectors { - simpleType: SimpleSelectorType.PseudoClass; - colon: ":"; -} - -class PseudoElement extends Selector { - simpleType: SimpleSelectorType.PseudoElement; - colon: ":" | "::"; -} - -class Universal extends Selector>, HasNamespace { - simpleType: SimpleSelectorType.Universal; -} - -class ParentReference extends Selector> { - simpleType: SimpleSelectorType.ParentReference; -} - -class Tag extends Selector, HasNamespace { - simpleType: SimpleSelectorType.Tag; -} - -// ====== Value Nodes ====== - -interface HasValue { - value: T; - raw: T extends string ? T : never | undefined; // only available when T is a string -} - -class Value extends Node implements HasValue { - kind: KindOfNode.Value; - value: T; - raw: T | undefined; -} - -enum IgnorableType { - comment = "comment", - whitespace = "whitespace", -} - -class Comment extends SourceNode implements HasValue { - kind: KindOfNode.Ignorable; - ignorableType: IgnorableType.comment; - value: string; - raw: string | undefined; - open: string; // usually set to "/*" but could be "//" for single-line comments - close: string | undefined; // single line comments and comments at the end of the file -} - -class Whitespace extends SourceNode implements HasValue { - kind: KindOfNode.Ignorable; - ignorableType: IgnorableType.whitespace; - value: string; - raw: string | undefined; -} - -type Ignorable = Comment | Whitespace; - -enum ValueType { - Ident = "ident", - String = "string", - Literal = "literal", -} - - -class Ident extends Value { - kind: KindOfNode.Value; - valueType = ValueType.Ident; -} - -class String extends Value { - valueType = ValueType.String; - quoteMark: "'" | '"'; -} - -class Literal extends Value { - valueType = ValueType.Literal; -} - -// ==== Common Node ====== - -interface Position { - line: number; - column: number; -} -interface Location { - start: Position; - end: Position; -} - -class SourceNode { - source: Location; - sourceIndex: number; - sourceLength: number; -} - -class Node extends SourceNode { - before: Array; - after: Array; -} \ No newline at end of file diff --git a/postcss-selector-parser-core.d.ts b/postcss-selector-parser-core.d.ts new file mode 100644 index 0000000..f635915 --- /dev/null +++ b/postcss-selector-parser-core.d.ts @@ -0,0 +1,229 @@ +declare module "postcss-selector-parser" { + // ==== Common Node ====== + + interface Position { + line: number; + column: number; + } + + interface Location { + start: Position; + end: Position; + } + + class SourceNode { + source: Location; + sourceIndex: number; + sourceLength: number; + } + + enum NodeOrigin { + Root, + Selector, + AtRule, + Declaration, + } + class Node extends SourceNode { + origin: NodeOrigin; + kind: KindOfNode; + before: Array; + after: Array; + } + + // ====== Value Nodes ====== + + interface HasValue { + value: T; + raw: T extends string ? (T | undefined) : never; // only available when T is a string + } + + class Value extends Node implements HasValue { + kind: KindOfNode.Value; + value: T; + raw: T extends string ? (T | undefined) : never; + } + + enum IgnorableType { + comment = "comment", + whitespace = "whitespace", + } + + class Comment extends SourceNode implements HasValue { + kind: KindOfNode.Ignorable; + ignorableType: IgnorableType.comment; + value: string; + raw: string | undefined; + open: string; // usually set to "/*" but could be "//" for single-line comments + close: string | undefined; // single line comments and comments at the end of the file + } + + class Whitespace extends SourceNode implements HasValue { + kind: KindOfNode.Ignorable; + ignorableType: IgnorableType.whitespace; + value: string; + raw: string | undefined; + } + + type Ignorable = Comment | Whitespace; + + enum ValueType { + Ident = "ident", + String = "string", + Literal = "literal", + } + + + class Ident extends Value { + kind: KindOfNode.Value; + valueType: ValueType.Ident; + } + + class String extends Value { + valueType: ValueType.String; + quoteMark: "'" | '"'; + } + + class Literal extends Value { + valueType: ValueType.Literal; + } + + + + // ====== Selector Nodes ====== + + enum KindOfNode { + Selector = "selector", + Value = "value", + Ignorable = "ignorable", + } + enum SelectorType { + List = "list", + Complex = "complex", + Relative = "relative", + Compound = "compound", + Simple = "simple", + } + + interface HasComplexSelectors { + selectors: Array; + } + + class SelectorNode extends Node { + kind: KindOfNode.Selector; + selectorType: SelectorType; + } + + // Rule would have an accessor to get a parsed selector list. + // This is the `Root` class right now. + class SelectorList extends SelectorNode implements HasComplexSelectors { + selectorType: SelectorType.List; + selectors: Array; + } + + class ComplexSelector extends SelectorNode { + selectorType: SelectorType.Complex; + readonly firstSelector: CompoundSelector; // head of the linked list + keySelector: CompoundSelector; // The compound selector that matches the element receiving the styles. + selectors: Array; // random access into the linked list + combinators: Array; // random access into the linked list + } + + class Combinator extends Literal<" " | ">" | "~" | "+" | ">>>" | ""> { + + } + + // Sass and Less allow selectors to begin with a combinator, + // so does some new pseudo selectors + // https://drafts.csswg.org/selectors-4/#relative + class RelativeSelector extends SelectorNode { + selectorType: SelectorType.Relative; + leadingCombinator: Combinator; + readonly firstSelector: CompoundSelector; // head of the linked list + keySelector: CompoundSelector; // The compound selector that matches the element receiving the styles. + selectors: Array; // random access into the linked list + combinators: Array; // random access into the linked list + } + + // linked list where the next object has a combinator and the following selector. + class CompoundSelector extends SelectorNode { + selectorType: SelectorType.Compound; + selectors: Array + next?: { + combinator: Combinator; + selector?: CompoundSelector; + } + } + + type SimpleSelector = Identifier | ClassName | Attribute + | PseudoClass | PseudoElement | ParentReference + | Universal | Tag; + + enum SimpleSelectorType { + Identifier = "identifier", + ClassName = "class", + Attribute = "attribute", + PseudoClass = "pseudoclass", + PseudoElement = "pseudoelement", + ParentReference = "parentref", + Universal = "univeral", + Tag = "tag", + } + class Selector extends SelectorNode { + selectorType: SelectorType.Simple; + simpleType: SimpleSelectorType; + value: T; + } + + interface HasNamespace { + namespace?: Ident | Literal<"*">; + } + + class Attribute extends Selector implements HasNamespace { + namespace?: Ident | Literal<"*">; + simpleType: SimpleSelectorType.Attribute; + name: Ident; + operator?: Literal<"=" | "|=" | "^=" | "$=" | "*=" | "~=">; + flags: Ident; // E.g. the i for case insensitivity + } + + // A proxy for reading/writing node attributes as strings + type Reader = { + [P in keyof T]: T[P] extends Value ? string : never; + } + + class Identifier extends Selector { + simpleType: SimpleSelectorType.Identifier; + } + + class ClassName extends Selector { + simpleType: SimpleSelectorType.ClassName; + } + + // classes and elements are the same node type right now and that's + // just weird. + class PseudoClass extends Selector implements HasComplexSelectors { + simpleType: SimpleSelectorType.PseudoClass; + selectors: (ComplexSelector | RelativeSelector)[]; + colon: ":"; + } + + class PseudoElement extends Selector { + simpleType: SimpleSelectorType.PseudoElement; + colon: ":" | "::"; + } + + class Universal extends Selector> implements HasNamespace { + namespace?: Ident | Literal<"*">; + simpleType: SimpleSelectorType.Universal; + } + + class ParentReference extends Selector> { + simpleType: SimpleSelectorType.ParentReference; + } + + class Tag extends Selector implements HasNamespace { + namespace?: Ident | Literal<"*">; + simpleType: SimpleSelectorType.Tag; + } + +} \ No newline at end of file