Skip to content

Commit 1677593

Browse files
authored
Vendor cssesc dependency (#1710)
1 parent ba21414 commit 1677593

10 files changed

Lines changed: 120 additions & 25 deletions

File tree

.changeset/eight-tigers-poke.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@vanilla-extract/css': patch
3+
---
4+
5+
Replace `cssesc` dependency with vendored version

.changeset/hot-geese-end.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@vanilla-extract/compiler': minor
3+
---
4+
5+
Don't mark `cssesc` dependency as `external`
6+
7+
`cssesc` has been vendored into the `@vanilla-extract/css` package due to its lack of ESM support

packages/compiler/src/compiler.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,11 +130,6 @@ const createViteServer = async ({
130130
},
131131
ssr: {
132132
noExternal: true,
133-
// `cssesc` is CJS-only, so we need to mark it as external as Vite's transform pipeline
134-
// can't handle CJS during dev-time.
135-
// See https://github.com/withastro/astro/blob/0879cc2ce7e15a2e7330c68d6667d9a2edea52ab/packages/astro/src/core/create-vite.ts#L86
136-
// and https://github.com/withastro/astro/issues/11395
137-
external: ['cssesc'],
138133
},
139134
plugins: [
140135
{

packages/css/package.json

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,6 @@
121121
"@emotion/hash": "^0.9.0",
122122
"@vanilla-extract/private": "workspace:^",
123123
"css-what": "^6.1.0",
124-
"cssesc": "^3.0.0",
125124
"csstype": "^3.2.3",
126125
"dedent": "^1.5.3",
127126
"deep-object-diff": "^1.1.9",
@@ -130,8 +129,5 @@
130129
"media-query-parser": "^2.0.2",
131130
"modern-ahocorasick": "^1.0.0",
132131
"picocolors": "^1.0.0"
133-
},
134-
"devDependencies": {
135-
"@types/cssesc": "^3.0.0"
136132
}
137133
}

packages/css/src/cssesc.ts

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/* eslint-disable regexp/control-character-escape */
2+
/* eslint-disable no-control-regex */
3+
/* eslint-disable regexp/no-optional-assertion */
4+
/* eslint-disable regexp/no-useless-escape */
5+
/* eslint-disable regexp/no-obscure-range */
6+
// ESM vendored version of cssesc: https://github.com/mathiasbynens/cssesc/blob/cb894eb42f27c8d3cd793f16afe35b3ab38000a1/cssesc.js
7+
// See https://github.com/vanilla-extract-css/vanilla-extract/pull/1710
8+
9+
const regexAnySingleEscape = /[ -,\.\/:-@\[-\^`\{-~]/;
10+
const regexSingleEscape = /[ -,\.\/:-@\[\]\^`\{-~]/;
11+
const regexExcessiveSpaces =
12+
/(^|\\+)?(\\[A-F0-9]{1,6})\x20(?![a-fA-F0-9\x20])/g;
13+
14+
interface Options {
15+
escapeEverything: boolean;
16+
isIdentifier: boolean;
17+
quotes: 'single' | 'double';
18+
wrap: boolean;
19+
}
20+
21+
const DEFAULT_OPTIONS: Options = {
22+
escapeEverything: false,
23+
isIdentifier: false,
24+
quotes: 'single',
25+
wrap: false,
26+
};
27+
28+
export function cssesc(string: string, options: Partial<Options> = {}) {
29+
options = { ...DEFAULT_OPTIONS, ...options };
30+
const quote = options.quotes === 'double' ? '"' : "'";
31+
const { isIdentifier } = options;
32+
33+
const firstChar = string.charAt(0);
34+
let output = '';
35+
let counter = 0;
36+
const length = string.length;
37+
while (counter < length) {
38+
const character = string.charAt(counter++);
39+
let codePoint = character.charCodeAt(0);
40+
let value: string;
41+
// If it’s not a printable ASCII character…
42+
if (codePoint < 0x20 || codePoint > 0x7e) {
43+
if (codePoint >= 0xd800 && codePoint <= 0xdbff && counter < length) {
44+
// It’s a high surrogate, and there is a next character.
45+
const extra = string.charCodeAt(counter++);
46+
if ((extra & 0xfc00) === 0xdc00) {
47+
// next character is low surrogate
48+
codePoint = ((codePoint & 0x3ff) << 10) + (extra & 0x3ff) + 0x10000;
49+
} else {
50+
// It’s an unmatched surrogate; only append this code unit, in case
51+
// the next code unit is the high surrogate of a surrogate pair.
52+
counter--;
53+
}
54+
}
55+
value = '\\' + codePoint.toString(16).toUpperCase() + ' ';
56+
} else {
57+
if (options.escapeEverything) {
58+
if (regexAnySingleEscape.test(character)) {
59+
value = '\\' + character;
60+
} else {
61+
value = '\\' + codePoint.toString(16).toUpperCase() + ' ';
62+
}
63+
} else if (/[\t\n\f\r\x0B]/.test(character)) {
64+
value = '\\' + codePoint.toString(16).toUpperCase() + ' ';
65+
} else if (
66+
character === '\\' ||
67+
(!isIdentifier &&
68+
((character === '"' && quote === character) ||
69+
(character === "'" && quote === character))) ||
70+
(isIdentifier && regexSingleEscape.test(character))
71+
) {
72+
value = '\\' + character;
73+
} else {
74+
value = character;
75+
}
76+
}
77+
output += value;
78+
}
79+
80+
if (isIdentifier) {
81+
if (/^-[-\d]/.test(output)) {
82+
output = '\\-' + output.slice(1);
83+
} else if (/\d/.test(firstChar)) {
84+
output = '\\3' + firstChar + ' ' + output.slice(1);
85+
}
86+
}
87+
88+
// Remove spaces after `\HEX` escapes that are not followed by a hex digit,
89+
// since they’re redundant. Note that this is only possible if the escape
90+
// sequence isn’t preceded by an odd number of backslashes.
91+
output = output.replace(regexExcessiveSpaces, function ($0, $1, $2) {
92+
if ($1 && $1.length % 2) {
93+
// It’s not safe to remove the space, so don’t.
94+
return $0;
95+
}
96+
// Strip the space.
97+
return ($1 || '') + $2;
98+
});
99+
100+
if (!isIdentifier && options.wrap) {
101+
return quote + output + quote;
102+
}
103+
return output;
104+
}

packages/css/src/style.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import cssesc from 'cssesc';
21
import dedent from 'dedent';
32
import deepmerge from 'deepmerge';
43

@@ -19,6 +18,7 @@ import {
1918
import { getFileScope, hasFileScope } from './fileScope';
2019
import { generateIdentifier } from './identifier';
2120
import { dedupeAndJoinClassList } from './utils';
21+
import { cssesc } from './cssesc';
2222

2323
function composedStyle(rules: Array<StyleRule | ClassNames>, debugId?: string) {
2424
const className = generateIdentifier(debugId);

packages/css/src/transformCss.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { getVarName } from '@vanilla-extract/private';
2-
import cssesc from 'cssesc';
32
import AhoCorasick from 'modern-ahocorasick';
43

54
import type {
@@ -21,6 +20,7 @@ import { validateSelector } from './validateSelector';
2120
import { ConditionalRuleset } from './conditionalRulesets';
2221
import { simplePseudos, simplePseudoLookup } from './simplePseudos';
2322
import { validateMediaQuery } from './validateMediaQuery';
23+
import { cssesc } from './cssesc';
2424

2525
const DECLARATION = '__DECLARATION';
2626

packages/css/src/validateSelector.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { parse } from 'css-what';
2-
import cssesc from 'cssesc';
32
import dedent from 'dedent';
3+
import { cssesc } from './cssesc';
44

55
// https://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript
66
function escapeRegex(string: string) {

packages/css/src/vars.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ import {
77
type MapLeafNodes,
88
type CSSVarFunction,
99
} from '@vanilla-extract/private';
10-
import cssesc from 'cssesc';
1110

1211
import type { Tokens, NullableTokens, ThemeVars } from './types';
1312
import { validateContract } from './validateContract';
1413
import { getFileScope } from './fileScope';
1514
import { generateIdentifier } from './identifier';
1615
import type { PropertySyntax } from './types';
1716
import { appendCss } from './adapter';
17+
import { cssesc } from './cssesc';
1818

1919
type VarDeclaration =
2020
| {

pnpm-lock.yaml

Lines changed: 0 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)