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

Add more statement parsing for sass-parser #2317

Merged
merged 7 commits into from
Sep 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 0 additions & 1 deletion lib/src/parse/sass.dart
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,6 @@ class SassParser extends StylesheetParser {

_readIndentation();
}
if (!buffer.trailingString.trimRight().endsWith("*/")) buffer.write(" */");

return LoudComment(buffer.interpolation(scanner.spanFrom(start)));
}
Expand Down
14 changes: 12 additions & 2 deletions lib/src/parse/stylesheet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -748,12 +748,12 @@ abstract class StylesheetParser extends Parser {
buffer.writeCharCode($lparen);
whitespace();

buffer.add(_expression());
_addOrInject(buffer, _expression());
if (scanner.scanChar($colon)) {
whitespace();
buffer.writeCharCode($colon);
buffer.writeCharCode($space);
buffer.add(_expression());
_addOrInject(buffer, _expression());
}

scanner.expectChar($rparen);
Expand Down Expand Up @@ -3519,6 +3519,16 @@ abstract class StylesheetParser extends Parser {
span());
}

/// Adds [expression] to [buffer], or if it's an unquoted string adds the
/// interpolation it contains instead.
void _addOrInject(InterpolationBuffer buffer, Expression expression) {
if (expression is StringExpression && !expression.hasQuotes) {
buffer.addInterpolation(expression.text);
} else {
buffer.add(expression);
}
}

// ## Abstract Methods

/// Whether this is parsing the indented syntax.
Expand Down
6 changes: 4 additions & 2 deletions lib/src/visitor/async_evaluate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1911,8 +1911,10 @@ final class _EvaluateVisitor
_endOfImports++;
}

_parent.addChild(ModifiableCssComment(
await _performInterpolation(node.text), node.span));
var text = await _performInterpolation(node.text);
// Indented syntax doesn't require */
if (!text.endsWith("*/")) text += " */";
_parent.addChild(ModifiableCssComment(text, node.span));
return null;
}

Expand Down
8 changes: 5 additions & 3 deletions lib/src/visitor/evaluate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// DO NOT EDIT. This file was generated from async_evaluate.dart.
// See tool/grind/synchronize.dart for details.
//
// Checksum: ebf292c26dcfdd7f61fd70ce3dc9e0be2b6708b3
// Checksum: 2ab69d23a3b34cb54ddd74e2e854614dda582174
//
// ignore_for_file: unused_import

Expand Down Expand Up @@ -1903,8 +1903,10 @@ final class _EvaluateVisitor
_endOfImports++;
}

_parent.addChild(
ModifiableCssComment(_performInterpolation(node.text), node.span));
var text = _performInterpolation(node.text);
// Indented syntax doesn't require */
if (!text.endsWith("*/")) text += " */";
_parent.addChild(ModifiableCssComment(text, node.span));
return null;
}

