8000 Add support for color literals (#2503) · sass/dart-sass@879f484 · GitHub
  • [go: up one dir, main page]

    Skip to content

    Commit 879f484

    Browse files
    nex3Goodwine
    andauthored
    Add support for color literals (#2503)
    Co-authored-by: Carlos (Goodwine) <2022649+Goodwine@users.noreply.github.com>
    1 parent ae4b757 commit 879f484

    File tree

    18 files changed

    +470
    -20
    lines changed

    18 files changed

    +470
    -20
    lines changed

    CHANGELOG.md

    Lines changed: 4 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -1,3 +1,7 @@
    1+
    ## 1.84.1-dev
    2+
    3+
    * No user-visible changes.
    4+
    15
    ## 1.84.0
    26

    37
    * Allow newlines in whitespace in the indented syntax.

    pkg/sass-parser/CHANGELOG.md

    Lines changed: 4 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -1,3 +1,7 @@
    1+
    ## 0.4.14-dev
    2+
    3+
    * Add support for parsing color expressions.
    4+
    15
    ## 0.4.13
    26

    37
    * No user-visible changes.

    pkg/sass-parser/lib/index.ts

    Lines changed: 5 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -65,6 +65,11 @@ export {
    6565
    BooleanExpressionProps,
    6666
    BooleanExpressionRaws,
    6767
    } from './src/expression/boolean';
    68+
    export {
    69+
    ColorExpression,
    70+
    ColorExpressionProps,
    71+
    ColorExpressionRaws,
    72+
    } from './src/expression/color';
    6873
    export {
    6974
    NumberExpression,
    7075
    NumberExpressionProps,
    Lines changed: 25 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,25 @@
    1+
    // Jest Snapshot v1, https://goo.gl/fbAQLP
    2+
    3+
    exports[`a color expression toJSON 1`] = `
    4+
    {
    5+
    "inputs": [
    6+
    {
    7+
    "css": "@#{#00f}",
    8+
    "hasBOM": false,
    9+
    "id": "<input css _____>",
    10+
    },
    11+
    ],
    12+
    "raws": {},
    13+
    "sassType": "color",
    14+
    "source": <1:4-1:8 in 0>,
    15+
    "value": {
    16+
    "alpha": 1,
    17+
    "channels": [
    18+
    0,
    19+
    0,
    20+
    255,
    21+
    ],
    22+
    "space": "rgb",
    23+
    },
    24+
    }
    25+
    `;
    Lines changed: 246 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,246 @@
    1+
    // Copyright 2025 Google Inc. Use of this source code is governed by an
    2+
    // MIT-style license that can be found in the LICENSE file or at
    3+
    // https://opensource.org/licenses/MIT.
    4+
    5+
    import {SassColor} from 'sass';
    6+
    7+
    import {ColorExpression} from '../..';
    8+
    import * as utils from '../../../test/utils';
    9+
    10+
    const blue = new SassColor({space: 'rgb', red: 0, green: 0, blue: 255});
    11+
    12+
    describe('a color expression', () => {
    13+
    let node: ColorExpression;
    14+
    15+
    describe('with no alpha', () => {
    16+
    function describeNode(
    17+
    description: string,
    18+
    create: () => ColorExpression,
    19+
    ): void {
    20+
    describe(description, () => {
    21+
    beforeEach(() => void (node = create()));
    22+
    23+
    it('has sassType color', () => expect(node.sassType).toBe('color'));
    24+
    25+
    it('is a color', () => expect(node.value).toEqual(blue));
    26+
    });
    27+
    }
    28+
    29+
    describe('parsed', () => {
    30+
    describeNode('hex', () => utils.parseExpression('#00f'));
    31+
    32+
    describeNode('keyword', () => utils.parseExpression('blue'));
    33+
    });
    34+
    35+
    describeNode(
    36+
    'constructed manually',
    37+
    () => new ColorExpression({value: blue}),
    38+
    );
    39+
    40+
    describeNode('constructed from ExpressionProps', () =>
    41+
    utils.fromExpressionProps({value: blue}),
    42+
    );
    43+
    });
    44+
    45+
    describe('with alpha', () => {
    46+
    function describeNode(
    47+
    description: string,
    48+
    create: () => ColorExpression,
    49+
    ): void {
    50+
    describe(description, () => {
    51+
    beforeEach(() => void (node = create()));
    52+
    53+
    it('has sassType color', () => expect(node.sassType).toBe('color'));
    54+
    55+
    it('is a color', () =>
    56+
    expect(node.value).toEqual(
    57+
    new SassColor({
    58+
    space: 'rgb',
    59+
    red: 10,
    60+
    green: 20,
    61+
    blue: 30,
    62+
    alpha: 0.4,
    63+
    }),
    64+
    ));
    65+
    });
    66+
    }
    67+
    68+
    describeNode('parsed', () => utils.parseExpression('#0a141E66'));
    69+
    70+
    describeNode(
    71+
    'constructed manually',
    72+
    () =>
    73+
    new ColorExpression({
    74+
    value: new SassColor({
    75+
    space: 'rgb',
    76+
    red: 10,
    77+
    green: 20,
    78+
    blue: 30,
    79+
    alpha: 0.4,
    80+
    }),
    81+
    }),
    82+
    );
    83+
    84+
    describeNode('constructed from ExpressionProps', () =>
    85+
    utils.fromExpressionProps({
    86+
    value: new SassColor({
    87+
    space: 'rgb',
    88+
    red: 10,
    89+
    green: 20,
    90+
    blue: 30,
    91+
    alpha: 0.4,
    92+
    }),
    93+
    }),
    94+
    );
    95+
    });
    96+
    97+
    describe('throws an error for non-RGB colors', () => {
    98+
    beforeEach(() => void (node = utils.parseExpression('#123')));
    99+
    100+
    it('in the constructor', () =>
    101+
    expect(
    102+
    () =>
    103+
    new ColorExpression({
    104+
    value: new SassColor({
    105+
    space: 'hsl',
    106+
    hue: 180,
    107+
    saturation: 50,
    108+
    lightness: 50,
    109+
    }),
    110+
    }),
    111+
    ).toThrow());
    112+
    113+
    it('in the property', () =>
    114+
    expect(() => {
    115+
    node.value = new SassColor({
    116+
    space: 'hsl',
    117+
    hue: 180,
    118+
    saturation: 50,
    119+
    lightness: 50,
    120+
    });
    121+
    }).toThrow());
    122+
    123+
    it('in clone', () =>
    124+
    expect(() =>
    125+
    node.clone({
    126+
    value: new SassColor({
    127+
    space: 'hsl',
    128+
    hue: 180,
    129+
    saturation: 50,
    130+
    lightness: 50,
    131+
    }),
    132+
    }),
    133+
    ).toThrow());
    134+
    });
    135+
    136+
    it('assigned new value', () => {
    137+
    const node = utils.parseExpression('#123') as ColorExpression;
    138+
    node.value = new SassColor({
    139+
    space: 'rgb',
    140+
    red: 10,
    141+
    green: 20,
    142+
    blue: 30,
    143+
    alpha: 0.4,
    144+
    });
    145+
    expect(node.value).toEqual(
    146+
    new SassColor({
    147+
    space: 'rgb',
    148+
    red: 10,
    149+
    green: 20,
    150+
    blue: 30,
    151+
    alpha: 0.4,
    152+
    }),
    153+
    );
    154+
    });
    155+
    156+
    describe('stringifies', () => {
    157+
    it('without alpha', () =>
    158+
    expect(utils.parseExpression('#abc').toString()).toBe('#aabbcc'));
    159+
    160+
    it('with alpha', () =>
    161+
    expect(utils.parseExpression('#abcd').toString()).toBe('#aabbccdd'));
    162+
    163+
    describe('raws', () => {
    164+
    it('with the same raw value as the expression', () =>
    165+
    expect(
    166+
    new ColorExpression({
    167+
    value: blue,
    168+
    raws: {value: {raw: 'blue', value: blue}},
    169+
    }).toString(),
    170+
    ).toBe('blue'));
    171+
    172+
    it('with a different raw value than the expression', () =>
    173+
    expect(
    174+
    new ColorExpression({
    175+
    value: new SassColor({space: 'rgb', red: 10, green: 20, blue: 30}),
    176+
    raws: {value: {raw: 'blue', value: blue}},
    177+
    }).toString(),
    178+
    ).toBe('#0a141e'));
    179+
    });
    180+
    });
    181+
    182+
    describe('clone', () => {
    183+
    let original: ColorExpression;
    184+
    185+
    beforeEach(() => {
    186+
    original = utils.parseExpression('#00f');
    187+
    // TODO: remove this once raws are properly parsed.
    188+
    original.raws.value = {raw: 'blue', value: blue};
    189+
    });
    190+
    191+
    describe('with no overrides', () => {
    192+
    let clone: ColorExpression;
    193+
    194+
    beforeEach(() => void (clone = original.clone()));
    195+
    196+
    describe('has the same properties:', () => {
    197+
    it('value', () => expect(clone.value).toEqual(blue));
    198+
    199+
    it('raws', () => {
    200+
    expect(clone.raws.value!.raw).toBe('blue');
    201+
    expect(clone.raws.value!.value).toEqual(blue);
    202+
    });
    203+
    204+
    it('source', () => expect(clone.source).toBe(original.source));
    205+
    });
    206+
    207+
    it('creates a new self', () => expect(clone).not.toBe(original));
    208+
    });
    209+
    210+
    describe('overrides', () => {
    211+
    describe('value', () => {
    212+
    it('defined', () =>
    213+
    expect(
    214+
    original.clone({
    215+
    value: new SassColor({
    216+
    space: 'rgb',
    217+
    red: 10,
    218+
    green: 20,
    219+
    blue: 30,
    220+
    }),
    221+
    }).value,
    222+
    ).toEqual(
    223+
    new SassColor({space: 'rgb', red: 10, green: 20, blue: 30}),
    224+
    ));
    225+
    226+
    it('undefined', () =>
    227+
    expect(original.clone({value: undefined}).value).toEqual(blue));
    228+
    });
    229+
    230+
    describe('raws', () => {
    231+
    it('defined', () =>
    232+
    expect(
    233+
    original.clone({raws: {value: {raw: '#0000FF', value: blue}}}).raws
    234+
    .value!.raw,
    235+
    ).toBe('#0000FF'));
    236+
    237+
    it('undefined', () =>
    238+
    expect(original.clone({raws: undefined}).raws.value!.raw).toBe(
    239+
    'blue',
    240+
    ));
    241+
    });
    242+
    });
    243+
    });
    244+
    245+
    it('toJSON', () => expect(utils.parseExpression('#00f')).toMatchSnapshot());
    246+
    });

    0 commit comments

    Comments
     (0)
    0