Skip to content

Commit

Permalink
Add support for declarations
Browse files Browse the repository at this point in the history
  • Loading branch information
nex3 committed Dec 20, 2024
1 parent 3ed48c7 commit 32a3556
Show file tree
Hide file tree
Showing 26 changed files with 1,078 additions and 128 deletions.
9 changes: 8 additions & 1 deletion pkg/sass-parser/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ export {
DebugRuleProps,
DebugRuleRaws,
} from './src/statement/debug-rule';
export {
Declaration,
DeclarationProps,
DeclarationRaws,
} from './src/statement/declaration';
export {EachRule, EachRuleProps, EachRuleRaws} from './src/statement/each-rule';
export {
ErrorRule,
Expand Down Expand Up @@ -142,10 +147,12 @@ export {
} from './src/statement/sass-comment';
export {UseRule, UseRuleProps, UseRuleRaws} from './src/statement/use-rule';
export {
AnyDeclaration,
AnyStatement,
AtRule,
ChildNode,
ChildProps,
Comment,
ContainerProps,
NewNode,
Statement,
Expand Down Expand Up @@ -196,7 +203,7 @@ class _Syntax implements Syntax {
}

stringify(node: postcss.AnyNode, builder: postcss.Builder): void {
new Stringifier(builder).stringify(node, true);
new Stringifier(builder).stringify(node, false);
}
}

Expand Down
18 changes: 9 additions & 9 deletions pkg/sass-parser/lib/src/parameter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,15 @@ export type ParameterObjectProps = NodeProps & {
raws?: ParameterRaws;
name: string;
} & (
| {
defaultValue?: Expression | ExpressionProps;
rest?: never;
}
| {
defaultValue?: never;
rest?: boolean;
}
);
| {
defaultValue?: Expression | ExpressionProps;
rest?: never;
}
| {
defaultValue?: never;
rest?: boolean;
}
);

/**
* Properties used to initialize a {@link Parameter} without an explicit name.
Expand Down
7 changes: 7 additions & 0 deletions pkg/sass-parser/lib/src/sass-internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,11 @@ declare namespace SassInternal {
readonly expression: Expression;
}

class Declaration extends ParentStatement<Statement[] | null> {
readonly name: Interpolation;
readonly value?: Expression;
}

class EachRule extends ParentStatement<Statement[]> {
readonly variables: string[];
readonly list: Expression;
Expand Down Expand Up @@ -317,6 +322,7 @@ export type AtRootRule = SassInternal.AtRootRule;
export type AtRule = SassInternal.AtRule;
export type ContentBlock = SassInternal.ContentBlock;
export type DebugRule = SassInternal.DebugRule;
export type Declaration = SassInternal.Declaration;
export type EachRule = SassInternal.EachRule;
export type ErrorRule = SassInternal.ErrorRule;
export type ExtendRule = SassInternal.ExtendRule;
Expand Down Expand Up @@ -350,6 +356,7 @@ export interface StatementVisitorObject<T> {
visitAtRootRule(node: AtRootRule): T;
visitAtRule(node: AtRule): T;
visitDebugRule(node: DebugRule): T;
visitDeclaration(node: Declaration): T;
visitEachRule(node: EachRule): T;
visitErrorRule(node: ErrorRule): T;
visitExtendRule(node: ExtendRule): T;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`a property declaration toJSON with expression and no nodes 1`] = `
{
"expression": <bar>,
"inputs": [
{
"css": "a {foo: bar}",
"hasBOM": false,
"id": "<input css _____>",
},
],
"propInterpolation": <foo>,
"raws": {},
"sassType": "decl",
"source": <1:4-1:12 in 0>,
"type": "decl",
}
`;
exports[`a property declaration toJSON with expression and nodes 1`] = `
{
"expression": <bar>,
"inputs": [
{
"css": "a {foo: bar {baz: bang}}",
"hasBOM": false,
"id": "<input css _____>",
},
],
"nodes": [
<baz: bang>,
],
"propInterpolation": <foo>,
"raws": {},
"sassType": "decl",
"source": <1:4-1:24 in 0>,
"type": "decl",
}
`;
exports[`a property declaration toJSON with no expression and nodes 1`] = `
{
"inputs": [
{
"css": "a {foo: {baz: bang}}",
"hasBOM": false,
"id": "<input css _____>",
},
],
"nodes": [
<baz: bang>,
],
"propInterpolation": <foo>,
"raws": {},
"sassType": "decl",
"source": <1:4-1:20 in 0>,
"type": "decl",
}
`;
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ exports[`a generic @-rule toJSON with a child 1`] = `
"name": "foo",
"nameInterpolation": <foo>,
"nodes": [
<@bar;>,
<@bar>,
],
"params": "",
"raws": {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ exports[`a @include rule toJSON with a child 1`] = `
],
"name": "include",
"nodes": [
<@qux;>,
<@qux>,
],
"params": "foo(bar)",
"raws": {},
Expand Down Expand Up @@ -56,7 +56,7 @@ exports[`a @include rule toJSON with using and a child 1`] = `
],
"name": "include",
"nodes": [
<@qux;>,
<@qux>,
],
"params": "foo(bar) using ($baz)",
"raws": {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ exports[`a style rule toJSON with a child 1`] = `
},
],
"nodes": [
<@bar;>,
<@bar>,
],
"raws": {},
"sassType": "rule",
Expand Down
6 changes: 3 additions & 3 deletions pkg/sass-parser/lib/src/statement/at-rule-internal.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import * as postcss from 'postcss';

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

/**
* A fake intermediate class to convince TypeScript to use Sass types for
Expand Down Expand Up @@ -60,10 +60,10 @@ export class _AtRule<Props> extends postcss.AtRule {
): false | undefined;
walkDecls(
propFilter: RegExp | string,
callback: (decl: Declaration, index: number) => false | void,
callback: (decl: AnyDeclaration, index: number) => false | void,
): false | undefined;
walkDecls(
callback: (decl: Declaration, index: number) => false | void,
callback: (decl: AnyDeclaration, index: number) => false | void,
): false | undefined;
walkRules(
selectorFilter: RegExp | string,
Expand Down
6 changes: 3 additions & 3 deletions pkg/sass-parser/lib/src/statement/debug-rule.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,23 +107,23 @@ describe('a @debug rule', () => {
new DebugRule({
debugExpression: {text: 'foo'},
}).toString(),
).toBe('@debug foo;'));
).toBe('@debug foo'));

it('with afterName', () =>
expect(
new DebugRule({
debugExpression: {text: 'foo'},
raws: {afterName: '/**/'},
}).toString(),
).toBe('@debug/**/foo;'));
).toBe('@debug/**/foo'));