Expand Down
11 changes: 11 additions & 0 deletions pkg/sass-parser/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -246,3 +246,14 @@ const sassParser = require('sass-parser');
const root = new sassParser.Root();
root.append('content: "hello, world!"');
```

### Known Incompatibilities

There are a few cases where an operation that's valid in PostCSS won't work with
`sass-parser`:

* Trying to convert a Sass-specific at-rule like `@if` or `@mixin` into a
different at-rule by changing its name is not supported.

* Trying to add child nodes to a Sass statement that doesn't support children
like `@use` or `@error` is not supported.
1 change: 1 addition & 0 deletions pkg/sass-parser/jest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ const config = {
roots: ['lib'],
testEnvironment: 'node',
setupFilesAfterEnv: ['jest-extended/all', '<rootDir>/test/setup.ts'],
verbose: false,
};

export default config;
17 changes: 17 additions & 0 deletions pkg/sass-parser/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,23 @@ export {
InterpolationRaws,
NewNodeForInterpolation,
} from './src/interpolation';
export {
CssComment,
CssCommentProps,
CssCommentRaws,
} from './src/statement/css-comment';
export {
DebugRule,
DebugRuleProps,
DebugRuleRaws,
} from './src/statement/debug-rule';
export {EachRule, EachRuleProps, EachRuleRaws} from './src/statement/each-rule';
export {
ErrorRule,
ErrorRuleProps,
ErrorRuleRaws,
} from './src/statement/error-rule';
export {ForRule, ForRuleProps, ForRuleRaws} from './src/statement/for-rule';
export {
GenericAtRule,
GenericAtRuleProps,
Expand Down
5 changes: 2 additions & 3 deletions pkg/sass-parser/lib/src/interpolation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,9 +112,8 @@ export class Interpolation extends Node {
*/
get asPlain(): string | null {
if (this.nodes.length === 0) return '';
if (this.nodes.length !== 1) return null;
if (typeof this.nodes[0] !== 'string') return null;
return this.nodes[0] as string;
if (this.nodes.some(node => typeof node !== 'string')) return null;
return this.nodes.join('');
}

/**
Expand Down
48 changes: 48 additions & 0 deletions pkg/sass-parser/lib/src/sass-internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,45 @@ declare namespace SassInternal {
readonly children: T;
}

class AtRootRule extends ParentStatement<Statement[]> {
readonly name: Interpolation;
readonly query?: Interpolation;
}

class AtRule extends ParentStatement<Statement[]> {
readonly name: Interpolation;
readonly value?: Interpolation;
}

class DebugRule extends Statement {
readonly expression: Expression;
}

class EachRule extends ParentStatement<Statement[]> {
readonly variables: string[];
readonly list: Expression;
}

class ErrorRule extends Statement {
readonly expression: Expression;
}

class ExtendRule extends Statement {
readonly selector: Interpolation;
readonly isOptional: boolean;
}

class ForRule extends ParentStatement<Statement[]> {
readonly variable: string;
readonly from: Expression;
readonly to: Expression;
readonly isExclusive: boolean;
}

class LoudComment extends Statement {
readonly text: Interpolation;
}

class Stylesheet extends ParentStatement<Statement[]> {}

class StyleRule extends ParentStatement<Statement[]> {
Expand Down Expand Up @@ -106,7 +140,14 @@ export type SassNode = SassInternal.SassNode;
export type Statement = SassInternal.Statement;
export type ParentStatement<T extends Statement[] | null> =
SassInternal.ParentStatement<T>;
export type AtRootRule = SassInternal.AtRootRule;
export type AtRule = SassInternal.AtRule;
export type DebugRule = SassInternal.DebugRule;
export type EachRule = SassInternal.EachRule;
export type ErrorRule = SassInternal.ErrorRule;
export type ExtendRule = SassInternal.ExtendRule;
export type ForRule = SassInternal.ForRule;
export type LoudComment = SassInternal.LoudComment;
export type Stylesheet = SassInternal.Stylesheet;
export type StyleRule = SassInternal.StyleRule;
export type Interpolation = SassInternal.Interpolation;
Expand All @@ -115,7 +156,14 @@ export type BinaryOperationExpression = SassInternal.BinaryOperationExpression;
export type StringExpression = SassInternal.StringExpression;

export interface StatementVisitorObject<T> {
visitAtRootRule(node: AtRootRule): T;
visitAtRule(node: AtRule): T;
visitDebugRule(node: DebugRule): T;
visitEachRule(node: EachRule): T;
visitErrorRule(node: ErrorRule): T;
visitExtendRule(node: ExtendRule): T;
visitForRule(node: ForRule): T;
visitLoudComment(node: LoudComment): T;
visitStyleRule(node: StyleRule): T;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`a CSS-style comment toJSON 1`] = `
{
"inputs": [
{
"css": "/* foo */",
"hasBOM": false,
"id": "<input css _____>",
},
],
"raws": {
"closed": true,
"left": " ",
"right": " ",
},
"sassType": "comment",
"source": <1:1-1:10 in 0>,
"text": "foo",
"textInterpolation": <foo>,
"type": "comment",
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`a @debug rule toJSON 1`] = `
{
"debugExpression": <foo>,
"inputs": [
{
"css": "@debug foo",
"hasBOM": false,
"id": "<input css _____>",
},
],
"name": "debug",
"params": "foo",
"raws": {},
"sassType": "debug-rule",
"source": <1:1-1:11 in 0>,
"type": "atrule",
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`an @each rule toJSON 1`] = `
{
"eachExpression": <baz>,
"inputs": [
{
"css": "@each $foo, $bar in baz {}",
"hasBOM": false,
"id": "<input css _____>",
},
],
"name": "each",
"nodes": [],
"params": "$foo, $bar in baz",
"raws": {},
"sassType": "each-rule",
"source": <1:1-1:27 in 0>,
"type": "atrule",
"variables": [
"foo",
"bar",
],
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`a @error rule toJSON 1`] = `
{
"errorExpression": <foo>,
"inputs": [
{
"css": "@error foo",
"hasBOM": false,
"id": "<input css _____>",
},
],
"name": "error",
"params": "foo",
"raws": {},
"sassType": "error-rule",
"source": <1:1-1:11 in 0>,
"type": "atrule",
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`an @for rule toJSON 1`] = `
{
"fromExpression": <bar>,
"inputs": [
{
"css": "@for $foo from bar to baz {}",
"hasBOM": false,
"id": "<input css _____>",
},
],
"name": "for",
"nodes": [],
"params": "$foo from bar to baz",
"raws": {},
"sassType": "for-rule",
"source": <1:1-1:29 in 0>,
"to": "to",
"toExpression": <baz>,
"type": "atrule",
"variable": "foo",
}
`;
Loading