Skip to content

Commit eb6c19e

Browse files
nex3stof
andauthored
Initial implementation of a PostCSS-compatible parser JS API (#2304)
This is just a vertical slice designed to solidify the general principles of the API design and ensure that everything works as expected. It's not yet usable as a full-fledged parser. Co-authored-by: Christophe Coevoet <stof@notk.org>
1 parent c3cccef commit eb6c19e

File tree

103 files changed

+6733
-205
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

103 files changed

+6733
-205
lines changed

.github/dependabot.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,12 @@ updates:
1010
- "/.github/util/*/"
1111
schedule:
1212
interval: "weekly"
13+
- package-ecosystem: "npm"
14+
directories:
15+
- "/"
16+
- "/package"
17+
- "/pkg/sass-parser"
18+
ignore:
19+
dependency-name: "sass"
20+
schedule:
21+
interval: "weekly"

.github/workflows/release.yml

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,8 @@ jobs:
102102
run: dart run grinder protobuf pkg-pub-deploy
103103
env: {PUB_CREDENTIALS: "${{ secrets.PUB_CREDENTIALS }}"}
104104

105-
deploy_sub_packages:
106-
name: Deploy Sub-Packages
105+
deploy_sass_api:
106+
name: Deploy sass_api
107107
runs-on: ubuntu-latest
108108
needs: [deploy_pub]
109109

@@ -113,12 +113,33 @@ jobs:
113113
with: {github-token: "${{ github.token }}"}
114114

115115
- name: Deploy
116-
run: dart run grinder deploy-sub-packages
116+
run: dart run grinder deploy-sass-api
117117
env:
118118
PUB_CREDENTIALS: "${{ secrets.PUB_CREDENTIALS }}"
119119
GH_TOKEN: "${{ secrets.GH_TOKEN }}"
120120
GH_USER: sassbot
121121

122+
deploy_sass_parser:
123+
name: Deploy sass-parser
124+
runs-on: ubuntu-latest
125+
needs: [deploy_npm]
126+
127+
steps:
128+
- uses: actions/checkout@v4
129+
with:
130+
token: ${{ secrets.GH_TOKEN }}
131+
132+
- run: npm publish
133+
env:
134+
NODE_AUTH_TOKEN: '${{ secrets.NPM_TOKEN }}'
135+
136+
- name: Get version
137+
id: version
138+
run: |
139+
echo "version=$(jq .version pkg/sass-parser/package.json)" | tee --append "$GITHUB_OUTPUT"
140+
- run: git tag sass-parser/${{ steps.version.outputs.version }}
141+
- run: git push --tag
142+
122143
deploy_homebrew:
123144
name: Deploy Homebrew
124145
runs-on: ubuntu-latest

.github/workflows/test.yml

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,3 +311,75 @@ jobs:
311311
run: dart run test -p chrome -j 2
312312
env:
313313
CHROME_EXECUTABLE: chrome
314+
315+
sass_parser_tests:
316+
name: "sass-parser Tests | Dart ${{ matrix.dart_channel }} | Node ${{ matrix.node-version }}"
317+
runs-on: ubuntu-latest
318+
319+
strategy:
320+
fail-fast: false
321+
matrix:
322+
dart_channel: [stable]
323+
node-version: ['lts/*']
324+
include:
325+
# Test older LTS versions
326+
#
327+
# TODO: Test on lts/-2 and lts/-3 once they support
328+
# `structuredClone()` (that is, once they're v18 or later).
329+
- os: ubuntu-latest
330+
dart_channel: stable
331+
node-version: lts/-1
332+
# Test LTS version with dart dev channel
333+
- os: ubuntu-latest
334+
dart_channel: dev
335+
node-version: 'lts/*'
336+
337+
steps:
338+
- uses: actions/checkout@v4
339+
- uses: ./.github/util/initialize
340+
with:
341+
dart-sdk: ${{ matrix.dart_channel }}
342+
github-token: ${{ github.token }}
343+
node-version: ${{ matrix.node-version }}
344+
345+
- run: dart run grinder pkg-npm-dev
346+
env: {UPDATE_SASS_SASS_REPO: false}
347+
- run: npm link
348+
working-directory: build/npm
349+
- run: npm install
350+
working-directory: pkg/sass-parser/
351+
- run: npm link sass
352+
working-directory: pkg/sass-parser/
353+
- name: Run tests
354+
run: npm test
355+
working-directory: pkg/sass-parser/
356+
357+
sass_parser_static_analysis:
358+
name: "sass-parser Static Analysis"
359+
runs-on: ubuntu-latest
360+
361+
steps:
362+
- uses: actions/checkout@v4
363+
- uses: actions/setup-node@v4
364+
with: {node-version: 'lts/*'}
365+
- run: npm install
366+
working-directory: pkg/sass-parser/
367+
- name: Run static analysis
368+
run: npm run check
369+
working-directory: pkg/sass-parser/
370+
371+
# TODO - postcss/postcss#1958: Enable this once PostCSS doesn't have TypeDoc
372+
# warnings.
373+
374+
# sass_parser_typedoc:
375+
# name: "sass-parser Typedoc"
376+
# runs-on: ubuntu-latest
377+
#
378+
# steps:
379+
# - uses: actions/checkout@v4
380+
# - uses: actions/setup-node@v4
381+
# with: {node-version: 'lts/*'}
382+
# - run: npm install
383+
# working-directory: pkg/sass-parser/
384+
# - run: npm run typedoc
385+
# working-directory: pkg/sass-parser/

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,10 @@ pubspec.lock
1212
package-lock.json
1313
/benchmark/source
1414
node_modules/
15+
dist/
1516
/doc/api
1617
/pkg/*/doc/api
18+
/pkg/sass-parser/doc
1719

1820
# Generated protocol buffer files.
1921
*.pb*.dart

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ A [Dart][dart] implementation of [Sass][sass]. **Sass makes CSS fun**.
33
<table>
44
<tr>
55
<td>
6-
<img width="118px" alt="Sass logo" src="https://rawgit.com/sass/sass-site/master/source/assets/img/logos/logo.svg" />
6+
<img width="118px" alt="Sass logo" src="https://rawgit.com/sass/sass-site/main/source/assets/img/logos/logo.svg" />
77
</td>
88
<td valign="middle">
99
<a href="https://www.npmjs.com/package/sass"><img width="100%" alt="npm statistics" src="https://nodei.co/npm/sass.png?downloads=true"></a>
@@ -14,6 +14,8 @@ A [Dart][dart] implementation of [Sass][sass]. **Sass makes CSS fun**.
1414
<a href="https://github.com/sass/dart-sass/actions"><img alt="GitHub actions build status" src="https://github.com/sass/dart-sass/workflows/CI/badge.svg"></a>
1515
</td>
1616
<td>
17+
<a href="https://front-end.social/@sass"><img alt="@sass@front-end.social on Fediverse" src="https://img.shields.io/mastodon/follow/110159358073946175?domain=https%3A%2F%2Ffront-end.social"></a>
18+
<br>
1719
<a href="https://twitter.com/SassCSS"><img alt="@SassCSS on Twitter" src="https://img.shields.io/twitter/follow/SassCSS?label=%40SassCSS&style=social"></a>
1820
<br>
1921
<a href="https://stackoverflow.com/questions/tagged/sass"><img alt="stackoverflow" src="https://img.shields.io/stackexchange/stackoverflow/t/sass?label=Sass%20questions&logo=stackoverflow&style=social"></a>

lib/src/ast/sass/expression.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,20 @@ import '../../value.dart';
1313
import '../../visitor/interface/expression.dart';
1414
import '../sass.dart';
1515

16+
// Note: despite not defining any methods here, this has to be a concrete class
17+
// so we can expose its accept() function to the JS parser.
18+
1619
/// A SassScript expression in a Sass syntax tree.
1720
///
1821
/// {@category AST}
1922
/// {@category Parsing}
2023
@sealed
21-
abstract interface class Expression implements SassNode {
24+
abstract class Expression implements SassNode {
2225
/// Calls the appropriate visit method on [visitor].
2326
T accept<T>(ExpressionVisitor<T> visitor);
2427

28+
Expression();
29+
2530
/// Parses an expression from [contents].
2631
///
2732
/// If passed, [url] is the name of the file from which [contents] comes.

lib/src/ast/sass/expression/binary_operation.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import 'list.dart';
1414
/// A binary operator, as in `1 + 2` or `$this and $other`.
1515
///
1616
/// {@category AST}
17-
final class BinaryOperationExpression implements Expression {
17+
final class BinaryOperationExpression extends Expression {
1818
/// The operator being invoked.
1919
final BinaryOperator operator;
2020

@@ -111,6 +111,9 @@ final class BinaryOperationExpression implements Expression {
111111
///
112112
/// {@category AST}
113113
enum BinaryOperator {
114+
// Note: When updating these operators, also update
115+
// pkg/sass-parser/lib/src/expression/binary-operation.ts.
116+
114117
/// The Microsoft equals operator, `=`.
115118
singleEquals('single equals', '=', 0),
116119

lib/src/ast/sass/expression/boolean.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import '../expression.dart';
1010
/// A boolean literal, `true` or `false`.
1111
///
1212
/// {@category AST}
13-
final class BooleanExpression implements Expression {
13+
final class BooleanExpression extends Expression {
1414
/// The value of this expression.
1515
final bool value;
1616

lib/src/ast/sass/expression/color.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import '../expression.dart';
1111
/// A color literal.
1212
///
1313
/// {@category AST}
14-
final class ColorExpression implements Expression {
14+
final class ColorExpression extends Expression {
1515
/// The value of this color.
1616
final SassColor value;
1717

lib/src/ast/sass/expression/function.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ import '../reference.dart';
1717
/// interpolation.
1818
///
1919
/// {@category AST}
20-
final class FunctionExpression
21-
implements Expression, CallableInvocation, SassReference {
20+
final class FunctionExpression extends Expression
21+
implements CallableInvocation, SassReference {
2222
/// The namespace of the function being invoked, or `null` if it's invoked
2323
/// without a namespace.
2424
final String? namespace;

lib/src/ast/sass/expression/if.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import '../../../visitor/interface/expression.dart';
1414
/// evaluated.
1515
///
1616
/// {@category AST}
17-
final class IfExpression implements Expression, CallableInvocation {
17+
final class IfExpression extends Expression implements CallableInvocation {
1818
/// The declaration of `if()`, as though it were a normal function.
1919
static final declaration = ArgumentDeclaration.parse(
2020
r"@function if($condition, $if-true, $if-false) {");

lib/src/ast/sass/expression/interpolated_function.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ import '../interpolation.dart';
1515
/// This is always a plain CSS function.
1616
///
1717
/// {@category AST}
18-
final class InterpolatedFunctionExpression
19-
implements Expression, CallableInvocation {
18+
final class InterpolatedFunctionExpression extends Expression
19+
implements CallableInvocation {
2020
/// The name of the function being invoked.
2121
final Interpolation name;
2222

lib/src/ast/sass/expression/list.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import 'unary_operation.dart';
1313
/// A list literal.
1414
///
1515
/// {@category AST}
16-
final class ListExpression implements Expression {
16+
final class ListExpression extends Expression {
1717
/// The elements of this list.
1818
final List<Expression> contents;
1919

lib/src/ast/sass/expression/map.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import '../expression.dart';
1010
/// A map literal.
1111
///
1212
/// {@category AST}
13-
final class MapExpression implements Expression {
13+
final class MapExpression extends Expression {
1414
/// The pairs in this map.
1515
///
1616
/// This is a list of pairs rather than a map because a map may have two keys

lib/src/ast/sass/expression/null.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import '../expression.dart';
1010
/// A null literal.
1111
///
1212
/// {@category AST}
13-
final class NullExpression implements Expression {
13+
final class NullExpression extends Expression {
1414
final FileSpan span;
1515

1616
NullExpression(this.span);

lib/src/ast/sass/expression/number.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import '../expression.dart';
1111
/// A number literal.
1212
///
1313
/// {@category AST}
14-
final class NumberExpression implements Expression {
14+
final class NumberExpression extends Expression {
1515
/// The numeric value.
1616
final double value;
1717

lib/src/ast/sass/expression/parenthesized.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import '../expression.dart';
1010
/// An expression wrapped in parentheses.
1111
///
1212
/// {@category AST}
13-
final class ParenthesizedExpression implements Expression {
13+
final class ParenthesizedExpression extends Expression {
1414
/// The internal expression.
1515
final Expression expression;
1616

lib/src/ast/sass/expression/selector.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import '../expression.dart';
1010
/// A parent selector reference, `&`.
1111
///
1212
/// {@category AST}
13-
final class SelectorExpression implements Expression {
13+
final class SelectorExpression extends Expression {
1414
final FileSpan span;
1515

1616
SelectorExpression(this.span);

lib/src/ast/sass/expression/string.dart

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@ import '../interpolation.dart';
1616
/// A string literal.
1717
///
1818
/// {@category AST}
19-
final class StringExpression implements Expression {
19+
final class StringExpression extends Expression {
2020
/// Interpolation that, when evaluated, produces the contents of this string.
2121
///
22-
/// Unlike [asInterpolation], escapes are resolved and quotes are not
23-
/// included.
22+
/// If this is a quoted string, escapes are resolved and quotes are not
23+
/// included in this text (unlike [asInterpolation]). If it's an unquoted
24+
/// string, escapes are *not* resolved.
2425
final Interpolation text;
2526

2627
/// Whether `this` has quotes.

lib/src/ast/sass/expression/supports.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import '../supports_condition.dart';
1414
/// doesn't include the function name wrapping the condition.
1515
///
1616
/// {@category AST}
17-
final class SupportsExpression implements Expression {
17+
final class SupportsExpression extends Expression {
1818
/// The condition itself.
1919
final SupportsCondition condition;
2020

lib/src/ast/sass/expression/unary_operation.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import 'list.dart';
1313
/// A unary operator, as in `+$var` or `not fn()`.
1414
///
1515
/// {@category AST}
16-
final class UnaryOperationExpression implements Expression {
16+
final class UnaryOperationExpression extends Expression {
1717
/// The operator being invoked.
1818
final UnaryOperator operator;
1919

lib/src/ast/sass/expression/value.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import '../expression.dart';
1414
/// constructed dynamically, as for the `call()` function.
1515
///
1616
/// {@category AST}
17-
final class ValueExpression implements Expression {
17+
final class ValueExpression extends Expression {
1818
/// The embedded value.
1919
final Value value;
2020

lib/src/ast/sass/expression/variable.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import '../reference.dart';
1212
/// A Sass variable.
1313
///
1414
/// {@category AST}
15-
final class VariableExpression implements Expression, SassReference {
15+
final class VariableExpression extends Expression implements SassReference {
1616
/// The namespace of the variable being referenced, or `null` if it's
1717
/// referenced without a namespace.
1818
final String? namespace;

lib/src/ast/sass/statement.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@
55
import '../../visitor/interface/statement.dart';
66
import 'node.dart';
77

8+
// Note: despite not defining any methods here, this has to be a concrete class
9+
// so we can expose its accept() function to the JS parser.
10+
811
/// A statement in a Sass syntax tree.
912
///
1013
/// {@category AST}
11-
abstract interface class Statement implements SassNode {
14+
abstract class Statement implements SassNode {
1215
/// Calls the appropriate visit method on [visitor].
1316
T accept<T>(StatementVisitor<T> visitor);
1417
}

lib/src/ast/sass/statement/content_rule.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import '../statement.dart';
1414
/// caller.
1515
///
1616
/// {@category AST}
17-
final class ContentRule implements Statement {
17+
final class ContentRule extends Statement {
1818
/// The arguments pass to this `@content` rule.
1919
///
2020
/// This will be an empty invocation if `@content` has no arguments.

lib/src/ast/sass/statement/debug_rule.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import '../statement.dart';
1313
/// This prints a Sass value for debugging purposes.
1414
///
1515
/// {@category AST}
16-
final class DebugRule implements Statement {
16+
final class DebugRule extends Statement {
1717
/// The expression to print.
1818
final Expression expression;
1919

0 commit comments

Comments
 (0)