it('with between', () =>
expect(
new DebugRule({
debugExpression: {text: 'foo'},
raws: {between: '/**/'},
}).toString(),
).toBe('@debug foo/**/;'));
).toBe('@debug foo/**/'));
});
});

Expand Down
70 changes: 61 additions & 9 deletions pkg/sass-parser/lib/src/statement/declaration-internal.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
// https://opensource.org/licenses/MIT.

import * as postcss from 'postcss';
import {ContainerWithChildren} from 'postcss/lib/container';

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

/**
* A fake intermediate class to convince TypeScript to use Sass types for
Expand All @@ -15,30 +16,81 @@ import {AtRule, ChildNode, Comment, Declaration, NewNode} from '.';
* @hidden
*/
export class _Declaration<Props> extends postcss.Declaration {
// Override the PostCSS container types to constrain them to Sass types only.
// Override the PostCSS 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;
next(): ChildNode | undefined;
prev(): ChildNode | undefined;
replaceWith(...nodes: NewNode[]): this;
root(): Root;
}

// This functionally extends *both* `_Declaration<Props>` and
// `postcss.Container`, but because TypeScript doesn't support proper multiple
// inheritance and the latter has protected properties we need to explicitly
// extend it.

/**
* A fake intermediate class to convince TypeScript to use Sass types for
* various upstream methods.
*
* @hidden
*/
export class _DeclarationWithChildren<Props>
extends postcss.Container
implements _Declaration<Props>
{
declare parent: ContainerWithChildren | undefined;
declare type: 'decl';

get prop(): string;
get value(): string;
get important(): boolean;
get variable(): boolean;

after(newNode: NewNode): this;
assign(overrides: Partial<Props>): this;
before(newNode: NewNode): this;
clone(overrides?: Partial<Props>): this;
cloneAfter(overrides?: Partial<Props>): this;
cloneBefore(overrides?: Partial<Props>): this;
next(): ChildNode | undefined;
prev(): ChildNode | undefined;
replaceWith(...nodes: NewNode[]): this;
root(): Root;

append(...nodes: NewNode[]): this;
each(
callback: (node: ChildNode, index: number) => false | void,
): false | undefined;
every(
condition: (node: ChildNode, index: number, nodes: ChildNode[]) => boolean,
): boolean;
index(child: postcss.ChildNode | number): number;
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;
push(child: ChildNode): this;
removeAll(): this;
removeChild(child: postcss.ChildNode | number): this;
replaceValues(
pattern: RegExp | string,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
replaced: {(substring: string, ...args: any[]): string} | string,
): this;
replaceValues(
pattern: RegExp | string,
options: {fast?: string; props?: readonly string[]},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
replaced: {(substring: string, ...args: any[]): string} | string,
): this;
some(
condition: (node: ChildNode, index: number, nodes: ChildNode[]) => boolean,
): boolean;
Expand All @@ -60,10 +112,10 @@ export class _Declaration<Props> extends postcss.Declaration {
): false | undefined;
walkDecls(
propFilter: RegExp | string,
callback: (decl: Declaration, index: number) => false | void,
callback: (decl: AnyDeclaration, index: number) => false | void,
): false | undefined;
walkDecls(
callback: (decl: Declaration, index: number) => false | void,
callback: (decl: AnyDeclaration, index: number) => false | void,
): false | undefined;
walkRules(
selectorFilter: RegExp | string,
Expand Down
12 changes: 11 additions & 1 deletion pkg/sass-parser/lib/src/statement/declaration-internal.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,14 @@
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

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

exports._Declaration = postcss.Declaration;

// Inject PostCSS's container implementation into a declaration subclass so we
// can define declarations that have child nodes.
class _DeclarationWithChildren extends postcss.Declaration {}
const containerProperties = Object.getOwnPropertyDescriptors(postcss.Container.prototype);
Object.defineProperties(_DeclarationWithChildren.prototype, containerProperties);

exports._DeclarationWithChildren = _DeclarationWithChildren;
Loading

0 comments on commit 32a3556

Please sign in to comment.