Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Various improvements of the code #53

Merged
merged 25 commits into from
Apr 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
d3fb004
Unify linefeeds in the repository
danny0838 Mar 31, 2024
d8f318a
Unify indentation to 2-spaces
danny0838 Mar 31, 2024
e3d0912
Use 2-space indentation for test output
danny0838 Mar 31, 2024
4c7d753
Fix more bad indentation
danny0838 Mar 31, 2024
6c911de
Support globalThis
danny0838 Mar 31, 2024
f83644d
Unify all tests into refactored tests.js
danny0838 Mar 31, 2024
696363e
Optimize test output using insertAdjacentHTML
danny0838 Mar 31, 2024
ac55984
Revise outdated README.md
danny0838 Mar 31, 2024
558d725
Throw Error for CSSParserToken.toSource()
danny0838 Mar 31, 2024
064e54e
Make sure thrown thing is an Error
danny0838 Mar 31, 2024
28c723b
Support testing another method by providing "parser" property
danny0838 Mar 31, 2024
9b6207c
Adjust curly brackets styling
danny0838 Mar 31, 2024
e53bea3
Fix a failure test
danny0838 Mar 31, 2024
ae68eca
Preprocess a standalone surrogate to \uFFFD
danny0838 Mar 31, 2024
de18c28
Fix escaping of \u0000 and a standalone surrogate
danny0838 Mar 31, 2024
04abb09
Add more tests from Chromium source
danny0838 Mar 31, 2024
6d44cff
Update tests to match the latest spec
danny0838 Mar 31, 2024
b07b86b
Fix missing isInteger property for DimensionToken
danny0838 Mar 31, 2024
0cf7f44
Fix precision issue for float number
danny0838 Mar 31, 2024
7ca4aa5
Fix inconsistently missing EOFToken for tokenize()
danny0838 Mar 31, 2024
2902404
Throw Error for infinite looping
danny0838 Mar 31, 2024
1e4514f
Add a test for escaped ")" in a bad URL
danny0838 Mar 31, 2024
f0c54b5
Fix bad calls
danny0838 Apr 1, 2024
20ca4f6
Simplify BadURLToken
danny0838 Apr 1, 2024
b7d408b
Prevent extra double quote for BadStringToken
danny0838 Apr 1, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.gitattributes text
.gitignore text
*.html text
*.js text
*.json text
*.md text
131 changes: 2 additions & 129 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,141 +53,14 @@ They do exactly what they say in their name,
because they're named exactly the same as the corresponding section of the Syntax spec:

* `parseAStylesheet()`
* `parseAListOfRules()`
* `parseAStylesheetsContents()`
* `parseABlocksContents()`
* `parseARule()`
* `parseADeclaration()`
* `parseAListOfDeclarations()`
* `parseAComponentValue()`
* `parseAListOfComponentValues()`
* `parseACommaSeparatedListOfComponentValues()`

Canonicalizing Against A Grammar
--------------------------------

By default, the parser can only do so much;
it knows how to interpret the top-level rules in a stylesheet,
but not how to interpret the contents of anything below that.
This means that anything nested within a top-level block is left as a bare token stream,
requiring you to call the correct parsing function on it.

The `canonicalize()` function takes a parsing result and a grammar
and transforms the result accordingly,
rendering the result into an easier-to-digest form.

A grammar is an object with one of the following four forms:

```js
{"stylesheet":true}
```

```js
{
"qualified": <grammar>,
"@foo": <grammar>,
"unknown": <function>
}
```

```js
{
"declarations": true,
"@foo": <grammar>
"unknown": <function>
}
```

```js
null
```

A `stylesheet` block contains nothing else;
it just means that this rule uses the top-level grammar for its contents.
This is true, for example, of the `@media` rule.

A `qualified` block means that the rule's contents are qualified rules (style rules) and at-rules.
The "qualified" key must have another grammar as its value (often `{declarations:true}`).
Any at-rules that are valid in this context must be listed,
also with a grammar for their contents.
Optionally, the "unknown" key can be provided with a function value;
this will be called with any unknown at-rules (ones not listed in the grammar)/
If it returns a truthy value, it's inserted into the structure with everything else;
if falsey, the rule is put into the "errors" entry of the resulting block for later processing or ignoring.

A `declarations` block means that the rule's contents are declarations and at-rules.
Currently, the "declarations" key only accepts the value `true`;
eventually it'll allow you to specify what declarations are valid.
Similar to `qualified` blocks,
you must list what at-rules are allowed,
and can provide an "unknown" function.

A `null` just means that the block has no contents.
This is used for at-rules that are statements,
ended with a semicolon rather than a block,
like `@import`.

A `CSSGrammar` object is provided with a default grammar for CSS.
If you call `canonicalize()` without a grammar,
this is used automatically.
This is what it currently looks like:

```js
{
qualified: {declarations:true},
"@media": {stylesheet:true},
"@keyframes": {qualified:{declarations:true}},
"@font-face": {declarations:true},
"@supports": {stylesheet:true},
"@scope": {stylesheet:true},
"@counter-style": {declarations:true},
"@import": null,
"@font-feature-values": {
// No qualified rules actually allowed,
// but have to declare it one way or the other.
qualified: true,
"@stylistic": {declarations:true},
"@styleset": {declarations:true},
"@character-variants": {declarations:true},
"@swash": {declarations:true},
"@ornaments": {declarations:true},
"@annotation": {declarations:true},
},
"@viewport": {declarations:true},
"@page": {
declarations: true,
"@top-left-corner": {declarations:true},
"@top-left": {declarations:true},
"@top-center": {declarations:true},
"@top-right": {declarations:true},
"@top-right-corner": {declarations:true},
"@right-top": {declarations:true},
"@right-middle": {declarations:true},
"@right-bottom": {declarations:true},
"@right-bottom-corner": {declarations:true},
"@bottom-right": {declarations:true},
"@bottom-center": {declarations:true},
"@bottom-left": {declarations:true},
"@bottom-left-corner": {declarations:true},
"@left-bottom": {declarations:true},
"@left-center": {declarations:true},
"@left-top": {declarations:true},
},
"@custom-selector": null,
"@custom-media": null
}
```

The return value is a nested structure of objects.
Each has a "type" key, set to either "stylesheet", "qualified-rule" or "at-rule".
Unless it's a statement at-rule,
each has a "rules" key set to an array of contained rules/declarations.
At-rules also have a "name" (string) and "prelude" (list of tokens for the part before the block).
Qualified rules have a "declarations",
which is an object mapping declaration name to value (list of tokens),
for ease of use
(all the declarations are in the `.rules` property already,
but this gives you easy access to them by name,
and only stores the last of each if they're repeated).

Node Integration
----------------

Expand Down
Loading