Skip to content

Commit 8dc1a6d

Browse files
authored
Convert @emotion/cache's source code to TypeScript (#3277)
* Convert `@emotion/cache`'s source code to TypeScript * remove extra comment types * tweak pkg json * fixed pkg.json#imports * try with this * use .ts * try this * try this * one more * try this * update `@types/stylis`
1 parent 282b61d commit 8dc1a6d

File tree

13 files changed

+168
-210
lines changed

13 files changed

+168
-210
lines changed

.changeset/fluffy-garlics-smash.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@emotion/cache': minor
3+
---
4+
5+
Source code has been migrated to TypeScript. From now on type declarations will be emitted based on that, instead of being hand-written.

packages/cache/package.json

+10-10
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"description": "emotion's cache",
55
"main": "dist/emotion-cache.cjs.js",
66
"module": "dist/emotion-cache.esm.js",
7+
"types": "dist/emotion-cache.cjs.d.ts",
78
"exports": {
89
".": {
910
"types": {
@@ -63,18 +64,17 @@
6364
},
6465
"imports": {
6566
"#is-development": {
66-
"development": "./src/conditions/true.js",
67-
"default": "./src/conditions/false.js"
67+
"development": "./src/conditions/true.ts",
68+
"default": "./src/conditions/false.ts"
6869
},
6970
"#is-browser": {
70-
"edge-light": "./src/conditions/false.js",
71-
"workerd": "./src/conditions/false.js",
72-
"worker": "./src/conditions/false.js",
73-
"browser": "./src/conditions/true.js",
74-
"default": "./src/conditions/is-browser.js"
71+
"edge-light": "./src/conditions/false.ts",
72+
"workerd": "./src/conditions/false.ts",
73+
"worker": "./src/conditions/false.ts",
74+
"browser": "./src/conditions/true.ts",
75+
"default": "./src/conditions/is-browser.ts"
7576
}
7677
},
77-
"types": "types/index.d.ts",
7878
"license": "MIT",
7979
"repository": "https://github.com/emotion-js/emotion/tree/main/packages/cache",
8080
"scripts": {
@@ -90,11 +90,11 @@
9090
"devDependencies": {
9191
"@definitelytyped/dtslint": "0.0.112",
9292
"@emotion/hash": "*",
93+
"@types/stylis": "^4.2.7",
9394
"typescript": "^5.4.5"
9495
},
9596
"files": [
9697
"src",
97-
"dist",
98-
"types/*.d.ts"
98+
"dist"
9999
]
100100
}
File renamed without changes.
File renamed without changes.

packages/cache/src/index.d.ts

-2
This file was deleted.

packages/cache/src/index.js packages/cache/src/index.ts

+39-55
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { StyleSheet } from '@emotion/sheet'
2-
/* import { type EmotionCache, type SerializedStyles } from '@emotion/utils' */
2+
import type { EmotionCache, SerializedStyles } from '@emotion/utils'
33
import {
44
serialize,
55
compile,
@@ -8,6 +8,7 @@ import {
88
stringify,
99
COMMENT
1010
} from 'stylis'
11+
import type { Element as StylisElement } from 'stylis'
1112
import weakMemoize from '@emotion/weak-memoize'
1213
import memoize from '@emotion/memoize'
1314
import isDevelopment from '#is-development'
@@ -19,43 +20,37 @@ import {
1920
incorrectImportAlarm
2021
} from './stylis-plugins'
2122
import { prefixer } from './prefixer'
22-
/* import type { StylisPlugin } from './types' */
23+
import { StylisPlugin } from './types'
2324

24-
/*
25-
export type Options = {
26-
nonce?: string,
27-
stylisPlugins?: StylisPlugin[],
28-
key: string,
29-
container?: HTMLElement,
30-
speedy?: boolean,
31-
prepend?: boolean,
25+
export interface Options {
26+
nonce?: string
27+
stylisPlugins?: Array<StylisPlugin>
28+
key: string
29+
container?: Node
30+
speedy?: boolean
31+
/** @deprecate use `insertionPoint` instead */
32+
prepend?: boolean
3233
insertionPoint?: HTMLElement
3334
}
34-
*/
3535

3636
let getServerStylisCache = isBrowser
3737
? undefined
38-
: weakMemoize(() =>
39-
memoize(() => {
40-
let cache = {}
41-
return name => cache[name]
42-
})
43-
)
38+
: weakMemoize(() => memoize<Record<string, string>>(() => ({})))
4439

4540
const defaultStylisPlugins = [prefixer]
4641

47-
let getSourceMap
42+
let getSourceMap: ((styles: string) => string | undefined) | undefined
4843
if (isDevelopment) {
4944
let sourceMapPattern =
5045
/\/\*#\ssourceMappingURL=data:application\/json;\S+\s+\*\//g
51-
getSourceMap = (styles /*: string */) => {
46+
getSourceMap = styles => {
5247
let matches = styles.match(sourceMapPattern)
5348
if (!matches) return
5449
return matches[matches.length - 1]
5550
}
5651
}
5752

58-
let createCache = (options /*: Options */) /*: EmotionCache */ => {
53+
let createCache = (options: Options): EmotionCache => {
5954
let key = options.key
6055

6156
if (isDevelopment && !key) {
@@ -74,14 +69,14 @@ let createCache = (options /*: Options */) /*: EmotionCache */ => {
7469
// document.head is a safe place to move them to(though note document.head is not necessarily the last place they will be)
7570
// note this very very intentionally targets all style elements regardless of the key to ensure
7671
// that creating a cache works inside of render of a React component
77-
Array.prototype.forEach.call(ssrStyles, (node /*: HTMLStyleElement */) => {
72+
Array.prototype.forEach.call(ssrStyles, (node: HTMLStyleElement) => {
7873
// we want to only move elements which have a space in the data-emotion attribute value
7974
// because that indicates that it is an Emotion 11 server-side rendered style elements
8075
// while we will already ignore Emotion 11 client-side inserted styles because of the :not([data-s]) part in the selector
8176
// Emotion 10 client-side inserted styles did not have data-s (but importantly did not have a space in their data-emotion attributes)
8277
// so checking for the space ensures that loading Emotion 11 after Emotion 10 has inserted some styles
8378
// will not result in the Emotion 10 styles being destroyed
84-
const dataEmotionAttribute = node.getAttribute('data-emotion')
79+
const dataEmotionAttribute = node.getAttribute('data-emotion')!
8580
if (dataEmotionAttribute.indexOf(' ') === -1) {
8681
return
8782
}
@@ -100,18 +95,18 @@ let createCache = (options /*: Options */) /*: EmotionCache */ => {
10095
)
10196
}
10297
}
103-
let inserted = {}
104-
let container /* : Node */
105-
const nodesToHydrate = []
98+
let inserted: EmotionCache['inserted'] = {}
99+
let container: Node
100+
const nodesToHydrate: HTMLStyleElement[] = []
106101
if (isBrowser) {
107102
container = options.container || document.head
108103

109104
Array.prototype.forEach.call(
110105
// this means we will ignore elements which don't have a space in them which
111106
// means that the style elements we're looking at are only Emotion 11 server-rendered style elements
112107
document.querySelectorAll(`style[data-emotion^="${key} "]`),
113-
(node /*: HTMLStyleElement */) => {
114-
const attrib = node.getAttribute(`data-emotion`).split(' ')
108+
(node: HTMLStyleElement) => {
109+
const attrib = node.getAttribute(`data-emotion`)!.split(' ')
115110
for (let i = 1; i < attrib.length; i++) {
116111
inserted[attrib[i]] = true
117112
}
@@ -120,12 +115,12 @@ let createCache = (options /*: Options */) /*: EmotionCache */ => {
120115
)
121116
}
122117

123-
let insert /*: (
118+
let insert: (
124119
selector: string,
125120
serialized: SerializedStyles,
126121
sheet: StyleSheet,
127122
shouldCache: boolean
128-
) => string | void */
123+
) => string | void
129124
const omnipresentPlugins = [compat, removeLabel]
130125

131126
if (isDevelopment) {
@@ -139,13 +134,13 @@ let createCache = (options /*: Options */) /*: EmotionCache */ => {
139134
)
140135
}
141136

142-
if (isBrowser) {
143-
let currentSheet
137+
if (!getServerStylisCache) {
138+
let currentSheet: Pick<StyleSheet, 'insert'>
144139

145140
const finalizingPlugins = [
146141
stringify,
147142
isDevelopment
148-
? element => {
143+
? (element: StylisElement) => {
149144
if (!element.root) {
150145
if (element.return) {
151146
currentSheet.insert(element.return)
@@ -164,21 +159,16 @@ let createCache = (options /*: Options */) /*: EmotionCache */ => {
164159
const serializer = middleware(
165160
omnipresentPlugins.concat(stylisPlugins, finalizingPlugins)
166161
)
167-
const stylis = styles => serialize(compile(styles), serializer)
162+
const stylis = (styles: string) => serialize(compile(styles), serializer)
168163

169-
insert = (
170-
selector /*: string */,
171-
serialized /*: SerializedStyles */,
172-
sheet /*: StyleSheet */,
173-
shouldCache /*: boolean */
174-
) /*: void */ => {
164+
insert = (selector, serialized, sheet, shouldCache) => {
175165
currentSheet = sheet
176166

177-
if (isDevelopment) {
167+
if (getSourceMap) {
178168
let sourceMap = getSourceMap(serialized.styles)
179169
if (sourceMap) {
180170
currentSheet = {
181-
insert: (rule /*: string */) => {
171+
insert: rule => {
182172
sheet.insert(rule + sourceMap)
183173
}
184174
}
@@ -196,13 +186,10 @@ let createCache = (options /*: Options */) /*: EmotionCache */ => {
196186
const serializer = middleware(
197187
omnipresentPlugins.concat(stylisPlugins, finalizingPlugins)
198188
)
199-
const stylis = styles => serialize(compile(styles), serializer)
189+
const stylis = (styles: string) => serialize(compile(styles), serializer)
200190

201191
let serverStylisCache = getServerStylisCache(stylisPlugins)(key)
202-
let getRules = (
203-
selector /*: string */,
204-
serialized /*: SerializedStyles */
205-
) /*: string */ => {
192+
let getRules = (selector: string, serialized: SerializedStyles): string => {
206193
let name = serialized.name
207194
if (serverStylisCache[name] === undefined) {
208195
serverStylisCache[name] = stylis(
@@ -211,12 +198,7 @@ let createCache = (options /*: Options */) /*: EmotionCache */ => {
211198
}
212199
return serverStylisCache[name]
213200
}
214-
insert = (
215-
selector /*: string */,
216-
serialized /*: SerializedStyles */,
217-
sheet /*: StyleSheet */,
218-
shouldCache /*: boolean */
219-
) /*: string | void */ => {
201+
insert = (selector, serialized, sheet, shouldCache) => {
220202
let name = serialized.name
221203
let rules = getRules(selector, serialized)
222204
if (cache.compat === undefined) {
@@ -226,7 +208,7 @@ let createCache = (options /*: Options */) /*: EmotionCache */ => {
226208
if (shouldCache) {
227209
cache.inserted[name] = true
228210
}
229-
if (isDevelopment) {
211+
if (getSourceMap) {
230212
let sourceMap = getSourceMap(serialized.styles)
231213
if (sourceMap) {
232214
return rules + sourceMap
@@ -251,11 +233,11 @@ let createCache = (options /*: Options */) /*: EmotionCache */ => {
251233
}
252234
}
253235

254-
const cache /*: EmotionCache */ = {
236+
const cache: EmotionCache = {
255237
key,
256238
sheet: new StyleSheet({
257239
key,
258-
container,
240+
container: container!,
259241
nonce: options.nonce,
260242
speedy: options.speedy,
261243
prepend: options.prepend,
@@ -273,3 +255,5 @@ let createCache = (options /*: Options */) /*: EmotionCache */ => {
273255
}
274256

275257
export default createCache
258+
export type { EmotionCache }
259+
export type { StylisElement, StylisPlugin, StylisPluginCallback } from './types'

packages/cache/src/prefixer.js packages/cache/src/prefixer.ts

+11-4
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,14 @@ import {
1515
RULESET,
1616
serialize,
1717
strlen,
18-
WEBKIT
18+
WEBKIT,
19+
Element,
20+
Middleware
1921
} from 'stylis'
2022

2123
// this is a copy of [email protected] prefixer, the latter version introduced grid prefixing which we don't want
2224

23-
function prefix(value, length) {
25+
function prefix(value: string, length: number): string {
2426
switch (hash(value, length)) {
2527
// color-adjust
2628
case 5103:
@@ -279,7 +281,12 @@ function prefix(value, length) {
279281
return value
280282
}
281283

282-
export let prefixer = (element, index, children, callback) => {
284+
export let prefixer = (
285+
element: Element,
286+
index: number,
287+
children: Element[],
288+
callback: Middleware
289+
) => {
283290
if (element.length > -1)
284291
if (!element.return)
285292
switch (element.type) {
@@ -297,7 +304,7 @@ export let prefixer = (element, index, children, callback) => {
297304
)
298305
case RULESET:
299306
if (element.length)
300-
return combine(element.props, function (value) {
307+
return combine(element.props as string[], function (value) {
301308
switch (match(value, /(::plac\w+|:read-\w+)/)) {
302309
// :read-(only|write)
303310
case ':read-only':

0 commit comments

Comments
 (0)