Skip to content

Commit

Permalink
Initial implementation of a PostCSS-compatible parser JS API (#2304)
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
nex3 and stof committed Aug 22, 2024
1 parent c3cccef commit eb6c19e
Show file tree
Hide file tree
Showing 103 changed files with 6,733 additions and 205 deletions.
9 changes: 9 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,12 @@ updates:
- "/.github/util/*/"
schedule:
interval: "weekly"
- package-ecosystem: "npm"
directories:
- "/"
- "/package"
- "/pkg/sass-parser"
ignore:
dependency-name: "sass"
schedule:
interval: "weekly"
27 changes: 24 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,8 @@ jobs:
run: dart run grinder protobuf pkg-pub-deploy
env: {PUB_CREDENTIALS: "${{ secrets.PUB_CREDENTIALS }}"}

deploy_sub_packages:
name: Deploy Sub-Packages
deploy_sass_api:
name: Deploy sass_api
runs-on: ubuntu-latest
needs: [deploy_pub]

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

- name: Deploy
run: dart run grinder deploy-sub-packages
run: dart run grinder deploy-sass-api
env:
PUB_CREDENTIALS: "${{ secrets.PUB_CREDENTIALS }}"
GH_TOKEN: "${{ secrets.GH_TOKEN }}"
GH_USER: sassbot

deploy_sass_parser:
name: Deploy sass-parser
runs-on: ubuntu-latest
needs: [deploy_npm]

steps:
- uses: actions/checkout@v4
with:
token: ${{ secrets.GH_TOKEN }}

- run: npm publish
env:
NODE_AUTH_TOKEN: '${{ secrets.NPM_TOKEN }}'

- name: Get version
id: version
run: |
echo "version=$(jq .version pkg/sass-parser/package.json)" | tee --append "$GITHUB_OUTPUT"
- run: git tag sass-parser/${{ steps.version.outputs.version }}
- run: git push --tag

deploy_homebrew:
name: Deploy Homebrew
runs-on: ubuntu-latest
Expand Down
72 changes: 72 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -311,3 +311,75 @@ jobs:
run: dart run test -p chrome -j 2
env:
CHROME_EXECUTABLE: chrome

sass_parser_tests:
name: "sass-parser Tests | Dart ${{ matrix.dart_channel }} | Node ${{ matrix.node-version }}"
runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
dart_channel: [stable]
node-version: ['lts/*']
include:
# Test older LTS versions
#
# TODO: Test on lts/-2 and lts/-3 once they support
# `structuredClone()` (that is, once they're v18 or later).
- os: ubuntu-latest
dart_channel: stable
node-version: lts/-1
# Test LTS version with dart dev channel
- os: ubuntu-latest
dart_channel: dev
node-version: 'lts/*'

steps:
- uses: actions/checkout@v4
- uses: ./.github/util/initialize
with:
dart-sdk: ${{ matrix.dart_channel }}
github-token: ${{ github.token }}
node-version: ${{ matrix.node-version }}

- run: dart run grinder pkg-npm-dev
env: {UPDATE_SASS_SASS_REPO: false}
- run: npm link
working-directory: build/npm
- run: npm install
working-directory: pkg/sass-parser/
- run: npm link sass
working-directory: pkg/sass-parser/
- name: Run tests
run: npm test
working-directory: pkg/sass-parser/

sass_parser_static_analysis:
name: "sass-parser Static Analysis"
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: {node-version: 'lts/*'}
- run: npm install
working-directory: pkg/sass-parser/
- name: Run static analysis
run: npm run check
working-directory: pkg/sass-parser/

# TODO - postcss/postcss#1958: Enable this once PostCSS doesn't have TypeDoc
# warnings.

# sass_parser_typedoc:
# name: "sass-parser Typedoc"
# runs-on: ubuntu-latest
#
# steps:
# - uses: actions/checkout@v4
# - uses: actions/setup-node@v4
# with: {node-version: 'lts/*'}
# - run: npm install
# working-directory: pkg/sass-parser/
# - run: npm run typedoc
# working-directory: pkg/sass-parser/
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,10 @@ pubspec.lock
package-lock.json
/benchmark/source
node_modules/
dist/
/doc/api
/pkg/*/doc/api
/pkg/sass-parser/doc

# Generated protocol buffer files.
*.pb*.dart
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ A [Dart][dart] implementation of [Sass][sass]. **Sass makes CSS fun**.
<table>
<tr>
<td>
<img width="118px" alt="Sass logo" src="https://rawgit.com/sass/sass-site/master/source/assets/img/logos/logo.svg" />
<img width="118px" alt="Sass logo" src="https://rawgit.com/sass/sass-site/main/source/assets/img/logos/logo.svg" />
</td>
<td valign="middle">
<a href="https://www.npmjs.com/package/sass"><img width="100%" alt="npm statistics" src="https://nodei.co/npm/sass.png?downloads=true"></a>
Expand All @@ -14,6 +14,8 @@ A [Dart][dart] implementation of [Sass][sass]. **Sass makes CSS fun**.
<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>
</td>
<td>
<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>
<br>
<a href="https://twitter.com/SassCSS"><img alt="@SassCSS on Twitter" src="https://img.shields.io/twitter/follow/SassCSS?label=%40SassCSS&style=social"></a>
<br>
<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>
Expand Down
7 changes: 6 additions & 1 deletion lib/src/ast/sass/expression.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,20 @@ import '../../value.dart';
import '../../visitor/interface/expression.dart';
import '../sass.dart';

// Note: despite not defining any methods here, this has to be a concrete class
// so we can expose its accept() function to the JS parser.

/// A SassScript expression in a Sass syntax tree.
///
/// {@category AST}
/// {@category Parsing}
@sealed
abstract interface class Expression implements SassNode {
abstract class Expression implements SassNode {
/// Calls the appropriate visit method on [visitor].
T accept<T>(ExpressionVisitor<T> visitor);

Expression();

/// Parses an expression from [contents].
///
/// If passed, [url] is the name of the file from which [contents] comes.
Expand Down
5 changes: 4 additions & 1 deletion lib/src/ast/sass/expression/binary_operation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import 'list.dart';
/// A binary operator, as in `1 + 2` or `$this and $other`.
///
/// {@category AST}
final class BinaryOperationExpression implements Expression {
final class BinaryOperationExpression extends Expression {
/// The operator being invoked.
final BinaryOperator operator;

Expand Down Expand Up @@ -111,6 +111,9 @@ final class BinaryOperationExpression implements Expression {
///
/// {@category AST}
enum BinaryOperator {
// Note: When updating these operators, also update
// pkg/sass-parser/lib/src/expression/binary-operation.ts.

/// The Microsoft equals operator, `=`.
singleEquals('single equals', '=', 0),

Expand Down
2 changes: 1 addition & 1 deletion lib/src/ast/sass/expression/boolean.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import '../expression.dart';
/// A boolean literal, `true` or `false`.
///
/// {@category AST}
final class BooleanExpression implements Expression {
final class BooleanExpression extends Expression {
/// The value of this expression.
final bool value;

Expand Down
2 changes: 1 addition & 1 deletion lib/src/ast/sass/expression/color.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import '../expression.dart';
/// A color literal.
///
/// {@category AST}
final class ColorExpression implements Expression {
final class ColorExpression extends Expression {
/// The value of this color.
final SassColor value;

Expand Down
4 changes: 2 additions & 2 deletions lib/src/ast/sass/expression/function.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ import '../reference.dart';
/// interpolation.
///
/// {@category AST}
final class FunctionExpression
implements Expression, CallableInvocation, SassReference {
final class FunctionExpression extends Expression
implements CallableInvocation, SassReference {
/// The namespace of the function being invoked, or `null` if it's invoked
/// without a namespace.
final String? namespace;
Expand Down
2 changes: 1 addition & 1 deletion lib/src/ast/sass/expression/if.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import '../../../visitor/interface/expression.dart';
/// evaluated.
///
/// {@category AST}
final class IfExpression implements Expression, CallableInvocation {
final class IfExpression extends Expression implements CallableInvocation {
/// The declaration of `if()`, as though it were a normal function.
static final declaration = ArgumentDeclaration.parse(
r"@function if($condition, $if-true, $if-false) {");
Expand Down
4 changes: 2 additions & 2 deletions lib/src/ast/sass/expression/interpolated_function.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ import '../interpolation.dart';
/// This is always a plain CSS function.
///
/// {@category AST}
final class InterpolatedFunctionExpression
implements Expression, CallableInvocation {
final class InterpolatedFunctionExpression extends Expression
implements CallableInvocation {
/// The name of the function being invoked.
final Interpolation name;

Expand Down
2 changes: 1 addition & 1 deletion lib/src/ast/sass/expression/list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import 'unary_operation.dart';
/// A list literal.
///
/// {@category AST}
final class ListExpression implements Expression {
final class ListExpression extends Expression {
/// The elements of this list.
final List<Expression> contents;

Expand Down
2 changes: 1 addition & 1 deletion lib/src/ast/sass/expression/map.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import '../expression.dart';
/// A map literal.
///
/// {@category AST}
final class MapExpression implements Expression {
final class MapExpression extends Expression {
/// The pairs in this map.
///
/// This is a list of pairs rather than a map because a map may have two keys
Expand Down
2 changes: 1 addition & 1 deletion lib/src/ast/sass/expression/null.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import '../expression.dart';
/// A null literal.
///
/// {@category AST}
final class NullExpression implements Expression {
final class NullExpression extends Expression {
final FileSpan span;

NullExpression(this.span);
Expand Down
2 changes: 1 addition & 1 deletion lib/src/ast/sass/expression/number.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import '../expression.dart';
/// A number literal.
///
/// {@category AST}
final class NumberExpression implements Expression {
final class NumberExpression extends Expression {
/// The numeric value.
final double value;

Expand Down
2 changes: 1 addition & 1 deletion lib/src/ast/sass/expression/parenthesized.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import '../expression.dart';
/// An expression wrapped in parentheses.
///
/// {@category AST}
final class ParenthesizedExpression implements Expression {
final class ParenthesizedExpression extends Expression {
/// The internal expression.
final Expression expression;

Expand Down
2 changes: 1 addition & 1 deletion lib/src/ast/sass/expression/selector.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import '../expression.dart';
/// A parent selector reference, `&`.
///
/// {@category AST}
final class SelectorExpression implements Expression {
final class SelectorExpression extends Expression {
final FileSpan span;

SelectorExpression(this.span);
Expand Down
7 changes: 4 additions & 3 deletions lib/src/ast/sass/expression/string.dart
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ import '../interpolation.dart';
/// A string literal.
///
/// {@category AST}
final class StringExpression implements Expression {
final class StringExpression extends Expression {
/// Interpolation that, when evaluated, produces the contents of this string.
///
/// Unlike [asInterpolation], escapes are resolved and quotes are not
/// included.
/// If this is a quoted string, escapes are resolved and quotes are not
/// included in this text (unlike [asInterpolation]). If it's an unquoted
/// string, escapes are *not* resolved.
final Interpolation text;

/// Whether `this` has quotes.
Expand Down
2 changes: 1 addition & 1 deletion lib/src/ast/sass/expression/supports.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import '../supports_condition.dart';
/// doesn't include the function name wrapping the condition.
///
/// {@category AST}
final class SupportsExpression implements Expression {
final class SupportsExpression extends Expression {
/// The condition itself.
final SupportsCondition condition;

Expand Down
2 changes: 1 addition & 1 deletion lib/src/ast/sass/expression/unary_operation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import 'list.dart';
/// A unary operator, as in `+$var` or `not fn()`.
///
/// {@category AST}
final class UnaryOperationExpression implements Expression {
final class UnaryOperationExpression extends Expression {
/// The operator being invoked.
final UnaryOperator operator;

Expand Down
2 changes: 1 addition & 1 deletion lib/src/ast/sass/expression/value.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import '../expression.dart';
/// constructed dynamically, as for the `call()` function.
///
/// {@category AST}
final class ValueExpression implements Expression {
final class ValueExpression extends Expression {
/// The embedded value.
final Value value;

Expand Down
2 changes: 1 addition & 1 deletion lib/src/ast/sass/expression/variable.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import '../reference.dart';
/// A Sass variable.
///
/// {@category AST}
final class VariableExpression implements Expression, SassReference {
final class VariableExpression extends Expression implements SassReference {
/// The namespace of the variable being referenced, or `null` if it's
/// referenced without a namespace.
final String? namespace;
Expand Down
5 changes: 4 additions & 1 deletion lib/src/ast/sass/statement.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@
import '../../visitor/interface/statement.dart';
import 'node.dart';

// Note: despite not defining any methods here, this has to be a concrete class
// so we can expose its accept() function to the JS parser.

/// A statement in a Sass syntax tree.
///
/// {@category AST}
abstract interface class Statement implements SassNode {
abstract class Statement implements SassNode {
/// Calls the appropriate visit method on [visitor].
T accept<T>(StatementVisitor<T> visitor);
}
2 changes: 1 addition & 1 deletion lib/src/ast/sass/statement/content_rule.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import '../statement.dart';
/// caller.
///
/// {@category AST}
final class ContentRule implements Statement {
final class ContentRule extends Statement {
/// The arguments pass to this `@content` rule.
///
/// This will be an empty invocation if `@content` has no arguments.
Expand Down
2 changes: 1 addition & 1 deletion lib/src/ast/sass/statement/debug_rule.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import '../statement.dart';
/// This prints a Sass value for debugging purposes.
///
/// {@category AST}
final class DebugRule implements Statement {
final class DebugRule extends Statement {
/// The expression to print.
final Expression expression;

Expand Down
Loading

0 comments on commit eb6c19e

Please sign in to comment.