-
Notifications
You must be signed in to change notification settings - Fork 359
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[WIP] Add
sass-parser
support for the @use
rule
- Loading branch information
Showing
7 changed files
with
496 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
// 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 type {AtRuleRaws} from 'postcss/lib/at-rule'; | ||
|
||
import {convertExpression} from '../expression/convert'; | ||
import {Expression, ExpressionProps} from '../expression'; | ||
import {fromProps} from '../expression/from-props'; | ||
import {LazySource} from '../lazy-source'; | ||
import {RawWithValue} from '../raw-with-value'; | ||
import type * as sassInternal from '../sass-internal'; | ||
import * as utils from '../utils'; | ||
import { | ||
ChildNode, | ||
ContainerProps, | ||
NewNode, | ||
Statement, | ||
StatementWithChildren, | ||
appendInternalChildren, | ||
normalize, | ||
} from '.'; | ||
import {_AtRule} from './at-rule-internal'; | ||
import {interceptIsClean} from './intercept-is-clean'; | ||
import * as sassParser from '../..'; | ||
|
||
/** | ||
* The set of raws supported by {@link Configuration}. | ||
* | ||
* @category Statement | ||
*/ | ||
export interface ConfigurationRaws { | ||
/** The whitespace after the opening parenthesis. */ | ||
afterOpen?: string; | ||
|
||
/** | ||
* The space symbols and optionally comma between the last configured variable | ||
* and the closing parenthesis. | ||
*/ | ||
after?: string; | ||
} | ||
|
||
/** | ||
* The initializer properties for {@link Configuration}. | ||
* | ||
* @category Statement | ||
*/ | ||
export type ConfigurationProps { | ||
raws?: ConfigurationRaws; | ||
variables: Record<string, ConfiguredVariableValueProps> | Array<ConfiguredVariable|ConfiguredVariableProps>; | ||
} | ||
|
||
/** | ||
* A configuration map for a `@use` or `@forward` rule. | ||
* | ||
* @category Statement | ||
*/ | ||
export class Configuration extends Node { | ||
readonly sassType = 'configuration' as const; | ||
declare raws: ConfigurationRaws; | ||
|
||
/** The underlying map from variable names to their values. */ | ||
private _variables: Map<string, ConfiguredVariable> = new Map(); | ||
|
||
/** The number of variables in this configuration. */ | ||
get size(): number { | ||
return this._variables.size; | ||
} | ||
|
||
constructor(defaults?: ConfigurationProps); | ||
/** @hidden */ | ||
constructor(_: undefined, inner: sassInternal.ConfiguredVariable[]); | ||
constructor(defaults?: ConfigurationProps, inner?: sassInternal.ConfiguredVariable[]) { | ||
this.raws = defaults?.raws ?? {}; | ||
|
||
if (defaults) { | ||
for (const variable of Array.isArray(defaults.variables) ? defaults.variables : Object.entries(defaults.variables)) { | ||
this.add(variable); | ||
} | ||
} else if (inner) { | ||
this.source = new LazySource({ | ||
get span(): FileSpan { | ||
// TODO: expand inner[0] and inner.at(-1) out through `(` and `)` | ||
// respectively and then combine them. | ||
} | ||
}); | ||
for (const variable of inner) { | ||
this.add(new ConfiguredVariable(undefined, variable)); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Adds {@link variable} to this configuration. | ||
* | ||
* If there's already a variable with that name, it's removed first. | ||
*/ | ||
add(variable: ConfiguredVariable|ConfiguredVariableProps): this { | ||
if (!('sassType' in variable)) variable = new ConfiguredVariable(variable); | ||
variable.parent = this; | ||
this._variables.get(variable.name)?.parent = undefined; | ||
this._variables.set(variable.name, variable); | ||
return this; | ||
} | ||
|
||
/** Removes all variables from this configuration. */ | ||
clear(): void { | ||
for (const variable of this._variables.values()) { | ||
variable.parent = undefined; | ||
} | ||
this._variables.clear(); | ||
} | ||
|
||
/** Removes the variable named {@link name} from this configuration. */ | ||
delete(key: string): boolean { | ||
this._variables.get(name)?.parent = undefined; | ||
return this._variables.delete(name); | ||
} | ||
|
||
/** | ||
* Returns the variable named {@link name} from this configuration if it | ||
* contains one. | ||
*/ | ||
get(key: string): ConfiguredVariable|undefined { | ||
return this._variables.get(key); | ||
} | ||
|
||
/** | ||
* Returns whether this configuration has a variable named {@link name}. | ||
*/ | ||
has(key: string): boolean { | ||
return this._variables.has(key); | ||
} | ||
|
||
/** | ||
* Sets the value for the variable named {@link key}. This fully overrides the | ||
* previous value, so all previous raws and guarded state are discarded. | ||
*/ | ||
set(key: string, value: ConfiguredVariableValueProps): this { | ||
const variable = new ConfiguredVariable([key, value]); | ||
variable.parent = this; | ||
this._variables.get(key)?.parent = undefined; | ||
this._variables.set(key, value); | ||
return this; | ||
} | ||
|
||
/** Returns all the variables in this configuration. */ | ||
variables(): IterableIterator<ConfiguredVariable> { | ||
return this._variables.values(); | ||
} | ||
|
||
clone(overrides?: Partial<ConfigurationProps>): this { | ||
// We can't use `utils.cloneNode` here because variables isn't a public | ||
// field. Fortunately this class doesn't have any settable derived fields to | ||
// make cloning more complicated. | ||
return new Configuration({ | ||
raws: overrides?.raws ?? this.raws, | ||
variables: overrides?.variables ?? [...this._variables.values()] | ||
}); | ||
} | ||
|
||
toJSON(): object; | ||
/** @hidden */ | ||
toJSON(_: string, inputs: Map<postcss.Input, number>): object; | ||
toJSON(_?: string, inputs?: Map<postcss.Input, number>): object { | ||
return utils.toJSON(this, ['variables'], inputs); | ||
} | ||
|
||
toString(): string { | ||
let result = `(${this.raws.afterOpen ?? ''}`; | ||
for (const variable of this._variables.values()) { | ||
result += variable.toString(); | ||
} | ||
return result + `${this.raws.after ?? ''})`; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
// 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 type {AtRuleRaws} from 'postcss/lib/at-rule'; | ||
|
||
import {convertExpression} from '../expression/convert'; | ||
import {Expression, ExpressionProps} from '../expression'; | ||
import {fromProps} from '../expression/from-props'; | ||
import {LazySource} from '../lazy-source'; | ||
import {RawWithValue} from '../raw-with-value'; | ||
import type * as sassInternal from '../sass-internal'; | ||
import * as utils from '../utils'; | ||
import { | ||
ChildNode, | ||
ContainerProps, | ||
NewNode, | ||
Statement, | ||
StatementWithChildren, | ||
appendInternalChildren, | ||
normalize, | ||
} from '.'; | ||
import {_AtRule} from './at-rule-internal'; | ||
import {interceptIsClean} from './intercept-is-clean'; | ||
import * as sassParser from '../..'; | ||
|
||
export interface ConfiguredVariablePropsWithoutName { | ||
raws?: ConfiguredVariableRaws; | ||
value: Expression; | ||
guarded?: boolean; | ||
} | ||
|
||
export type ConfiguredVariableValueProps = Expression|ExpressionProps|ConfiguredVariablePropsWithoutName; | ||
|
||
export type ConfiguredVariableProps = (ConfiguredVariablePropsWithoutName & {name?: string}) | [string, ConfiguredVariableValueProps]; | ||
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
// 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. | ||
|
||
/** | ||
* An object describing how a value is represented in a stylesheet's source. | ||
* | ||
* This is used for values that can have multiple different representations that | ||
* all produce the same value. The {@link raw} field indicates the textual | ||
* representation in the stylesheet, while the {@link value} indicates the value | ||
* it represents. | ||
* | ||
* When serializing, if {@link value} doesn't match the value in the AST node, | ||
* this is ignored. This ensures that if a plugin overwrites the AST value | ||
* and ignores the raws, its change is preserved in the serialized output. | ||
*/ | ||
export interface RawWithValue<T> { | ||
/** The textual representation of {@link value} in the stylesheet. */ | ||
raw: string; | ||
|
||
/** | ||
* The parsed value that {@link raw} represents. This is used to verify that | ||
* this raw is still valid for the AST node that contains it. | ||
*/ | ||
value: T; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.