Skip to content

Commit

Permalink
Merge branch 'main' of github.com:sass/dart-sass into release
Browse files Browse the repository at this point in the history
  • Loading branch information
nex3 committed Oct 25, 2024
2 parents 9d5d709 + 7129352 commit b94f55e
Show file tree
Hide file tree
Showing 23 changed files with 1,516 additions and 28 deletions.
10 changes: 9 additions & 1 deletion lib/src/ast/sass/statement/stylesheet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ final class Stylesheet extends ParentStatement<List<Statement>> {
@internal
final List<ParseTimeWarning> parseTimeWarnings;

/// The set of (normalized) global variable names defined by this stylesheet
/// to the spans where they're defined.
@internal
final Map<String, FileSpan> globalVariables;

Stylesheet(Iterable<Statement> children, FileSpan span)
: this.internal(children, span, []);

Expand All @@ -62,8 +67,11 @@ final class Stylesheet extends ParentStatement<List<Statement>> {
@internal
Stylesheet.internal(Iterable<Statement> children, this.span,
List<ParseTimeWarning> parseTimeWarnings,
{this.plainCss = false})
{this.plainCss = false, Map<String, FileSpan>? globalVariables})
: parseTimeWarnings = UnmodifiableListView(parseTimeWarnings),
globalVariables = globalVariables == null
? const {}
: Map.unmodifiable(globalVariables),
super(List.unmodifiable(children)) {
loop:
for (var child in this.children) {
Expand Down
1 change: 1 addition & 0 deletions lib/src/deprecation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ enum Deprecation {
isFuture = false;

/// Constructs a future deprecation.
// ignore: unused_element
const Deprecation.future(this.id, {this.description})
: _deprecatedIn = null,
_obsoleteIn = null,
Expand Down
14 changes: 7 additions & 7 deletions lib/src/embedded/compilation_dispatcher.dart
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ final class CompilationDispatcher {

try {
var importers = request.importers.map((importer) =>
_decodeImporter(request, importer) ??
_decodeImporter(importer) ??
(throw mandatoryError("Importer.importer")));

var globalFunctions = request.globalFunctions
Expand All @@ -159,7 +159,7 @@ final class CompilationDispatcher {
color: request.alertColor,
logger: logger,
importers: importers,
importer: _decodeImporter(request, input.importer) ??
importer: _decodeImporter(input.importer) ??
(input.url.startsWith("file:") ? null : sass.Importer.noOp),
functions: globalFunctions,
syntax: syntaxToSyntax(input.syntax),
Expand Down Expand Up @@ -234,7 +234,7 @@ final class CompilationDispatcher {
}

/// Converts [importer] into a [sass.Importer].
sass.Importer? _decodeImporter(InboundMessage_CompileRequest request,
sass.Importer? _decodeImporter(
InboundMessage_CompileRequest_Importer importer) {
switch (importer.whichImporter()) {
case InboundMessage_CompileRequest_Importer_Importer.path:
Expand All @@ -249,13 +249,13 @@ final class CompilationDispatcher {
_checkNoNonCanonicalScheme(importer);
return FileImporter(this, importer.fileImporterId);

case InboundMessage_CompileRequest_Importer_Importer.notSet:
_checkNoNonCanonicalScheme(importer);
return null;

case InboundMessage_CompileRequest_Importer_Importer.nodePackageImporter:
return npi.NodePackageImporter(
importer.nodePackageImporter.entryPointDirectory);

case InboundMessage_CompileRequest_Importer_Importer.notSet:
_checkNoNonCanonicalScheme(importer);
return null;
}
}

Expand Down
2 changes: 1 addition & 1 deletion lib/src/functions/color.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1610,7 +1610,7 @@ BuiltInCallable _channelFunction(
warnForDeprecation(
"${global ? '' : 'color.'}$name() is deprecated. Suggestion:\n"
"\n"
'color.channel(\$color, \"$name\", \$space: $space)\n'
'color.channel(\$color, "$name", \$space: $space)\n'
"\n"
"More info: https://sass-lang.com/d/color-functions",
Deprecation.colorFunctions);
Expand Down
15 changes: 4 additions & 11 deletions lib/src/parse/stylesheet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,13 @@ abstract class StylesheetParser extends Parser {
var _inExpression = false;

/// A map from all variable names that are assigned with `!global` in the
/// current stylesheet to the nodes where they're defined.
/// current stylesheet to the spans where they're defined.
///
/// These are collected at parse time because they affect the variables
/// exposed by the module generated for this stylesheet, *even if they aren't
/// evaluated*. This allows us to ensure that the stylesheet always exposes
/// the same set of variable names no matter how it's evaluated.
final _globalVariables = <String, VariableDeclaration>{};
final _globalVariables = <String, FileSpan>{};

/// Warnings discovered while parsing that should be emitted during
/// evaluation once a proper logger is available.
Expand Down Expand Up @@ -100,15 +100,8 @@ abstract class StylesheetParser extends Parser {
});
scanner.expectDone();

/// Ensure that all global variable assignments produce a variable in this
/// stylesheet, even if they aren't evaluated. See sass/language#50.
statements.addAll(_globalVariables.values.map((declaration) =>
VariableDeclaration(declaration.name,
NullExpression(declaration.expression.span), declaration.span,
guarded: true)));

return Stylesheet.internal(statements, scanner.spanFrom(start), warnings,
plainCss: plainCss);
plainCss: plainCss, globalVariables: _globalVariables);
});
}

Expand Down Expand Up @@ -288,7 +281,7 @@ abstract class StylesheetParser extends Parser {
guarded: guarded,
global: global,
comment: precedingComment);
if (global) _globalVariables.putIfAbsent(name, () => declaration);
if (global) _globalVariables.putIfAbsent(name, () => declaration.span);
return declaration;
}

Expand Down
8 changes: 8 additions & 0 deletions lib/src/visitor/async_evaluate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1005,6 +1005,14 @@ final class _EvaluateVisitor
for (var child in node.children) {
await child.accept(this);
}

// Make sure all global variables declared in a module always appear in the
// module's definition, even if their assignments aren't reached.
for (var (name, span) in node.globalVariables.pairs) {
visitVariableDeclaration(
VariableDeclaration(name, NullExpression(span), span, guarded: true));
}

return null;
}

Expand Down
10 changes: 9 additions & 1 deletion 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: e7260fedcd4f374ba517a93d038c3c53586c9622
// Checksum: 396c8f169d95c601598b8c3be1f4b948ca22effa
//
// ignore_for_file: unused_import

Expand Down Expand Up @@ -1005,6 +1005,14 @@ final class _EvaluateVisitor
for (var child in node.children) {
child.accept(this);
}

// Make sure all global variables declared in a module always appear in the
// module's definition, even if their assignments aren't reached.
for (var (name, span) in node.globalVariables.pairs) {
visitVariableDeclaration(
VariableDeclaration(name, NullExpression(span), span, guarded: true));
}

return null;
}

Expand Down
4 changes: 3 additions & 1 deletion pkg/sass-parser/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
## 0.4.2

* No user-visible changes.
* Add support for parsing variable declarations.

* Add support for parsing the `@warn` rule.

## 0.4.1

Expand Down
6 changes: 6 additions & 0 deletions pkg/sass-parser/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ export {
StatementType,
StatementWithChildren,
} from './src/statement';
export {
VariableDeclaration,
VariableDeclarationProps,
VariableDeclarationRaws,
} from './src/statement/variable-declaration';
export {WarnRule, WarnRuleProps, WarnRuleRaws} from './src/statement/warn-rule';

/** Options that can be passed to the Sass parsers to control their behavior. */
export type SassParserOptions = Pick<postcss.ProcessOptions, 'from' | 'map'>;
Expand Down
16 changes: 16 additions & 0 deletions pkg/sass-parser/lib/src/sass-internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,18 @@ declare namespace SassInternal {
readonly configuration: ConfiguredVariable[];
}

class VariableDeclaration extends Statement {
readonly namespace: string | null;
readonly name: string;
readonly expression: Expression;
readonly isGuarded: boolean;
readonly isGlobal: boolean;
}

class WarnRule extends Statement {
readonly expression: Expression;
}

class ConfiguredVariable extends SassNode {
readonly name: string;
readonly expression: Expression;
Expand Down Expand Up @@ -238,6 +250,8 @@ export type Stylesheet = SassInternal.Stylesheet;
export type StyleRule = SassInternal.StyleRule;
export type SupportsRule = SassInternal.SupportsRule;
export type UseRule = SassInternal.UseRule;
export type VariableDeclaration = SassInternal.VariableDeclaration;
export type WarnRule = SassInternal.WarnRule;
export type ConfiguredVariable = SassInternal.ConfiguredVariable;
export type Interpolation = SassInternal.Interpolation;
export type Expression = SassInternal.Expression;
Expand All @@ -260,6 +274,8 @@ export interface StatementVisitorObject<T> {
visitStyleRule(node: StyleRule): T;
visitSupportsRule(node: SupportsRule): T;
visitUseRule(node: UseRule): T;
visitVariableDeclaration(node: VariableDeclaration): T;
visitWarnRule(node: WarnRule): T;
}

export interface ExpressionVisitorObject<T> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`a variable declaration toJSON 1`] = `
{
"expression": <"bar">,
"global": false,
"guarded": false,
"inputs": [
{
"css": "baz.$foo: "bar"",
"hasBOM": false,
"id": "<input css _____>",
},
],
"namespace": "baz",
"raws": {},
"sassType": "variable-declaration",
"source": <1:1-1:16 in 0>,
"type": "decl",
"variableName": "foo",
}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`a @warn rule toJSON 1`] = `
{
"inputs": [
{
"css": "@warn foo",
"hasBOM": false,
"id": "<input css _____>",
},
],
"name": "warn",
"params": "foo",
"raws": {},
"sassType": "warn-rule",
"source": <1:1-1:10 in 0>,
"type": "atrule",
"warnExpression": <foo>,
}
`;
77 changes: 77 additions & 0 deletions pkg/sass-parser/lib/src/statement/declaration-internal.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright 2024 Google Inc. Use of this source code is governed by an
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

import * as postcss from 'postcss';

import {Rule} from './rule';
import {Root} from './root';
import {AtRule, ChildNode, Comment, Declaration, NewNode} from '.';

/**
* A fake intermediate class to convince TypeScript to use Sass types for
* various upstream methods.
*
* @hidden
*/
export class _Declaration<Props> extends postcss.Declaration {
// Override the PostCSS container types to constrain them to Sass types only.
// Unfortunately, there's no way to abstract this out, because anything
// mixin-like returns an intersection type which doesn't actually override
// parent methods. See microsoft/TypeScript#59394.

after(newNode: NewNode): this;
append(...nodes: NewNode[]): this;
assign(overrides: Partial<Props>): this;
before(newNode: NewNode): this;
cloneAfter(overrides?: Partial<Props>): this;
cloneBefore(overrides?: Partial<Props>): this;
each(
callback: (node: ChildNode, index: number) => false | void
): false | undefined;
every(
condition: (node: ChildNode, index: number, nodes: ChildNode[]) => boolean
): boolean;
insertAfter(oldNode: postcss.ChildNode | number, newNode: NewNode): this;
insertBefore(oldNode: postcss.ChildNode | number, newNode: NewNode): this;
next(): ChildNode | undefined;
prepend(...nodes: NewNode[]): this;
prev(): ChildNode | undefined;
replaceWith(...nodes: NewNode[]): this;
root(): Root;
some(
condition: (node: ChildNode, index: number, nodes: ChildNode[]) => boolean
): boolean;
walk(
callback: (node: ChildNode, index: number) => false | void
): false | undefined;
walkAtRules(
nameFilter: RegExp | string,
callback: (atRule: AtRule, index: number) => false | void
): false | undefined;
walkAtRules(
callback: (atRule: AtRule, index: number) => false | void
): false | undefined;
walkComments(
callback: (comment: Comment, indexed: number) => false | void
): false | undefined;
walkComments(
callback: (comment: Comment, indexed: number) => false | void
): false | undefined;
walkDecls(
propFilter: RegExp | string,
callback: (decl: Declaration, index: number) => false | void
): false | undefined;
walkDecls(
callback: (decl: Declaration, index: number) => false | void
): false | undefined;
walkRules(
selectorFilter: RegExp | string,
callback: (rule: Rule, index: number) => false | void
): false | undefined;
walkRules(
callback: (rule: Rule, index: number) => false | void
): false | undefined;
get first(): ChildNode | undefined;
get last(): ChildNode | undefined;
}
5 changes: 5 additions & 0 deletions pkg/sass-parser/lib/src/statement/declaration-internal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// Copyright 2024 Google Inc. Use of this source code is governed by an
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

exports._Declaration = require('postcss').Declaration;
Loading

0 comments on commit b94f55e

Please sign in to comment.