-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
[serialize]: Convert to Typescript #2543
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Andarist
merged 13 commits into
emotion-js:ts-migration
from
danilofuchs:ts-migration-serialize
Apr 19, 2022
Merged
Changes from 3 commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
8268e1a
[serialize]: Convert to Typescript
6197b7b
fix: Some tests
38a2606
chore: Revert unrelated change
95e16b4
chore: Revert code behaviour changes
b371ac7
chore: Revert toString method addition
0ebd60f
chore: Changeset
a613327
fix: Add missing return of ComponentSelector
d89396e
fix: Export missing interfaces
7ceab45
small tweaks
Andarist 0cc37c9
Merge branch 'ts-migration' into ts-migration-serialize
Andarist 25d913f
fix stuff
Andarist 0cfb120
Merge branch 'ts-migration' into ts-migration-serialize
Andarist 62719e2
Merge branch 'ts-migration' into ts-migration-serialize
Andarist File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 hidden or 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 |
|---|---|---|
| @@ -1,11 +1,71 @@ | ||
| /* import type { | ||
| Interpolation, | ||
| SerializedStyles, | ||
| RegisteredCache | ||
| } from '@emotion/utils' */ | ||
| import hashString from '@emotion/hash' | ||
| import unitless from '@emotion/unitless' | ||
| import memoize from '@emotion/memoize' | ||
| import { RegisteredCache, SerializedStyles } from '@emotion/utils' | ||
| import * as CSS from 'csstype' | ||
|
|
||
| type Props = Record<string, unknown> | ||
| type Cursor = { | ||
| name: string | ||
| styles: string | ||
| next?: Cursor | ||
| } | ||
|
|
||
| export type CSSProperties = CSS.PropertiesFallback<number | string> | ||
| export type CSSPropertiesWithMultiValues = { | ||
| [K in keyof CSSProperties]: | ||
| | CSSProperties[K] | ||
| | Array<Extract<CSSProperties[K], string>> | ||
| } | ||
|
|
||
| export type CSSPseudos = { [K in CSS.Pseudos]?: CSSObject } | ||
|
|
||
| export interface ArrayCSSInterpolation extends Array<CSSInterpolation> {} | ||
|
|
||
| export type InterpolationPrimitive = | ||
| | null | ||
| | undefined | ||
| | boolean | ||
| | number | ||
| | string | ||
| | ComponentSelector | ||
| | Keyframes | ||
| | SerializedStyles | ||
| | CSSObject | ||
|
|
||
| export type CSSInterpolation = InterpolationPrimitive | ArrayCSSInterpolation | ||
|
|
||
| export interface CSSOthersObject { | ||
| [propertiesName: string]: CSSInterpolation | ||
| } | ||
|
|
||
| export interface CSSObject | ||
| extends CSSPropertiesWithMultiValues, | ||
| CSSPseudos, | ||
| CSSOthersObject {} | ||
|
|
||
| export interface ComponentSelector { | ||
| __emotion_styles: any | ||
| } | ||
|
|
||
| export type Keyframes = { | ||
| name: string | ||
| styles: string | ||
| anim: number | ||
| toString: () => string | ||
| } & string | ||
|
|
||
| export interface ArrayInterpolation<Props> | ||
| extends Array<Interpolation<Props>> {} | ||
|
|
||
| export interface FunctionInterpolation<Props> { | ||
| (props: Props): Interpolation<Props> | ||
| } | ||
|
|
||
| export type Interpolation<Props> = | ||
| | InterpolationPrimitive | ||
| | ArrayInterpolation<Props> | ||
| | FunctionInterpolation<Props> | ||
|
|
||
| const ILLEGAL_ESCAPE_SEQUENCE_ERROR = `You have illegal escape sequence in your template literal, most likely inside content's property value. | ||
| Because you write your CSS inside a JavaScript string you actually have to do double escaping, so for example "content: '\\00d7';" should become "content: '\\\\00d7';". | ||
|
|
@@ -18,9 +78,30 @@ const UNDEFINED_AS_OBJECT_KEY_ERROR = | |
| let hyphenateRegex = /[A-Z]|^ms/g | ||
| let animationRegex = /_EMO_([^_]+?)_([^]*?)_EMO_/g | ||
|
|
||
| const isCustomProperty = (property /*: string */) => | ||
| property.charCodeAt(1) === 45 | ||
| const isProcessableValue = value => value != null && typeof value !== 'boolean' | ||
| const isCustomProperty = (property: string) => property.charCodeAt(1) === 45 | ||
| const isProcessableValue = <Props>(value: Interpolation<Props>) => | ||
| value != null && typeof value !== 'boolean' | ||
|
|
||
| const isComponentSelector = ( | ||
| interpolation: any | ||
| ): interpolation is ComponentSelector => | ||
| interpolation !== null && | ||
| typeof interpolation === 'object' && | ||
| '__emotion_styles' in interpolation | ||
|
|
||
| const isKeyframes = (interpolation: any): interpolation is Keyframes => | ||
| interpolation !== null && | ||
| typeof interpolation === 'object' && | ||
| 'anim' in interpolation && | ||
| interpolation.anim === 1 | ||
|
|
||
| const isSerializedStyles = ( | ||
| interpolation: any | ||
| ): interpolation is SerializedStyles => | ||
| interpolation !== null && | ||
| typeof interpolation === 'object' && | ||
| 'styles' in interpolation && | ||
| interpolation.styles !== undefined | ||
|
|
||
| const processStyleName = /* #__PURE__ */ memoize((styleName /*: string */) => | ||
| isCustomProperty(styleName) | ||
|
|
@@ -29,9 +110,9 @@ const processStyleName = /* #__PURE__ */ memoize((styleName /*: string */) => | |
| ) | ||
|
|
||
| let processStyleValue = ( | ||
| key /*: string */, | ||
| value /*: string | number */ | ||
| ) /*: string | number */ => { | ||
| key: string, | ||
| value: string | number | ||
| ): string | number => { | ||
| switch (key) { | ||
| case 'animation': | ||
| case 'animationName': { | ||
|
|
@@ -49,7 +130,7 @@ let processStyleValue = ( | |
| } | ||
|
|
||
| if ( | ||
| unitless[key] !== 1 && | ||
| unitless[key as keyof typeof unitless] !== 1 && | ||
| !isCustomProperty(key) && | ||
| typeof value === 'number' && | ||
| value !== 0 | ||
|
|
@@ -69,9 +150,9 @@ if (process.env.NODE_ENV !== 'production') { | |
| let msPattern = /^-ms-/ | ||
| let hyphenPattern = /-(.)/g | ||
|
|
||
| let hyphenatedCache = {} | ||
| let hyphenatedCache: Record<string, boolean | undefined> = {} | ||
|
|
||
| processStyleValue = (key /*: string */, value /*: string */) => { | ||
| processStyleValue = (key: string, value: string | number) => { | ||
| if (key === 'content') { | ||
| if ( | ||
| typeof value !== 'string' || | ||
|
|
@@ -106,15 +187,15 @@ if (process.env.NODE_ENV !== 'production') { | |
| } | ||
| } | ||
|
|
||
| function handleInterpolation( | ||
| mergedProps /*: void | Object */, | ||
| registered /*: RegisteredCache | void */, | ||
| interpolation /*: Interpolation */ | ||
| ) /*: string | number */ { | ||
| function handleInterpolation<Props>( | ||
| mergedProps: Props | undefined, | ||
| registered: RegisteredCache | undefined, | ||
| interpolation: Interpolation<Props> | TemplateStringsArray | ||
| ): string | number { | ||
| if (interpolation == null) { | ||
| return '' | ||
| } | ||
| if (interpolation.__emotion_styles !== undefined) { | ||
| if (isComponentSelector(interpolation)) { | ||
| if ( | ||
| process.env.NODE_ENV !== 'production' && | ||
| interpolation.toString() === 'NO_COMPONENT_SELECTOR' | ||
|
|
@@ -123,15 +204,14 @@ function handleInterpolation( | |
| 'Component selectors can only be used in conjunction with @emotion/babel-plugin.' | ||
| ) | ||
| } | ||
| return interpolation | ||
| } | ||
|
|
||
| switch (typeof interpolation) { | ||
| case 'boolean': { | ||
| return '' | ||
| } | ||
| case 'object': { | ||
| if (interpolation.anim === 1) { | ||
| if (isKeyframes(interpolation)) { | ||
| cursor = { | ||
| name: interpolation.name, | ||
| styles: interpolation.styles, | ||
|
|
@@ -140,7 +220,7 @@ function handleInterpolation( | |
|
|
||
| return interpolation.name | ||
| } | ||
| if (interpolation.styles !== undefined) { | ||
| if (isSerializedStyles(interpolation)) { | ||
| let next = interpolation.next | ||
| if (next !== undefined) { | ||
| // not the most efficient thing ever but this is a pretty rare case | ||
|
|
@@ -187,10 +267,10 @@ function handleInterpolation( | |
| } | ||
| case 'string': | ||
| if (process.env.NODE_ENV !== 'production') { | ||
| const matched = [] | ||
| const matched: string[] = [] | ||
| const replaced = interpolation.replace( | ||
| animationRegex, | ||
| (match, p1, p2) => { | ||
| (_match, _p1, p2) => { | ||
| const fakeVarName = `animation${matched.length}` | ||
| matched.push( | ||
| `const ${fakeVarName} = keyframes\`${p2.replace( | ||
|
|
@@ -203,30 +283,39 @@ function handleInterpolation( | |
| ) | ||
| if (matched.length) { | ||
| console.error( | ||
| '`keyframes` output got interpolated into plain string, please wrap it with `css`.\n\n' + | ||
| 'Instead of doing this:\n\n' + | ||
| [...matched, `\`${replaced}\``].join('\n') + | ||
| '\n\nYou should wrap it with `css` like this:\n\n' + | ||
| `css\`${replaced}\`` | ||
| `\`keyframes\` output got interpolated into plain string, please wrap it with \`css\`. | ||
|
|
||
| Instead of doing this: | ||
|
|
||
| ${[...matched, `\`${replaced}\``].join('\n')} | ||
|
|
||
| You should wrap it with \`css\` like this: | ||
|
|
||
| css\`${replaced}\`` | ||
|
Comment on lines
+274
to
+282
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
| ) | ||
| } | ||
| } | ||
| break | ||
| } | ||
|
|
||
| // finalize string values (regular strings and functions interpolated into css calls) | ||
| const asString = interpolation as string | ||
danilofuchs marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if (registered == null) { | ||
| return interpolation | ||
| return asString | ||
| } | ||
| const cached = registered[interpolation] | ||
| return cached !== undefined ? cached : interpolation | ||
| const cached = registered[asString] | ||
| return cached !== undefined ? cached : asString | ||
| } | ||
|
|
||
| function createStringFromObject( | ||
| mergedProps /*: void | Object */, | ||
| registered /*: RegisteredCache | void */, | ||
| obj /*: { [key: string]: Interpolation } */ | ||
| ) /*: string */ { | ||
| function createStringFromObject<Props>( | ||
danilofuchs marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| mergedProps: Props | undefined, | ||
| registered: RegisteredCache | undefined, | ||
| obj: | ||
| | ArrayInterpolation<Props> | ||
| | CSSObject | ||
| | ComponentSelector | ||
| | TemplateStringsArray | ||
| ): string { | ||
| let string = '' | ||
|
|
||
| if (Array.isArray(obj)) { | ||
|
|
@@ -235,8 +324,12 @@ function createStringFromObject( | |
| } | ||
| } else { | ||
| for (let key in obj) { | ||
| let value = obj[key] | ||
| if (typeof value !== 'object') { | ||
| let value = (obj as any)[key] as Interpolation<Props> | ||
| if ( | ||
| typeof value === 'string' || | ||
| typeof value === 'number' || | ||
| typeof value === 'symbol' | ||
| ) { | ||
danilofuchs marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if (registered != null && registered[value] !== undefined) { | ||
| string += `${key}{${registered[value]}}` | ||
| } else if (isProcessableValue(value)) { | ||
|
|
@@ -260,7 +353,7 @@ function createStringFromObject( | |
| if (isProcessableValue(value[i])) { | ||
| string += `${processStyleName(key)}:${processStyleValue( | ||
| key, | ||
| value[i] | ||
| value[i] as string | number | ||
| )};` | ||
| } | ||
| } | ||
|
|
@@ -296,34 +389,33 @@ function createStringFromObject( | |
|
|
||
| let labelPattern = /label:\s*([^\s;\n{]+)\s*(;|$)/g | ||
|
|
||
| let sourceMapPattern | ||
| let sourceMapPattern: RegExp | undefined | ||
| if (process.env.NODE_ENV !== 'production') { | ||
| sourceMapPattern = | ||
| /\/\*#\ssourceMappingURL=data:application\/json;\S+\s+\*\//g | ||
| } | ||
|
|
||
| // this is the cursor for keyframes | ||
| // keyframes are stored on the SerializedStyles object as a linked list | ||
| let cursor | ||
| let cursor: Cursor | undefined | ||
|
|
||
| export const serializeStyles = function ( | ||
| args /*: Array<Interpolation> */, | ||
| registered /*: RegisteredCache | void */, | ||
| mergedProps /*: void | Object */ | ||
| ) /*: SerializedStyles */ { | ||
| export const serializeStyles = function <Props>( | ||
| args: Array<TemplateStringsArray | Interpolation<Props>>, | ||
| registered: RegisteredCache, | ||
| mergedProps?: Props | ||
| ): SerializedStyles { | ||
| if ( | ||
| args.length === 1 && | ||
| typeof args[0] === 'object' && | ||
| args[0] !== null && | ||
| args[0].styles !== undefined | ||
| !Array.isArray(args[0]) && | ||
| isSerializedStyles(args[0]) | ||
danilofuchs marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| ) { | ||
| return args[0] | ||
| return args[0] as SerializedStyles | ||
| } | ||
| let stringMode = true | ||
| let styles = '' | ||
|
|
||
| cursor = undefined | ||
| let strings = args[0] | ||
| let strings = args[0] as TemplateStringsArray | ||
| if (strings == null || strings.raw === undefined) { | ||
| stringMode = false | ||
| styles += handleInterpolation(mergedProps, registered, strings) | ||
|
|
@@ -345,7 +437,7 @@ export const serializeStyles = function ( | |
| } | ||
| let sourceMap | ||
|
|
||
| if (process.env.NODE_ENV !== 'production') { | ||
| if (process.env.NODE_ENV !== 'production' && sourceMapPattern !== undefined) { | ||
| styles = styles.replace(sourceMapPattern, match => { | ||
danilofuchs marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| sourceMap = match | ||
| return '' | ||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.

Uh oh!
There was an error while loading. Please reload this page.