diff --git a/.changeset/clever-clocks-yell.md b/.changeset/clever-clocks-yell.md new file mode 100644 index 0000000000..e322531102 --- /dev/null +++ b/.changeset/clever-clocks-yell.md @@ -0,0 +1,5 @@ +--- +'@emotion/unitless': minor +--- + +Source code has been migrated to TypeScript. From now on type declarations will be emitted based on that, instead of being hand-written. diff --git a/.changeset/eighty-spies-beam.md b/.changeset/eighty-spies-beam.md new file mode 100644 index 0000000000..1ac2b956ae --- /dev/null +++ b/.changeset/eighty-spies-beam.md @@ -0,0 +1,5 @@ +--- +'@emotion/css': minor +--- + +Source code has been migrated to TypeScript. From now on type declarations will be emitted based on that, instead of being hand-written. diff --git a/.changeset/healthy-elephants-serve.md b/.changeset/healthy-elephants-serve.md new file mode 100644 index 0000000000..78b7db376f --- /dev/null +++ b/.changeset/healthy-elephants-serve.md @@ -0,0 +1,5 @@ +--- +'@emotion/serialize': minor +--- + +Source code has been migrated to TypeScript. From now on type declarations will be emitted based on that, instead of being hand-written. diff --git a/.changeset/hip-moons-play.md b/.changeset/hip-moons-play.md new file mode 100644 index 0000000000..b8fc6c69c3 --- /dev/null +++ b/.changeset/hip-moons-play.md @@ -0,0 +1,5 @@ +--- +'@emotion/memoize': minor +--- + +Source code has been migrated to TypeScript. From now on type declarations will be emitted based on that, instead of being hand-written. diff --git a/.changeset/hot-yaks-flow.md b/.changeset/hot-yaks-flow.md new file mode 100644 index 0000000000..a6c9313f88 --- /dev/null +++ b/.changeset/hot-yaks-flow.md @@ -0,0 +1,5 @@ +--- +'@emotion/is-prop-valid': minor +--- + +Source code has been migrated to TypeScript. From now on type declarations will be emitted based on that, instead of being hand-written. diff --git a/.changeset/loud-hairs-approve.md b/.changeset/loud-hairs-approve.md new file mode 100644 index 0000000000..1ed791aa5c --- /dev/null +++ b/.changeset/loud-hairs-approve.md @@ -0,0 +1,5 @@ +--- +'@emotion/weak-memoize': minor +--- + +Source code has been migrated to TypeScript. From now on type declarations will be emitted based on that, instead of being hand-written. diff --git a/.changeset/lovely-zebras-admire.md b/.changeset/lovely-zebras-admire.md new file mode 100644 index 0000000000..69c62f845d --- /dev/null +++ b/.changeset/lovely-zebras-admire.md @@ -0,0 +1,5 @@ +--- +'@emotion/eslint-plugin': patch +--- + +An empty css prop (`
`) will now raise an error in the `@emotion/syntax-preference` rule instead of crashing on this case. diff --git a/.changeset/modern-penguins-play.md b/.changeset/modern-penguins-play.md new file mode 100644 index 0000000000..816b0c5a5f --- /dev/null +++ b/.changeset/modern-penguins-play.md @@ -0,0 +1,5 @@ +--- +'@emotion/eslint-plugin': minor +--- + +Source code has been migrated to TypeScript. From now on type declarations will be emitted based on that, instead of being hand-written. diff --git a/.changeset/modern-tomatoes-work.md b/.changeset/modern-tomatoes-work.md new file mode 100644 index 0000000000..0aace4bba1 --- /dev/null +++ b/.changeset/modern-tomatoes-work.md @@ -0,0 +1,5 @@ +--- +'@emotion/css': patch +--- + +Fixed `options` parameter to `createEmotion` from `@emotion/css/create-instance` incorrectly being marked as optional when it's required. diff --git a/.changeset/neat-shoes-search.md b/.changeset/neat-shoes-search.md new file mode 100644 index 0000000000..c568c40d0f --- /dev/null +++ b/.changeset/neat-shoes-search.md @@ -0,0 +1,9 @@ +--- +'@emotion/primitives-core': minor +--- + +author: @srmagura +pr: #2818 +commit: 8546dd0 + +Source code has been migrated to TypeScript so from now on type declarations will be available in the published package. diff --git a/.changeset/old-years-breathe.md b/.changeset/old-years-breathe.md new file mode 100644 index 0000000000..e0f7c880e4 --- /dev/null +++ b/.changeset/old-years-breathe.md @@ -0,0 +1,5 @@ +--- +'@emotion/utils': minor +--- + +Source code has been migrated to TypeScript. From now on type declarations will be emitted based on that, instead of being hand-written. diff --git a/.changeset/sharp-trees-smell.md b/.changeset/sharp-trees-smell.md new file mode 100644 index 0000000000..2a27ad044f --- /dev/null +++ b/.changeset/sharp-trees-smell.md @@ -0,0 +1,5 @@ +--- +'@emotion/eslint-plugin': patch +--- + +Fixed a crash on empty css prop (`
`) in the `@emotion/jsx-import` rule. diff --git a/.changeset/stale-dogs-wink.md b/.changeset/stale-dogs-wink.md new file mode 100644 index 0000000000..1e9201e248 --- /dev/null +++ b/.changeset/stale-dogs-wink.md @@ -0,0 +1,5 @@ +--- +'@emotion/hash': patch +--- + +Source code has been migrated to TypeScript. From now on type declarations will be emitted based on that, instead of being hand-written. diff --git a/.changeset/thick-tips-join.md b/.changeset/thick-tips-join.md new file mode 100644 index 0000000000..f87fd4e67f --- /dev/null +++ b/.changeset/thick-tips-join.md @@ -0,0 +1,5 @@ +--- +'@emotion/sheet': minor +--- + +Source code has been migrated to TypeScript. From now on type declarations will be emitted based on that, instead of being hand-written. diff --git a/.changeset/thirty-years-divide.md b/.changeset/thirty-years-divide.md new file mode 100644 index 0000000000..fcfd0af765 --- /dev/null +++ b/.changeset/thirty-years-divide.md @@ -0,0 +1,5 @@ +--- +'@emotion/sheet': patch +--- + +Type declaration for `StyleSheet`'s constructor has been fixed. It incorrectly was specifying that `options` were optional when in reality they weren't. diff --git a/.changeset/wet-boxes-raise.md b/.changeset/wet-boxes-raise.md new file mode 100644 index 0000000000..32c7a707c9 --- /dev/null +++ b/.changeset/wet-boxes-raise.md @@ -0,0 +1,5 @@ +--- +'@emotion/babel-plugin-jsx-pragmatic': minor +--- + +Source code has been migrated to TypeScript. From now on type declarations will be emitted based on that, instead of being hand-written. diff --git a/.eslintignore b/.eslintignore index 738ec7934d..3406ffb853 100644 --- a/.eslintignore +++ b/.eslintignore @@ -4,8 +4,4 @@ coverage/ node_modules/ stylis.min.js /demo/dist -flow-typed/ - -# This is to prevent ESLint parsing errors in the website which is written in -# TypeScript. TODO: Reenable once the codebase is converted to TypeScript. -/site/ \ No newline at end of file +/site/out \ No newline at end of file diff --git a/.flowconfig b/.flowconfig deleted file mode 100644 index d04879273d..0000000000 --- a/.flowconfig +++ /dev/null @@ -1,24 +0,0 @@ -[version] -0.128.0 - -[ignore] -.*/node_modules/config-chain/.* -.*/node_modules/styled-components/.* -.*/node_modules/graphql/.* -.*/node_modules/metro.* -.*/node_modules/@parcel/.* -.*/node_modules/resolve/.* - -[untyped] -.*/node_modules/polished/.* - - -[include] - -[libs] - -[declarations] -.*/node_modules/react-native/.* - -[options] -sharedmemory.hash_table_pow=21 diff --git a/.flowconfig-ci b/.flowconfig-ci deleted file mode 100644 index b161c6790f..0000000000 --- a/.flowconfig-ci +++ /dev/null @@ -1,25 +0,0 @@ -[version] -0.128.0 - -[ignore] -.*/node_modules/config-chain/.* -.*/node_modules/styled-components/.* -.*/node_modules/graphql/.* -.*/node_modules/metro.* -.*/node_modules/@parcel/.* -.*/node_modules/resolve/.* - -[untyped] -.*/node_modules/polished/.* - - -[include] - -[libs] - -[declarations] -.*/node_modules/react-native/.* - -[options] -server.max_workers=1 -sharedmemory.hash_table_pow=21 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 453ccbcff1..e39a445c30 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -4,6 +4,7 @@ on: push: branches: - main + - ts-migration pull_request: permissions: @@ -30,15 +31,15 @@ jobs: uses: codecov/codecov-action@v1 if: ${{ matrix.platform == 'ubuntu-latest' && always() }} - flow: - name: Flow + typescript: + name: TypeScript runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: ./.github/actions/ci-setup - name: Check Types - run: yarn flow:check + run: yarn tsc:all test_react18: name: Test React 18 @@ -70,7 +71,7 @@ jobs: - name: ESLint run: yarn lint:check - typescript: + dtslint: name: dtslint runs-on: ubuntu-latest steps: diff --git a/.gitignore b/.gitignore index 6721288e71..579f7df299 100644 --- a/.gitignore +++ b/.gitignore @@ -21,5 +21,5 @@ package-lock.json !.yarn/versions # Website -site/out -.next \ No newline at end of file +/site/out +.next diff --git a/.prettierrc.yaml b/.prettierrc.yaml index 2219cd6a40..1320c69db7 100644 --- a/.prettierrc.yaml +++ b/.prettierrc.yaml @@ -6,6 +6,3 @@ overrides: - files: 'docs/*.md' options: printWidth: 60 - - files: '*.js' - options: - parser: flow diff --git a/__mocks__/react-native.js b/__mocks__/react-native.js index 6626710208..6a8703720e 100644 --- a/__mocks__/react-native.js +++ b/__mocks__/react-native.js @@ -1,4 +1,3 @@ -// @flow /* eslint-env jest */ let components = [ diff --git a/__mocks__/react-primitives.js b/__mocks__/react-primitives.js index 83501e4778..80ff2af8b2 100644 --- a/__mocks__/react-primitives.js +++ b/__mocks__/react-primitives.js @@ -1,2 +1 @@ -// @flow export * from 'react-primitives/lib/index.web' diff --git a/babel.config.js b/babel.config.js index 05e09be180..5010931b43 100644 --- a/babel.config.js +++ b/babel.config.js @@ -10,7 +10,7 @@ let isTestFile = filename => module.exports = api => { api.cache(true) return { - presets: ['babel-preset-emotion-dev'], + presets: ['babel-preset-emotion-dev', '@babel/preset-typescript'], overrides: [ { test: filename => diff --git a/docs/docs.yaml b/docs/docs.yaml index 199c46e151..73aa90f147 100644 --- a/docs/docs.yaml +++ b/docs/docs.yaml @@ -32,7 +32,6 @@ - source-maps - testing - typescript - - flow - eslint-plugin-react # This loads the READMEs instead of files in docs/ diff --git a/docs/flow.mdx b/docs/flow.mdx deleted file mode 100644 index 60ccc5579e..0000000000 --- a/docs/flow.mdx +++ /dev/null @@ -1,115 +0,0 @@ ---- -title: 'Flow' ---- - -Emotion is built with Flow, so it exports type definitions for most of its packages, -including `@emotion/styled`. - -## @emotion/styled - -The styled package can be used to define styled components in two ways, by calling `styled()`, -or by using the `styled.*` shortcuts. - -Unfortunately, Flow doesn't currently support generic types on tagged templates, this means if -you'd like to explictly type a styled component props, you will have to use one of the following -alternatives: - -```jsx -import styled from '@emotion/styled' - -// Option A -const A = styled('div')` - color: red; -` - -// Option B -const B = styled.div({ - color: 'red', -}) -``` - -Styled components are annotated the same way normal React components are: - -```jsx -import styled from '@emotion/styled' - -type Props = { a: string } -const Link = styled('a')` - color: red; -` - -const App = () => Click me -``` - -Just like for normal React components, you don't need to provide type annotations -for your styled components if you don't plan to export them from your module: - -```jsx -import styled from '@emotion/styled' - -const Internal = styled.div` - color: red; -` -``` - -Be aware, Flow infers the return type of your components by referencing their return type, -this means you will need to annotate the properties of the root component in the case below: - -```jsx - -const Container = styled.div` - ^^^^^^^^^^^ Missing type annotation for P. P is a type parameter declared in function type [1] and was implicitly instantiated at -encaps tag [2]. - color: red; -` - -export const App = () => -``` - -You can use `React$ElementConfig` to obtain the props type of a HTML tag, or of -any existing React component: - -```jsx -import type { ElementConfig } from 'react' - -type Props = ElementConfig<'div'> -const Container = styled('div')` - color: red; -` - -export const App = () => -``` - - -```jsx -import type { ElementConfig } from 'react' -import styled from '@emotion/styled' - -const Container = styled>('div')` - background-color: yellow; -` - -const App = () => ( - {() => 10} - ^^^^^^^^^^ Cannot create Container element because in property children: - • Either inexact function [1] is incompatible with exact React.Element [2]. - • Or function [1] is incompatible with React.Portal [3]. - • Or property @@iterator is missing in function [1] but exists in $Iterable [4]. -) -``` - -Alternatively, you can define the return type of your component, so that -Flow doesn't need to infer it reading the props type of the internal component: - -```jsx -import type { Node } from 'react' - -const Container = styled.div` - color: red; -` - -export const App = (): Node => -``` - - - diff --git a/flow-typed/npm/gatsby_vx.x.x.js b/flow-typed/npm/gatsby_vx.x.x.js deleted file mode 100644 index 776c5a9805..0000000000 --- a/flow-typed/npm/gatsby_vx.x.x.js +++ /dev/null @@ -1,20 +0,0 @@ -// flow-typed signature: 47a1ce76579bcf60e33bc03fcf5c8762 -// flow-typed version: <>/gatsby_v^1.9.100/flow_v0.59.0 - -/** - * This is an autogenerated libdef stub for: - * - * 'gatsby' - * - * Fill this stub out by replacing all the `any` types. - * - * Once filled out, we encourage you to share your work with the - * community by sending a pull request to: - * https://github.com/flowtype/flow-typed - */ - -declare module 'gatsby' { - declare module.exports: any -} -// eslint-disable-next-line no-unused-vars -declare var graphql: Function diff --git a/flow-typed/npm/jest-glamor-react_vx.x.x.js b/flow-typed/npm/jest-glamor-react_vx.x.x.js deleted file mode 100644 index 357758973f..0000000000 --- a/flow-typed/npm/jest-glamor-react_vx.x.x.js +++ /dev/null @@ -1,24 +0,0 @@ -// flow-typed signature: 22afe792d07ce86b99954c5d2a83c46e -// flow-typed version: <>/jest-glamor-react_v^3.1.1/flow_v0.59.0 - -/** - * This is an autogenerated libdef stub for: - * - * 'jest-glamor-react' - * - * Fill this stub out by replacing all the `any` types. - * - * Once filled out, we encourage you to share your work with the - * community by sending a pull request to: - * https://github.com/flowtype/flow-typed - */ - -import type { JestSnapshotSerializer } from 'jest' - -interface GlamorStyleSheet { - tags: Array; -} -declare module 'jest-glamor-react' { - declare module.exports: JestSnapshotSerializer & - ((sheet: GlamorStyleSheet) => JestSnapshotSerializer) -} diff --git a/flow-typed/npm/jest_v25.x.x.js b/flow-typed/npm/jest_v25.x.x.js deleted file mode 100644 index 36734ca194..0000000000 --- a/flow-typed/npm/jest_v25.x.x.js +++ /dev/null @@ -1,1212 +0,0 @@ -// flow-typed signature: a0fbdb22ab391eceafc1d5643528e257 -// flow-typed version: dd2428a21d/jest_v25.x.x/flow_>=v0.104.x - -type JestMockFn, TReturn> = { - (...args: TArguments): TReturn, - /** - * An object for introspecting mock calls - */ - mock: { - /** - * An array that represents all calls that have been made into this mock - * function. Each call is represented by an array of arguments that were - * passed during the call. - */ - calls: Array, - /** - * An array that contains all the object instances that have been - * instantiated from this mock function. - */ - instances: Array, - /** - * An array that contains all the object results that have been - * returned by this mock function call - */ - results: Array<{ - isThrow: boolean, - value: TReturn, - ... - }>, - ... - }, - /** - * Resets all information stored in the mockFn.mock.calls and - * mockFn.mock.instances arrays. Often this is useful when you want to clean - * up a mock's usage data between two assertions. - */ - mockClear(): void, - /** - * Resets all information stored in the mock. This is useful when you want to - * completely restore a mock back to its initial state. - */ - mockReset(): void, - /** - * Removes the mock and restores the initial implementation. This is useful - * when you want to mock functions in certain test cases and restore the - * original implementation in others. Beware that mockFn.mockRestore only - * works when mock was created with jest.spyOn. Thus you have to take care of - * restoration yourself when manually assigning jest.fn(). - */ - mockRestore(): void, - /** - * Accepts a function that should be used as the implementation of the mock. - * The mock itself will still record all calls that go into and instances - * that come from itself -- the only difference is that the implementation - * will also be executed when the mock is called. - */ - mockImplementation( - fn: (...args: TArguments) => TReturn - ): JestMockFn, - /** - * Accepts a function that will be used as an implementation of the mock for - * one call to the mocked function. Can be chained so that multiple function - * calls produce different results. - */ - mockImplementationOnce( - fn: (...args: TArguments) => TReturn - ): JestMockFn, - /** - * Accepts a string to use in test result output in place of "jest.fn()" to - * indicate which mock function is being referenced. - */ - mockName(name: string): JestMockFn, - /** - * Just a simple sugar function for returning `this` - */ - mockReturnThis(): void, - /** - * Accepts a value that will be returned whenever the mock function is called. - */ - mockReturnValue(value: TReturn): JestMockFn, - /** - * Sugar for only returning a value once inside your mock - */ - mockReturnValueOnce(value: TReturn): JestMockFn, - /** - * Sugar for jest.fn().mockImplementation(() => Promise.resolve(value)) - */ - mockResolvedValue(value: TReturn): JestMockFn>, - /** - * Sugar for jest.fn().mockImplementationOnce(() => Promise.resolve(value)) - */ - mockResolvedValueOnce( - value: TReturn - ): JestMockFn>, - /** - * Sugar for jest.fn().mockImplementation(() => Promise.reject(value)) - */ - mockRejectedValue(value: TReturn): JestMockFn>, - /** - * Sugar for jest.fn().mockImplementationOnce(() => Promise.reject(value)) - */ - mockRejectedValueOnce(value: TReturn): JestMockFn>, - ... -} - -type JestAsymmetricEqualityType = { - /** - * A custom Jasmine equality tester - */ - asymmetricMatch(value: mixed): boolean, - ... -} - -type JestCallsType = { - allArgs(): mixed, - all(): mixed, - any(): boolean, - count(): number, - first(): mixed, - mostRecent(): mixed, - reset(): void, - ... -} - -type JestClockType = { - install(): void, - mockDate(date: Date): void, - tick(milliseconds?: number): void, - uninstall(): void, - ... -} - -type JestMatcherResult = { - message?: string | (() => string), - pass: boolean, - ... -} - -type JestMatcher = ( - received: any, - ...actual: Array -) => JestMatcherResult | Promise - -type JestPromiseType = { - /** - * Use rejects to unwrap the reason of a rejected promise so any other - * matcher can be chained. If the promise is fulfilled the assertion fails. - */ - rejects: JestExpectType, - /** - * Use resolves to unwrap the value of a fulfilled promise so any other - * matcher can be chained. If the promise is rejected the assertion fails. - */ - resolves: JestExpectType, - ... -} - -/** - * Jest allows functions and classes to be used as test names in test() and - * describe() - */ -type JestTestName = string | Function - -/** - * Plugin: jest-styled-components - */ - -type JestStyledComponentsMatcherValue = - | string - | JestAsymmetricEqualityType - | RegExp - | typeof undefined - -type JestStyledComponentsMatcherOptions = { - media?: string, - modifier?: string, - supports?: string, - ... -} - -type JestStyledComponentsMatchersType = { - toHaveStyleRule( - property: string, - value: JestStyledComponentsMatcherValue, - options?: JestStyledComponentsMatcherOptions - ): void, - ... -} - -/** - * Plugin: jest-enzyme - */ -type EnzymeMatchersType = { - // 5.x - toBeEmpty(): void, - toBePresent(): void, - // 6.x - toBeChecked(): void, - toBeDisabled(): void, - toBeEmptyRender(): void, - toContainMatchingElement(selector: string): void, - toContainMatchingElements(n: number, selector: string): void, - toContainExactlyOneMatchingElement(selector: string): void, - toContainReact(element: React$Element): void, - toExist(): void, - toHaveClassName(className: string): void, - toHaveHTML(html: string): void, - toHaveProp: ((propKey: string, propValue?: any) => void) & - ((props: { ... }) => void), - toHaveRef(refName: string): void, - toHaveState: ((stateKey: string, stateValue?: any) => void) & - ((state: { ... }) => void), - toHaveStyle: ((styleKey: string, styleValue?: any) => void) & - ((style: { ... }) => void), - toHaveTagName(tagName: string): void, - toHaveText(text: string): void, - toHaveValue(value: any): void, - toIncludeText(text: string): void, - toMatchElement( - element: React$Element, - options?: {| ignoreProps?: boolean, verbose?: boolean |} - ): void, - toMatchSelector(selector: string): void, - // 7.x - toHaveDisplayName(name: string): void, - ... -} - -// DOM testing library extensions (jest-dom) -// https://github.com/testing-library/jest-dom -type DomTestingLibraryType = { - /** - * @deprecated - */ - toBeInTheDOM(container?: HTMLElement): void, - toBeInTheDocument(): void, - toBeVisible(): void, - toBeEmpty(): void, - toBeDisabled(): void, - toBeEnabled(): void, - toBeInvalid(): void, - toBeRequired(): void, - toBeValid(): void, - toContainElement(element: HTMLElement | null): void, - toContainHTML(htmlText: string): void, - toHaveAttribute(attr: string, value?: any): void, - toHaveClass(...classNames: string[]): void, - toHaveFocus(): void, - toHaveFormValues(expectedValues: { [name: string]: any, ... }): void, - toHaveStyle(css: string): void, - toHaveTextContent( - text: string | RegExp, - options?: { normalizeWhitespace: boolean, ... } - ): void, - toHaveValue(value?: string | string[] | number): void, - ... -} - -// Jest JQuery Matchers: https://github.com/unindented/custom-jquery-matchers -type JestJQueryMatchersType = { - toExist(): void, - toHaveLength(len: number): void, - toHaveId(id: string): void, - toHaveClass(className: string): void, - toHaveTag(tag: string): void, - toHaveAttr(key: string, val?: any): void, - toHaveProp(key: string, val?: any): void, - toHaveText(text: string | RegExp): void, - toHaveData(key: string, val?: any): void, - toHaveValue(val: any): void, - toHaveCss(css: { [key: string]: any, ... }): void, - toBeChecked(): void, - toBeDisabled(): void, - toBeEmpty(): void, - toBeHidden(): void, - toBeSelected(): void, - toBeVisible(): void, - toBeFocused(): void, - toBeInDom(): void, - toBeMatchedBy(sel: string): void, - toHaveDescendant(sel: string): void, - toHaveDescendantWithText(sel: string, text: string | RegExp): void, - ... -} - -// Jest Extended Matchers: https://github.com/jest-community/jest-extended -type JestExtendedMatchersType = { - /** - * Note: Currently unimplemented - * Passing assertion - * - * @param {String} message - */ - // pass(message: string): void; - - /** - * Note: Currently unimplemented - * Failing assertion - * - * @param {String} message - */ - // fail(message: string): void; - - /** - * Use .toBeEmpty when checking if a String '', Array [] or Object {} is empty. - */ - toBeEmpty(): void, - /** - * Use .toBeOneOf when checking if a value is a member of a given Array. - * @param {Array.<*>} members - */ - toBeOneOf(members: any[]): void, - /** - * Use `.toBeNil` when checking a value is `null` or `undefined`. - */ - toBeNil(): void, - /** - * Use `.toSatisfy` when you want to use a custom matcher by supplying a predicate function that returns a `Boolean`. - * @param {Function} predicate - */ - toSatisfy(predicate: (n: any) => boolean): void, - /** - * Use `.toBeArray` when checking if a value is an `Array`. - */ - toBeArray(): void, - /** - * Use `.toBeArrayOfSize` when checking if a value is an `Array` of size x. - * @param {Number} x - */ - toBeArrayOfSize(x: number): void, - /** - * Use `.toIncludeAllMembers` when checking if an `Array` contains all of the same members of a given set. - * @param {Array.<*>} members - */ - toIncludeAllMembers(members: any[]): void, - /** - * Use `.toIncludeAnyMembers` when checking if an `Array` contains any of the members of a given set. - * @param {Array.<*>} members - */ - toIncludeAnyMembers(members: any[]): void, - /** - * Use `.toSatisfyAll` when you want to use a custom matcher by supplying a predicate function that returns a `Boolean` for all values in an array. - * @param {Function} predicate - */ - toSatisfyAll(predicate: (n: any) => boolean): void, - /** - * Use `.toBeBoolean` when checking if a value is a `Boolean`. - */ - toBeBoolean(): void, - /** - * Use `.toBeTrue` when checking a value is equal (===) to `true`. - */ - toBeTrue(): void, - /** - * Use `.toBeFalse` when checking a value is equal (===) to `false`. - */ - toBeFalse(): void, - /** - * Use .toBeDate when checking if a value is a Date. - */ - toBeDate(): void, - /** - * Use `.toBeFunction` when checking if a value is a `Function`. - */ - toBeFunction(): void, - /** - * Use `.toHaveBeenCalledBefore` when checking if a `Mock` was called before another `Mock`. - * - * Note: Required Jest version >22 - * Note: Your mock functions will have to be asynchronous to cause the timestamps inside of Jest to occur in a differentJS event loop, otherwise the mock timestamps will all be the same - * - * @param {Mock} mock - */ - toHaveBeenCalledBefore(mock: JestMockFn): void, - /** - * Use `.toBeNumber` when checking if a value is a `Number`. - */ - toBeNumber(): void, - /** - * Use `.toBeNaN` when checking a value is `NaN`. - */ - toBeNaN(): void, - /** - * Use `.toBeFinite` when checking if a value is a `Number`, not `NaN` or `Infinity`. - */ - toBeFinite(): void, - /** - * Use `.toBePositive` when checking if a value is a positive `Number`. - */ - toBePositive(): void, - /** - * Use `.toBeNegative` when checking if a value is a negative `Number`. - */ - toBeNegative(): void, - /** - * Use `.toBeEven` when checking if a value is an even `Number`. - */ - toBeEven(): void, - /** - * Use `.toBeOdd` when checking if a value is an odd `Number`. - */ - toBeOdd(): void, - /** - * Use `.toBeWithin` when checking if a number is in between the given bounds of: start (inclusive) and end (exclusive). - * - * @param {Number} start - * @param {Number} end - */ - toBeWithin(start: number, end: number): void, - /** - * Use `.toBeObject` when checking if a value is an `Object`. - */ - toBeObject(): void, - /** - * Use `.toContainKey` when checking if an object contains the provided key. - * - * @param {String} key - */ - toContainKey(key: string): void, - /** - * Use `.toContainKeys` when checking if an object has all of the provided keys. - * - * @param {Array.} keys - */ - toContainKeys(keys: string[]): void, - /** - * Use `.toContainAllKeys` when checking if an object only contains all of the provided keys. - * - * @param {Array.} keys - */ - toContainAllKeys(keys: string[]): void, - /** - * Use `.toContainAnyKeys` when checking if an object contains at least one of the provided keys. - * - * @param {Array.} keys - */ - toContainAnyKeys(keys: string[]): void, - /** - * Use `.toContainValue` when checking if an object contains the provided value. - * - * @param {*} value - */ - toContainValue(value: any): void, - /** - * Use `.toContainValues` when checking if an object contains all of the provided values. - * - * @param {Array.<*>} values - */ - toContainValues(values: any[]): void, - /** - * Use `.toContainAllValues` when checking if an object only contains all of the provided values. - * - * @param {Array.<*>} values - */ - toContainAllValues(values: any[]): void, - /** - * Use `.toContainAnyValues` when checking if an object contains at least one of the provided values. - * - * @param {Array.<*>} values - */ - toContainAnyValues(values: any[]): void, - /** - * Use `.toContainEntry` when checking if an object contains the provided entry. - * - * @param {Array.} entry - */ - toContainEntry(entry: [string, string]): void, - /** - * Use `.toContainEntries` when checking if an object contains all of the provided entries. - * - * @param {Array.>} entries - */ - toContainEntries(entries: [string, string][]): void, - /** - * Use `.toContainAllEntries` when checking if an object only contains all of the provided entries. - * - * @param {Array.>} entries - */ - toContainAllEntries(entries: [string, string][]): void, - /** - * Use `.toContainAnyEntries` when checking if an object contains at least one of the provided entries. - * - * @param {Array.>} entries - */ - toContainAnyEntries(entries: [string, string][]): void, - /** - * Use `.toBeExtensible` when checking if an object is extensible. - */ - toBeExtensible(): void, - /** - * Use `.toBeFrozen` when checking if an object is frozen. - */ - toBeFrozen(): void, - /** - * Use `.toBeSealed` when checking if an object is sealed. - */ - toBeSealed(): void, - /** - * Use `.toBeString` when checking if a value is a `String`. - */ - toBeString(): void, - /** - * Use `.toEqualCaseInsensitive` when checking if a string is equal (===) to another ignoring the casing of both strings. - * - * @param {String} string - */ - toEqualCaseInsensitive(string: string): void, - /** - * Use `.toStartWith` when checking if a `String` starts with a given `String` prefix. - * - * @param {String} prefix - */ - toStartWith(prefix: string): void, - /** - * Use `.toEndWith` when checking if a `String` ends with a given `String` suffix. - * - * @param {String} suffix - */ - toEndWith(suffix: string): void, - /** - * Use `.toInclude` when checking if a `String` includes the given `String` substring. - * - * @param {String} substring - */ - toInclude(substring: string): void, - /** - * Use `.toIncludeRepeated` when checking if a `String` includes the given `String` substring the correct number of times. - * - * @param {String} substring - * @param {Number} times - */ - toIncludeRepeated(substring: string, times: number): void, - /** - * Use `.toIncludeMultiple` when checking if a `String` includes all of the given substrings. - * - * @param {Array.} substring - */ - toIncludeMultiple(substring: string[]): void, - ... -} - -// Diffing snapshot utility for Jest (snapshot-diff) -// https://github.com/jest-community/snapshot-diff -type SnapshotDiffType = { - /** - * Compare the difference between the actual in the `expect()` - * vs the object inside `valueB` with some extra options. - */ - toMatchDiffSnapshot( - valueB: any, - options?: {| - expand?: boolean, - colors?: boolean, - contextLines?: number, - stablePatchmarks?: boolean, - aAnnotation?: string, - bAnnotation?: string - |}, - testName?: string - ): void, - ... -} - -interface JestExpectType { - not: JestExpectType & - EnzymeMatchersType & - DomTestingLibraryType & - JestJQueryMatchersType & - JestStyledComponentsMatchersType & - JestExtendedMatchersType & - SnapshotDiffType; - /** - * If you have a mock function, you can use .lastCalledWith to test what - * arguments it was last called with. - */ - lastCalledWith(...args: Array): void; - /** - * toBe just checks that a value is what you expect. It uses === to check - * strict equality. - */ - toBe(value: any): void; - /** - * Use .toBeCalledWith to ensure that a mock function was called with - * specific arguments. - */ - toBeCalledWith(...args: Array): void; - /** - * Using exact equality with floating point numbers is a bad idea. Rounding - * means that intuitive things fail. - */ - toBeCloseTo(num: number, delta: any): void; - /** - * Use .toBeDefined to check that a variable is not undefined. - */ - toBeDefined(): void; - /** - * Use .toBeFalsy when you don't care what a value is, you just want to - * ensure a value is false in a boolean context. - */ - toBeFalsy(): void; - /** - * To compare floating point numbers, you can use toBeGreaterThan. - */ - toBeGreaterThan(number: number): void; - /** - * To compare floating point numbers, you can use toBeGreaterThanOrEqual. - */ - toBeGreaterThanOrEqual(number: number): void; - /** - * To compare floating point numbers, you can use toBeLessThan. - */ - toBeLessThan(number: number): void; - /** - * To compare floating point numbers, you can use toBeLessThanOrEqual. - */ - toBeLessThanOrEqual(number: number): void; - /** - * Use .toBeInstanceOf(Class) to check that an object is an instance of a - * class. - */ - toBeInstanceOf(cls: Class<*>): void; - /** - * .toBeNull() is the same as .toBe(null) but the error messages are a bit - * nicer. - */ - toBeNull(): void; - /** - * Use .toBeTruthy when you don't care what a value is, you just want to - * ensure a value is true in a boolean context. - */ - toBeTruthy(): void; - /** - * Use .toBeUndefined to check that a variable is undefined. - */ - toBeUndefined(): void; - /** - * Use .toContain when you want to check that an item is in a list. For - * testing the items in the list, this uses ===, a strict equality check. - */ - toContain(item: any): void; - /** - * Use .toContainEqual when you want to check that an item is in a list. For - * testing the items in the list, this matcher recursively checks the - * equality of all fields, rather than checking for object identity. - */ - toContainEqual(item: any): void; - /** - * Use .toEqual when you want to check that two objects have the same value. - * This matcher recursively checks the equality of all fields, rather than - * checking for object identity. - */ - toEqual(value: any): void; - /** - * Use .toHaveBeenCalled to ensure that a mock function got called. - */ - toHaveBeenCalled(): void; - toBeCalled(): void; - /** - * Use .toHaveBeenCalledTimes to ensure that a mock function got called exact - * number of times. - */ - toHaveBeenCalledTimes(number: number): void; - toBeCalledTimes(number: number): void; - /** - * - */ - toHaveBeenNthCalledWith(nthCall: number, ...args: Array): void; - nthCalledWith(nthCall: number, ...args: Array): void; - /** - * - */ - toHaveReturned(): void; - toReturn(): void; - /** - * - */ - toHaveReturnedTimes(number: number): void; - toReturnTimes(number: number): void; - /** - * - */ - toHaveReturnedWith(value: any): void; - toReturnWith(value: any): void; - /** - * - */ - toHaveLastReturnedWith(value: any): void; - lastReturnedWith(value: any): void; - /** - * - */ - toHaveNthReturnedWith(nthCall: number, value: any): void; - nthReturnedWith(nthCall: number, value: any): void; - /** - * Use .toHaveBeenCalledWith to ensure that a mock function was called with - * specific arguments. - */ - toHaveBeenCalledWith(...args: Array): void; - toBeCalledWith(...args: Array): void; - /** - * Use .toHaveBeenLastCalledWith to ensure that a mock function was last called - * with specific arguments. - */ - toHaveBeenLastCalledWith(...args: Array): void; - lastCalledWith(...args: Array): void; - /** - * Check that an object has a .length property and it is set to a certain - * numeric value. - */ - toHaveLength(number: number): void; - /** - * - */ - toHaveProperty(propPath: string | $ReadOnlyArray, value?: any): void; - /** - * Use .toMatch to check that a string matches a regular expression or string. - */ - toMatch(regexpOrString: RegExp | string): void; - /** - * Use .toMatchObject to check that a javascript object matches a subset of the properties of an object. - */ - toMatchObject(object: Object | Array): void; - /** - * Use .toStrictEqual to check that a javascript object matches a subset of the properties of an object. - */ - toStrictEqual(value: any): void; - /** - * This ensures that an Object matches the most recent snapshot. - */ - toMatchSnapshot(propertyMatchers?: any, name?: string): void; - /** - * This ensures that an Object matches the most recent snapshot. - */ - toMatchSnapshot(name: string): void; - - toMatchInlineSnapshot(snapshot?: string): void; - toMatchInlineSnapshot(propertyMatchers?: any, snapshot?: string): void; - /** - * Use .toThrow to test that a function throws when it is called. - * If you want to test that a specific error gets thrown, you can provide an - * argument to toThrow. The argument can be a string for the error message, - * a class for the error, or a regex that should match the error. - * - * Alias: .toThrowError - */ - toThrow(message?: string | Error | Class | RegExp): void; - toThrowError(message?: string | Error | Class | RegExp): void; - /** - * Use .toThrowErrorMatchingSnapshot to test that a function throws a error - * matching the most recent snapshot when it is called. - */ - toThrowErrorMatchingSnapshot(): void; - toThrowErrorMatchingInlineSnapshot(snapshot?: string): void; -} - -type JestObjectType = { - /** - * Disables automatic mocking in the module loader. - * - * After this method is called, all `require()`s will return the real - * versions of each module (rather than a mocked version). - */ - disableAutomock(): JestObjectType, - /** - * An un-hoisted version of disableAutomock - */ - autoMockOff(): JestObjectType, - /** - * Enables automatic mocking in the module loader. - */ - enableAutomock(): JestObjectType, - /** - * An un-hoisted version of enableAutomock - */ - autoMockOn(): JestObjectType, - /** - * Clears the mock.calls and mock.instances properties of all mocks. - * Equivalent to calling .mockClear() on every mocked function. - */ - clearAllMocks(): JestObjectType, - /** - * Resets the state of all mocks. Equivalent to calling .mockReset() on every - * mocked function. - */ - resetAllMocks(): JestObjectType, - /** - * Restores all mocks back to their original value. - */ - restoreAllMocks(): JestObjectType, - /** - * Removes any pending timers from the timer system. - */ - clearAllTimers(): void, - /** - * Returns the number of fake timers still left to run. - */ - getTimerCount(): number, - /** - * The same as `mock` but not moved to the top of the expectation by - * babel-jest. - */ - doMock(moduleName: string, moduleFactory?: any): JestObjectType, - /** - * The same as `unmock` but not moved to the top of the expectation by - * babel-jest. - */ - dontMock(moduleName: string): JestObjectType, - /** - * Returns a new, unused mock function. Optionally takes a mock - * implementation. - */ - fn, TReturn>( - implementation?: (...args: TArguments) => TReturn - ): JestMockFn, - /** - * Determines if the given function is a mocked function. - */ - isMockFunction(fn: Function): boolean, - /** - * Given the name of a module, use the automatic mocking system to generate a - * mocked version of the module for you. - */ - genMockFromModule(moduleName: string): any, - /** - * Mocks a module with an auto-mocked version when it is being required. - * - * The second argument can be used to specify an explicit module factory that - * is being run instead of using Jest's automocking feature. - * - * The third argument can be used to create virtual mocks -- mocks of modules - * that don't exist anywhere in the system. - */ - mock( - moduleName: string, - moduleFactory?: any, - options?: Object - ): JestObjectType, - /** - * Returns the actual module instead of a mock, bypassing all checks on - * whether the module should receive a mock implementation or not. - */ - requireActual(moduleName: string): any, - /** - * Returns a mock module instead of the actual module, bypassing all checks - * on whether the module should be required normally or not. - */ - requireMock(moduleName: string): any, - /** - * Resets the module registry - the cache of all required modules. This is - * useful to isolate modules where local state might conflict between tests. - */ - resetModules(): JestObjectType, - /** - * Creates a sandbox registry for the modules that are loaded inside the - * callback function. This is useful to isolate specific modules for every - * test so that local module state doesn't conflict between tests. - */ - isolateModules(fn: () => void): JestObjectType, - /** - * Exhausts the micro-task queue (usually interfaced in node via - * process.nextTick). - */ - runAllTicks(): void, - /** - * Exhausts the macro-task queue (i.e., all tasks queued by setTimeout(), - * setInterval(), and setImmediate()). - */ - runAllTimers(): void, - /** - * Exhausts all tasks queued by setImmediate(). - */ - runAllImmediates(): void, - /** - * Executes only the macro task queue (i.e. all tasks queued by setTimeout() - * or setInterval() and setImmediate()). - */ - advanceTimersByTime(msToRun: number): void, - /** - * Executes only the macro task queue (i.e. all tasks queued by setTimeout() - * or setInterval() and setImmediate()). - * - * Renamed to `advanceTimersByTime`. - */ - runTimersToTime(msToRun: number): void, - /** - * Executes only the macro-tasks that are currently pending (i.e., only the - * tasks that have been queued by setTimeout() or setInterval() up to this - * point) - */ - runOnlyPendingTimers(): void, - /** - * Explicitly supplies the mock object that the module system should return - * for the specified module. Note: It is recommended to use jest.mock() - * instead. - */ - setMock(moduleName: string, moduleExports: any): JestObjectType, - /** - * Indicates that the module system should never return a mocked version of - * the specified module from require() (e.g. that it should always return the - * real module). - */ - unmock(moduleName: string): JestObjectType, - /** - * Instructs Jest to use fake versions of the standard timer functions - * (setTimeout, setInterval, clearTimeout, clearInterval, nextTick, - * setImmediate and clearImmediate). - */ - useFakeTimers(): JestObjectType, - /** - * Instructs Jest to use the real versions of the standard timer functions. - */ - useRealTimers(): JestObjectType, - /** - * Creates a mock function similar to jest.fn but also tracks calls to - * object[methodName]. - */ - spyOn( - object: Object, - methodName: string, - accessType?: 'get' | 'set' - ): JestMockFn, - /** - * Set the default timeout interval for tests and before/after hooks in milliseconds. - * Note: The default timeout interval is 5 seconds if this method is not called. - */ - setTimeout(timeout: number): JestObjectType, - ... -} - -type JestSpyType = { calls: JestCallsType, ... } - -type JestDoneFn = {| - (): void, - fail: (error: Error) => void -|} - -/** Runs this function after every test inside this context */ -declare function afterEach( - fn: (done: JestDoneFn) => ?Promise, - timeout?: number -): void -/** Runs this function before every test inside this context */ -declare function beforeEach( - fn: (done: JestDoneFn) => ?Promise, - timeout?: number -): void -/** Runs this function after all tests have finished inside this context */ -declare function afterAll( - fn: (done: JestDoneFn) => ?Promise, - timeout?: number -): void -/** Runs this function before any tests have started inside this context */ -declare function beforeAll( - fn: (done: JestDoneFn) => ?Promise, - timeout?: number -): void - -/** A context for grouping tests together */ -declare var describe: { - /** - * Creates a block that groups together several related tests in one "test suite" - */ - (name: JestTestName, fn: () => void): void, - /** - * Only run this describe block - */ - only(name: JestTestName, fn: () => void): void, - /** - * Skip running this describe block - */ - skip(name: JestTestName, fn: () => void): void, - /** - * each runs this test against array of argument arrays per each run - * - * @param {table} table of Test - */ - each( - ...table: Array | mixed> | [Array, string] - ): ( - name: JestTestName, - fn?: (...args: Array) => ?Promise, - timeout?: number - ) => void, - ... -} - -/** An individual test unit */ -declare var it: { - /** - * An individual test unit - * - * @param {JestTestName} Name of Test - * @param {Function} Test - * @param {number} Timeout for the test, in milliseconds. - */ - ( - name: JestTestName, - fn?: (done: JestDoneFn) => ?Promise, - timeout?: number - ): void, - /** - * Only run this test - * - * @param {JestTestName} Name of Test - * @param {Function} Test - * @param {number} Timeout for the test, in milliseconds. - */ - only: {| - ( - name: JestTestName, - fn?: (done: JestDoneFn) => ?Promise, - timeout?: number - ): void, - each( - ...table: Array | mixed> | [Array, string] - ): ( - name: JestTestName, - fn?: (...args: Array) => ?Promise, - timeout?: number - ) => void - |}, - /** - * Skip running this test - * - * @param {JestTestName} Name of Test - * @param {Function} Test - * @param {number} Timeout for the test, in milliseconds. - */ - skip( - name: JestTestName, - fn?: (done: JestDoneFn) => ?Promise, - timeout?: number - ): void, - /** - * Highlight planned tests in the summary output - * - * @param {String} Name of Test to do - */ - todo(name: string): void, - /** - * Run the test concurrently - * - * @param {JestTestName} Name of Test - * @param {Function} Test - * @param {number} Timeout for the test, in milliseconds. - */ - concurrent( - name: JestTestName, - fn?: (done: JestDoneFn) => ?Promise, - timeout?: number - ): void, - /** - * each runs this test against array of argument arrays per each run - * - * @param {table} table of Test - */ - each( - ...table: Array | mixed> | [Array, string] - ): ( - name: JestTestName, - fn?: (...args: Array) => ?Promise, - timeout?: number - ) => void, - ... -} - -declare function fit( - name: JestTestName, - fn: (done: JestDoneFn) => ?Promise, - timeout?: number -): void -/** An individual test unit */ -declare var test: typeof it -/** A disabled group of tests */ -declare var xdescribe: typeof describe -/** A focused group of tests */ -declare var fdescribe: typeof describe -/** A disabled individual test */ -declare var xit: typeof it -/** A disabled individual test */ -declare var xtest: typeof it - -type JestPrettyFormatColors = { - comment: { - close: string, - open: string, - ... - }, - content: { - close: string, - open: string, - ... - }, - prop: { - close: string, - open: string, - ... - }, - tag: { - close: string, - open: string, - ... - }, - value: { - close: string, - open: string, - ... - }, - ... -} - -type JestPrettyFormatIndent = string => string -type JestPrettyFormatRefs = Array -type JestPrettyFormatPrint = any => string -type JestPrettyFormatStringOrNull = string | null - -type JestPrettyFormatOptions = {| - callToJSON: boolean, - edgeSpacing: string, - escapeRegex: boolean, - highlight: boolean, - indent: number, - maxDepth: number, - min: boolean, - plugins: JestPrettyFormatPlugins, - printFunctionName: boolean, - spacing: string, - theme: {| - comment: string, - content: string, - prop: string, - tag: string, - value: string - |} -|} - -type JestPrettyFormatPlugin = { - print: ( - val: any, - serialize: JestPrettyFormatPrint, - indent: JestPrettyFormatIndent, - opts: JestPrettyFormatOptions, - colors: JestPrettyFormatColors - ) => string, - test: any => boolean, - ... -} - -type JestPrettyFormatPlugins = Array - -/** The expect function is used every time you want to test a value */ -declare var expect: { - /** The object that you want to make assertions against */ - ( - value: any - ): JestExpectType & - JestPromiseType & - EnzymeMatchersType & - DomTestingLibraryType & - JestJQueryMatchersType & - JestStyledComponentsMatchersType & - JestExtendedMatchersType & - SnapshotDiffType, - /** Add additional Jasmine matchers to Jest's roster */ - extend(matchers: { [name: string]: JestMatcher, ... }): void, - /** Add a module that formats application-specific data structures. */ - addSnapshotSerializer(pluginModule: JestPrettyFormatPlugin): void, - assertions(expectedAssertions: number): void, - hasAssertions(): void, - any(value: mixed): JestAsymmetricEqualityType, - anything(): any, - arrayContaining(value: Array): Array, - objectContaining(value: Object): Object, - /** Matches any received string that contains the exact expected string. */ - stringContaining(value: string): string, - stringMatching(value: string | RegExp): string, - not: { - arrayContaining: (value: $ReadOnlyArray) => Array, - objectContaining: (value: { ... }) => Object, - stringContaining: (value: string) => string, - stringMatching: (value: string | RegExp) => string, - ... - }, - ... -} - -// TODO handle return type -// http://jasmine.github.io/2.4/introduction.html#section-Spies -declare function spyOn(value: mixed, method: string): Object - -/** Holds all functions related to manipulating test runner */ -declare var jest: JestObjectType - -/** - * The global Jasmine object, this is generally not exposed as the public API, - * using features inside here could break in later versions of Jest. - */ -declare var jasmine: { - DEFAULT_TIMEOUT_INTERVAL: number, - any(value: mixed): JestAsymmetricEqualityType, - anything(): any, - arrayContaining(value: Array): Array, - clock(): JestClockType, - createSpy(name: string): JestSpyType, - createSpyObj( - baseName: string, - methodNames: Array - ): { [methodName: string]: JestSpyType, ... }, - objectContaining(value: Object): Object, - stringMatching(value: string): string, - ... -} diff --git a/flow-typed/npm/react-test-renderer_vx.x.x.js b/flow-typed/npm/react-test-renderer_vx.x.x.js deleted file mode 100644 index 2f2d85c1f3..0000000000 --- a/flow-typed/npm/react-test-renderer_vx.x.x.js +++ /dev/null @@ -1,43 +0,0 @@ -// flow-typed signature: b39646fcd6b54764b610c38b101a4fdd -// flow-typed version: <>/react-test-renderer_v^16.0.0/flow_v0.59.0 - -/** - * This is an autogenerated libdef stub for: - * - * 'react-test-renderer' - * - * Fill this stub out by replacing all the `any` types. - * - * Once filled out, we encourage you to share your work with the - * community by sending a pull request to: - * https://github.com/flowtype/flow-typed - */ - -type TestRendererOptions = { - createNodeMock: (element: React$Element) => any -} - -type ReactTestRendererNode = ReactTestRendererJSON | string - -type ReactTestRendererJSON = {| - type: string, - props: { [propName: string]: any }, - children: null | Array, - $$typeof?: Symbol // Optional because we add it with defineProperty(). -|} - -declare module 'react-test-renderer' { - declare module.exports: { - create: ( - element: React$Element, - options?: TestRendererOptions - ) => { - toJSON: () => ReactTestRendererJSON, - update: (newElement: React$Element) => void, - unmount: () => void, - toTree: () => any, - getInstance: () => any, - root: any - } - } -} diff --git a/jest.config.js b/jest.config.js index 28c0931b85..1b3ba88166 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,7 +1,7 @@ module.exports = { testEnvironment: 'jsdom', transform: { - '^.+\\.js?$': 'babel-jest' + '^.+\\.(tsx|ts|js)?$': 'babel-jest' }, watchPlugins: [ 'jest-watch-typeahead/filename', diff --git a/package.json b/package.json index 0fa50d67e9..d59f96d005 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "scripts": { "build:watch": "preconstruct watch", "build": "preconstruct build", + "tsc:all": "tsc && tsc --project site", "test:size": "npm-run-all build size", "test:debug": "node --inspect-brk ./node_modules/jest/bin/jest.js --runInBand --watch", "test": "jest", @@ -18,8 +19,6 @@ "size": "bundlesize", "lint": "eslint . --fix", "benchmark": "cd scripts/benchmarks && yarn build && yarn run-benchmark", - "flow": "flow", - "flow:check": "flow check --flowconfig-name=.flowconfig-ci", "preinstall": "node ./scripts/ensure-yarn.js", "postinstall": "preconstruct dev && manypkg check", "changeset": "changeset", @@ -45,27 +44,25 @@ ], "eslintConfig": { "extends": [ - "standard", - "standard-react", - "prettier" + "prettier", + "plugin:@typescript-eslint/eslint-recommended" ], "plugins": [ "prettier", - "flowtype", - "@emotion" + "@emotion", + "react", + "@typescript-eslint" ], - "parser": "babel-eslint", + "parser": "@typescript-eslint/parser", "rules": { "camelcase": 0, "no-template-curly-in-string": 0, "prefer-const": 0, "no-unused-vars": 0, - "flowtype/define-flow-type": 2, - "import/no-duplicates": 0, "prettier/prettier": [ "error", { - "parser": "flow" + "parser": "typescript" } ], "react/jsx-curly-brace-presence": 0, @@ -73,7 +70,6 @@ "react/no-unused-prop-types": 0, "react/prop-types": 0, "react/react-in-jsx-scope": 0, - "standard/computed-property-even-spacing": 0, "@emotion/pkg-renaming": 2 }, "env": { @@ -91,11 +87,16 @@ }, { "files": [ - "**/packages/*/src/*", - "**/packages/*/src/**/*" + "**/packages/**/*.ts", + "**/packages/**/*.tsx" ], "rules": { - "import/no-commonjs": 2 + "prettier/prettier": [ + "error", + { + "parser": "typescript" + } + ] } }, { @@ -170,11 +171,10 @@ "@babel/helper-module-imports": "^7.16.7", "@babel/plugin-proposal-class-properties": "^7.17.12", "@babel/plugin-syntax-jsx": "^7.17.12", - "@babel/plugin-transform-flow-strip-types": "^7.17.12", "@babel/plugin-transform-react-jsx": "^7.17.12", "@babel/preset-env": "^7.18.2", - "@babel/preset-flow": "^7.17.12", "@babel/preset-react": "^7.17.12", + "@babel/preset-typescript": "^7.18.6", "@babel/register": "^7.17.7", "@babel/runtime": "^7.18.3", "@changesets/changelog-github": "^0.4.0", @@ -185,9 +185,10 @@ "@types/jest": "^27.0.3", "@types/node": "^12.20.37", "@types/react": "^18.0.9", + "@typescript-eslint/eslint-plugin": "^4.22.0", + "@typescript-eslint/parser": "^4.22.0", "babel-check-duplicated-nodes": "^1.0.0", "babel-eslint": "^10.1.0", - "babel-flow-types": "^1.2.3", "babel-jest": "^27.4.5", "babel-plugin-codegen": "^4.1.5", "babel-plugin-jsx-pragmatic": "^1.0.2", @@ -202,17 +203,11 @@ "eslint": "^7.10.0", "eslint-config-prettier": "^8.3.0", "eslint-config-react": "^1.1.7", - "eslint-config-standard": "^14.1.1", - "eslint-config-standard-react": "^9.2.0", - "eslint-plugin-flowtype": "^5.2.0", - "eslint-plugin-import": "^2.22.1", "eslint-plugin-node": "^11.1.0", "eslint-plugin-prettier": "^3.4.0", "eslint-plugin-promise": "^4.2.1", "eslint-plugin-react": "^7.21.3", "eslint-plugin-react-hooks": "^4.1.2", - "eslint-plugin-standard": "^4.0.1", - "flow-bin": "^0.128.0", "html-tag-names": "^1.1.2", "husky": "^3.0.9", "jest": "^27.4.5", @@ -240,6 +235,7 @@ "react18-test-renderer": "npm:react-test-renderer@18.0.0-rc.0-next-aa8f2bdbc-20211215", "svg-tag-names": "^1.1.1", "through": "^2.3.8", + "typescript": "^4.5.5", "unified": "^6.1.6", "webpack-bundle-analyzer": "3.3.2" }, diff --git a/packages/babel-plugin-jsx-pragmatic/babel__plugin-syntax-jsx.d.ts b/packages/babel-plugin-jsx-pragmatic/babel__plugin-syntax-jsx.d.ts new file mode 100644 index 0000000000..26446987ad --- /dev/null +++ b/packages/babel-plugin-jsx-pragmatic/babel__plugin-syntax-jsx.d.ts @@ -0,0 +1,4 @@ +declare module '@babel/plugin-syntax-jsx' { + const plugin: any + export default plugin +} diff --git a/packages/babel-plugin-jsx-pragmatic/package.json b/packages/babel-plugin-jsx-pragmatic/package.json index 12ebba9857..31e230f416 100644 --- a/packages/babel-plugin-jsx-pragmatic/package.json +++ b/packages/babel-plugin-jsx-pragmatic/package.json @@ -28,6 +28,7 @@ "access": "public" }, "devDependencies": { - "@babel/core": "^7.18.5" + "@babel/core": "^7.18.5", + "@types/babel__core": "^7.1.18" } } diff --git a/packages/babel-plugin-jsx-pragmatic/src/index.js b/packages/babel-plugin-jsx-pragmatic/src/index.ts similarity index 72% rename from packages/babel-plugin-jsx-pragmatic/src/index.js rename to packages/babel-plugin-jsx-pragmatic/src/index.ts index c2523b9d94..2315326e70 100644 --- a/packages/babel-plugin-jsx-pragmatic/src/index.js +++ b/packages/babel-plugin-jsx-pragmatic/src/index.ts @@ -1,17 +1,38 @@ +import type { + NodePath, + PluginObj, + PluginPass, + types as BabelTypes +} from '@babel/core' import syntaxJsx from '@babel/plugin-syntax-jsx' -const findLast = (arr, predicate) => { +const findLast = (arr: T[], predicate: (item: T) => boolean): T | null => { for (let i = arr.length - 1; i >= 0; i--) { if (predicate(arr[i])) { return arr[i] } } + + return null +} + +interface PluginPassWithOpts extends PluginPass { + opts: { + module: string + import: string + export?: string + } } -export default function jsxPragmatic(babel) { +export default function jsxPragmatic(babel: { + types: typeof BabelTypes +}): PluginObj { const t = babel.types - function addPragmaImport(path, state) { + function addPragmaImport( + path: NodePath, + state: PluginPassWithOpts + ) { const importDeclar = t.importDeclaration( [ t.importSpecifier( diff --git a/packages/babel-plugin/README.md b/packages/babel-plugin/README.md index 9fcbabe984..12541ee557 100644 --- a/packages/babel-plugin/README.md +++ b/packages/babel-plugin/README.md @@ -304,8 +304,8 @@ This option allows you to tell @emotion/babel-plugin what imports it should look An example file: ```js -import { anotherExport } from 'my-package'; -import { someExport, thisIsTheJsxExport } from 'some-package'; +import { anotherExport } from 'my-package' +import { someExport, thisIsTheJsxExport } from 'some-package' ``` An example config: diff --git a/packages/babel-plugin/__tests__/__fixtures__/core-with-component.js b/packages/babel-plugin/__tests__/__fixtures__/core-with-component.js index 9985981ae0..2dd0408025 100644 --- a/packages/babel-plugin/__tests__/__fixtures__/core-with-component.js +++ b/packages/babel-plugin/__tests__/__fixtures__/core-with-component.js @@ -1,4 +1,3 @@ -// @flow import styled from '@emotion/styled' const MyComponent = styled.div({ color: 'hotpink' }) diff --git a/packages/babel-plugin/__tests__/__fixtures__/function-declaration.js b/packages/babel-plugin/__tests__/__fixtures__/function-declaration.js index b2f0327c21..8663c9c652 100644 --- a/packages/babel-plugin/__tests__/__fixtures__/function-declaration.js +++ b/packages/babel-plugin/__tests__/__fixtures__/function-declaration.js @@ -1,4 +1,3 @@ -// @flow import * as React from 'react' import { jsx } from '@emotion/react' diff --git a/packages/babel-plugin/__tests__/__fixtures__/object-property.js b/packages/babel-plugin/__tests__/__fixtures__/object-property.js index fa222c87fd..c06dd8b678 100644 --- a/packages/babel-plugin/__tests__/__fixtures__/object-property.js +++ b/packages/babel-plugin/__tests__/__fixtures__/object-property.js @@ -1,4 +1,3 @@ -// @flow import * as React from 'react' import { jsx } from '@emotion/react' import styled from '@emotion/styled' diff --git a/packages/babel-plugin/__tests__/__snapshots__/index.js.snap b/packages/babel-plugin/__tests__/__snapshots__/index.js.snap index a9bd2119ae..1916b69115 100644 --- a/packages/babel-plugin/__tests__/__snapshots__/index.js.snap +++ b/packages/babel-plugin/__tests__/__snapshots__/index.js.snap @@ -56,8 +56,7 @@ const OtherComponent = () =>
;" `; exports[`@emotion/babel-plugin core-with-component 1`] = ` -"// @flow -import styled from '@emotion/styled' +"import styled from '@emotion/styled' const MyComponent = styled.div({ color: 'hotpink' }) @@ -70,7 +69,6 @@ import _styled from "@emotion/styled/base"; function _EMOTION_STRINGIFIED_CSS_ERROR__() { return "You have tried to stringify object returned from \`css\` function. It isn't supposed to be used directly (e.g. as value of the \`className\` prop), but rather handed to emotion so it can handle it (e.g. as value of \`css\` prop)."; } -// @flow const MyComponent = /*#__PURE__*/_styled("div", process.env.NODE_ENV === "production" ? { target: "eck06en0" } : { @@ -82,7 +80,7 @@ const MyComponent = /*#__PURE__*/_styled("div", process.env.NODE_ENV === "produc } : { name: "3sn2xs", styles: "color:hotpink", - map: "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImNvcmUtd2l0aC1jb21wb25lbnQuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBR29CIiwiZmlsZSI6ImNvcmUtd2l0aC1jb21wb25lbnQuanMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBAZmxvd1xuaW1wb3J0IHN0eWxlZCBmcm9tICdAZW1vdGlvbi9zdHlsZWQnXG5cbmNvbnN0IE15Q29tcG9uZW50ID0gc3R5bGVkLmRpdih7IGNvbG9yOiAnaG90cGluaycgfSlcblxuY29uc3QgT3RoZXJDb21wb25lbnQgPSBNeUNvbXBvbmVudC53aXRoQ29tcG9uZW50KCdzZWN0aW9uJylcbiJdfQ== */", + map: "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImNvcmUtd2l0aC1jb21wb25lbnQuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBRW9CIiwiZmlsZSI6ImNvcmUtd2l0aC1jb21wb25lbnQuanMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgc3R5bGVkIGZyb20gJ0BlbW90aW9uL3N0eWxlZCdcblxuY29uc3QgTXlDb21wb25lbnQgPSBzdHlsZWQuZGl2KHsgY29sb3I6ICdob3RwaW5rJyB9KVxuXG5jb25zdCBPdGhlckNvbXBvbmVudCA9IE15Q29tcG9uZW50LndpdGhDb21wb25lbnQoJ3NlY3Rpb24nKVxuIl19 */", toString: _EMOTION_STRINGIFIED_CSS_ERROR__ }); @@ -220,8 +218,7 @@ const SomeComponent = props =>
;" `; exports[`@emotion/babel-plugin object-property 1`] = ` -"// @flow -import * as React from 'react' +"import * as React from 'react' import { jsx } from '@emotion/react' import styled from '@emotion/styled' @@ -323,7 +318,6 @@ import _styled from "@emotion/styled/base"; function _EMOTION_STRINGIFIED_CSS_ERROR__() { return "You have tried to stringify object returned from \`css\` function. It isn't supposed to be used directly (e.g. as value of the \`className\` prop), but rather handed to emotion so it can handle it (e.g. as value of \`css\` prop)."; } -// @flow import * as React from 'react'; import { jsx } from '@emotion/react'; const MyObject = { @@ -338,7 +332,7 @@ const MyObject = { } : { name: "3sn2xs", styles: "color:hotpink", - map: "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm9iamVjdC1wcm9wZXJ0eS5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFNYyIsImZpbGUiOiJvYmplY3QtcHJvcGVydHkuanMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBAZmxvd1xuaW1wb3J0ICogYXMgUmVhY3QgZnJvbSAncmVhY3QnXG5pbXBvcnQgeyBqc3ggfSBmcm9tICdAZW1vdGlvbi9yZWFjdCdcbmltcG9ydCBzdHlsZWQgZnJvbSAnQGVtb3Rpb24vc3R5bGVkJ1xuXG5jb25zdCBNeU9iamVjdCA9IHtcbiAgTXlQcm9wZXJ0eTogc3R5bGVkLmRpdih7IGNvbG9yOiAnaG90cGluaycgfSlcbn1cblxuZnVuY3Rpb24gTG9nbyhwcm9wcykge1xuICByZXR1cm4gPE15T2JqZWN0Lk15UHJvcGVydHkgLz5cbn1cbiJdfQ== */", + map: "/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm9iamVjdC1wcm9wZXJ0eS5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFLYyIsImZpbGUiOiJvYmplY3QtcHJvcGVydHkuanMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBSZWFjdCBmcm9tICdyZWFjdCdcbmltcG9ydCB7IGpzeCB9IGZyb20gJ0BlbW90aW9uL3JlYWN0J1xuaW1wb3J0IHN0eWxlZCBmcm9tICdAZW1vdGlvbi9zdHlsZWQnXG5cbmNvbnN0IE15T2JqZWN0ID0ge1xuICBNeVByb3BlcnR5OiBzdHlsZWQuZGl2KHsgY29sb3I6ICdob3RwaW5rJyB9KVxufVxuXG5mdW5jdGlvbiBMb2dvKHByb3BzKSB7XG4gIHJldHVybiA8TXlPYmplY3QuTXlQcm9wZXJ0eSAvPlxufVxuIl19 */", toString: _EMOTION_STRINGIFIED_CSS_ERROR__ }) }; diff --git a/packages/babel-plugin/__tests__/css-macro/index.js b/packages/babel-plugin/__tests__/css-macro/index.js index fae1b1815f..4d73fb4e84 100644 --- a/packages/babel-plugin/__tests__/css-macro/index.js +++ b/packages/babel-plugin/__tests__/css-macro/index.js @@ -1,4 +1,3 @@ -// @flow import babelTester from 'babel-tester' babelTester('@emotion/react - css macro', __dirname) diff --git a/packages/babel-plugin/__tests__/css-requires-options.js b/packages/babel-plugin/__tests__/css-requires-options.js index fd91b0c079..9173c489df 100644 --- a/packages/babel-plugin/__tests__/css-requires-options.js +++ b/packages/babel-plugin/__tests__/css-requires-options.js @@ -1,4 +1,3 @@ -// @flow import nodePath from 'path' import babelTester from 'babel-tester' import plugin from '@emotion/babel-plugin' diff --git a/packages/babel-plugin/__tests__/global-macro/index.js b/packages/babel-plugin/__tests__/global-macro/index.js index f2d2067288..c3eb1874e2 100644 --- a/packages/babel-plugin/__tests__/global-macro/index.js +++ b/packages/babel-plugin/__tests__/global-macro/index.js @@ -1,4 +1,3 @@ -// @flow import babelTester from 'babel-tester' babelTester('@emotion/react - Global macro', __dirname) diff --git a/packages/babel-plugin/__tests__/global-requires-options.js b/packages/babel-plugin/__tests__/global-requires-options.js index e8e7cf1324..a8cd7cfad1 100644 --- a/packages/babel-plugin/__tests__/global-requires-options.js +++ b/packages/babel-plugin/__tests__/global-requires-options.js @@ -1,4 +1,3 @@ -// @flow import babelTester from 'babel-tester' import plugin from '@emotion/babel-plugin' diff --git a/packages/babel-plugin/__tests__/styled-macro/index.js b/packages/babel-plugin/__tests__/styled-macro/index.js index f183501efa..26c27d241d 100644 --- a/packages/babel-plugin/__tests__/styled-macro/index.js +++ b/packages/babel-plugin/__tests__/styled-macro/index.js @@ -1,4 +1,3 @@ -// @flow import babelTester from 'babel-tester' babelTester('@emotion/styled.macro', __dirname) diff --git a/packages/babel-plugin/__tests__/styled-requires-options.js b/packages/babel-plugin/__tests__/styled-requires-options.js index a2d1a57e26..05e003fb36 100644 --- a/packages/babel-plugin/__tests__/styled-requires-options.js +++ b/packages/babel-plugin/__tests__/styled-requires-options.js @@ -1,4 +1,3 @@ -// @flow import babelTester from 'babel-tester' import plugin from '@emotion/babel-plugin' diff --git a/packages/babel-plugin/__tests__/vanilla-emotion-macro/index.js b/packages/babel-plugin/__tests__/vanilla-emotion-macro/index.js index 07961ee8fe..cdce44dffd 100644 --- a/packages/babel-plugin/__tests__/vanilla-emotion-macro/index.js +++ b/packages/babel-plugin/__tests__/vanilla-emotion-macro/index.js @@ -1,4 +1,3 @@ -// @flow import babelTester from 'babel-tester' babelTester('vanilla emotion', __dirname) diff --git a/packages/babel-plugin/src/core-macro.js b/packages/babel-plugin/src/core-macro.js index 77f39f1244..c7f8c76961 100644 --- a/packages/babel-plugin/src/core-macro.js +++ b/packages/babel-plugin/src/core-macro.js @@ -1,4 +1,3 @@ -// @flow import { transformExpressionWithStyles, createTransformerMacro, @@ -6,19 +5,15 @@ import { addImport } from './utils' -export const transformCssCallExpression = ({ - state, - babel, - path, - sourceMap, - annotateAsPure = true -}: { +export const transformCssCallExpression = ( + { state, babel, path, sourceMap, annotateAsPure = true } /*: { state: *, babel: *, path: *, sourceMap?: string, annotateAsPure?: boolean -}) => { +} */ +) => { let node = transformExpressionWithStyles({ babel, state, @@ -34,15 +29,13 @@ export const transformCssCallExpression = ({ } } -export const transformCsslessArrayExpression = ({ - state, - babel, - path -}: { +export const transformCsslessArrayExpression = ( + { state, babel, path } /*: { babel: *, state: *, path: * -}) => { +} */ +) => { let t = babel.types let expressionPath = path.get('value.expression') let sourceMap = @@ -72,17 +65,14 @@ export const transformCsslessArrayExpression = ({ } } -export const transformCsslessObjectExpression = ({ - state, - babel, - path, - cssImport -}: { +export const transformCsslessObjectExpression = ( + { state, babel, path, cssImport } /*: { babel: *, state: *, path: *, cssImport: { importSource: string, cssExport: string } -}) => { +} */ +) => { let t = babel.types let expressionPath = path.get('value.expression') let sourceMap = @@ -115,31 +105,25 @@ export const transformCsslessObjectExpression = ({ } } -let cssTransformer = ({ - state, - babel, - reference -}: { +let cssTransformer = ( + { state, babel, reference } /*: { state: any, babel: any, reference: any -}) => { +} */ +) => { transformCssCallExpression({ babel, state, path: reference.parentPath }) } -let globalTransformer = ({ - state, - babel, - reference, - importSource, - options -}: { +let globalTransformer = ( + { state, babel, reference, importSource, options } /*: { state: any, babel: any, reference: any, importSource: string, options: { cssExport?: string } -}) => { +} */ +) => { const t = babel.types if ( diff --git a/packages/babel-plugin/src/emotion-macro.js b/packages/babel-plugin/src/emotion-macro.js index 96b5954a67..67bf2c8e13 100644 --- a/packages/babel-plugin/src/emotion-macro.js +++ b/packages/babel-plugin/src/emotion-macro.js @@ -1,4 +1,3 @@ -// @flow import { transformExpressionWithStyles, createTransformerMacro } from './utils' const isAlreadyTranspiled = path => { @@ -30,8 +29,10 @@ const isAlreadyTranspiled = path => { } let createEmotionTransformer = - (isPure: boolean) => - ({ state, babel, importSource, reference, importSpecifierName }: Object) => { + (isPure /*: boolean */) => + ( + { state, babel, importSource, reference, importSpecifierName } /*: Object */ + ) => { const path = reference.parentPath if (isAlreadyTranspiled(path)) { @@ -59,5 +60,5 @@ export let transformers = { keyframes: createEmotionTransformer(true) } -export let createEmotionMacro = (importSource: string) => +export let createEmotionMacro = (importSource /*: string */) => createTransformerMacro(transformers, { importSource }) diff --git a/packages/babel-plugin/src/index.js b/packages/babel-plugin/src/index.js index 95731cd432..74f889c391 100644 --- a/packages/babel-plugin/src/index.js +++ b/packages/babel-plugin/src/index.js @@ -1,4 +1,3 @@ -// @flow import { createEmotionMacro, transformers as vanillaTransformers @@ -68,13 +67,15 @@ export const macros = { vanillaEmotion: vanillaEmotionMacro } +/* export type BabelPath = any export type EmotionBabelPluginPass = any +*/ const AUTO_LABEL_VALUES = ['dev-only', 'never', 'always'] -export default function (babel: *, options: *) { +export default function (babel, options) { if ( options.autoLabel !== undefined && !AUTO_LABEL_VALUES.includes(options.autoLabel) @@ -90,7 +91,7 @@ export default function (babel: *, options: *) { return { name: '@emotion', // https://github.com/babel/babel/blob/0c97749e0fe8ad845b902e0b23a24b308b0bf05d/packages/babel-plugin-syntax-jsx/src/index.ts#L9-L18 - manipulateOptions(opts: *, parserOpts: *) { + manipulateOptions(opts, parserOpts) { const { plugins } = parserOpts if ( @@ -105,7 +106,7 @@ export default function (babel: *, options: *) { plugins.push('jsx') }, visitor: { - ImportDeclaration(path: *, state: *) { + ImportDeclaration(path, state) { const macro = state.pluginMacros[path.node.source.value] // most of this is from https://github.com/kentcdodds/babel-plugin-macros/blob/main/src/index.js if (macro === undefined) { @@ -159,13 +160,13 @@ export default function (babel: *, options: *) { isBabelMacrosCall: true }) }, - Program(path: *, state: *) { + Program(path, state) { let macros = {} - let jsxReactImports: Array<{ + let jsxReactImports /*: Array<{ importSource: string, export: string, cssExport: string - }> = [ + }> */ = [ { importSource: '@emotion/react', export: 'jsx', cssExport: 'css' } ] state.jsxReactImport = jsxReactImports[0] @@ -209,11 +210,11 @@ export default function (babel: *, options: *) { } } - let [exportTransformer, defaultOptions] = - // $FlowFixMe - Array.isArray(packageTransformers[exportName]) - ? packageTransformers[exportName] - : [packageTransformers[exportName]] + let [exportTransformer, defaultOptions] = Array.isArray( + packageTransformers[exportName] + ) + ? packageTransformers[exportName] + : [packageTransformers[exportName]] transformers[localExportName] = [ exportTransformer, @@ -266,7 +267,7 @@ export default function (babel: *, options: *) { state.emotionSourceMap = true } }, - JSXAttribute(path: *, state: *) { + JSXAttribute(path, state) { if (path.node.name.name !== 'css' || !state.transformCssProp) { return } @@ -289,7 +290,7 @@ export default function (babel: *, options: *) { } }, CallExpression: { - exit(path: BabelPath, state: EmotionBabelPluginPass) { + exit(path /*: BabelPath */, state /*: EmotionBabelPluginPass */) { try { if ( path.node.callee && diff --git a/packages/babel-plugin/src/styled-macro.js b/packages/babel-plugin/src/styled-macro.js index 1ccde3726c..5f4094fc65 100644 --- a/packages/babel-plugin/src/styled-macro.js +++ b/packages/babel-plugin/src/styled-macro.js @@ -1,4 +1,3 @@ -// @flow import { transformExpressionWithStyles, getStyledOptions, @@ -13,15 +12,16 @@ const getReferencedSpecifier = (path, specifierName) => { : specifiers.find(p => p.node.local.name === specifierName) } -export let styledTransformer = ({ - state, - babel, - path, - importSource, - reference, - importSpecifierName, - options: { styledBaseImport, isWeb } -}: { +export let styledTransformer = ( + { + state, + babel, + path, + importSource, + reference, + importSpecifierName, + options: { styledBaseImport, isWeb } + } /*: { state: Object, babel: Object, path: any, @@ -29,7 +29,8 @@ export let styledTransformer = ({ importSpecifierName: string, reference: Object, options: { styledBaseImport?: [string, string], isWeb: boolean } -}) => { +} */ +) => { let t = babel.types let getStyledIdentifier = () => { @@ -119,17 +120,19 @@ export let styledTransformer = ({ } } -export let createStyledMacro = ({ - importSource, - originalImportSource = importSource, - baseImportName = 'default', - isWeb -}: { +export let createStyledMacro = ( + { + importSource, + originalImportSource = importSource, + baseImportName = 'default', + isWeb + } /*: { importSource: string, originalImportSource?: string, baseImportName?: string, isWeb: boolean -}) => +} */ +) => createTransformerMacro( { default: [ diff --git a/packages/babel-plugin/src/utils/add-import.js b/packages/babel-plugin/src/utils/add-import.js index 4d1113ac87..393ef1fb5f 100644 --- a/packages/babel-plugin/src/utils/add-import.js +++ b/packages/babel-plugin/src/utils/add-import.js @@ -1,10 +1,10 @@ import { addDefault, addNamed } from '@babel/helper-module-imports' export function addImport( - state: any, - importSource: string, - importedSpecifier: string, - nameHint?: string + state, + importSource /*: string */, + importedSpecifier /*: string */, + nameHint /* ?: string */ ) { let cacheKey = ['import', importSource, importedSpecifier].join(':') if (state[cacheKey] === undefined) { diff --git a/packages/babel-plugin/src/utils/get-styled-options.js b/packages/babel-plugin/src/utils/get-styled-options.js index b37b027f28..351afad60e 100644 --- a/packages/babel-plugin/src/utils/get-styled-options.js +++ b/packages/babel-plugin/src/utils/get-styled-options.js @@ -1,9 +1,8 @@ -// @flow import { getLabelFromPath } from './label' import { getTargetClassName } from './get-target-class-name' import createNodeEnvConditional from './create-node-env-conditional' -const getKnownProperties = (t: *, node: *) => +const getKnownProperties = (t, node) => new Set( node.properties .filter(n => t.isObjectProperty(n) && !n.computed) @@ -13,7 +12,7 @@ const getKnownProperties = (t: *, node: *) => const createObjectSpreadLike = (t, file, ...objs) => t.callExpression(file.addHelper('extends'), [t.objectExpression([]), ...objs]) -export let getStyledOptions = (t: *, path: *, state: *) => { +export let getStyledOptions = (t, path, state) => { const autoLabel = state.opts.autoLabel || 'dev-only' let args = path.node.arguments diff --git a/packages/babel-plugin/src/utils/get-target-class-name.js b/packages/babel-plugin/src/utils/get-target-class-name.js index 9b78a9725c..5d524b9206 100644 --- a/packages/babel-plugin/src/utils/get-target-class-name.js +++ b/packages/babel-plugin/src/utils/get-target-class-name.js @@ -1,11 +1,10 @@ -// @flow import findRoot from 'find-root' import memoize from '@emotion/memoize' import nodePath from 'path' import hashString from '@emotion/hash' import escapeRegexp from 'escape-string-regexp' -let hashArray = (arr: Array) => hashString(arr.join('')) +let hashArray = (arr /*: Array */) => hashString(arr.join('')) const unsafeRequire = require @@ -15,7 +14,7 @@ const separator = new RegExp(escapeRegexp(nodePath.sep), 'g') const normalizePath = path => nodePath.normalize(path).replace(separator, '/') -export function getTargetClassName(state: *, t: *) { +export function getTargetClassName(state, t) { if (state.emotionTargetClassNameCount === undefined) { state.emotionTargetClassNameCount = 0 } diff --git a/packages/babel-plugin/src/utils/index.js b/packages/babel-plugin/src/utils/index.js index a4696280b2..7ec45184f5 100644 --- a/packages/babel-plugin/src/utils/index.js +++ b/packages/babel-plugin/src/utils/index.js @@ -1,4 +1,3 @@ -// @flow export { getLabelFromPath } from './label' export { getSourceMap } from './source-maps' export { getTargetClassName } from './get-target-class-name' diff --git a/packages/babel-plugin/src/utils/label.js b/packages/babel-plugin/src/utils/label.js index f20ace5a2d..5d4d1f7120 100644 --- a/packages/babel-plugin/src/utils/label.js +++ b/packages/babel-plugin/src/utils/label.js @@ -1,20 +1,21 @@ -// @flow import nodePath from 'path' +/* type LabelFormatOptions = { name: string, path: string } +*/ const invalidClassNameCharacters = /[!"#$%&'()*+,./:;<=>?@[\]^`|}~{]/g -const sanitizeLabelPart = (labelPart: string) => +const sanitizeLabelPart = (labelPart /*: string */) => labelPart.trim().replace(invalidClassNameCharacters, '-') function getLabel( - identifierName?: string, - labelFormat?: string | (LabelFormatOptions => string), - filename: string + identifierName /* ?: string */, + labelFormat /* ?: string | (LabelFormatOptions => string) */, + filename /*: string */ ) { if (!identifierName) return null @@ -45,7 +46,7 @@ function getLabel( .replace(/\[dirname\]/gi, sanitizeLabelPart(localDirname)) } -export function getLabelFromPath(path: *, state: *, t: *) { +export function getLabelFromPath(path, state, t) { return getLabel( getIdentifierName(path, t), state.opts.labelFormat, @@ -72,7 +73,6 @@ const getObjPropertyLikeName = (path, t) => { } function getDeclaratorName(path, t) { - // $FlowFixMe const parent = path.findParent( p => p.isVariableDeclarator() || @@ -154,14 +154,13 @@ function getDeclaratorName(path, t) { return variableDeclarator.node.id.name } -function getIdentifierName(path: *, t: *) { +function getIdentifierName(path, t) { let objPropertyLikeName = getObjPropertyLikeName(path.parentPath, t) if (objPropertyLikeName) { return objPropertyLikeName } - // $FlowFixMe let classOrClassPropertyParent = path.findParent( p => t.isClassProperty(p) || t.isClass(p) ) diff --git a/packages/babel-plugin/src/utils/minify.js b/packages/babel-plugin/src/utils/minify.js index 14281a98ed..7d5c18e79d 100644 --- a/packages/babel-plugin/src/utils/minify.js +++ b/packages/babel-plugin/src/utils/minify.js @@ -1,4 +1,3 @@ -// @flow import { compile } from 'stylis' const haveSameLocation = (element1, element2) => { @@ -59,18 +58,17 @@ var stringifyTree = elements => { .join('') } -const interleave = (strings: Array<*>, interpolations: Array<*>) => +const interleave = (strings /*: Array<*> */, interpolations /*: Array<*> */) => interpolations.reduce( (array, interp, i) => array.concat([interp], strings[i + 1]), [strings[0]] ) -function getDynamicMatches(str: string) { +function getDynamicMatches(str /*: string */) { const re = /xxx(\d+):xxx/gm let match const matches = [] while ((match = re.exec(str)) !== null) { - // so that flow doesn't complain if (match !== null) { matches.push({ value: match[0], @@ -84,9 +82,9 @@ function getDynamicMatches(str: string) { } function replacePlaceholdersWithExpressions( - str: string, - expressions: Array<*>, - t: * + str /*: string */, + expressions /*: Array<*> */, + t ) { const matches = getDynamicMatches(str) if (matches.length === 0) { @@ -116,15 +114,17 @@ function replacePlaceholdersWithExpressions( }) return interleave(strings, finalExpressions).filter( - (node: { value: string }) => { + (node /*: { value: string } */) => { return node.value !== '' } ) } -function createRawStringFromTemplateLiteral(quasi: { +function createRawStringFromTemplateLiteral( + quasi /*: { quasis: Array<{ value: { cooked: string } }> -}) { +} */ +) { let strs = quasi.quasis.map(x => x.value.cooked) const src = strs @@ -140,7 +140,7 @@ function createRawStringFromTemplateLiteral(quasi: { return src } -export default function minify(path: *, t: *): void { +export default function minify(path, t) { const quasi = path.node.quasi const raw = createRawStringFromTemplateLiteral(quasi) const minified = stringifyTree(toInputTree(compile(raw), [])) diff --git a/packages/babel-plugin/src/utils/object-to-string.js b/packages/babel-plugin/src/utils/object-to-string.js index a3bfa56460..f275c5b07d 100644 --- a/packages/babel-plugin/src/utils/object-to-string.js +++ b/packages/babel-plugin/src/utils/object-to-string.js @@ -1,10 +1,9 @@ -// @flow import { serializeStyles } from '@emotion/serialize' // to anyone looking at this, this isn't intended to simplify every single case // it's meant to simplify the most common cases so i don't want to make it especially complex // also, this will be unnecessary when prepack is ready -export function simplifyObject(node: *, t: Object) { +export function simplifyObject(node, t /*: Object */) { let finalString = '' for (let i = 0; i < node.properties.length; i++) { let property = node.properties[i] diff --git a/packages/babel-plugin/src/utils/source-maps.js b/packages/babel-plugin/src/utils/source-maps.js index b499f33cca..e4926711b3 100644 --- a/packages/babel-plugin/src/utils/source-maps.js +++ b/packages/babel-plugin/src/utils/source-maps.js @@ -1,4 +1,3 @@ -// @flow import { SourceMapGenerator } from 'source-map' import convert from 'convert-source-map' @@ -6,7 +5,7 @@ function getGeneratorOpts(file) { return file.opts.generatorOpts ? file.opts.generatorOpts : file.opts } -export function makeSourceMapGenerator(file: *) { +export function makeSourceMapGenerator(file) { const generatorOpts = getGeneratorOpts(file) const filename = generatorOpts.sourceFileName const generator = new SourceMapGenerator({ @@ -19,12 +18,12 @@ export function makeSourceMapGenerator(file: *) { } export function getSourceMap( - offset: { + offset /*: { line: number, column: number - }, - state: * -): string { + } */, + state +) /*: string */ { const generator = makeSourceMapGenerator(state.file) const generatorOpts = getGeneratorOpts(state.file) if ( diff --git a/packages/babel-plugin/src/utils/strings.js b/packages/babel-plugin/src/utils/strings.js index 6c91c62161..5e85223e92 100644 --- a/packages/babel-plugin/src/utils/strings.js +++ b/packages/babel-plugin/src/utils/strings.js @@ -1,13 +1,12 @@ -// @flow import { getTypeScriptMakeTemplateObjectPath, isTaggedTemplateTranspiledByBabel } from './transpiled-output-utils' export const appendStringReturningExpressionToArguments = ( - t: *, - path: *, - expression: * + t, + path, + expression ) => { let lastIndex = path.node.arguments.length - 1 let last = path.node.arguments[lastIndex] @@ -44,7 +43,7 @@ export const appendStringReturningExpressionToArguments = ( } } -export const joinStringLiterals = (expressions: Array<*>, t: *) => { +export const joinStringLiterals = (expressions /*: Array<*> */, t) => { return expressions.reduce((finalExpressions, currentExpression, i) => { if (!t.isStringLiteral(currentExpression)) { finalExpressions.push(currentExpression) diff --git a/packages/babel-plugin/src/utils/transform-expression-with-styles.js b/packages/babel-plugin/src/utils/transform-expression-with-styles.js index c47e7366e4..0e61f74730 100644 --- a/packages/babel-plugin/src/utils/transform-expression-with-styles.js +++ b/packages/babel-plugin/src/utils/transform-expression-with-styles.js @@ -1,5 +1,3 @@ -// @flow - import { serializeStyles } from '@emotion/serialize' import minify from './minify' import { getLabelFromPath } from './label' @@ -14,19 +12,15 @@ import createNodeEnvConditional from './create-node-env-conditional' const CSS_OBJECT_STRINGIFIED_ERROR = "You have tried to stringify object returned from `css` function. It isn't supposed to be used directly (e.g. as value of the `className` prop), but rather handed to emotion so it can handle it (e.g. as value of `css` prop)." -export let transformExpressionWithStyles = ({ +export let transformExpressionWithStyles = ( + { babel, state, path, shouldLabel, sourceMap = '' } /*: { babel, state, path, - shouldLabel, - sourceMap = '' -}: { - babel: *, - state: *, - path: *, shouldLabel: boolean, sourceMap?: string -}): * => { +} */ +) => { const autoLabel = state.opts.autoLabel || 'dev-only' let t = babel.types if (t.isTaggedTemplateExpression(path)) { diff --git a/packages/babel-plugin/src/utils/transformer-macro.js b/packages/babel-plugin/src/utils/transformer-macro.js index ea10489699..679ad1af38 100644 --- a/packages/babel-plugin/src/utils/transformer-macro.js +++ b/packages/babel-plugin/src/utils/transformer-macro.js @@ -1,11 +1,12 @@ -// @flow import { createMacro } from 'babel-plugin-macros' +/* type Transformer = Function +*/ export function createTransformerMacro( - transformers: { [key: string]: Transformer | [Transformer, Object] }, - { importSource }: { importSource: string } + transformers /*: { [key: string]: Transformer | [Transformer, Object] } */, + { importSource } /*: { importSource: string } */ ) { let macro = createMacro( ({ path, source, references, state, babel, isEmotionCall }) => { diff --git a/packages/babel-plugin/src/utils/transpiled-output-utils.js b/packages/babel-plugin/src/utils/transpiled-output-utils.js index e6943e3b64..74187e413f 100644 --- a/packages/babel-plugin/src/utils/transpiled-output-utils.js +++ b/packages/babel-plugin/src/utils/transpiled-output-utils.js @@ -1,8 +1,6 @@ -// @flow - // this only works correctly in modules, but we don't run on scripts anyway, so it's fine // the difference is that in modules template objects are being cached per call site -export function getTypeScriptMakeTemplateObjectPath(path: *) { +export function getTypeScriptMakeTemplateObjectPath(path) { if (path.node.arguments.length === 0) { return null } @@ -28,7 +26,7 @@ export function getTypeScriptMakeTemplateObjectPath(path: *) { // we could push them to found array expressions, as we do it for TS-transpile output ¯\_(ツ)_/¯ // it seems overly complicated though - mainly because we'd also have to check against existing stuff of a particular type (source maps & labels) // considering Babel double-transpilation as a valid use case seems rather far-fetched -export function isTaggedTemplateTranspiledByBabel(path: *) { +export function isTaggedTemplateTranspiledByBabel(path) { if (path.node.arguments.length === 0) { return false } diff --git a/packages/cache/__tests__/hydration.js b/packages/cache/__tests__/hydration.js index 132f26237b..851e3ffb94 100644 --- a/packages/cache/__tests__/hydration.js +++ b/packages/cache/__tests__/hydration.js @@ -1,4 +1,3 @@ -// @flow import { safeQuerySelector } from 'test-utils' import hashString from '@emotion/hash' import createCache from '@emotion/cache' diff --git a/packages/cache/__tests__/index.js b/packages/cache/__tests__/index.js index 15751f2166..d89af730b9 100644 --- a/packages/cache/__tests__/index.js +++ b/packages/cache/__tests__/index.js @@ -1,4 +1,3 @@ -// @flow /** @jsx jsx */ import 'test-utils/next-env' import { safeQuerySelector } from 'test-utils' diff --git a/packages/cache/src/index.js b/packages/cache/src/index.js index 39d66bf915..82378f02b0 100644 --- a/packages/cache/src/index.js +++ b/packages/cache/src/index.js @@ -1,6 +1,5 @@ -// @flow import { StyleSheet } from '@emotion/sheet' -import { type EmotionCache, type SerializedStyles } from '@emotion/utils' +/* import { type EmotionCache, type SerializedStyles } from '@emotion/utils' */ import { serialize, compile, @@ -18,10 +17,11 @@ import { incorrectImportAlarm } from './stylis-plugins' import { prefixer } from './prefixer' -import type { StylisPlugin } from './types' +/* import type { StylisPlugin } from './types' */ let isBrowser = typeof document !== 'undefined' +/* export type Options = { nonce?: string, stylisPlugins?: StylisPlugin[], @@ -31,6 +31,7 @@ export type Options = { prepend?: boolean, insertionPoint?: HTMLElement } +*/ let getServerStylisCache = isBrowser ? undefined @@ -43,7 +44,7 @@ let getServerStylisCache = isBrowser const defaultStylisPlugins = [prefixer] -let createCache = (options: Options): EmotionCache => { +let createCache = (options /*: Options */) /*: EmotionCache */ => { let key = options.key if (process.env.NODE_ENV !== 'production' && !key) { @@ -62,21 +63,19 @@ let createCache = (options: Options): EmotionCache => { // document.head is a safe place to move them to(though note document.head is not necessarily the last place they will be) // note this very very intentionally targets all style elements regardless of the key to ensure // that creating a cache works inside of render of a React component - Array.prototype.forEach.call(ssrStyles, (node: HTMLStyleElement) => { + Array.prototype.forEach.call(ssrStyles, (node /*: HTMLStyleElement */) => { // we want to only move elements which have a space in the data-emotion attribute value // because that indicates that it is an Emotion 11 server-side rendered style elements // while we will already ignore Emotion 11 client-side inserted styles because of the :not([data-s]) part in the selector // Emotion 10 client-side inserted styles did not have data-s (but importantly did not have a space in their data-emotion attributes) // so checking for the space ensures that loading Emotion 11 after Emotion 10 has inserted some styles // will not result in the Emotion 10 styles being destroyed - const dataEmotionAttribute = ((node.getAttribute( - 'data-emotion' - ): any): string) + const dataEmotionAttribute = node.getAttribute('data-emotion') if (dataEmotionAttribute.indexOf(' ') === -1) { return } - ;((document.head: any): HTMLHeadElement).appendChild(node) + document.head.appendChild(node) node.setAttribute('data-s', '') }) } @@ -84,7 +83,6 @@ let createCache = (options: Options): EmotionCache => { const stylisPlugins = options.stylisPlugins || defaultStylisPlugins if (process.env.NODE_ENV !== 'production') { - // $FlowFixMe if (/[^a-z-]/.test(key)) { throw new Error( `Emotion key must only contain lower case alphabetical characters and - but "${key}" was passed` @@ -92,20 +90,17 @@ let createCache = (options: Options): EmotionCache => { } } let inserted = {} - let container: Node + let container /* : Node */ const nodesToHydrate = [] if (isBrowser) { - container = options.container || ((document.head: any): HTMLHeadElement) + container = options.container || document.head Array.prototype.forEach.call( // this means we will ignore elements which don't have a space in them which // means that the style elements we're looking at are only Emotion 11 server-rendered style elements document.querySelectorAll(`style[data-emotion^="${key} "]`), - (node: HTMLStyleElement) => { - const attrib = ((node.getAttribute(`data-emotion`): any): string).split( - ' ' - ) - // $FlowFixMe + (node /*: HTMLStyleElement */) => { + const attrib = node.getAttribute(`data-emotion`).split(' ') for (let i = 1; i < attrib.length; i++) { inserted[attrib[i]] = true } @@ -114,13 +109,12 @@ let createCache = (options: Options): EmotionCache => { ) } - let insert: ( + let insert /*: ( selector: string, serialized: SerializedStyles, sheet: StyleSheet, shouldCache: boolean - ) => string | void - + ) => string | void */ const omnipresentPlugins = [compat, removeLabel] if (process.env.NODE_ENV !== 'production') { @@ -162,19 +156,19 @@ let createCache = (options: Options): EmotionCache => { const stylis = styles => serialize(compile(styles), serializer) insert = ( - selector: string, - serialized: SerializedStyles, - sheet: StyleSheet, - shouldCache: boolean - ): void => { + selector /*: string */, + serialized /*: SerializedStyles */, + sheet /*: StyleSheet */, + shouldCache /*: boolean */ + ) /*: void */ => { currentSheet = sheet if ( process.env.NODE_ENV !== 'production' && serialized.map !== undefined ) { currentSheet = { - insert: (rule: string) => { - sheet.insert(rule + ((serialized.map: any): string)) + insert: (rule /*: string */) => { + sheet.insert(rule + serialized.map) } } } @@ -192,9 +186,11 @@ let createCache = (options: Options): EmotionCache => { ) const stylis = styles => serialize(compile(styles), serializer) - // $FlowFixMe let serverStylisCache = getServerStylisCache(stylisPlugins)(key) - let getRules = (selector: string, serialized: SerializedStyles): string => { + let getRules = ( + selector /*: string */, + serialized /*: SerializedStyles */ + ) /*: string */ => { let name = serialized.name if (serverStylisCache[name] === undefined) { serverStylisCache[name] = stylis( @@ -204,11 +200,11 @@ let createCache = (options: Options): EmotionCache => { return serverStylisCache[name] } insert = ( - selector: string, - serialized: SerializedStyles, - sheet: StyleSheet, - shouldCache: boolean - ): string | void => { + selector /*: string */, + serialized /*: SerializedStyles */, + sheet /*: StyleSheet */, + shouldCache /*: boolean */ + ) /*: string | void */ => { let name = serialized.name let rules = getRules(selector, serialized) if (cache.compat === undefined) { @@ -245,11 +241,11 @@ let createCache = (options: Options): EmotionCache => { } } - const cache: EmotionCache = { + const cache /*: EmotionCache */ = { key, sheet: new StyleSheet({ key, - container: ((container: any): Node), + container, nonce: options.nonce, speedy: options.speedy, prepend: options.prepend, diff --git a/packages/cache/src/types.js b/packages/cache/src/types.js index 92312fb30c..f02fb33414 100644 --- a/packages/cache/src/types.js +++ b/packages/cache/src/types.js @@ -1,14 +1,13 @@ -// @flow - +/* export type StylisElement = { - type: string, - value: string, - props: Array, - root: StylisElement | null, - children: Array, - line: number, - column: number, - length: number, + type: string + value: string + props: Array + root: StylisElement | null + children: Array + line: number + column: number + length: number return: string } export type StylisPluginCallback = ( @@ -24,3 +23,4 @@ export type StylisPlugin = ( children: Array, callback: StylisPluginCallback ) => string | void +*/ diff --git a/packages/cache/types/index.d.ts b/packages/cache/types/index.d.ts index 7822587db8..3bba3ded23 100644 --- a/packages/cache/types/index.d.ts +++ b/packages/cache/types/index.d.ts @@ -1,5 +1,8 @@ // Definitions by: Junyoung Clare Jang // TypeScript Version: 2.2 + +/// + import { EmotionCache } from '@emotion/utils' export { EmotionCache } diff --git a/packages/css/create-instance/package.json b/packages/css/create-instance/package.json index 203a18da18..bd294c0d39 100644 --- a/packages/css/create-instance/package.json +++ b/packages/css/create-instance/package.json @@ -2,7 +2,7 @@ "main": "dist/emotion-css-create-instance.cjs.js", "module": "dist/emotion-css-create-instance.esm.js", "umd:main": "dist/emotion-css-create-instance.umd.min.js", - "types": "../types/create-instance", + "types": "dist/emotion-css-create-instance.cjs.d.ts", "preconstruct": { "umdName": "createEmotion" } diff --git a/packages/css/macro.js.flow b/packages/css/macro.js.flow deleted file mode 100644 index 63ae97e66d..0000000000 --- a/packages/css/macro.js.flow +++ /dev/null @@ -1,2 +0,0 @@ -// @flow -export * from './src/index.js' diff --git a/packages/css/package.json b/packages/css/package.json index caed679ae1..c119f34f87 100644 --- a/packages/css/package.json +++ b/packages/css/package.json @@ -4,7 +4,7 @@ "description": "The Next Generation of CSS-in-JS.", "main": "dist/emotion-css.cjs.js", "module": "dist/emotion-css.esm.js", - "types": "types/index.d.ts", + "types": "dist/emotion-css.cjs.d.ts", "files": [ "src", "dist", @@ -64,8 +64,8 @@ "preconstruct": { "umdName": "emotion", "entrypoints": [ - "./index.js", - "./create-instance.js" + "./index.ts", + "./create-instance.ts" ], "exports": { "extra": { diff --git a/packages/css/src/create-instance.d.ts b/packages/css/src/create-instance.d.ts deleted file mode 100644 index 5329dce3b6..0000000000 --- a/packages/css/src/create-instance.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from '../types/create-instance' -export { default } from '../types/create-instance' diff --git a/packages/css/src/create-instance.js b/packages/css/src/create-instance.ts similarity index 52% rename from packages/css/src/create-instance.js rename to packages/css/src/create-instance.ts index 3b18761368..2bf7cc2813 100644 --- a/packages/css/src/create-instance.js +++ b/packages/css/src/create-instance.ts @@ -1,21 +1,80 @@ -// @flow import createCache from '@emotion/cache' -import { serializeStyles } from '@emotion/serialize' +import { + serializeStyles, + CSSInterpolation, + Interpolation +} from '@emotion/serialize' import { insertStyles, getRegisteredStyles, - type EmotionCache, - type SerializedStyles + SerializedStyles, + RegisteredCache } from '@emotion/utils' +import { EmotionCache, Options } from '@emotion/cache' +import { StyleSheet } from '@emotion/sheet' + +export type { + CSSInterpolation, + ArrayCSSInterpolation, + ComponentSelector, + CSSObject +} from '@emotion/serialize' -function insertWithoutScoping(cache, serialized: SerializedStyles) { +function insertWithoutScoping( + cache: EmotionCache, + serialized: SerializedStyles +) { if (cache.inserted[serialized.name] === undefined) { return cache.insert('', serialized, cache.sheet, true) } } -function merge(registered: Object, css: (*) => string, className: string) { - const registeredStyles = [] +export type { EmotionCache, Options } + +export interface ArrayClassNamesArg extends Array {} +export type ClassNamesArg = + | undefined + | null + | string + | boolean + | { [className: string]: boolean | null | undefined } + | ArrayClassNamesArg + +export interface CSSStyleSheet extends StyleSheet { + speedy(value: boolean): void +} + +export interface Emotion { + css(template: TemplateStringsArray, ...args: Array): string + css(...args: Array): string + cx(...classNames: Array): string + flush(): void + hydrate(ids: Array): void + injectGlobal( + template: TemplateStringsArray, + ...args: Array + ): void + injectGlobal(...args: Array): void + keyframes( + template: TemplateStringsArray, + ...args: Array + ): string + keyframes(...args: Array): string + sheet: CSSStyleSheet + cache: EmotionCache + merge(className: string): string + getRegisteredStyles( + registeredStyles: Array, + className: string + ): string +} + +function merge( + registered: RegisteredCache, + css: Emotion['css'], + className: string +) { + const registeredStyles: string[] = [] const rawClassName = getRegisteredStyles( registered, registeredStyles, @@ -28,60 +87,29 @@ function merge(registered: Object, css: (*) => string, className: string) { return rawClassName + css(registeredStyles) } -export type Interpolation = any -export type Interpolations = Array - -type CreateStyles = (...args: Interpolations) => ReturnValue - -type ClassNameArg = - | string - | boolean - | { [key: string]: boolean | void | null } - | Array - | void - | null - -declare class StyleSheet { - insert(rule: string): void; - flush(): void; - speedy(newVal: boolean): void; - tags: Array; - isSpeedy: number; - ctr: number; -} - -export type Emotion = { - css: CreateStyles, - cx: (...classNames: Array) => string, - flush: () => void, - hydrate: (ids: Array) => void, - injectGlobal: CreateStyles, - keyframes: CreateStyles, - sheet: StyleSheet, - cache: EmotionCache, - merge: *, - getRegisteredStyles: * -} - -let createEmotion = (options: *): Emotion => { +let createEmotion = (options: Options): Emotion => { let cache = createCache(options) - // $FlowFixMe - cache.sheet.speedy = function (value: boolean) { + ;(cache.sheet as CSSStyleSheet).speedy = function (value: boolean) { if (process.env.NODE_ENV !== 'production' && this.ctr !== 0) { throw new Error('speedy must be changed before any rules are inserted') } this.isSpeedy = value } + cache.compat = true - let css = (...args) => { + let css: Emotion['css'] = ( + ...args: (TemplateStringsArray | Interpolation)[] + ) => { let serialized = serializeStyles(args, cache.registered, undefined) insertStyles(cache, serialized, false) return `${cache.key}-${serialized.name}` } - let keyframes = (...args) => { + let keyframes: Emotion['keyframes'] = ( + ...args: (TemplateStringsArray | Interpolation)[] + ) => { let serialized = serializeStyles(args, cache.registered) let animation = `animation-${serialized.name}` insertWithoutScoping(cache, { @@ -91,12 +119,14 @@ let createEmotion = (options: *): Emotion => { return animation } - let injectGlobal = (...args) => { + let injectGlobal: Emotion['injectGlobal'] = ( + ...args: (TemplateStringsArray | Interpolation)[] + ) => { let serialized = serializeStyles(args, cache.registered) insertWithoutScoping(cache, serialized) } - let cx = (...args) => { + let cx: Emotion['cx'] = (...args) => { return merge(cache.registered, css, classnames(args)) } return { @@ -104,7 +134,7 @@ let createEmotion = (options: *): Emotion => { cx, injectGlobal, keyframes, - hydrate(ids: Array) { + hydrate(ids) { ids.forEach(key => { cache.inserted[key] = true }) @@ -114,15 +144,14 @@ let createEmotion = (options: *): Emotion => { cache.inserted = {} cache.sheet.flush() }, - // $FlowFixMe - sheet: cache.sheet, + sheet: cache.sheet as CSSStyleSheet, cache, getRegisteredStyles: getRegisteredStyles.bind(null, cache.registered), merge: merge.bind(null, cache.registered, css) } } -let classnames = args => { +let classnames = (args: ClassNamesArg[]) => { let cls = '' for (let i = 0; i < args.length; i++) { let arg = args[i] diff --git a/packages/css/src/index.d.ts b/packages/css/src/index.d.ts deleted file mode 100644 index 51a3b4100a..0000000000 --- a/packages/css/src/index.d.ts +++ /dev/null @@ -1 +0,0 @@ -export * from '../types' diff --git a/packages/css/src/index.js b/packages/css/src/index.ts similarity index 95% rename from packages/css/src/index.js rename to packages/css/src/index.ts index 523fed93ef..9e4000e3d8 100644 --- a/packages/css/src/index.js +++ b/packages/css/src/index.ts @@ -1,4 +1,3 @@ -// @flow import createEmotion from './create-instance' export const { diff --git a/packages/css/test/css.test.js b/packages/css/test/css.test.js index b32630a6d1..7b44dab7a8 100644 --- a/packages/css/test/css.test.js +++ b/packages/css/test/css.test.js @@ -1,4 +1,3 @@ -// @flow import 'test-utils/legacy-env' import React from 'react' import renderer from 'react-test-renderer' diff --git a/packages/css/test/cx.test.js b/packages/css/test/cx.test.js index fc074cbbaf..30370209ed 100644 --- a/packages/css/test/cx.test.js +++ b/packages/css/test/cx.test.js @@ -1,4 +1,3 @@ -// @flow import 'test-utils/legacy-env' import React from 'react' import renderer from 'react-test-renderer' diff --git a/packages/css/test/inject-global.test.js b/packages/css/test/inject-global.test.js index 44e9d0d66e..44050042ee 100644 --- a/packages/css/test/inject-global.test.js +++ b/packages/css/test/inject-global.test.js @@ -1,4 +1,3 @@ -// @flow import 'test-utils/legacy-env' import { injectGlobal, sheet, flush, css } from '@emotion/css' diff --git a/packages/css/test/instance/css.test.js b/packages/css/test/instance/css.test.js index 73685174d9..67a2a02ea4 100644 --- a/packages/css/test/instance/css.test.js +++ b/packages/css/test/instance/css.test.js @@ -1,4 +1,3 @@ -// @flow import 'test-utils/next-env' import React from 'react' import renderer from 'react-test-renderer' diff --git a/packages/css/test/instance/emotion-instance.js b/packages/css/test/instance/emotion-instance.js index 943d712879..59a4d1f8b6 100644 --- a/packages/css/test/instance/emotion-instance.js +++ b/packages/css/test/instance/emotion-instance.js @@ -1,4 +1,3 @@ -// @flow import createEmotion from '@emotion/css/create-instance' import createEmotionServer from '@emotion/server/create-instance' @@ -12,7 +11,6 @@ export let container if (typeof document !== 'undefined') { container = document.createElement('div') - // $FlowFixMe document.head.appendChild(container) } diff --git a/packages/css/test/instance/instance.test.js b/packages/css/test/instance/instance.test.js index af9f5e668d..b3ee02629b 100644 --- a/packages/css/test/instance/instance.test.js +++ b/packages/css/test/instance/instance.test.js @@ -1,4 +1,3 @@ -// @flow import createEmotion from '@emotion/css/create-instance' import { container, css, sheet } from './emotion-instance' diff --git a/packages/css/test/keyframes.test.js b/packages/css/test/keyframes.test.js index fc2a5b0626..961568ca82 100644 --- a/packages/css/test/keyframes.test.js +++ b/packages/css/test/keyframes.test.js @@ -1,4 +1,3 @@ -// @flow import 'test-utils/legacy-env' import React from 'react' import renderer from 'react-test-renderer' diff --git a/packages/css/test/no-babel/index.test.js b/packages/css/test/no-babel/index.test.js index 527671accf..2b0daf8e72 100644 --- a/packages/css/test/no-babel/index.test.js +++ b/packages/css/test/no-babel/index.test.js @@ -1,4 +1,3 @@ -// @flow import 'test-utils/legacy-env' import React from 'react' import renderer from 'react-test-renderer' @@ -228,7 +227,7 @@ describe('css', () => { expect(tree).toMatchSnapshot() }) test('name with class component', () => { - class SomeComponent extends React.Component<{ className: string }> { + class SomeComponent extends React.Component /* <{ className: string }> */ { render() { return
} diff --git a/packages/css/test/no-babel/warnings.test.js b/packages/css/test/no-babel/warnings.test.js index 3e1e74430a..67cbc5e9ee 100644 --- a/packages/css/test/no-babel/warnings.test.js +++ b/packages/css/test/no-babel/warnings.test.js @@ -1,8 +1,6 @@ -// @flow import 'test-utils/legacy-env' import { css } from '@emotion/css' -// $FlowFixMe console.error = jest.fn() afterEach(() => { @@ -16,7 +14,7 @@ it('warns about illegal escape sequences inside first quasi of template literal' } ` - expect((console.error: any).mock.calls[0]).toMatchInlineSnapshot(` + expect(console.error.mock.calls[0]).toMatchInlineSnapshot(` [ "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';". @@ -36,7 +34,7 @@ it('warns about illegal escape sequences inside non-first quasi of template lite } ` - expect((console.error: any).mock.calls[0]).toMatchInlineSnapshot(` + expect(console.error.mock.calls[0]).toMatchInlineSnapshot(` [ "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';". diff --git a/packages/css/test/selectivity.test.js b/packages/css/test/selectivity.test.js index dd66dc32b0..c6782b88d2 100644 --- a/packages/css/test/selectivity.test.js +++ b/packages/css/test/selectivity.test.js @@ -1,4 +1,3 @@ -// @flow import 'test-utils/legacy-env' import { css, sheet, flush } from '@emotion/css' diff --git a/packages/css/test/sheet.dom.test.js b/packages/css/test/sheet.dom.test.js index d482d84c02..90833e56e1 100644 --- a/packages/css/test/sheet.dom.test.js +++ b/packages/css/test/sheet.dom.test.js @@ -1,4 +1,3 @@ -// @flow import { sheet } from '@emotion/css' const consoleError = console.error diff --git a/packages/css/test/warnings.test.js b/packages/css/test/warnings.test.js index 61c4235214..0996161b15 100644 --- a/packages/css/test/warnings.test.js +++ b/packages/css/test/warnings.test.js @@ -1,11 +1,9 @@ -// @flow import 'test-utils/legacy-env' import { css } from '@emotion/css' import createCss from '@emotion/css/create-instance' import * as React from 'react' import renderer from 'react-test-renderer' -// $FlowFixMe console.error = jest.fn() const validValues = [ @@ -67,7 +65,7 @@ it('does warn when @import rule is being inserted after order-insensitive rules' injectGlobal`.thing {display:flex;}` injectGlobal`@import 'custom.css';` - expect((console.error: any).mock.calls).toMatchInlineSnapshot(` + expect(console.error.mock.calls).toMatchInlineSnapshot(` [ [ "You're attempting to insert the following rule: diff --git a/packages/css/types/create-instance.d.ts b/packages/css/types/create-instance.d.ts index 9e560390f1..e505b19935 100644 --- a/packages/css/types/create-instance.d.ts +++ b/packages/css/types/create-instance.d.ts @@ -1,55 +1,4 @@ // Definitions by: Junyoung Clare Jang // TypeScript Version: 2.8 - -import { EmotionCache, Options } from '@emotion/cache' -import { CSSInterpolation } from '@emotion/serialize' -import { StyleSheet } from '@emotion/sheet' - -export { - CSSInterpolation, - ArrayCSSInterpolation, - ComponentSelector, - CSSObject -} from '@emotion/serialize' - -export { EmotionCache, Options } - -export interface ArrayClassNamesArg extends Array {} -export type ClassNamesArg = - | undefined - | null - | string - | boolean - | { [className: string]: boolean | null | undefined } - | ArrayClassNamesArg - -export interface CSSStyleSheet extends StyleSheet { - speedy(value: boolean): void -} - -export interface Emotion { - css(template: TemplateStringsArray, ...args: Array): string - css(...args: Array): string - cx(...classNames: Array): string - flush(): void - hydrate(ids: Array): void - injectGlobal( - template: TemplateStringsArray, - ...args: Array - ): void - injectGlobal(...args: Array): void - keyframes( - template: TemplateStringsArray, - ...args: Array - ): string - keyframes(...args: Array): string - sheet: CSSStyleSheet - cache: EmotionCache - merge(className: string): string - getRegisteredStyles( - registeredStyles: Array, - className: string - ): string -} - -export default function createEmotion(options?: Options): Emotion +export * from '../create-instance' +export { default } from '../create-instance' diff --git a/packages/css/types/index.d.ts b/packages/css/types/index.d.ts index 7efec6edee..23f9a3c26e 100644 --- a/packages/css/types/index.d.ts +++ b/packages/css/types/index.d.ts @@ -1,26 +1,3 @@ -// Definitions by: Junyoung Clare Jang -// TypeScript Version: 2.8 +/// -import { Emotion } from './create-instance' - -export { - ArrayClassNamesArg, - ArrayCSSInterpolation, - ClassNamesArg, - ComponentSelector, - EmotionCache, - CSSInterpolation, - CSSObject, - CSSStyleSheet -} from './create-instance' - -export const flush: Emotion['flush'] -export const hydrate: Emotion['hydrate'] -export const cx: Emotion['cx'] -export const merge: Emotion['merge'] -export const getRegisteredStyles: Emotion['getRegisteredStyles'] -export const css: Emotion['css'] -export const injectGlobal: Emotion['injectGlobal'] -export const keyframes: Emotion['keyframes'] -export const sheet: Emotion['sheet'] -export const cache: Emotion['cache'] +export * from '..' diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index 996c688f92..9db1a82c36 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -27,7 +27,12 @@ "peerDependencies": { "eslint": "6 || 7 || 8" }, + "dependencies": { + "@typescript-eslint/utils": "^5.25.0" + }, "devDependencies": { - "eslint": "^7.10.0" + "@types/eslint": "^7.0.0", + "eslint": "^7.10.0", + "resolve-from": "^5.0.0" } } diff --git a/packages/eslint-plugin/src/index.js b/packages/eslint-plugin/src/index.ts similarity index 94% rename from packages/eslint-plugin/src/index.js rename to packages/eslint-plugin/src/index.ts index e626a190cb..3c27f57e22 100644 --- a/packages/eslint-plugin/src/index.js +++ b/packages/eslint-plugin/src/index.ts @@ -1,5 +1,3 @@ -// @flow - import importFromEmotion from './rules/import-from-emotion' import noVanilla from './rules/no-vanilla' import syntaxPreference from './rules/syntax-preference' @@ -7,7 +5,7 @@ import styledImport from './rules/styled-import' import jsxImport from './rules/jsx-import' import pkgRenaming from './rules/pkg-renaming' -export let rules = { +export const rules = { 'import-from-emotion': importFromEmotion, 'no-vanilla': noVanilla, 'syntax-preference': syntaxPreference, diff --git a/packages/eslint-plugin/src/rules/import-from-emotion.js b/packages/eslint-plugin/src/rules/import-from-emotion.js deleted file mode 100644 index 7889e3ca5b..0000000000 --- a/packages/eslint-plugin/src/rules/import-from-emotion.js +++ /dev/null @@ -1,42 +0,0 @@ -export default { - meta: { - fixable: 'code' - }, - create(context) { - return { - ImportDeclaration(node) { - if ( - node.source.value === 'react-emotion' && - node.specifiers.some(x => x.type !== 'ImportDefaultSpecifier') - ) { - context.report({ - node: node.source, - message: `emotion's exports should be imported directly from emotion rather than from react-emotion`, - fix(fixer) { - if (node.specifiers[0].type === 'ImportNamespaceSpecifier') { - return - } - // default specifiers are always first - if (node.specifiers[0].type === 'ImportDefaultSpecifier') { - return fixer.replaceText( - node, - `import ${ - node.specifiers[0].local.name - } from '@emotion/styled';\nimport { ${node.specifiers - .filter(x => x.type === 'ImportSpecifier') - .map(x => - x.local.name === x.imported.name - ? x.local.name - : `${x.imported.name} as ${x.local.name}` - ) - .join(', ')} } from 'emotion';` - ) - } - return fixer.replaceText(node.source, "'emotion'") - } - }) - } - } - } - } -} diff --git a/packages/eslint-plugin/src/rules/import-from-emotion.ts b/packages/eslint-plugin/src/rules/import-from-emotion.ts new file mode 100644 index 0000000000..c390ff1d74 --- /dev/null +++ b/packages/eslint-plugin/src/rules/import-from-emotion.ts @@ -0,0 +1,69 @@ +import { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/utils' +import { createRule } from '../utils' + +const messages = { + incorrectImport: `emotion's exports should be imported directly from emotion rather than from react-emotion` +} + +export default createRule({ + name: __filename, + meta: { + docs: { + description: 'Ensure styled is imported from @emotion/styled', + recommended: false + }, + fixable: 'code', + messages, + schema: [], + type: 'problem' + }, + defaultOptions: [], + create(context) { + return { + ImportDeclaration(node) { + if ( + node.source.value === 'react-emotion' && + node.specifiers.some( + x => x.type !== AST_NODE_TYPES.ImportDefaultSpecifier + ) + ) { + context.report({ + node: node.source, + messageId: 'incorrectImport', + fix(fixer) { + if ( + node.specifiers[0].type === + AST_NODE_TYPES.ImportNamespaceSpecifier + ) { + return null + } + // default specifiers are always first + if ( + node.specifiers[0].type === + AST_NODE_TYPES.ImportDefaultSpecifier + ) { + return fixer.replaceText( + node, + `import ${ + node.specifiers[0].local.name + } from '@emotion/styled';\nimport { ${node.specifiers + .filter( + (x): x is TSESTree.ImportSpecifier => + x.type === AST_NODE_TYPES.ImportSpecifier + ) + .map(x => + x.local.name === x.imported.name + ? x.local.name + : `${x.imported.name} as ${x.local.name}` + ) + .join(', ')} } from 'emotion';` + ) + } + return fixer.replaceText(node.source, "'emotion'") + } + }) + } + } + } + } +}) diff --git a/packages/eslint-plugin/src/rules/jsx-import.js b/packages/eslint-plugin/src/rules/jsx-import.ts similarity index 57% rename from packages/eslint-plugin/src/rules/jsx-import.js rename to packages/eslint-plugin/src/rules/jsx-import.ts index 8b7cab8a65..2ee930f8d2 100644 --- a/packages/eslint-plugin/src/rules/jsx-import.js +++ b/packages/eslint-plugin/src/rules/jsx-import.ts @@ -1,3 +1,6 @@ +import { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/utils' +import { createRule, REPO_URL } from '../utils' + const JSX_ANNOTATION_REGEX = /\*?\s*@jsx\s+([^\s]+)/ const JSX_IMPORT_SOURCE_REGEX = /\*?\s*@jsxImportSource\s+([^\s]+)/ @@ -6,9 +9,34 @@ const JSX_IMPORT_SOURCE_REGEX = /\*?\s*@jsxImportSource\s+([^\s]+)/ // to //
+ import { css } -export default { +declare module '@typescript-eslint/utils/dist/ts-eslint/Rule' { + export interface SharedConfigurationSettings { + react?: { pragma?: string } + } +} + +type JSXConfig = { + runtime: string + importSource?: string +} + +type RuleOptions = [(JSXConfig | string)?] + +const messages = { + cssProp: `The css prop can only be used if jsxImportSource is set to {{ importSource }}`, + cssPropWithPragma: `The css prop can only be used if jsx from @emotion/react is imported and it is set as the jsx pragma`, + templateLiterals: `Template literals should be replaced with tagged template literals using \`css\` when using the css prop` +} + +export default createRule({ + name: __filename, meta: { + docs: { + description: 'Ensure jsx from @emotion/react is imported', + recommended: false + }, fixable: 'code', + messages, schema: { type: 'array', items: { @@ -29,11 +57,14 @@ export default { }, uniqueItems: true, minItems: 0 - } + }, + type: 'problem' }, + defaultOptions: [], create(context) { const jsxRuntimeMode = context.options.find( - option => option && option.runtime === 'automatic' + (option): option is JSXConfig => + typeof option === 'object' && option.runtime === 'automatic' ) if (jsxRuntimeMode) { @@ -42,15 +73,14 @@ export default { if (node.name.name !== 'css') { return } - const importSource = - (jsxRuntimeMode || {}).importSource || '@emotion/react' - let jsxImportSourcePragmaNode + const importSource = jsxRuntimeMode?.importSource || '@emotion/react' + let jsxImportSourcePragmaComment: TSESTree.Comment | null = null let jsxImportSourceMatch let validJsxImportSource = false let sourceCode = context.getSourceCode() - let pragma = sourceCode.getAllComments().find(node => { - if (JSX_IMPORT_SOURCE_REGEX.test(node.value)) { - jsxImportSourcePragmaNode = node + let pragma = sourceCode.getAllComments().find(comment => { + if (JSX_IMPORT_SOURCE_REGEX.test(comment.value)) { + jsxImportSourcePragmaComment = comment return true } }) @@ -65,7 +95,8 @@ export default { if (!jsxImportSourceMatch) { context.report({ node, - message: `The css prop can only be used if jsxImportSource is set to ${importSource}`, + messageId: 'cssProp', + data: { importSource }, fix(fixer) { return fixer.insertTextBefore( sourceCode.ast.body[0], @@ -73,13 +104,21 @@ export default { ) } }) - } else if (!validJsxImportSource && jsxImportSourcePragmaNode) { + } else if (!validJsxImportSource && jsxImportSourcePragmaComment) { context.report({ node, - message: `The css prop can only be used if jsxImportSource is set to ${importSource}`, + messageId: 'cssProp', + data: { importSource }, fix(fixer) { + /* istanbul ignore if */ + if (jsxImportSourcePragmaComment === null) { + throw new Error( + `Unexpected null when attempting to fix ${context.getFilename()} - please file a github issue at ${REPO_URL}` + ) + } + return fixer.replaceText( - jsxImportSourcePragmaNode, + jsxImportSourcePragmaComment, `/** @jsxImportSource ${importSource} */` ) } @@ -95,12 +134,12 @@ export default { return } let hasJsxImport = false - let emotionCoreNode = null - let local = null + let emotionCoreNode = null as TSESTree.ImportDeclaration | null + let local: string | null = null let sourceCode = context.getSourceCode() sourceCode.ast.body.forEach(x => { if ( - x.type === 'ImportDeclaration' && + x.type === AST_NODE_TYPES.ImportDeclaration && (x.source.value === '@emotion/react' || x.source.value === '@emotion/core') ) { @@ -108,13 +147,15 @@ export default { if ( x.specifiers.length === 1 && - x.specifiers[0].type === 'ImportNamespaceSpecifier' + x.specifiers[0].type === AST_NODE_TYPES.ImportNamespaceSpecifier ) { hasJsxImport = true local = x.specifiers[0].local.name + '.jsx' } else { let jsxSpecifier = x.specifiers.find( - x => x.type === 'ImportSpecifier' && x.imported.name === 'jsx' + x => + x.type === AST_NODE_TYPES.ImportSpecifier && + x.imported.name === 'jsx' ) if (jsxSpecifier) { hasJsxImport = true @@ -138,10 +179,16 @@ export default { if (!hasJsxImport || !hasSetPragma) { context.report({ node, - message: - 'The css prop can only be used if jsx from @emotion/react is imported and it is set as the jsx pragma', + messageId: 'cssPropWithPragma', fix(fixer) { if (hasJsxImport) { + /* istanbul ignore if */ + if (emotionCoreNode === null) { + throw new Error( + `Unexpected null when attempting to fix ${context.getFilename()} - please file a github issue at ${REPO_URL}` + ) + } + return fixer.insertTextBefore( emotionCoreNode, `/** @jsx ${local} */\n` @@ -154,7 +201,9 @@ export default { emotionCoreNode.specifiers.length - 1 ] - if (lastSpecifier.type === 'ImportDefaultSpecifier') { + if ( + lastSpecifier.type === AST_NODE_TYPES.ImportDefaultSpecifier + ) { return fixer.insertTextAfter(lastSpecifier, ', { jsx }') } @@ -174,38 +223,48 @@ export default { }) return } + + /* istanbul ignore if */ + if (emotionCoreNode === null) { + throw new Error( + `Unexpected null when attempting to fix ${context.getFilename()} - please file a github issue at ${REPO_URL}` + ) + } + + const { specifiers } = emotionCoreNode + const { value } = node + if ( - node.value.type === 'JSXExpressionContainer' && - node.value.expression.type === 'TemplateLiteral' + value && + value.type === AST_NODE_TYPES.JSXExpressionContainer && + value.expression.type === AST_NODE_TYPES.TemplateLiteral ) { - let cssSpecifier = emotionCoreNode.specifiers.find( - x => x.imported.name === 'css' + let cssSpecifier = specifiers.find( + x => + x.type === AST_NODE_TYPES.ImportSpecifier && + x.imported.name === 'css' ) context.report({ node, - message: - 'Template literals should be replaced with tagged template literals using `css` when using the css prop', + messageId: 'templateLiterals', fix(fixer) { if (cssSpecifier) { return fixer.insertTextBefore( - node.value.expression, + value.expression, cssSpecifier.local.name ) } - let lastSpecifier = - emotionCoreNode.specifiers[ - emotionCoreNode.specifiers.length - 1 - ] + let lastSpecifier = specifiers[specifiers.length - 1] if (context.getScope().variables.some(x => x.name === 'css')) { return [ fixer.insertTextAfter(lastSpecifier, `, css as _css`), - fixer.insertTextBefore(node.value.expression, '_css') + fixer.insertTextBefore(value.expression, '_css') ] } return [ fixer.insertTextAfter(lastSpecifier, `, css`), - fixer.insertTextBefore(node.value.expression, 'css') + fixer.insertTextBefore(value.expression, 'css') ] } }) @@ -213,4 +272,4 @@ export default { } } } -} +}) diff --git a/packages/eslint-plugin/src/rules/no-vanilla.js b/packages/eslint-plugin/src/rules/no-vanilla.js deleted file mode 100644 index 793819576a..0000000000 --- a/packages/eslint-plugin/src/rules/no-vanilla.js +++ /dev/null @@ -1,17 +0,0 @@ -export default { - meta: { - fixable: 'code' - }, - create(context) { - return { - ImportDeclaration(node) { - if (node.source.value === '@emotion/css') { - context.report({ - node: node.source, - message: `Vanilla emotion should not be used` - }) - } - } - } - } -} diff --git a/packages/eslint-plugin/src/rules/no-vanilla.ts b/packages/eslint-plugin/src/rules/no-vanilla.ts new file mode 100644 index 0000000000..72b0524757 --- /dev/null +++ b/packages/eslint-plugin/src/rules/no-vanilla.ts @@ -0,0 +1,31 @@ +import { createRule } from '../utils' + +const messages = { + vanillaEmotion: 'Vanilla emotion should not be used' +} + +export default createRule({ + name: __filename, + meta: { + docs: { + description: 'Ensure vanilla emotion is not used', + recommended: false + }, + messages, + schema: [], + type: 'problem' + }, + defaultOptions: [], + create(context) { + return { + ImportDeclaration(node) { + if (node.source.value === '@emotion/css') { + context.report({ + node: node.source, + messageId: 'vanillaEmotion' + }) + } + } + } + } +}) diff --git a/packages/eslint-plugin/src/rules/pkg-renaming.js b/packages/eslint-plugin/src/rules/pkg-renaming.js deleted file mode 100644 index 2e6dbfaf85..0000000000 --- a/packages/eslint-plugin/src/rules/pkg-renaming.js +++ /dev/null @@ -1,67 +0,0 @@ -let simpleMappings = { - '@emotion/core': '@emotion/react', - emotion: '@emotion/css', - 'emotion/macro': '@emotion/css/macro', - '@emotion/styled-base': '@emotion/styled/base', - 'jest-emotion': '@emotion/jest', - 'babel-plugin-emotion': '@emotion/babel-plugin', - 'eslint-plugin-emotion': '@emotion/eslint-plugin', - 'create-emotion-server': '@emotion/server/create-instance', - 'create-emotion': '@emotion/css/create-instance', - 'emotion-server': '@emotion/server' -} - -export default { - meta: { - fixable: 'code' - }, - create(context) { - return { - ImportDeclaration(node) { - let maybeMapping = simpleMappings[node.source.value] - if (maybeMapping !== undefined) { - context.report({ - node: node.source, - message: `${JSON.stringify( - node.source.value - )} has been renamed to ${JSON.stringify( - maybeMapping - )}, please import it from ${JSON.stringify(maybeMapping)} instead`, - fix: fixer => fixer.replaceText(node.source, `'${maybeMapping}'`) - }) - } - if ( - (node.source.value === '@emotion/css' || - node.source.value === '@emotion/css/macro') && - node.specifiers.length === 1 && - node.specifiers[0].type === 'ImportDefaultSpecifier' - ) { - let replacement = - node.source.value === '@emotion/css' - ? '@emotion/react' - : '@emotion/react/macro' - context.report({ - node: node.source, - message: `The default export of "${node.source.value}" in Emotion 10 has been moved to a named export, \`css\`, from "${replacement}" in Emotion 11, please import it from "${replacement}"`, - fix: fixer => - fixer.replaceText( - node, - `import { css${ - node.specifiers[0].local.name === 'css' - ? '' - : ` as ${node.specifiers[0].local.name}` - } } from '${replacement}'` - ) - }) - } - if (node.source.value === 'emotion-theming') { - context.report({ - node: node.source, - message: `"emotion-theming" has been moved into "@emotion/react", please import its exports from "@emotion/react"`, - fix: fixer => fixer.replaceText(node.source, `'@emotion/react'`) - }) - } - } - } - } -} diff --git a/packages/eslint-plugin/src/rules/pkg-renaming.ts b/packages/eslint-plugin/src/rules/pkg-renaming.ts new file mode 100644 index 0000000000..9b546015dd --- /dev/null +++ b/packages/eslint-plugin/src/rules/pkg-renaming.ts @@ -0,0 +1,89 @@ +import { AST_NODE_TYPES } from '@typescript-eslint/utils' +import { createRule } from '../utils' + +const simpleMappings = new Map([ + ['@emotion/core', '@emotion/react'], + ['emotion', '@emotion/css'], + ['emotion/macro', '@emotion/css/macro'], + ['@emotion/styled-base', '@emotion/styled/base'], + ['jest-emotion', '@emotion/jest'], + ['babel-plugin-emotion', '@emotion/babel-plugin'], + ['eslint-plugin-emotion', '@emotion/eslint-plugin'], + ['create-emotion-server', '@emotion/server/create-instance'], + ['create-emotion', '@emotion/css/create-instance'], + ['emotion-server', '@emotion/server'] +]) + +const messages = { + renamePackage: `{{ beforeName }} has been renamed to {{ afterName }}, please import it from {{ afterName }} instead`, + exportChange: `The default export of "{{ name }}" in Emotion 10 has been moved to a named export, \`css\`, from "{{ replacement }}" in Emotion 11, please import it from "{{ replacement }}"`, + emotionTheming: `"emotion-theming" has been moved into "@emotion/react", please import its exports from "@emotion/react"` +} + +export default createRule({ + name: __filename, + meta: { + docs: { + description: 'Internal rule', + recommended: false + }, + fixable: 'code', + messages, + schema: [], + type: 'problem' + }, + defaultOptions: [], + create(context) { + return { + ImportDeclaration(node) { + const maybeMapping = simpleMappings.get(node.source.value) + if (maybeMapping !== undefined) { + context.report({ + node: node.source, + messageId: 'renamePackage', + data: { + beforeName: JSON.stringify(node.source.value), + afterName: JSON.stringify(maybeMapping) + }, + fix: fixer => fixer.replaceText(node.source, `'${maybeMapping}'`) + }) + } + if ( + (node.source.value === '@emotion/css' || + node.source.value === '@emotion/css/macro') && + node.specifiers.length === 1 && + node.specifiers[0].type === AST_NODE_TYPES.ImportDefaultSpecifier + ) { + let replacement = + node.source.value === '@emotion/css' + ? '@emotion/react' + : '@emotion/react/macro' + context.report({ + node: node.source, + messageId: 'exportChange', + data: { + name: node.source.value, + replacement + }, + fix: fixer => + fixer.replaceText( + node, + `import { css${ + node.specifiers[0].local.name === 'css' + ? '' + : ` as ${node.specifiers[0].local.name}` + } } from '${replacement}'` + ) + }) + } + if (node.source.value === 'emotion-theming') { + context.report({ + node: node.source, + messageId: 'emotionTheming', + fix: fixer => fixer.replaceText(node.source, `'@emotion/react'`) + }) + } + } + } + } +}) diff --git a/packages/eslint-plugin/src/rules/styled-import.js b/packages/eslint-plugin/src/rules/styled-import.js deleted file mode 100644 index 89ccf2310a..0000000000 --- a/packages/eslint-plugin/src/rules/styled-import.js +++ /dev/null @@ -1,25 +0,0 @@ -export default { - meta: { - fixable: 'code' - }, - create(context) { - return { - ImportDeclaration(node) { - if (node.source.value === 'react-emotion') { - let newImportPath = '@emotion/styled' - context.report({ - node: node.source, - message: `styled should be imported from @emotion/styled`, - fix: - node.specifiers.length === 1 && - node.specifiers[0].type === 'ImportDefaultSpecifier' - ? fixer => { - return fixer.replaceText(node.source, `'${newImportPath}'`) - } - : undefined - }) - } - } - } - } -} diff --git a/packages/eslint-plugin/src/rules/styled-import.ts b/packages/eslint-plugin/src/rules/styled-import.ts new file mode 100644 index 0000000000..e9aeefbbe8 --- /dev/null +++ b/packages/eslint-plugin/src/rules/styled-import.ts @@ -0,0 +1,41 @@ +import { AST_NODE_TYPES } from '@typescript-eslint/utils' +import { createRule } from '../utils' + +const messages = { + incorrectImport: 'styled should be imported from @emotion/styled' +} + +export default createRule({ + name: __filename, + meta: { + docs: { + description: 'Ensure styled is imported from @emotion/styled', + recommended: false + }, + fixable: 'code', + messages, + schema: [], + type: 'problem' + }, + defaultOptions: [], + create(context) { + return { + ImportDeclaration(node) { + if (node.source.value === 'react-emotion') { + let newImportPath = '@emotion/styled' + context.report({ + node: node.source, + messageId: 'incorrectImport', + fix: + node.specifiers.length === 1 && + node.specifiers[0].type === AST_NODE_TYPES.ImportDefaultSpecifier + ? fixer => { + return fixer.replaceText(node.source, `'${newImportPath}'`) + } + : undefined + }) + } + } + } + } +}) diff --git a/packages/eslint-plugin/src/rules/syntax-preference.js b/packages/eslint-plugin/src/rules/syntax-preference.ts similarity index 55% rename from packages/eslint-plugin/src/rules/syntax-preference.js rename to packages/eslint-plugin/src/rules/syntax-preference.ts index 891713a879..7568eb805b 100644 --- a/packages/eslint-plugin/src/rules/syntax-preference.js +++ b/packages/eslint-plugin/src/rules/syntax-preference.ts @@ -1,16 +1,20 @@ +import { AST_NODE_TYPES, TSESLint, TSESTree } from '@typescript-eslint/utils' +import { createRule } from '../utils' + /** * @fileoverview Choose between string or object syntax * @author alex-pex */ -function isStringStyle(node) { - if (node.tag.type === 'Identifier' && node.tag.name === 'css') { +function isStringStyle(node: TSESTree.TaggedTemplateExpression) { + if (node.tag.type === AST_NODE_TYPES.Identifier && node.tag.name === 'css') { return true } // shorthand notation // eg: styled.h1` color: red; ` if ( - node.tag.type === 'MemberExpression' && + node.tag.type === AST_NODE_TYPES.MemberExpression && + node.tag.object.type === AST_NODE_TYPES.Identifier && node.tag.object.name === 'styled' ) { // string syntax used @@ -19,7 +23,11 @@ function isStringStyle(node) { // full notation // eg: styled('h1')` color: red; ` - if (node.tag.type === 'CallExpression' && node.tag.callee.name === 'styled') { + if ( + node.tag.type === AST_NODE_TYPES.CallExpression && + node.tag.callee.type === AST_NODE_TYPES.Identifier && + node.tag.callee.name === 'styled' + ) { // string syntax used return true } @@ -27,15 +35,19 @@ function isStringStyle(node) { return false } -function isObjectStyle(node) { - if (node.callee.type === 'Identifier' && node.callee.name === 'css') { +function isObjectStyle(node: TSESTree.CallExpression) { + if ( + node.callee.type === AST_NODE_TYPES.Identifier && + node.callee.name === 'css' + ) { return true } // shorthand notation // eg: styled.h1({ color: 'red' }) if ( - node.callee.type === 'MemberExpression' && + node.callee.type === AST_NODE_TYPES.MemberExpression && + node.callee.object.type === AST_NODE_TYPES.Identifier && node.callee.object.name === 'styled' ) { // object syntax used @@ -45,7 +57,8 @@ function isObjectStyle(node) { // full notation // eg: styled('h1')({ color: 'red' }) if ( - node.callee.type === 'CallExpression' && + node.callee.type === AST_NODE_TYPES.CallExpression && + node.callee.callee.type === AST_NODE_TYPES.Identifier && node.callee.callee.name === 'styled' ) { // object syntax used @@ -59,42 +72,42 @@ function isObjectStyle(node) { // Rule Definition // ------------------------------------------------------------------------------ -const MSG_PREFER_STRING_STYLE = 'Styles should be written using strings.' -const MSG_PREFER_OBJECT_STYLE = 'Styles should be written using objects.' -const MSG_PREFER_WRAPPING_WITH_CSS = - 'Prefer wrapping your string styles with `css` call.' - -const checkExpressionPreferringObject = (context, node) => { +const checkExpressionPreferringObject = ( + context: RuleContext, + node: TSESTree.Node +) => { switch (node.type) { - case 'ArrayExpression': + case AST_NODE_TYPES.ArrayExpression: node.elements.forEach(element => checkExpressionPreferringObject(context, element) ) return - case 'TemplateLiteral': + case AST_NODE_TYPES.TemplateLiteral: context.report({ node, - message: MSG_PREFER_OBJECT_STYLE + messageId: 'preferObjectStyle' }) return - case 'Literal': + case AST_NODE_TYPES.Literal: // validating other literal types seems out of scope of this plugin if (typeof node.value !== 'string') { return } context.report({ node, - message: MSG_PREFER_OBJECT_STYLE + messageId: 'preferObjectStyle' }) } } -const createPreferredObjectVisitor = context => ({ +const createPreferredObjectVisitor = ( + context: RuleContext +): TSESLint.RuleListener => ({ TaggedTemplateExpression(node) { if (isStringStyle(node)) { context.report({ node, - message: MSG_PREFER_OBJECT_STYLE + messageId: 'preferObjectStyle' }) } }, @@ -110,24 +123,35 @@ const createPreferredObjectVisitor = context => ({ return } + if (!node.value) { + context.report({ + node: node, + messageId: 'emptyCssProp' + }) + return + } + switch (node.value.type) { - case 'Literal': + case AST_NODE_TYPES.Literal: // validating other literal types seems out of scope of this plugin if (typeof node.value.value !== 'string') { return } context.report({ node: node.value, - message: MSG_PREFER_OBJECT_STYLE + messageId: 'preferObjectStyle' }) return - case 'JSXExpressionContainer': + case AST_NODE_TYPES.JSXExpressionContainer: checkExpressionPreferringObject(context, node.value.expression) } } }) -const checkExpressionPreferringString = (context, node) => { +const checkExpressionPreferringString = ( + context: RuleContext, + node: TSESTree.Node +) => { switch (node.type) { case 'ArrayExpression': node.elements.forEach(element => @@ -137,7 +161,7 @@ const checkExpressionPreferringString = (context, node) => { case 'ObjectExpression': context.report({ node, - message: MSG_PREFER_STRING_STYLE + messageId: 'preferStringStyle' }) return case 'Literal': @@ -147,12 +171,14 @@ const checkExpressionPreferringString = (context, node) => { } context.report({ node, - message: MSG_PREFER_WRAPPING_WITH_CSS + messageId: 'preferWrappingWithCSS' }) } } -const createPreferredStringVisitor = context => ({ +const createPreferredStringVisitor = ( + context: RuleContext +): TSESLint.RuleListener => ({ CallExpression(node) { if (isObjectStyle(node)) { node.arguments.forEach(argument => @@ -166,38 +192,62 @@ const createPreferredStringVisitor = context => ({ return } + if (!node.value) { + context.report({ + node: node, + messageId: 'emptyCssProp' + }) + return + } + switch (node.value.type) { - case 'Literal': + case AST_NODE_TYPES.Literal: // validating other literal types seems out of scope of this plugin if (typeof node.value.value !== 'string') { return } context.report({ node: node.value, - message: MSG_PREFER_WRAPPING_WITH_CSS + messageId: 'preferWrappingWithCSS' }) return - case 'JSXExpressionContainer': + case AST_NODE_TYPES.JSXExpressionContainer: checkExpressionPreferringString(context, node.value.expression) } } }) -export default { +type RuleOptions = [('string' | 'object')?] + +type MessageId = + | 'preferStringStyle' + | 'preferObjectStyle' + | 'preferWrappingWithCSS' + | 'emptyCssProp' + +type RuleContext = TSESLint.RuleContext + +export default createRule({ + name: __filename, meta: { docs: { - description: 'Choose between string or object styles', - category: 'Stylistic Issues', + description: 'Choose between styles written as strings or objects', recommended: false }, - fixable: null, // or "code" or "whitespace" + messages: { + preferStringStyle: 'Styles should be written using strings.', + preferObjectStyle: 'Styles should be written using objects.', + preferWrappingWithCSS: `Prefer wrapping your string styles with \`css\` call.`, + emptyCssProp: `Empty \`css\` prop is not valid.` + }, schema: [ { enum: ['string', 'object'] } - ] + ], + type: 'problem' }, - + defaultOptions: [], create(context) { const preferredSyntax = context.options[0] @@ -210,4 +260,4 @@ export default { return {} } } -} +}) diff --git a/packages/eslint-plugin/src/utils.ts b/packages/eslint-plugin/src/utils.ts new file mode 100644 index 0000000000..7fbef3077c --- /dev/null +++ b/packages/eslint-plugin/src/utils.ts @@ -0,0 +1,12 @@ +import { ESLintUtils } from '@typescript-eslint/utils' +import { parse as parsePath } from 'path' + +const { version } = require('../package.json') + +export const REPO_URL = 'https://github.com/emotion-js/emotion' + +export const createRule = ESLintUtils.RuleCreator(name => { + const ruleName = parsePath(name).name + + return `${REPO_URL}/blob/@emotion/eslint-plugin@${version}/packages/eslint-plugin/docs/rules/${ruleName}.md` +}) diff --git a/packages/eslint-plugin/test/rules/import-from-emotion.test.js b/packages/eslint-plugin/test/rules/import-from-emotion.test.ts similarity index 60% rename from packages/eslint-plugin/test/rules/import-from-emotion.test.js rename to packages/eslint-plugin/test/rules/import-from-emotion.test.ts index b28f99730d..99be3a0fa0 100644 --- a/packages/eslint-plugin/test/rules/import-from-emotion.test.js +++ b/packages/eslint-plugin/test/rules/import-from-emotion.test.ts @@ -2,12 +2,12 @@ * @jest-environment node */ -import { RuleTester } from 'eslint' -import { rules as emotionRules } from '@emotion/eslint-plugin' +import { TSESLint } from '@typescript-eslint/utils' +import rule from '../../src/rules/import-from-emotion' +import { espreeParser } from '../test-utils' -const rule = emotionRules['import-from-emotion'] - -RuleTester.setDefaultConfig({ +const ruleTester = new TSESLint.RuleTester({ + parser: espreeParser, parserOptions: { ecmaVersion: 2018, sourceType: 'module', @@ -17,8 +17,6 @@ RuleTester.setDefaultConfig({ } }) -const ruleTester = new RuleTester() - ruleTester.run('emotion jsx', rule, { valid: [ { @@ -31,8 +29,7 @@ ruleTester.run('emotion jsx', rule, { code: `import { css } from 'react-emotion'`, errors: [ { - message: - "emotion's exports should be imported directly from emotion rather than from react-emotion" + messageId: 'incorrectImport' } ], output: `import { css } from 'emotion'` @@ -41,8 +38,7 @@ ruleTester.run('emotion jsx', rule, { code: `import styled, { css } from 'react-emotion'`, errors: [ { - message: - "emotion's exports should be imported directly from emotion rather than from react-emotion" + messageId: 'incorrectImport' } ], output: `import styled from '@emotion/styled';\nimport { css } from 'emotion';` @@ -51,8 +47,7 @@ ruleTester.run('emotion jsx', rule, { code: `import styled, { css as somethingElse } from 'react-emotion'`, errors: [ { - message: - "emotion's exports should be imported directly from emotion rather than from react-emotion" + messageId: 'incorrectImport' } ], output: `import styled from '@emotion/styled';\nimport { css as somethingElse } from 'emotion';` diff --git a/packages/eslint-plugin/test/rules/jsx-import.test.js b/packages/eslint-plugin/test/rules/jsx-import.test.ts similarity index 71% rename from packages/eslint-plugin/test/rules/jsx-import.test.js rename to packages/eslint-plugin/test/rules/jsx-import.test.ts index 6a0fa0b793..f245357e64 100644 --- a/packages/eslint-plugin/test/rules/jsx-import.test.js +++ b/packages/eslint-plugin/test/rules/jsx-import.test.ts @@ -2,12 +2,12 @@ * @jest-environment node */ -import { RuleTester } from 'eslint' -import { rules as emotionRules } from '@emotion/eslint-plugin' +import { TSESLint } from '@typescript-eslint/utils' +import rule from '../../src/rules/jsx-import' +import { espreeParser } from '../test-utils' -const rule = emotionRules['jsx-import'] - -RuleTester.setDefaultConfig({ +const ruleTester = new TSESLint.RuleTester({ + parser: espreeParser, parserOptions: { ecmaVersion: 2018, sourceType: 'module', @@ -17,8 +17,6 @@ RuleTester.setDefaultConfig({ } }) -const ruleTester = new RuleTester() - ruleTester.run('emotion jsx', rule, { valid: [ { @@ -73,6 +71,14 @@ ruleTester.run('emotion jsx', rule, { let ele =
` + }, + { + code: ` + /** @jsx jsx */ + import {jsx} from '@emotion/react' + // it's invalid but not for this rule + let ele =
+ ` } ], @@ -84,8 +90,7 @@ let ele =
`.trim(), errors: [ { - message: - 'The css prop can only be used if jsx from @emotion/react is imported and it is set as the jsx pragma' + messageId: 'cssPropWithPragma' } ], output: ` @@ -101,8 +106,8 @@ let ele =
`.trim(), errors: [ { - message: - 'The css prop can only be used if jsxImportSource is set to @emotion/react' + messageId: 'cssProp', + data: { importSource: '@emotion/react' } } ], output: ` @@ -117,8 +122,8 @@ let ele =
`.trim(), errors: [ { - message: - 'The css prop can only be used if jsxImportSource is set to @iChenLei/react' + messageId: 'cssProp', + data: { importSource: '@iChenLei/react' } } ], output: ` @@ -134,8 +139,8 @@ let ele =
`.trim(), errors: [ { - message: - 'The css prop can only be used if jsxImportSource is set to @iChenLei/react' + messageId: 'cssProp', + data: { importSource: '@iChenLei/react' } } ], output: ` @@ -150,8 +155,7 @@ let ele =
`.trim(), errors: [ { - message: - 'The css prop can only be used if jsx from @emotion/react is imported and it is set as the jsx pragma' + messageId: 'cssPropWithPragma' } ], output: ` @@ -168,8 +172,7 @@ let ele =
`.trim(), errors: [ { - message: - 'The css prop can only be used if jsx from @emotion/react is imported and it is set as the jsx pragma' + messageId: 'cssPropWithPragma' } ], output: ` @@ -186,8 +189,7 @@ let ele =
`.trim(), errors: [ { - message: - 'The css prop can only be used if jsx from @emotion/react is imported and it is set as the jsx pragma' + messageId: 'cssPropWithPragma' } ], output: ` @@ -203,8 +205,7 @@ let ele =
`.trim(), errors: [ { - message: - 'The css prop can only be used if jsx from @emotion/react is imported and it is set as the jsx pragma' + messageId: 'cssPropWithPragma' } ], output: ` @@ -219,8 +220,7 @@ let ele =
`.trim(), errors: [ { - message: - 'The css prop can only be used if jsx from @emotion/react is imported and it is set as the jsx pragma' + messageId: 'cssPropWithPragma' } ], output: ` @@ -231,13 +231,30 @@ let ele =
}, { code: ` +/** @jsx jsx */ +import * as emotion from '@emotion/react' +let ele =
+ `.trim(), + errors: [ + { + messageId: 'cssPropWithPragma' + } + ], + output: ` +/** @jsx jsx */ +/** @jsx emotion.jsx */ +import * as emotion from '@emotion/react' +let ele =
+ `.trim() + }, + { + code: ` import {jsx} from '@emotion/react' let ele =
`.trim(), errors: [ { - message: - 'The css prop can only be used if jsx from @emotion/react is imported and it is set as the jsx pragma' + messageId: 'cssPropWithPragma' } ], output: ` @@ -254,12 +271,10 @@ let ele2 =
`.trim(), errors: [ { - message: - 'The css prop can only be used if jsx from @emotion/react is imported and it is set as the jsx pragma' + messageId: 'cssPropWithPragma' }, { - message: - 'The css prop can only be used if jsx from @emotion/react is imported and it is set as the jsx pragma' + messageId: 'cssPropWithPragma' } ], output: ` @@ -278,8 +293,7 @@ let ele2 =
`.trim(), errors: [ { - message: - 'Template literals should be replaced with tagged template literals using `css` when using the css prop' + messageId: 'templateLiterals' } ], output: ` @@ -297,8 +311,7 @@ let ele2 =
`.trim(), errors: [ { - message: - 'Template literals should be replaced with tagged template literals using `css` when using the css prop' + messageId: 'templateLiterals' } ], output: ` @@ -316,8 +329,7 @@ let ele2 =
`.trim(), errors: [ { - message: - 'Template literals should be replaced with tagged template literals using `css` when using the css prop' + messageId: 'templateLiterals' } ], output: ` diff --git a/packages/eslint-plugin/test/rules/no-vanilla.test.js b/packages/eslint-plugin/test/rules/no-vanilla.test.ts similarity index 58% rename from packages/eslint-plugin/test/rules/no-vanilla.test.js rename to packages/eslint-plugin/test/rules/no-vanilla.test.ts index cb77156431..a897ec3a70 100644 --- a/packages/eslint-plugin/test/rules/no-vanilla.test.js +++ b/packages/eslint-plugin/test/rules/no-vanilla.test.ts @@ -2,12 +2,12 @@ * @jest-environment node */ -import { RuleTester } from 'eslint' -import { rules as emotionRules } from '@emotion/eslint-plugin' +import { TSESLint } from '@typescript-eslint/utils' +import rule from '../../src/rules/no-vanilla' +import { espreeParser } from '../test-utils' -const rule = emotionRules['no-vanilla'] - -RuleTester.setDefaultConfig({ +const ruleTester = new TSESLint.RuleTester({ + parser: espreeParser, parserOptions: { ecmaVersion: 2018, sourceType: 'module', @@ -17,8 +17,6 @@ RuleTester.setDefaultConfig({ } }) -const ruleTester = new RuleTester() - ruleTester.run('no-vanilla', rule, { valid: [{ code: `import { css } from '@emotion/react'` }], invalid: [ @@ -26,7 +24,7 @@ ruleTester.run('no-vanilla', rule, { code: `import { css } from '@emotion/css'`, errors: [ { - message: `Vanilla emotion should not be used` + messageId: 'vanillaEmotion' } ] } diff --git a/packages/eslint-plugin/test/rules/pkg-renaming.test.js b/packages/eslint-plugin/test/rules/pkg-renaming.test.ts similarity index 53% rename from packages/eslint-plugin/test/rules/pkg-renaming.test.js rename to packages/eslint-plugin/test/rules/pkg-renaming.test.ts index 0377b13ee4..6e7093212e 100644 --- a/packages/eslint-plugin/test/rules/pkg-renaming.test.js +++ b/packages/eslint-plugin/test/rules/pkg-renaming.test.ts @@ -2,10 +2,12 @@ * @jest-environment node */ -const { RuleTester } = require('eslint') -const rule = require('@emotion/eslint-plugin').rules['pkg-renaming'] +import { TSESLint } from '@typescript-eslint/utils' +import rule from '../../src/rules/pkg-renaming' +import { espreeParser } from '../test-utils' -RuleTester.setDefaultConfig({ +const ruleTester = new TSESLint.RuleTester({ + parser: espreeParser, parserOptions: { ecmaVersion: 2018, sourceType: 'module', @@ -15,8 +17,6 @@ RuleTester.setDefaultConfig({ } }) -const ruleTester = new RuleTester() - ruleTester.run('pkg-renaming', rule, { valid: [ { @@ -31,8 +31,11 @@ ruleTester.run('pkg-renaming', rule, { code: `import { css } from 'emotion'`, errors: [ { - message: - '"emotion" has been renamed to "@emotion/css", please import it from "@emotion/css" instead' + messageId: 'renamePackage', + data: { + beforeName: '"emotion"', + afterName: '"@emotion/css"' + } } ], output: `import { css } from '@emotion/css'` @@ -41,8 +44,11 @@ ruleTester.run('pkg-renaming', rule, { code: `import { css } from '@emotion/core'`, errors: [ { - message: - '"@emotion/core" has been renamed to "@emotion/react", please import it from "@emotion/react" instead' + messageId: 'renamePackage', + data: { + beforeName: '"@emotion/core"', + afterName: '"@emotion/react"' + } } ], output: `import { css } from '@emotion/react'` @@ -51,8 +57,11 @@ ruleTester.run('pkg-renaming', rule, { code: `import css from '@emotion/css'`, errors: [ { - message: - 'The default export of "@emotion/css" in Emotion 10 has been moved to a named export, `css`, from "@emotion/react" in Emotion 11, please import it from "@emotion/react"' + messageId: 'exportChange', + data: { + name: '@emotion/css', + replacement: '@emotion/react' + } } ], output: `import { css } from '@emotion/react'` @@ -61,8 +70,11 @@ ruleTester.run('pkg-renaming', rule, { code: `import css from '@emotion/css/macro'`, errors: [ { - message: - 'The default export of "@emotion/css/macro" in Emotion 10 has been moved to a named export, `css`, from "@emotion/react/macro" in Emotion 11, please import it from "@emotion/react/macro"' + messageId: 'exportChange', + data: { + name: '@emotion/css/macro', + replacement: '@emotion/react/macro' + } } ], output: `import { css } from '@emotion/react/macro'` @@ -71,8 +83,7 @@ ruleTester.run('pkg-renaming', rule, { code: `import {ThemeProvider, withTheme} from 'emotion-theming'`, errors: [ { - message: - '"emotion-theming" has been moved into "@emotion/react", please import its exports from "@emotion/react"' + messageId: 'emotionTheming' } ], output: `import {ThemeProvider, withTheme} from '@emotion/react'` diff --git a/packages/eslint-plugin/test/rules/styled-import.test.js b/packages/eslint-plugin/test/rules/styled-import.test.ts similarity index 63% rename from packages/eslint-plugin/test/rules/styled-import.test.js rename to packages/eslint-plugin/test/rules/styled-import.test.ts index 4909d2dc73..944053cd46 100644 --- a/packages/eslint-plugin/test/rules/styled-import.test.js +++ b/packages/eslint-plugin/test/rules/styled-import.test.ts @@ -2,12 +2,12 @@ * @jest-environment node */ -import { RuleTester } from 'eslint' -import { rules as emotionRules } from '@emotion/eslint-plugin' +import { TSESLint } from '@typescript-eslint/utils' +import rule from '../../src/rules/styled-import' +import { espreeParser } from '../test-utils' -const rule = emotionRules['styled-import'] - -RuleTester.setDefaultConfig({ +const ruleTester = new TSESLint.RuleTester({ + parser: espreeParser, parserOptions: { ecmaVersion: 2018, sourceType: 'module', @@ -17,8 +17,6 @@ RuleTester.setDefaultConfig({ } }) -const ruleTester = new RuleTester() - ruleTester.run('emotion styled', rule, { valid: [ { @@ -35,7 +33,7 @@ import styled from 'react-emotion' `.trim(), errors: [ { - message: `styled should be imported from @emotion/styled` + messageId: 'incorrectImport' } ], output: ` diff --git a/packages/eslint-plugin/test/rules/syntax-preference.test.js b/packages/eslint-plugin/test/rules/syntax-preference.test.ts similarity index 68% rename from packages/eslint-plugin/test/rules/syntax-preference.test.js rename to packages/eslint-plugin/test/rules/syntax-preference.test.ts index 58e2c9d0d1..4ea172d97a 100644 --- a/packages/eslint-plugin/test/rules/syntax-preference.test.js +++ b/packages/eslint-plugin/test/rules/syntax-preference.test.ts @@ -8,12 +8,12 @@ // Requirements // ------------------------------------------------------------------------------ -import { RuleTester } from 'eslint' -import { rules as emotionRules } from '@emotion/eslint-plugin' +import { AST_NODE_TYPES, TSESLint } from '@typescript-eslint/utils' +import rule from '../../src/rules/syntax-preference' +import { espreeParser } from '../test-utils' -const rule = emotionRules['syntax-preference'] - -RuleTester.setDefaultConfig({ +const ruleTester = new TSESLint.RuleTester({ + parser: espreeParser, parserOptions: { ecmaVersion: 2018, sourceType: 'module', @@ -27,8 +27,6 @@ RuleTester.setDefaultConfig({ // Tests // ------------------------------------------------------------------------------ -const ruleTester = new RuleTester() - ruleTester.run('syntax-preference (string)', rule, { valid: [ // give me some code that won't trigger a warning @@ -68,8 +66,8 @@ ruleTester.run('syntax-preference (string)', rule, { options: ['string'], errors: [ { - message: 'Styles should be written using strings.', - type: 'ObjectExpression' + messageId: 'preferStringStyle', + type: AST_NODE_TYPES.ObjectExpression } ] }, @@ -78,8 +76,8 @@ ruleTester.run('syntax-preference (string)', rule, { options: ['string'], errors: [ { - message: 'Styles should be written using strings.', - type: 'ObjectExpression' + messageId: 'preferStringStyle', + type: AST_NODE_TYPES.ObjectExpression } ] }, @@ -88,8 +86,8 @@ ruleTester.run('syntax-preference (string)', rule, { options: ['string'], errors: [ { - message: 'Styles should be written using strings.', - type: 'ObjectExpression' + messageId: 'preferStringStyle', + type: AST_NODE_TYPES.ObjectExpression } ] }, @@ -98,8 +96,8 @@ ruleTester.run('syntax-preference (string)', rule, { options: ['string'], errors: [ { - message: 'Prefer wrapping your string styles with `css` call.', - type: 'Literal' + messageId: 'preferWrappingWithCSS', + type: AST_NODE_TYPES.Literal } ] }, @@ -108,8 +106,8 @@ ruleTester.run('syntax-preference (string)', rule, { options: ['string'], errors: [ { - message: 'Prefer wrapping your string styles with `css` call.', - type: 'Literal' + messageId: 'preferWrappingWithCSS', + type: AST_NODE_TYPES.Literal } ] }, @@ -118,12 +116,12 @@ ruleTester.run('syntax-preference (string)', rule, { options: ['string'], errors: [ { - message: 'Prefer wrapping your string styles with `css` call.', - type: 'Literal' + messageId: 'preferWrappingWithCSS', + type: AST_NODE_TYPES.Literal }, { - message: 'Styles should be written using strings.', - type: 'ObjectExpression' + messageId: 'preferStringStyle', + type: AST_NODE_TYPES.ObjectExpression } ] }, @@ -132,8 +130,18 @@ ruleTester.run('syntax-preference (string)', rule, { options: ['string'], errors: [ { - message: 'Styles should be written using strings.', - type: 'ObjectExpression' + messageId: 'preferStringStyle', + type: AST_NODE_TYPES.ObjectExpression + } + ] + }, + { + code: `const Foo = () =>
`, + options: ['string'], + errors: [ + { + messageId: 'emptyCssProp', + type: AST_NODE_TYPES.JSXAttribute } ] } @@ -171,8 +179,8 @@ ruleTester.run('syntax-preference (object)', rule, { options: ['object'], errors: [ { - message: 'Styles should be written using objects.', - type: 'TaggedTemplateExpression' + messageId: 'preferObjectStyle', + type: AST_NODE_TYPES.TaggedTemplateExpression } ] }, @@ -181,8 +189,8 @@ ruleTester.run('syntax-preference (object)', rule, { options: ['object'], errors: [ { - message: 'Styles should be written using objects.', - type: 'TaggedTemplateExpression' + messageId: 'preferObjectStyle', + type: AST_NODE_TYPES.TaggedTemplateExpression } ] }, @@ -191,8 +199,8 @@ ruleTester.run('syntax-preference (object)', rule, { options: ['object'], errors: [ { - message: 'Styles should be written using objects.', - type: 'TaggedTemplateExpression' + messageId: 'preferObjectStyle', + type: AST_NODE_TYPES.TaggedTemplateExpression } ] }, @@ -201,8 +209,8 @@ ruleTester.run('syntax-preference (object)', rule, { options: ['object'], errors: [ { - message: 'Styles should be written using objects.', - type: 'Literal' + messageId: 'preferObjectStyle', + type: AST_NODE_TYPES.Literal } ] }, @@ -211,8 +219,8 @@ ruleTester.run('syntax-preference (object)', rule, { options: ['object'], errors: [ { - message: 'Styles should be written using objects.', - type: 'Literal' + messageId: 'preferObjectStyle', + type: AST_NODE_TYPES.Literal } ] }, @@ -221,12 +229,12 @@ ruleTester.run('syntax-preference (object)', rule, { options: ['object'], errors: [ { - message: 'Styles should be written using objects.', - type: 'Literal' + messageId: 'preferObjectStyle', + type: AST_NODE_TYPES.Literal }, { - message: 'Styles should be written using objects.', - type: 'TaggedTemplateExpression' + messageId: 'preferObjectStyle', + type: AST_NODE_TYPES.TaggedTemplateExpression } ] }, @@ -235,12 +243,22 @@ ruleTester.run('syntax-preference (object)', rule, { options: ['object'], errors: [ { - message: 'Styles should be written using objects.', - type: 'Literal' + messageId: 'preferObjectStyle', + type: AST_NODE_TYPES.Literal }, { - message: 'Styles should be written using objects.', - type: 'TaggedTemplateExpression' + messageId: 'preferObjectStyle', + type: AST_NODE_TYPES.TaggedTemplateExpression + } + ] + }, + { + code: `const Foo = () =>
`, + options: ['object'], + errors: [ + { + messageId: 'emptyCssProp', + type: AST_NODE_TYPES.JSXAttribute } ] } diff --git a/packages/eslint-plugin/test/test-utils.ts b/packages/eslint-plugin/test/test-utils.ts new file mode 100644 index 0000000000..551a54e9db --- /dev/null +++ b/packages/eslint-plugin/test/test-utils.ts @@ -0,0 +1,6 @@ +import resolveFrom from 'resolve-from' + +export const espreeParser: string = resolveFrom( + require.resolve('eslint'), + 'espree' +) diff --git a/packages/hash/package.json b/packages/hash/package.json index c22396e494..782efc7486 100644 --- a/packages/hash/package.json +++ b/packages/hash/package.json @@ -4,13 +4,12 @@ "description": "A MurmurHash2 implementation", "main": "dist/emotion-hash.cjs.js", "module": "dist/emotion-hash.esm.js", - "types": "types/index.d.ts", + "types": "dist/emotion-hash.cjs.d.ts", "license": "MIT", "repository": "https://github.com/emotion-js/emotion/tree/main/packages/hash", "files": [ "src", - "dist", - "types/*.d.ts" + "dist" ], "scripts": { "test:typescript": "dtslint types" diff --git a/packages/hash/src/index.d.ts b/packages/hash/src/index.d.ts deleted file mode 100644 index 9e46093759..0000000000 --- a/packages/hash/src/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from '../types' -export { default } from '../types' diff --git a/packages/hash/src/index.js b/packages/hash/src/index.ts similarity index 96% rename from packages/hash/src/index.js rename to packages/hash/src/index.ts index dacf52f904..c7d19839e7 100644 --- a/packages/hash/src/index.js +++ b/packages/hash/src/index.ts @@ -1,9 +1,8 @@ -// @flow /* eslint-disable */ // Inspired by https://github.com/garycourt/murmurhash-js // Ported from https://github.com/aappleby/smhasher/blob/61a0530f28277f2e850bfc39600ce61d02b518de/src/MurmurHash2.cpp#L37-L86 -export default function murmur2(str: string) { +export default function murmur2(str: string): string { // 'm' and 'r' are mixing constants generated offline. // They're not really 'magic', they just happen to work well. diff --git a/packages/hash/types/index.d.ts b/packages/hash/types/index.d.ts index 872aa0beff..2c736dff8d 100644 --- a/packages/hash/types/index.d.ts +++ b/packages/hash/types/index.d.ts @@ -1 +1 @@ -export default function murmurhash2_32_gc(str: string): string +export { default } from '..' diff --git a/packages/is-prop-valid/package.json b/packages/is-prop-valid/package.json index e5f5991960..370aed2872 100644 --- a/packages/is-prop-valid/package.json +++ b/packages/is-prop-valid/package.json @@ -4,7 +4,7 @@ "description": "A function to check whether a prop is valid for HTML and SVG elements", "main": "dist/emotion-is-prop-valid.cjs.js", "module": "dist/emotion-is-prop-valid.esm.js", - "types": "types/index.d.ts", + "types": "dist/emotion-is-prop-valid.cjs.d.ts", "license": "MIT", "repository": "https://github.com/emotion-js/emotion/tree/main/packages/is-prop-valid", "scripts": { @@ -22,8 +22,7 @@ }, "files": [ "src", - "dist", - "types/*.d.ts" + "dist" ], "exports": { ".": { diff --git a/packages/is-prop-valid/src/index.d.ts b/packages/is-prop-valid/src/index.d.ts deleted file mode 100644 index 9e46093759..0000000000 --- a/packages/is-prop-valid/src/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from '../types' -export { default } from '../types' diff --git a/packages/is-prop-valid/src/index.js b/packages/is-prop-valid/src/index.ts similarity index 69% rename from packages/is-prop-valid/src/index.js rename to packages/is-prop-valid/src/index.ts index 9763a339e7..88fb415329 100644 --- a/packages/is-prop-valid/src/index.js +++ b/packages/is-prop-valid/src/index.ts @@ -1,9 +1,9 @@ -// @flow import memoize from '@emotion/memoize' -declare var codegen: { require: string => RegExp } +declare const codegen: { require: (path: string) => any } -const reactPropsRegex = codegen.require('./props') +// eslint-disable-next-line no-undef +const reactPropsRegex: RegExp = codegen.require('./props') // https://esbench.com/bench/5bfee68a4cd7e6009ef61d23 const isPropValid = /* #__PURE__ */ memoize( diff --git a/packages/is-prop-valid/src/props.js b/packages/is-prop-valid/src/props.js index d93c7022c7..2dccc9b9a4 100644 --- a/packages/is-prop-valid/src/props.js +++ b/packages/is-prop-valid/src/props.js @@ -1,4 +1,6 @@ -// @flow +/** + * This module needs to remain pure JavaScript for codegen to work on it + */ const props = { // react props // https://github.com/facebook/react/blob/5495a7f24aef85ba6937truetrue1ce962673ca9f5fde6/src/renderers/dom/shared/hooks/ReactDOMUnknownPropertyHook.js @@ -490,7 +492,6 @@ const props = { class: true, autofocus: true } -// eslint-disable-next-line import/no-commonjs module.exports = `/^((${Object.keys(props).join( '|' )})|(([Dd][Aa][Tt][Aa]|[Aa][Rr][Ii][Aa]|x)-.*))$/` diff --git a/packages/is-prop-valid/types/index.d.ts b/packages/is-prop-valid/types/index.d.ts index e7d00bfdbf..5f85d28f68 100644 --- a/packages/is-prop-valid/types/index.d.ts +++ b/packages/is-prop-valid/types/index.d.ts @@ -1,5 +1,3 @@ -// Definitions by: Junyoung Clare Jang // TypeScript Version: 2.1 -declare function isPropValid(prop: string): boolean -export default isPropValid +export { default } from '..' diff --git a/packages/is-prop-valid/types/tslint.json b/packages/is-prop-valid/types/tslint.json index cd0be207a3..4326a0372b 100644 --- a/packages/is-prop-valid/types/tslint.json +++ b/packages/is-prop-valid/types/tslint.json @@ -17,6 +17,7 @@ "check-preblock" ], - "no-unnecessary-generics": false + "no-unnecessary-generics": false, + "no-default-import": false } } diff --git a/packages/jest/src/create-enzyme-serializer.js b/packages/jest/src/create-enzyme-serializer.js index c91d440922..2178056037 100644 --- a/packages/jest/src/create-enzyme-serializer.js +++ b/packages/jest/src/create-enzyme-serializer.js @@ -1,5 +1,4 @@ -// @flow -import type { Options } from './create-serializer' +/* import type { Options } from './create-serializer' */ import { createSerializer as createEmotionSerializer } from './create-serializer' import * as enzymeTickler from './enzyme-tickler' import { createSerializer as createEnzymeToJsonSerializer } from 'enzyme-to-json' @@ -68,23 +67,23 @@ export function createEnzymeSerializer({ classNameReplacer, DOMElements = true, includeStyles = true -}: Options = {}) { +} /* : Options */ = {}) { const emotionSerializer = createEmotionSerializer({ classNameReplacer, DOMElements, includeStyles }) return { - test(node: *) { + test(node) { return wrappedEnzymeSerializer.test(node) || emotionSerializer.test(node) }, serialize( - node: *, - config: *, - indentation: string, - depth: number, - refs: *, - printer: Function + node, + config, + indentation /*: string */, + depth /*: number */, + refs, + printer /*: Function */ ) { if (wrappedEnzymeSerializer.test(node)) { const tickled = enzymeTickler.tickle(node) diff --git a/packages/jest/src/create-serializer.js b/packages/jest/src/create-serializer.js index c1c5795bb6..533b7ecf0c 100644 --- a/packages/jest/src/create-serializer.js +++ b/packages/jest/src/create-serializer.js @@ -1,4 +1,3 @@ -// @flow import prettify from '@emotion/css-prettifier' import { replaceClassNames } from './replace-class-names' import * as enzymeTickler from './enzyme-tickler' @@ -49,13 +48,13 @@ function deepTransform(node, transform) { return node.map(child => deepTransform(child, transform)) } - const transformed: any = transform(node) + const transformed = transform(node) if (transformed !== node && transformed.children) { return copyProps(transformed, { // flatMap to allow a child of to be transformed to children: flatMap( - (deepTransform(transformed.children, transform): any), + deepTransform(transformed.children, transform), id => id ) }) @@ -65,18 +64,20 @@ function deepTransform(node, transform) { } function getPrettyStylesFromClassNames( - classNames: Array, - elements: Array, - indentation: string + classNames /*: Array */, + elements /*: Array */, + indentation /*: string */ ) { return prettify(getStylesFromClassNames(classNames, elements), indentation) } +/* export type Options = { classNameReplacer?: (className: string, index: number) => string, DOMElements?: boolean, includeStyles?: boolean } +*/ function filterEmotionProps(props = {}) { const { @@ -102,9 +103,9 @@ function getLabelsFromClassName(keys, className) { } function isShallowEnzymeElement( - element: any, - keys: string[], - labels: string[] + element /*: any */, + keys /*: string[] */, + labels /*: string[] */ ) { const childClassNames = (element.children || []) .map(({ props = {} }) => props.className || '') @@ -116,47 +117,48 @@ function isShallowEnzymeElement( }) } -const createConvertEmotionElements = (keys: string[]) => (node: any) => { - if (isPrimitive(node)) { - return node - } - if (isEmotionCssPropEnzymeElement(node)) { - const className = enzymeTickler.getTickledClassName(node.props.css) - const labels = getLabelsFromClassName(keys, className || '') - - if (isShallowEnzymeElement(node, keys, labels)) { - const emotionType = node.props.__EMOTION_TYPE_PLEASE_DO_NOT_USE__ - // emotionType will be a string for DOM elements - const type = - typeof emotionType === 'string' - ? emotionType - : emotionType.displayName || emotionType.name || 'Component' +const createConvertEmotionElements = + (keys /*: string[]*/) => (node /*: any*/) => { + if (isPrimitive(node)) { + return node + } + if (isEmotionCssPropEnzymeElement(node)) { + const className = enzymeTickler.getTickledClassName(node.props.css) + const labels = getLabelsFromClassName(keys, className || '') + + if (isShallowEnzymeElement(node, keys, labels)) { + const emotionType = node.props.__EMOTION_TYPE_PLEASE_DO_NOT_USE__ + // emotionType will be a string for DOM elements + const type = + typeof emotionType === 'string' + ? emotionType + : emotionType.displayName || emotionType.name || 'Component' + return { + ...node, + props: filterEmotionProps({ + ...node.props, + className + }), + type + } + } else { + return node.children[node.children.length - 1] + } + } + if (isEmotionCssPropElementType(node)) { return { ...node, - props: filterEmotionProps({ - ...node.props, - className - }), - type + props: filterEmotionProps(node.props), + type: node.props.__EMOTION_TYPE_PLEASE_DO_NOT_USE__ } - } else { - return node.children[node.children.length - 1] } - } - if (isEmotionCssPropElementType(node)) { - return { - ...node, - props: filterEmotionProps(node.props), - type: node.props.__EMOTION_TYPE_PLEASE_DO_NOT_USE__ + if (isReactElement(node)) { + return copyProps({}, node) } + return node } - if (isReactElement(node)) { - return copyProps({}, node) - } - return node -} -function clean(node: any, classNames: string[]) { +function clean(node, classNames /*: string[] */) { if (Array.isArray(node)) { for (const child of node) { clean(child, classNames) @@ -186,17 +188,17 @@ export function createSerializer({ classNameReplacer, DOMElements = true, includeStyles = true -}: Options = {}) { +} /* : Options */ = {}) { const cache = new WeakSet() const isTransformed = val => cache.has(val) function serialize( - val: *, - config: *, - indentation: string, - depth: number, - refs: *, - printer: Function + val, + config, + indentation /*: string */, + depth /*: number */, + refs, + printer /*: Function */ ) { const elements = getStyleElements() const keys = getKeys(elements) @@ -223,7 +225,7 @@ export function createSerializer({ } return { - test(val: *) { + test(val) { return ( val && !isTransformed(val) && diff --git a/packages/jest/src/enzyme-serializer.js b/packages/jest/src/enzyme-serializer.js index 78c5bba6ce..2b73962978 100644 --- a/packages/jest/src/enzyme-serializer.js +++ b/packages/jest/src/enzyme-serializer.js @@ -1,3 +1,2 @@ -// @flow import { createEnzymeSerializer } from './create-enzyme-serializer' export const { test, serialize } = createEnzymeSerializer() diff --git a/packages/jest/src/enzyme.js b/packages/jest/src/enzyme.js index 929a5b359f..72fdee8bd1 100644 --- a/packages/jest/src/enzyme.js +++ b/packages/jest/src/enzyme.js @@ -1,3 +1,2 @@ -// @flow export { createEnzymeSerializer } from './create-enzyme-serializer' export { matchers } from './matchers' diff --git a/packages/jest/src/index.js b/packages/jest/src/index.js index 0b67c3dd0d..c675404fda 100644 --- a/packages/jest/src/index.js +++ b/packages/jest/src/index.js @@ -1,3 +1,2 @@ -// @flow export { createSerializer } from './create-serializer' export { matchers } from './matchers' diff --git a/packages/jest/src/matchers.js b/packages/jest/src/matchers.js index 5e648fcca5..4edae6bb6c 100644 --- a/packages/jest/src/matchers.js +++ b/packages/jest/src/matchers.js @@ -1,4 +1,3 @@ -// @flow import chalk from 'chalk' import * as stylis from 'stylis' import * as specificity from 'specificity' @@ -40,10 +39,10 @@ function valueMatches(declaration, value) { } function toHaveStyleRule( - received: *, - property: *, - value: *, - options?: { target?: string | RegExp, media?: string } = {} + received, + property, + value, + options /* ?: { target?: string | RegExp, media?: string } */ = {} ) { if (Array.isArray(received)) { throw new Error( diff --git a/packages/jest/src/replace-class-names.js b/packages/jest/src/replace-class-names.js index 892b67081b..713b7c8b26 100644 --- a/packages/jest/src/replace-class-names.js +++ b/packages/jest/src/replace-class-names.js @@ -1,4 +1,3 @@ -// @flow function defaultClassNameReplacer(className, index) { return `emotion-${index}` } @@ -6,14 +5,14 @@ function defaultClassNameReplacer(className, index) { const componentSelectorClassNamePattern = /^e[a-zA-Z0-9]+[0-9]+$/ export const replaceClassNames = ( - classNames: Array, - styles: string, - code: string, - keys: Array, - classNameReplacer: ( + classNames /*: Array */, + styles /*: string */, + code /*: string */, + keys /*: Array */, + classNameReplacer /*: ( className: string, index: number - ) => string = defaultClassNameReplacer + ) => string */ = defaultClassNameReplacer ) => { let index = 0 let keyPattern = new RegExp(`^(${keys.join('|')})-`) diff --git a/packages/jest/src/serializer.js b/packages/jest/src/serializer.js index 3f6afed572..941aa43682 100644 --- a/packages/jest/src/serializer.js +++ b/packages/jest/src/serializer.js @@ -1,3 +1,2 @@ -// @flow import { createSerializer } from './create-serializer' export const { test, serialize } = createSerializer() diff --git a/packages/jest/src/utils.js b/packages/jest/src/utils.js index 8a4cad723b..378dec2dae 100644 --- a/packages/jest/src/utils.js +++ b/packages/jest/src/utils.js @@ -1,16 +1,20 @@ -// @flow - const isBrowser = typeof document !== 'undefined' function last(arr) { return arr.length > 0 ? arr[arr.length - 1] : undefined } -export function flatMap(arr: T[], iteratee: (arg: T) => S[] | S): S[] { +export function flatMap /* */( + arr /*: T[] */, + iteratee /*: (arg: T) => S[] | S */ +) /*: S[] */ { return [].concat(...arr.map(iteratee)) } -export function findLast(arr: T[], predicate: T => boolean) { +export function findLast /* */( + arr /*: T[] */, + predicate /*: T => boolean */ +) { for (let i = arr.length - 1; i >= 0; i--) { if (predicate(arr[i])) { return arr[i] @@ -18,10 +22,10 @@ export function findLast(arr: T[], predicate: T => boolean) { } } -export function findIndexFrom( - arr: T[], - fromIndex: number, - predicate: T => boolean +export function findIndexFrom /* */( + arr /*: T[] */, + fromIndex /*: number */, + predicate /*: T => boolean */ ) { for (let i = fromIndex; i < arr.length; i++) { if (predicate(arr[i])) { @@ -32,7 +36,7 @@ export function findIndexFrom( return -1 } -function getClassNames(selectors: any, classes?: string) { +function getClassNames(selectors, classes /* ?: string */) { return classes ? selectors.concat(classes.split(' ')) : selectors } @@ -58,7 +62,7 @@ function getClassNameProp(node) { return (node && node.prop('className')) || '' } -export function unwrapFromPotentialFragment(node: *) { +export function unwrapFromPotentialFragment(node) { if (node.type() === Symbol.for('react.fragment')) { const isShallow = !!node.dive if (isShallow) { @@ -86,25 +90,25 @@ function getClassNamesFromCheerio(selectors, node) { return getClassNames(selectors, classes) } -function getClassNamesFromDOMElement(selectors, node: any) { +function getClassNamesFromDOMElement(selectors, node) { return getClassNames(selectors, node.getAttribute('class')) } -export function isReactElement(val: any): boolean { +export function isReactElement(val) /*: boolean */ { return ( val.$$typeof === Symbol.for('react.test.json') || val.$$typeof === Symbol.for('react.element') ) } -export function isEmotionCssPropElementType(val: any): boolean { +export function isEmotionCssPropElementType(val) /*: boolean */ { return ( val.$$typeof === Symbol.for('react.element') && val.type.displayName === 'EmotionCssPropInternal' ) } -export function isStyledElementType(val: any): boolean { +export function isStyledElementType(val /* : any */) /* : boolean */ { if (val.$$typeof !== Symbol.for('react.element')) { return false } @@ -112,7 +116,7 @@ export function isStyledElementType(val: any): boolean { return type.__emotion_real === type } -export function isEmotionCssPropEnzymeElement(val: any): boolean { +export function isEmotionCssPropEnzymeElement(val /* : any */) /*: boolean */ { return ( val.$$typeof === Symbol.for('react.test.json') && val.type === 'EmotionCssPropInternal' @@ -120,7 +124,7 @@ export function isEmotionCssPropEnzymeElement(val: any): boolean { } const domElementPattern = /^((HTML|SVG)\w*)?Element$/ -export function isDOMElement(val: any): boolean { +export function isDOMElement(val) /*: boolean */ { return ( val.nodeType === 1 && val.constructor && @@ -129,15 +133,15 @@ export function isDOMElement(val: any): boolean { ) } -function isEnzymeElement(val: any): boolean { +function isEnzymeElement(val) /*: boolean */ { return typeof val.findWhere === 'function' } -function isCheerioElement(val: any): boolean { +function isCheerioElement(val) /*: boolean */ { return val.cheerio === '[cheerio object]' } -export function getClassNamesFromNodes(nodes: Array) { +export function getClassNamesFromNodes(nodes /*: Array */) { return nodes.reduce((selectors, node) => { if (isEnzymeElement(node)) { return getClassNamesFromEnzyme(selectors, node) @@ -154,7 +158,7 @@ const keyframesPattern = /^@keyframes\s+(animation-[^{\s]+)+/ const removeCommentPattern = /\/\*[\s\S]*?\*\//g -const getElementRules = (element: HTMLStyleElement): string[] => { +const getElementRules = (element /*: HTMLStyleElement */) /*: string[] */ => { const nonSpeedyRule = element.textContent if (nonSpeedyRule) { return [nonSpeedyRule] @@ -162,7 +166,6 @@ const getElementRules = (element: HTMLStyleElement): string[] => { if (!element.sheet) { return [] } - // $FlowFixMe - flow doesn't know about `cssRules` property return [].slice.call(element.sheet.cssRules).map(cssRule => cssRule.cssText) } @@ -180,9 +183,9 @@ const getKeyframesMap = rules => }, {}) export function getStylesFromClassNames( - classNames: Array, - elements: Array -): string { + classNames /*: Array */, + elements /*: Array */ +) /*: string */ { if (!classNames.length) { return '' } @@ -212,7 +215,7 @@ export function getStylesFromClassNames( const rules = flatMap(elements, getElementRules) let styles = rules - .map((rule: string) => { + .map((rule /*: string */) => { const match = rule.match(selectorPattern) if (!match) { return null @@ -259,35 +262,30 @@ export function getStylesFromClassNames( return (keyframesStyles + styles).replace(removeCommentPattern, '') } -export function getStyleElements(): Array { +export function getStyleElements() /*: Array */ { if (!isBrowser) { throw new Error( 'jest-emotion requires jsdom. See https://jestjs.io/docs/en/configuration#testenvironment-string for more information.' ) } const elements = Array.from(document.querySelectorAll('style[data-emotion]')) - // $FlowFixMe return elements } const unique = arr => Array.from(new Set(arr)) -export function getKeys(elements: Array) { +export function getKeys(elements /*: Array */) { const keys = unique( - elements.map( - element => - // $FlowFixMe we know it exists since we query for elements with this attribute - (element.getAttribute('data-emotion'): string) - ) + elements.map(element => element.getAttribute('data-emotion')) ).filter(Boolean) return keys } export function hasClassNames( - classNames: Array, - selectors: Array, - target?: string | RegExp -): boolean { + classNames /*: Array */, + selectors /*: Array */, + target /* ?: string | RegExp */ +) /*: boolean */ { // selectors is the classNames of specific css rule return selectors.some(selector => { // if no target, use className of the specific css rule and try to find it @@ -307,7 +305,10 @@ export function hasClassNames( }) } -export function getMediaRules(rules: Array, media: string): Array { +export function getMediaRules( + rules /*: Array */, + media /*: string */ +) /*: Array */ { return flatMap( rules.filter(rule => { if (rule.type !== '@media') { @@ -319,10 +320,10 @@ export function getMediaRules(rules: Array, media: string): Array { ) } -export function isPrimitive(test: any) { +export function isPrimitive(test) { return test !== Object(test) } -export function hasIntersection(left: any[], right: any[]) { +export function hasIntersection(left /* any[] */, right /* any[] */) { return left.some(value => right.includes(value)) } diff --git a/packages/jest/test/printer.test.js b/packages/jest/test/printer.test.js index e7f0c0837a..3a90c7f8bd 100644 --- a/packages/jest/test/printer.test.js +++ b/packages/jest/test/printer.test.js @@ -1,4 +1,3 @@ -// @flow import React from 'react' import 'test-utils/legacy-env' import renderer from 'react-test-renderer' diff --git a/packages/memoize/package.json b/packages/memoize/package.json index d017e54bf2..217ea21558 100644 --- a/packages/memoize/package.json +++ b/packages/memoize/package.json @@ -4,7 +4,7 @@ "description": "emotion's memoize utility", "main": "dist/emotion-memoize.cjs.js", "module": "dist/emotion-memoize.esm.js", - "types": "types/index.d.ts", + "types": "dist/emotion-memoize.cjs.d.ts", "license": "MIT", "repository": "https://github.com/emotion-js/emotion/tree/main/packages/memoize", "scripts": { @@ -19,8 +19,7 @@ }, "files": [ "src", - "dist", - "types/*.d.ts" + "dist" ], "exports": { ".": { diff --git a/packages/memoize/src/index.d.ts b/packages/memoize/src/index.d.ts deleted file mode 100644 index 9e46093759..0000000000 --- a/packages/memoize/src/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from '../types' -export { default } from '../types' diff --git a/packages/memoize/src/index.js b/packages/memoize/src/index.js deleted file mode 100644 index b1e3741a18..0000000000 --- a/packages/memoize/src/index.js +++ /dev/null @@ -1,10 +0,0 @@ -// @flow - -export default function memoize(fn: string => V): string => V { - const cache = Object.create(null) - - return (arg: string) => { - if (cache[arg] === undefined) cache[arg] = fn(arg) - return cache[arg] - } -} diff --git a/packages/memoize/src/index.ts b/packages/memoize/src/index.ts new file mode 100644 index 0000000000..2f218b1c8c --- /dev/null +++ b/packages/memoize/src/index.ts @@ -0,0 +1,8 @@ +export default function memoize(fn: (arg: string) => V): (arg: string) => V { + const cache: Record = Object.create(null) + + return (arg: string) => { + if (cache[arg] === undefined) cache[arg] = fn(arg) + return cache[arg] + } +} diff --git a/packages/memoize/types/index.d.ts b/packages/memoize/types/index.d.ts index 23f3580f10..2c736dff8d 100644 --- a/packages/memoize/types/index.d.ts +++ b/packages/memoize/types/index.d.ts @@ -1,3 +1 @@ -type Fn = (key: string) => T - -export default function memoize(fn: Fn): Fn +export { default } from '..' diff --git a/packages/memoize/types/tslint.json b/packages/memoize/types/tslint.json index 2ab14e84ff..20bc577159 100644 --- a/packages/memoize/types/tslint.json +++ b/packages/memoize/types/tslint.json @@ -18,6 +18,7 @@ ], "no-unnecessary-generics": false, - "strict-export-declare-modifiers": false + "strict-export-declare-modifiers": false, + "no-default-import": false } } diff --git a/packages/native/test/native-css.test.js b/packages/native/test/native-css.test.js index ac63ae78fe..f3f0bf870d 100644 --- a/packages/native/test/native-css.test.js +++ b/packages/native/test/native-css.test.js @@ -31,7 +31,6 @@ describe('Emotion native css', () => { // this test checks the keys instead of the objects // because we care about the order of the keys expect( - // $FlowFixMe Object.keys( StyleSheet.flatten( css({ color: 'green' }, `background-color:yellow;`, { flex: 2 }) @@ -39,7 +38,6 @@ describe('Emotion native css', () => { ) ).toEqual(['color', 'backgroundColor', 'flex']) expect( - // $FlowFixMe Object.keys( StyleSheet.flatten( css([ @@ -52,7 +50,6 @@ describe('Emotion native css', () => { ) ).toEqual(['color', 'backgroundColor', 'flex']) expect( - // $FlowFixMe Object.keys( StyleSheet.flatten( css([ @@ -68,7 +65,6 @@ describe('Emotion native css', () => { ) ).toEqual(['color', 'backgroundColor', 'flex']) expect( - // $FlowFixMe Object.keys( StyleSheet.flatten( css([ diff --git a/packages/primitives-core/package.json b/packages/primitives-core/package.json index 17e65a5622..87ff3459de 100644 --- a/packages/primitives-core/package.json +++ b/packages/primitives-core/package.json @@ -4,6 +4,7 @@ "description": "Shared utilities for emotion primitives and native", "main": "dist/emotion-primitives-core.cjs.js", "module": "dist/emotion-primitives-core.esm.js", + "types": "dist/emotion-primitives-core.cjs.d.ts", "files": [ "src", "dist" @@ -18,6 +19,7 @@ }, "devDependencies": { "@emotion/react": "11.11.4", + "@types/css-to-react-native": "^3.0.0", "react": "16.14.0" }, "homepage": "https://emotion.sh", diff --git a/packages/primitives-core/src/css.js b/packages/primitives-core/src/css.ts similarity index 77% rename from packages/primitives-core/src/css.js rename to packages/primitives-core/src/css.ts index 3d993c80f1..fde7c11674 100644 --- a/packages/primitives-core/src/css.js +++ b/packages/primitives-core/src/css.ts @@ -1,17 +1,22 @@ -// @flow -import transform from 'css-to-react-native' +import transform, { Style } from 'css-to-react-native' +import { AbstractStyleSheet } from './types' import { interleave } from './utils' // this is for handleInterpolation // they're reset on every call to css // this is done so we don't create a new // handleInterpolation function on every css call -let styles -let generated = {} +let styles: unknown[] | undefined +let generated: Record = {} let buffer = '' -let lastType - -function handleInterpolation(interpolation: *, i: number, arr: Array<*>) { +let lastType: string | undefined + +function handleInterpolation( + this: unknown, + interpolation: any, + i: number, + arr: any[] +) { let type = typeof interpolation if (type === 'string') { @@ -31,15 +36,7 @@ function handleInterpolation(interpolation: *, i: number, arr: Array<*>) { ) } } else { - handleInterpolation.call( - this, - interpolation( - // $FlowFixMe - this - ), - i, - arr - ) + handleInterpolation.call(this, interpolation(this), i, arr) } return } @@ -49,7 +46,7 @@ function handleInterpolation(interpolation: *, i: number, arr: Array<*>) { if (lastType === 'string' && (isRnStyle || isIrrelevant)) { let converted = convertStyles(buffer) if (converted !== undefined) { - styles.push(converted) + styles!.push(converted) } buffer = '' } @@ -63,13 +60,13 @@ function handleInterpolation(interpolation: *, i: number, arr: Array<*>) { if (arr.length - 1 === i) { let converted = convertStyles(buffer) if (converted !== undefined) { - styles.push(converted) + styles!.push(converted) } buffer = '' } } if (isRnStyle) { - styles.push(interpolation) + styles!.push(interpolation) } if (Array.isArray(interpolation)) { interpolation.forEach(handleInterpolation, this) @@ -79,10 +76,10 @@ function handleInterpolation(interpolation: *, i: number, arr: Array<*>) { // Use platform specific StyleSheet method for creating the styles. // This enables us to use the css``/css({}) in any environment (Native | Sketch | Web) -export function createCss(StyleSheet: Object) { - return function css(...args: any) { +export function createCss(StyleSheet: AbstractStyleSheet) { + return function css(this: unknown, ...args: any[]) { const prevBuffer = buffer - let vals + let vals: any[] // these are declared earlier // this is done so we don't create a new @@ -94,7 +91,7 @@ export function createCss(StyleSheet: Object) { if (args[0] == null || args[0].raw === undefined) { vals = args } else { - vals = interleave(args) + vals = interleave(args as [any, ...any[]]) } try { @@ -116,7 +113,7 @@ export function createCss(StyleSheet: Object) { let propertyValuePattern = /\s*([^\s]+)\s*:\s*(.+?)\s*$/ -function convertPropertyValue(style) { +function convertPropertyValue(this: [string, string][], style: string): void { // Get prop name and prop value let match = propertyValuePattern.exec(style) // match[2] will be " " in cases where there is no value @@ -126,14 +123,14 @@ function convertPropertyValue(style) { // be the whole string so we remove it match.shift() // yes i know this looks funny - this.push(match) + this.push(match as unknown as [string, string]) } } -function convertStyles(str: string) { +function convertStyles(str: string): Style | undefined { if (str.trim() === '') return - const stylePairs = [] + const stylePairs: [string, string][] = [] const parsedString = str.split(';') @@ -142,9 +139,9 @@ function convertStyles(str: string) { try { return transform(stylePairs) } catch (error) { - const msg = error.message + const msg = (error as { message?: string } | undefined)?.message - if (msg.includes('Failed to parse declaration')) { + if (msg && msg.includes('Failed to parse declaration')) { const values = msg .replace('Failed to parse declaration ', '') .replace(/"/g, '') diff --git a/packages/primitives-core/src/index.js b/packages/primitives-core/src/index.ts similarity index 100% rename from packages/primitives-core/src/index.js rename to packages/primitives-core/src/index.ts diff --git a/packages/primitives-core/src/styled.js b/packages/primitives-core/src/styled.ts similarity index 62% rename from packages/primitives-core/src/styled.js rename to packages/primitives-core/src/styled.ts index f5771552e8..e9371e3490 100644 --- a/packages/primitives-core/src/styled.js +++ b/packages/primitives-core/src/styled.ts @@ -1,25 +1,31 @@ -// @flow import * as React from 'react' import { interleave } from './utils' import { ThemeContext } from '@emotion/react' import { createCss } from './css' +import { AbstractStyleSheet } from './types' -let testOmitPropsOnComponent = prop => prop !== 'theme' && prop !== 'as' +let testOmitPropsOnComponent = (prop: string) => + prop !== 'theme' && prop !== 'as' -type CreateStyledOptions = { - getShouldForwardProp: (cmp: React.ElementType) => (prop: string) => boolean +interface CreateStyledOptions { + getShouldForwardProp(cmp: React.ElementType): (prop: string) => boolean } -type StyledOptions = { - shouldForwardProp?: (prop: string) => boolean +interface StyledOptions { + shouldForwardProp?(prop: string): boolean +} + +type StyledProps = Record & { + as?: React.ElementType } export function createStyled( - StyleSheet: Object, - { - getShouldForwardProp = () => testOmitPropsOnComponent - }: CreateStyledOptions = {} + StyleSheet: AbstractStyleSheet, + options?: CreateStyledOptions ) { + const getShouldForwardProp = + options?.getShouldForwardProp ?? (() => testOmitPropsOnComponent) + const css = createCss(StyleSheet) return function createEmotion( @@ -34,18 +40,17 @@ export function createStyled( shouldForwardProp || getShouldForwardProp(component) let shouldUseAs = !defaultShouldForwardProp('as') - return function createStyledComponent(...rawStyles: *) { - let styles + return function createStyledComponent(...rawStyles: any[]) { + let styles: any[] if (rawStyles[0] == null || rawStyles[0].raw === undefined) { styles = rawStyles } else { - styles = interleave(rawStyles) + styles = interleave(rawStyles as [any, ...any[]]) } // do we really want to use the same infra as the web since it only really uses theming? - // $FlowFixMe - let Styled = React.forwardRef((props, ref) => { + let Styled = React.forwardRef((props, ref) => { const finalTag = (shouldUseAs && props.as) || component let mergedProps = props @@ -62,7 +67,7 @@ export function createStyled( ? getShouldForwardProp(finalTag) : defaultShouldForwardProp - let newProps = {} + let newProps: Record = {} for (let key in props) { if (shouldUseAs && key === 'as') continue @@ -75,21 +80,28 @@ export function createStyled( newProps.style = [css.apply(mergedProps, styles), props.style] newProps.ref = ref - // $FlowFixMe return React.createElement(finalTag, newProps) }) - // $FlowFixMe - Styled.withComponent = (newComponent: React.ElementType) => - createEmotion(newComponent)(...styles) Styled.displayName = `emotion(${getDisplayName(component)})` - return Styled + const withComponent = (newComponent: React.ElementType) => + createEmotion(newComponent)(...styles) + + const castedStyled = Styled as typeof Styled & { + withComponent: typeof withComponent + } + + castedStyled.withComponent = withComponent + + return castedStyled } } } -const getDisplayName = primitive => +const getDisplayName = ( + primitive: string | { displayName?: string; name?: string } +) => typeof primitive === 'string' ? primitive : primitive.displayName || primitive.name || 'Styled' diff --git a/packages/primitives-core/src/types.ts b/packages/primitives-core/src/types.ts new file mode 100644 index 0000000000..f606163c52 --- /dev/null +++ b/packages/primitives-core/src/types.ts @@ -0,0 +1,10 @@ +type NamedStyles = { [P in keyof T]: unknown } + +// This is based on the StyleSheet type from @types/react-native +export interface AbstractStyleSheet { + create | NamedStyles>( + styles: T | NamedStyles + ): T + + flatten(style?: unknown[]): unknown +} diff --git a/packages/primitives-core/src/utils.js b/packages/primitives-core/src/utils.ts similarity index 61% rename from packages/primitives-core/src/utils.js rename to packages/primitives-core/src/utils.ts index 953c2043dc..49ee502438 100644 --- a/packages/primitives-core/src/utils.js +++ b/packages/primitives-core/src/utils.ts @@ -1,8 +1,8 @@ -// @flow - -export function interleave(vals: Array<*>) { +export function interleave( + vals: [TemplateStringsArray, ...unknown[]] +): unknown[] { let strings = vals[0] - let finalArray = [strings[0]] + let finalArray: unknown[] = [strings[0]] for (let i = 1, len = vals.length; i < len; i++) { finalArray.push(vals[i]) if (strings[i] !== undefined) { diff --git a/packages/primitives/src/index.js b/packages/primitives/src/index.js index 0dcb3a0d03..a7155513cc 100644 --- a/packages/primitives/src/index.js +++ b/packages/primitives/src/index.js @@ -1,4 +1,3 @@ -// @flow import { StyleSheet, Text, View, Image } from 'react-primitives' import { createCss } from '@emotion/primitives-core' diff --git a/packages/primitives/src/styled.js b/packages/primitives/src/styled.js index 894812d670..6e67d9b9f9 100644 --- a/packages/primitives/src/styled.js +++ b/packages/primitives/src/styled.js @@ -1,4 +1,3 @@ -// @flow import * as React from 'react' import { StyleSheet, View, Text, Image } from 'react-primitives' import { createStyled } from '@emotion/primitives-core' @@ -7,7 +6,7 @@ import { testPickPropsOnOtherComponent } from './test-props' -function getShouldForwardProp(component: React.ElementType) { +function getShouldForwardProp(component /*: React.ElementType */) { switch (component) { case View: case Text: @@ -22,6 +21,7 @@ function getShouldForwardProp(component: React.ElementType) { * a function that returns a styled component which render styles on multiple targets with same code */ +/* type CreateStyledComponent = ( ...styles: any ) => React.StatelessFunctionalComponent & { @@ -35,7 +35,8 @@ export type Styled = BaseStyled & { Text: CreateStyledComponent, Image: CreateStyledComponent } +*/ -let styled: Styled = createStyled(StyleSheet, { getShouldForwardProp }) +let styled /*: Styled */ = createStyled(StyleSheet, { getShouldForwardProp }) export { styled } diff --git a/packages/primitives/src/test-props.js b/packages/primitives/src/test-props.js index aa19f7f78f..ad72f3037a 100644 --- a/packages/primitives/src/test-props.js +++ b/packages/primitives/src/test-props.js @@ -1,4 +1,3 @@ -// @flow import isPropValid from '@emotion/is-prop-valid' const forwardableProps = { @@ -49,7 +48,7 @@ const forwardableProps = { textBreakStrategy: true } -export function testPickPropsOnPrimitiveComponent(prop: string) { +export function testPickPropsOnPrimitiveComponent(prop /*: string */) { return ( forwardableProps[prop] === true || // This will allow the standard react props @@ -59,6 +58,6 @@ export function testPickPropsOnPrimitiveComponent(prop: string) { ) } -export function testPickPropsOnOtherComponent(prop: string) { +export function testPickPropsOnOtherComponent(prop /*: string */) { return prop !== 'theme' } diff --git a/packages/primitives/test/css.test.js b/packages/primitives/test/css.test.js index 93fc9b2199..a5b0882d39 100644 --- a/packages/primitives/test/css.test.js +++ b/packages/primitives/test/css.test.js @@ -1,4 +1,3 @@ -// @flow import { css } from '@emotion/primitives' import { StyleSheet } from 'react-native' @@ -29,7 +28,6 @@ test('order with string and object', () => { // this test checks the keys instead of the objects // because we care about the order of the keys expect( - // $FlowFixMe Object.keys( StyleSheet.flatten( css({ color: 'green' }, `background-color:yellow;`, { flex: 2 }) @@ -37,7 +35,6 @@ test('order with string and object', () => { ) ).toEqual(['color', 'backgroundColor', 'flex']) expect( - // $FlowFixMe Object.keys( StyleSheet.flatten( css([ @@ -50,7 +47,6 @@ test('order with string and object', () => { ) ).toEqual(['color', 'backgroundColor', 'flex']) expect( - // $FlowFixMe Object.keys( StyleSheet.flatten( css([ @@ -66,7 +62,6 @@ test('order with string and object', () => { ) ).toEqual(['color', 'backgroundColor', 'flex']) expect( - // $FlowFixMe Object.keys( StyleSheet.flatten( css([ diff --git a/packages/primitives/test/emotion-primitives.test.js b/packages/primitives/test/emotion-primitives.test.js index 035b08c128..dc2c1bbaa3 100644 --- a/packages/primitives/test/emotion-primitives.test.js +++ b/packages/primitives/test/emotion-primitives.test.js @@ -1,4 +1,3 @@ -// @flow import * as React from 'react' import renderer from 'react-test-renderer' import { Text, StyleSheet } from 'react-primitives' @@ -17,7 +16,6 @@ describe('Emotion primitives', () => { }) test('should throw an error when used invalid primitive', () => { - // $FlowFixMe: expect error expect(() => styled.TEXT({})).toThrow() }) @@ -29,7 +27,6 @@ describe('Emotion primitives', () => { ` const tree = renderer .create( - // $FlowFixMe Emotion Primitives @@ -46,7 +43,6 @@ describe('Emotion primitives', () => { const tree = renderer .create( - {/* $FlowFixMe */} Hello World ) @@ -62,7 +58,6 @@ describe('Emotion primitives', () => { const { container, unmount } = render( - {/* $FlowFixMe */} Hello World @@ -78,7 +73,6 @@ describe('Emotion primitives', () => { color: props.decor })) const tree = renderer - // $FlowFixMe .create(Emotion Primitives) .toJSON() expect(tree).toMatchSnapshot() @@ -89,10 +83,7 @@ describe('Emotion primitives', () => { color: hotpink; ` const tree = renderer - .create( - // $FlowFixMe - Emotion primitives - ) + .create(Emotion primitives) .toJSON() expect(tree).toMatchSnapshot() }) @@ -104,7 +95,6 @@ describe('Emotion primitives', () => { ` const tree = renderer - // $FlowFixMe .create(Emotion Primitives) .toJSON() expect(tree).toMatchSnapshot() @@ -114,7 +104,6 @@ describe('Emotion primitives', () => { const StyledText = styled.Text` color: ${props => props.decor}; ` - // $FlowFixMe const Name = StyledText.withComponent(Text) const tree = renderer.create(Mike).toJSON() expect(tree).toMatchSnapshot() @@ -124,13 +113,11 @@ describe('Emotion primitives', () => { const Text = styled.Text` color: hotpink; ` - // $FlowFixMe const Title = () => Hello World const StyledTitle = styled(Title)` font-size: 20px; font-style: ${props => props.sty}; ` - // $FlowFixMe const tree = renderer.create().toJSON() expect(tree).toMatchSnapshot() }) @@ -151,9 +138,7 @@ describe('Emotion primitives', () => { const ViewOne = styled.View` background-color: ${props => props.color}; ` - // $FlowFixMe const treeOne = renderer.create() - // $FlowFixMe const ViewTwo = ViewOne.withComponent(Text) const treeTwo = renderer.create() @@ -167,7 +152,6 @@ describe('Emotion primitives', () => { ` const tree = renderer .create( - // $FlowFixMe { test('custom shouldForwardProp works', () => { const Text = styled.Text`` const Title = props => - // $FlowFixMe const StyledTitle = styled(Title, { shouldForwardProp: prop => prop !== 'color' && prop !== 'theme' })` diff --git a/packages/primitives/test/no-babel/basic.test.js b/packages/primitives/test/no-babel/basic.test.js index be39d3ab15..7697ac1256 100644 --- a/packages/primitives/test/no-babel/basic.test.js +++ b/packages/primitives/test/no-babel/basic.test.js @@ -1,4 +1,3 @@ -// @flow import * as React from 'react' import styled, { css } from '@emotion/primitives' import renderer from 'react-test-renderer' @@ -48,7 +47,6 @@ test('should render the primitive when styles applied using object style notatio ` const tree = renderer .create( - // $FlowFixMe Emotion Primitives diff --git a/packages/primitives/test/warnings.test.js b/packages/primitives/test/warnings.test.js index 7aa51c2bb2..12e5ef993c 100644 --- a/packages/primitives/test/warnings.test.js +++ b/packages/primitives/test/warnings.test.js @@ -1,7 +1,5 @@ -// @flow import { css } from '@emotion/primitives' -// $FlowFixMe console.error = jest.fn() afterEach(() => { diff --git a/packages/react/__tests__/at-import.js b/packages/react/__tests__/at-import.js index 82f8e26445..f51250df63 100644 --- a/packages/react/__tests__/at-import.js +++ b/packages/react/__tests__/at-import.js @@ -1,4 +1,3 @@ -// @flow import 'test-utils/prod-mode' import * as React from 'react' /** @jsx jsx */ @@ -7,9 +6,7 @@ import { render, unmountComponentAtNode } from 'react-dom' import { Global, css } from '@emotion/react' beforeEach(() => { - // $FlowFixMe document.head.innerHTML = '' - // $FlowFixMe document.body.innerHTML = `
` }) @@ -26,7 +23,7 @@ test('basic', () => { } `} /> - , // $FlowFixMe + , document.getElementById('root') ) expect(document.head).toMatchSnapshot() @@ -34,7 +31,6 @@ test('basic', () => { let elements = document.querySelectorAll('style') let rules = [] for (let element of elements) { - // $FlowFixMe for (let cssRule of element.sheet.cssRules) { rules.push(cssRule.cssText) } diff --git a/packages/react/__tests__/babel/__snapshots__/source-map-server.js.snap b/packages/react/__tests__/babel/__snapshots__/source-map-server.js.snap index 66744f44d2..e7150e2a0f 100644 --- a/packages/react/__tests__/babel/__snapshots__/source-map-server.js.snap +++ b/packages/react/__tests__/babel/__snapshots__/source-map-server.js.snap @@ -1,3 +1,3 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`basic 1`] = `"
some hotpink text
"`; +exports[`basic 1`] = `"
some hotpink text
"`; diff --git a/packages/react/__tests__/babel/source-map-server.js b/packages/react/__tests__/babel/source-map-server.js index 60ecf18571..e55735edfb 100644 --- a/packages/react/__tests__/babel/source-map-server.js +++ b/packages/react/__tests__/babel/source-map-server.js @@ -1,7 +1,7 @@ /** @jsx jsx * @jest-environment node */ -// @flow + import 'test-utils/dev-mode' import { jsx } from '@emotion/react' import { renderToString } from 'react-dom/server' diff --git a/packages/react/__tests__/class-names.js b/packages/react/__tests__/class-names.js index d165f3b593..7fe0c23050 100644 --- a/packages/react/__tests__/class-names.js +++ b/packages/react/__tests__/class-names.js @@ -1,4 +1,3 @@ -// @flow import * as React from 'react' import 'test-utils/next-env' import { ClassNames, ThemeProvider } from '@emotion/react' diff --git a/packages/react/__tests__/clone-element.js b/packages/react/__tests__/clone-element.js index dedd52c62b..8a73c23938 100644 --- a/packages/react/__tests__/clone-element.js +++ b/packages/react/__tests__/clone-element.js @@ -1,4 +1,3 @@ -// @flow /** @jsx jsx */ import { jsx } from '@emotion/react' import * as React from 'react' diff --git a/packages/react/__tests__/compat/browser.js b/packages/react/__tests__/compat/browser.js index 450a1d2677..cd12840f2a 100644 --- a/packages/react/__tests__/compat/browser.js +++ b/packages/react/__tests__/compat/browser.js @@ -1,4 +1,3 @@ -// @flow /** @jsx jsx */ import 'test-utils/dev-mode' import { throwIfFalsy } from 'test-utils' diff --git a/packages/react/__tests__/compat/server.js b/packages/react/__tests__/compat/server.js index 08218a2513..4e72d857c1 100644 --- a/packages/react/__tests__/compat/server.js +++ b/packages/react/__tests__/compat/server.js @@ -1,6 +1,5 @@ /** @jsx jsx * @jest-environment node - * @flow */ import { jsx, Global } from '@emotion/react' import createEmotionServer from '@emotion/server/create-instance' diff --git a/packages/react/__tests__/css-cache-hash.js b/packages/react/__tests__/css-cache-hash.js index 5e1a4fd55a..f7428bf46c 100644 --- a/packages/react/__tests__/css-cache-hash.js +++ b/packages/react/__tests__/css-cache-hash.js @@ -1,4 +1,3 @@ -// @flow /** @jsx jsx */ import 'test-utils/next-env' import { jsx, css } from '@emotion/react' diff --git a/packages/react/__tests__/css.js b/packages/react/__tests__/css.js index 9631e612e8..2d599f4df0 100644 --- a/packages/react/__tests__/css.js +++ b/packages/react/__tests__/css.js @@ -1,4 +1,3 @@ -// @flow /** @jsx jsx */ import 'test-utils/next-env' import { safeQuerySelector } from 'test-utils' @@ -8,9 +7,7 @@ import { render } from '@testing-library/react' import renderer from 'react-test-renderer' import createCache from '@emotion/cache' -// $FlowFixMe console.error = jest.fn() -// $FlowFixMe console.warn = jest.fn() afterEach(() => { @@ -18,12 +15,11 @@ afterEach(() => { safeQuerySelector('body').innerHTML = '' }) -const SomeComponent = (props: { lol: true }) => (props.lol ? 'yes' : 'no') +const SomeComponent = (props /*: { lol: true } */) => (props.lol ? 'yes' : 'no') // test to make sure flow prop errors work. // should probably try to make it so that components that require className props // and have the css prop passed to them don't have type errors -// $FlowFixMe ; // eslint-disable-line no-unused-expressions test('thing', () => { @@ -223,7 +219,7 @@ test('autoLabel without babel (sanitized)', () => { }) test('overwrite styles from parent', () => { - let SomeComponent = (props: Object) => ( + let SomeComponent = (props /*: Object */) => (
{ }) test('applies class when css prop is set to nil on wrapper component', () => { - const Button = (props: any) => ( - + } */ + ) => const tree = renderer.create( @@ -341,6 +334,6 @@ it("doesn't try to insert invalid rules caused by object style's value being fal ) - expect((console.error: any).mock.calls).toMatchInlineSnapshot(`[]`) - expect((console.warn: any).mock.calls).toMatchInlineSnapshot(`[]`) + expect(console.error.mock.calls).toMatchInlineSnapshot(`[]`) + expect(console.warn.mock.calls).toMatchInlineSnapshot(`[]`) }) diff --git a/packages/react/__tests__/custom-cache.js b/packages/react/__tests__/custom-cache.js index 2ccf1e3364..43907de7a4 100644 --- a/packages/react/__tests__/custom-cache.js +++ b/packages/react/__tests__/custom-cache.js @@ -1,4 +1,3 @@ -// @flow /** @jsx jsx */ import createCache from '@emotion/cache' import { CacheProvider, Global, jsx } from '@emotion/react' diff --git a/packages/react/__tests__/global-with-theme.js b/packages/react/__tests__/global-with-theme.js index 32b0d46c72..daa1f512b2 100644 --- a/packages/react/__tests__/global-with-theme.js +++ b/packages/react/__tests__/global-with-theme.js @@ -1,11 +1,9 @@ -// @flow import 'test-utils/dev-mode' import * as React from 'react' import { render } from '@testing-library/react' import { Global, ThemeProvider } from '@emotion/react' beforeEach(() => { - // $FlowFixMe document.head.innerHTML = '' }) diff --git a/packages/react/__tests__/global.js b/packages/react/__tests__/global.js index 2ecc075407..06dc4c79f9 100644 --- a/packages/react/__tests__/global.js +++ b/packages/react/__tests__/global.js @@ -1,4 +1,3 @@ -// @flow import 'test-utils/dev-mode' import * as React from 'react' import { render } from '@testing-library/react' @@ -15,7 +14,6 @@ import createCache from '@emotion/cache' console.error = jest.fn() beforeEach(() => { - // $FlowFixMe document.head.innerHTML = '' jest.resetAllMocks() }) @@ -76,7 +74,6 @@ test('no React hook order violations', () => { const theme = { color: 'blue' } const cache = createCache({ key: 'context' }) - // $FlowFixMe const Comp = ({ flag }) => ( diff --git a/packages/react/__tests__/globals-are-the-worst.js b/packages/react/__tests__/globals-are-the-worst.js index 33d7dd1bd3..437dcaf9c1 100644 --- a/packages/react/__tests__/globals-are-the-worst.js +++ b/packages/react/__tests__/globals-are-the-worst.js @@ -1,4 +1,3 @@ -// @flow import 'test-utils/dev-mode' import { render } from '@testing-library/react' import * as React from 'react' diff --git a/packages/react/__tests__/import-prod.js b/packages/react/__tests__/import-prod.js index a6ca906518..e357c881c5 100644 --- a/packages/react/__tests__/import-prod.js +++ b/packages/react/__tests__/import-prod.js @@ -1,4 +1,3 @@ -// @flow import 'test-utils/prod-mode' import * as React from 'react' import * as ReactDOM from 'react-dom' @@ -28,8 +27,8 @@ const render = children => // $FlowFixMe document.body.appendChild(el) - if ((ReactDOM: any).createRoot) { - const root = (ReactDOM: any).createRoot(el) + if (ReactDOM.createRoot) { + const root = ReactDOM.createRoot(el) root.render(
{children}
) } else { ReactDOM.render(children, el, resolve) diff --git a/packages/react/__tests__/keyframes.js b/packages/react/__tests__/keyframes.js index acf849f7da..481f866e08 100644 --- a/packages/react/__tests__/keyframes.js +++ b/packages/react/__tests__/keyframes.js @@ -1,4 +1,3 @@ -// @flow /** @jsx jsx */ import 'test-utils/next-env' import { jsx, css, keyframes } from '@emotion/react' diff --git a/packages/react/__tests__/legacy-class-name.js b/packages/react/__tests__/legacy-class-name.js index dd1d13dbf3..82345c4203 100644 --- a/packages/react/__tests__/legacy-class-name.js +++ b/packages/react/__tests__/legacy-class-name.js @@ -1,4 +1,3 @@ -// @flow /** @jsx jsx */ import 'test-utils/next-env' import { jsx, css } from '@emotion/react' diff --git a/packages/react/__tests__/ref.js b/packages/react/__tests__/ref.js index bb9766602f..0b82cce60b 100644 --- a/packages/react/__tests__/ref.js +++ b/packages/react/__tests__/ref.js @@ -1,4 +1,3 @@ -// @flow /** @jsx jsx */ import { jsx } from '@emotion/react' import * as React from 'react' diff --git a/packages/react/__tests__/rehydration.js b/packages/react/__tests__/rehydration.js index f03c88846a..113a96e2c2 100644 --- a/packages/react/__tests__/rehydration.js +++ b/packages/react/__tests__/rehydration.js @@ -1,10 +1,7 @@ -// @flow /** @jsx jsx */ import { safeQuerySelector, disableBrowserEnvTemporarily } from 'test-utils' -// $FlowFixMe console.error = jest.fn() -// $FlowFixMe console.warn = jest.fn() afterEach(() => { @@ -87,8 +84,8 @@ test("cache created in render doesn't cause a hydration mismatch", () => { container: safeQuerySelector('#root') }) - expect((console.error: any).mock.calls).toMatchInlineSnapshot(`[]`) - expect((console.warn: any).mock.calls).toMatchInlineSnapshot(`[]`) + expect(console.error.mock.calls).toMatchInlineSnapshot(`[]`) + expect(console.warn.mock.calls).toMatchInlineSnapshot(`[]`) }) test('initializing another Emotion instance should not move already moved styles elements', () => { @@ -607,13 +604,13 @@ test('duplicated global styles can be removed safely after rehydrating HTML SSRe `) }) -;((React: any).useId ? describe : describe.skip)('useId', () => { +;(React.useId ? describe : describe.skip)('useId', () => { test('no hydration mismatch for styled when using useId', async () => { const finalHTML = await disableBrowserEnvTemporarily(() => { resetAllModules() const StyledDivWithId = styled(function DivWithId({ className }) { - const id = (React: any).useId() + const id = React.useId() return
})({ border: '1px solid black' @@ -627,7 +624,7 @@ test('duplicated global styles can be removed safely after rehydrating HTML SSRe resetAllModules() const StyledDivWithId = styled(function DivWithId({ className }) { - const id = (React: any).useId() + const id = React.useId() return
})({ border: '1px solid black' @@ -638,16 +635,16 @@ test('duplicated global styles can be removed safely after rehydrating HTML SSRe container: safeQuerySelector('#root') }) - expect((console.error: any).mock.calls).toMatchInlineSnapshot(`[]`) - expect((console.warn: any).mock.calls).toMatchInlineSnapshot(`[]`) + expect(console.error.mock.calls).toMatchInlineSnapshot(`[]`) + expect(console.warn.mock.calls).toMatchInlineSnapshot(`[]`) }) test('no hydration mismatch for css prop when using useId', async () => { const finalHTML = await disableBrowserEnvTemporarily(() => { resetAllModules() - function DivWithId({ className }: { className?: string }) { - const id = (React: any).useId() + function DivWithId({ className } /*: { className?: string }*/) { + const id = React.useId() return
} @@ -664,8 +661,8 @@ test('duplicated global styles can be removed safely after rehydrating HTML SSRe resetAllModules() - function DivWithId({ className }: { className?: string }) { - const id = (React: any).useId() + function DivWithId({ className } /*: { className?: string }*/) { + const id = React.useId() return
} @@ -681,8 +678,8 @@ test('duplicated global styles can be removed safely after rehydrating HTML SSRe } ) - expect((console.error: any).mock.calls).toMatchInlineSnapshot(`[]`) - expect((console.warn: any).mock.calls).toMatchInlineSnapshot(`[]`) + expect(console.error.mock.calls).toMatchInlineSnapshot(`[]`) + expect(console.warn.mock.calls).toMatchInlineSnapshot(`[]`) }) test('no hydration mismatch for ClassNames when using useId', async () => { @@ -690,7 +687,7 @@ test('duplicated global styles can be removed safely after rehydrating HTML SSRe resetAllModules() const DivWithId = ({ className }) => { - const id = (React: any).useId() + const id = React.useId() return
} @@ -714,7 +711,7 @@ test('duplicated global styles can be removed safely after rehydrating HTML SSRe resetAllModules() const DivWithId = ({ className }) => { - const id = (React: any).useId() + const id = React.useId() return
} @@ -736,7 +733,7 @@ test('duplicated global styles can be removed safely after rehydrating HTML SSRe } ) - expect((console.error: any).mock.calls).toMatchInlineSnapshot(`[]`) - expect((console.warn: any).mock.calls).toMatchInlineSnapshot(`[]`) + expect(console.error.mock.calls).toMatchInlineSnapshot(`[]`) + expect(console.warn.mock.calls).toMatchInlineSnapshot(`[]`) }) }) diff --git a/packages/react/__tests__/server.js b/packages/react/__tests__/server.js index c6625a3851..44197477ff 100644 --- a/packages/react/__tests__/server.js +++ b/packages/react/__tests__/server.js @@ -1,7 +1,7 @@ /** @jsx jsx * @jest-environment node */ -// @flow + import 'test-utils/dev-mode' import * as React from 'react' import testCases from 'jest-in-case' diff --git a/packages/react/__tests__/theme-provider.dom.js b/packages/react/__tests__/theme-provider.dom.js index 412539c751..4e56567773 100644 --- a/packages/react/__tests__/theme-provider.dom.js +++ b/packages/react/__tests__/theme-provider.dom.js @@ -1,4 +1,3 @@ -// @flow /** @jsx jsx */ import 'test-utils/next-env' import 'test-utils/dev-mode' @@ -13,7 +12,7 @@ beforeEach(() => { }) test('provider with theme value that changes', () => { - class ThemeTest extends React.Component<*, *> { + class ThemeTest extends React.Component { state = { theme: { color: 'hotpink', padding: 4 } } render() { return ( diff --git a/packages/react/__tests__/theme-provider.js b/packages/react/__tests__/theme-provider.js index d9a06c0790..1e6b84bc64 100644 --- a/packages/react/__tests__/theme-provider.js +++ b/packages/react/__tests__/theme-provider.js @@ -1,4 +1,3 @@ -// @flow /** @jsx jsx */ import 'test-utils/next-env' import { ignoreConsoleErrors } from 'test-utils' @@ -57,7 +56,6 @@ cases( expect(() => { renderer.create( - {/* $FlowFixMe */}
({ diff --git a/packages/react/__tests__/use-theme.js b/packages/react/__tests__/use-theme.js index cbf5d8ca7c..301b5c3f07 100644 --- a/packages/react/__tests__/use-theme.js +++ b/packages/react/__tests__/use-theme.js @@ -1,4 +1,3 @@ -// @flow /** @jsx jsx */ import 'test-utils/next-env' import * as renderer from 'react-test-renderer' diff --git a/packages/react/__tests__/warnings.js b/packages/react/__tests__/warnings.js index 5af566acc0..4a244dc07c 100644 --- a/packages/react/__tests__/warnings.js +++ b/packages/react/__tests__/warnings.js @@ -1,4 +1,3 @@ -// @flow /** @jsx jsx */ import 'test-utils/next-env' import { jsx, css, Global, keyframes, ClassNames } from '@emotion/react' @@ -6,7 +5,6 @@ import styled from '@emotion/styled' import renderer from 'react-test-renderer' import { render } from '@testing-library/react' -// $FlowFixMe console.error = jest.fn() const validValues = [ @@ -48,7 +46,6 @@ it('does not warn when valid values are passed for the content property', () => const invalidValues = ['this is not valid', '', 'element'] it('does warn when invalid values are passed for the content property', () => { - // $FlowFixMe invalidValues.forEach(value => { expect(() => renderer.create(
) @@ -78,7 +75,7 @@ describe('unsafe pseudo classes', () => { color: hotpink; } ` - const match = (pseudoClass.match(/(:first|:nth|:nth-last)-child/): any) + const match = pseudoClass.match(/(:first|:nth|:nth-last)-child/) expect(match).not.toBeNull() expect(renderer.create(
).toJSON()).toMatchSnapshot() expect(console.error).toBeCalledWith( @@ -119,7 +116,7 @@ describe('unsafe pseudo classes', () => { { pseudoClass: `:first-child, :nth-child(3)` }, { pseudoClass: `:first-child:nth-child(3)` } ])('$pseudoClass', ({ pseudoClass }) => { - const match = (pseudoClass.match(/(:first|:nth|:nth-last)-child/): any) + const match = pseudoClass.match(/(:first|:nth|:nth-last)-child/) expect(match).not.toBeNull() expect( renderer.create(
).toJSON() @@ -145,7 +142,7 @@ describe('unsafe pseudo classes', () => { ) .toJSON() ).toMatchSnapshot() - expect((console.error: any).mock.calls).toMatchInlineSnapshot(` + expect(console.error.mock.calls).toMatchInlineSnapshot(` [ [ "The pseudo class ":first-child" is potentially unsafe when doing server-side rendering. Try changing it to ":first-of-type".", @@ -171,7 +168,7 @@ describe('unsafe pseudo classes', () => { ) .toJSON() ).toMatchSnapshot() - expect((console.error: any).mock.calls).toMatchInlineSnapshot(` + expect(console.error.mock.calls).toMatchInlineSnapshot(` [ [ "The pseudo class ":first-child" is potentially unsafe when doing server-side rendering. Try changing it to ":first-of-type".", @@ -195,7 +192,7 @@ describe('unsafe pseudo classes', () => { ) .toJSON() ).toMatchSnapshot() - expect((console.error: any).mock.calls).toMatchInlineSnapshot(` + expect(console.error.mock.calls).toMatchInlineSnapshot(` [ [ "The pseudo class ":first-child" is potentially unsafe when doing server-side rendering. Try changing it to ":first-of-type".", @@ -219,7 +216,7 @@ describe('unsafe pseudo classes', () => { ) .toJSON() ).toMatchSnapshot() - expect((console.error: any).mock.calls).toMatchInlineSnapshot(` + expect(console.error.mock.calls).toMatchInlineSnapshot(` [ [ "The pseudo class ":first-child" is potentially unsafe when doing server-side rendering. Try changing it to ":first-of-type".", @@ -242,7 +239,7 @@ describe('unsafe pseudo classes', () => { ) .toJSON() ).toMatchSnapshot() - expect((console.error: any).mock.calls).toMatchInlineSnapshot(` + expect(console.error.mock.calls).toMatchInlineSnapshot(` [ [ "The pseudo class ":first-child" is potentially unsafe when doing server-side rendering. Try changing it to ":first-of-type".", @@ -360,7 +357,7 @@ describe('unsafe pseudo classes', () => { ) .toJSON() ).toMatchSnapshot() - expect((console.error: any).mock.calls).toMatchInlineSnapshot(` + expect(console.error.mock.calls).toMatchInlineSnapshot(` [ [ "The pseudo class ":first-child" is potentially unsafe when doing server-side rendering. Try changing it to ":first-of-type".", @@ -393,7 +390,6 @@ describe('unsafe pseudo classes', () => { test('global with css prop', () => { let tree = renderer .create( - // $FlowFixMe { css({ '@media (min-width 800px)': undefined }) css({ '--primary-color': 'hotpink' }) css({ ':last-of-type': null }) - expect((console.error: any).mock.calls).toMatchInlineSnapshot(` + expect(console.error.mock.calls).toMatchInlineSnapshot(` [ [ "Using kebab-case for css properties in objects is not supported. Did you mean backgroundColor?", @@ -449,7 +445,7 @@ test('keyframes interpolated into plain string', () => { renderer.create(
) - expect((console.error: any).mock.calls).toMatchInlineSnapshot(` + expect(console.error.mock.calls).toMatchInlineSnapshot(` [ [ "\`keyframes\` output got interpolated into plain string, please wrap it with \`css\`. @@ -492,7 +488,6 @@ test('`css` opaque object passed to `cx` from ', () => { {({ cx }) => (
', () => { ) - expect((console.error: any).mock.calls).toMatchInlineSnapshot(` + expect(console.error.mock.calls).toMatchInlineSnapshot(` [ [ "You have passed styles created with \`css\` from \`@emotion/react\` package to the \`cx\`. @@ -526,7 +521,7 @@ test('@import nested in scoped `css`', () => { /> ) - expect((console.error: any).mock.calls).toMatchInlineSnapshot(` + expect(console.error.mock.calls).toMatchInlineSnapshot(` [ [ "\`@import\` rules can't be nested inside other rules. Please move it to the top level and put it before regular rules. Keep in mind that they can only be used within global styles.", @@ -548,7 +543,7 @@ test('@import prepended with other rules', () => { /> ) - expect((console.error: any).mock.calls).toMatchInlineSnapshot(` + expect(console.error.mock.calls).toMatchInlineSnapshot(` [ [ "\`@import\` rules can't be after other rules. Please put your \`@import\` rules before your other rules.", @@ -567,7 +562,7 @@ test('@import prepended by other @import', () => { /> ) - expect((console.error: any).mock.calls).toMatchInlineSnapshot(`[]`) + expect(console.error.mock.calls).toMatchInlineSnapshot(`[]`) }) test('when using `jsx` multiple static children should not result in a key-related warning', () => { @@ -577,5 +572,5 @@ test('when using `jsx` multiple static children should not result in a key-relat
) - expect((console.error: any).mock.calls).toMatchInlineSnapshot(`[]`) + expect(console.error.mock.calls).toMatchInlineSnapshot(`[]`) }) diff --git a/packages/react/__tests__/with-theme.js b/packages/react/__tests__/with-theme.js index 4512dc47e0..95c0b9c989 100644 --- a/packages/react/__tests__/with-theme.js +++ b/packages/react/__tests__/with-theme.js @@ -1,10 +1,9 @@ -// @flow import * as React from 'react' import * as renderer from 'react-test-renderer' import { withTheme, ThemeProvider } from '@emotion/react' test('withTheme works', () => { - class SomeComponent extends React.Component<{ theme: Object }> { + class SomeComponent extends React.Component /* <{ theme: Object }> */ { render() { return this.props.theme.color } @@ -22,7 +21,7 @@ test('withTheme works', () => { }) test(`withTheme(Comp) hoists non-react static class properties`, () => { - class ExampleComponent extends React.Component<*> { + class ExampleComponent extends React.Component { static displayName = 'foo' static someSpecialStatic = 'bar' } @@ -30,14 +29,13 @@ test(`withTheme(Comp) hoists non-react static class properties`, () => { const ComponentWithTheme = withTheme(ExampleComponent) expect(ComponentWithTheme.displayName).toBe('WithTheme(foo)') - // $FlowFixMe hoist-non-react-statics doesn't work with AbstractComponent https://github.com/facebook/flow/issues/7612 expect(ComponentWithTheme.someSpecialStatic).toBe( ExampleComponent.someSpecialStatic ) }) it('should forward the ref', () => { - class SomeComponent extends React.Component<*> { + class SomeComponent extends React.Component { render() { return this.props.theme.color } diff --git a/packages/react/macro.js.flow b/packages/react/macro.js.flow deleted file mode 100644 index 63ae97e66d..0000000000 --- a/packages/react/macro.js.flow +++ /dev/null @@ -1,2 +0,0 @@ -// @flow -export * from './src/index.js' diff --git a/packages/react/src/class-names.js b/packages/react/src/class-names.js index 6252324f22..2e8c8acc73 100644 --- a/packages/react/src/class-names.js +++ b/packages/react/src/class-names.js @@ -1,4 +1,3 @@ -// @flow import * as React from 'react' import { getRegisteredStyles, @@ -11,6 +10,7 @@ import { ThemeContext } from './theming' import { useInsertionEffectAlwaysWithSyncFallback } from '@emotion/use-insertion-effect-with-fallbacks' import { isBrowser } from './utils' +/* type ClassNameArg = | string | boolean @@ -18,8 +18,9 @@ type ClassNameArg = | Array | null | void +*/ -let classnames = (args: Array): string => { +let classnames = (args /*: Array */) /*: string */ => { let len = args.length let i = 0 let cls = '' @@ -67,9 +68,9 @@ let classnames = (args: Array): string => { return cls } function merge( - registered: Object, - css: (...args: Array) => string, - className: string + registered /*: Object */, + css /*: (...args: Array) => string */, + className /*: string */ ) { const registeredStyles = [] @@ -85,14 +86,6 @@ function merge( return rawClassName + css(registeredStyles) } -type Props = { - children: ({ - css: (...args: any) => string, - cx: (...args: Array) => string, - theme: Object - }) => React.Node -} - const Insertion = ({ cache, serializedArr }) => { let rules = useInsertionEffectAlwaysWithSyncFallback(() => { let rules = '' @@ -123,12 +116,21 @@ const Insertion = ({ cache, serializedArr }) => { return null } -export const ClassNames: React.AbstractComponent = +/* +type Props = { + children: ({ + css: (...args: any) => string, + cx: (...args: Array) => string, + theme: Object + }) => React.Node +} */ + +export const ClassNames /*: React.AbstractComponent*/ = /* #__PURE__ */ withEmotionCache((props, cache) => { let hasRendered = false let serializedArr = [] - let css = (...args: Array) => { + let css = (...args /*: Array */) => { if (hasRendered && process.env.NODE_ENV !== 'production') { throw new Error('css can only be used during render') } @@ -139,7 +141,7 @@ export const ClassNames: React.AbstractComponent = registerStyles(cache, serialized, false) return `${cache.key}-${serialized.name}` } - let cx = (...args: Array) => { + let cx = (...args /*: Array*/) => { if (hasRendered && process.env.NODE_ENV !== 'production') { throw new Error('cx can only be used during render') } diff --git a/packages/react/src/context.js b/packages/react/src/context.js index e74d4de212..ccf4e0f24c 100644 --- a/packages/react/src/context.js +++ b/packages/react/src/context.js @@ -1,11 +1,10 @@ -// @flow -import { type EmotionCache } from '@emotion/utils' +/* import { type EmotionCache } from '@emotion/utils' */ import * as React from 'react' import { useContext, forwardRef } from 'react' import createCache from '@emotion/cache' import { isBrowser } from './utils' -let EmotionCacheContext: React.Context = +let EmotionCacheContext /*: React.Context */ = /* #__PURE__ */ React.createContext( // we're doing this to avoid preconstruct's dead code elimination in this one case // because this module is primarily intended for the browser and node @@ -25,27 +24,27 @@ if (process.env.NODE_ENV !== 'production') { export let CacheProvider = EmotionCacheContext.Provider export let __unsafe_useEmotionCache = - function useEmotionCache(): EmotionCache | null { + function useEmotionCache() /*: EmotionCache | null*/ { return useContext(EmotionCacheContext) } -let withEmotionCache = function withEmotionCache>( - func: (props: Props, cache: EmotionCache, ref: Ref) => React.Node -): React.AbstractComponent { - // $FlowFixMe - return forwardRef((props: Props, ref: Ref) => { - // the cache will never be null in the browser - let cache = ((useContext(EmotionCacheContext): any): EmotionCache) +let withEmotionCache = + function withEmotionCache /* > */( + func /*: (props: Props, cache: EmotionCache, ref: Ref) => React.Node */ + ) /*: React.AbstractComponent */ { + return forwardRef((props /*: Props */, ref /*: Ref */) => { + // the cache will never be null in the browser + let cache = useContext(EmotionCacheContext) - return func(props, cache, ref) - }) -} + return func(props, cache, ref) + }) + } if (!isBrowser) { - withEmotionCache = function withEmotionCache( - func: (props: Props, cache: EmotionCache) => React.Node - ): React.StatelessFunctionalComponent { - return (props: Props) => { + withEmotionCache = function withEmotionCache /* */( + func /*: (props: Props, cache: EmotionCache) => React.Node */ + ) /*: React.StatelessFunctionalComponent */ { + return (props /*: Props */) => { let cache = useContext(EmotionCacheContext) if (cache === null) { // yes, we're potentially creating this on every render diff --git a/packages/react/src/css.js b/packages/react/src/css.js index ac79c1dfa3..785320e8f1 100644 --- a/packages/react/src/css.js +++ b/packages/react/src/css.js @@ -1,9 +1,7 @@ -// @flow - -import type { Interpolation, SerializedStyles } from '@emotion/utils' +/* import type { Interpolation, SerializedStyles } from '@emotion/utils' */ import { serializeStyles } from '@emotion/serialize' -function css(...args: Array): SerializedStyles { +function css(...args /*: Array */) /*: SerializedStyles */ { return serializeStyles(args) } diff --git a/packages/react/src/emotion-element.js b/packages/react/src/emotion-element.js index 0ae4c4b64c..211dbac662 100644 --- a/packages/react/src/emotion-element.js +++ b/packages/react/src/emotion-element.js @@ -1,4 +1,3 @@ -// @flow import * as React from 'react' import { withEmotionCache } from './context' import { ThemeContext } from './theming' @@ -16,7 +15,10 @@ let typePropName = '__EMOTION_TYPE_PLEASE_DO_NOT_USE__' let labelPropName = '__EMOTION_LABEL_PLEASE_DO_NOT_USE__' -export const createEmotionProps = (type: React.ElementType, props: Object) => { +export const createEmotionProps = ( + type /*: React.ElementType */, + props /*: Object */ +) => { if ( process.env.NODE_ENV !== 'production' && typeof props.css === 'string' && @@ -28,7 +30,7 @@ export const createEmotionProps = (type: React.ElementType, props: Object) => { ) } - let newProps: any = {} + let newProps /*: any */ = {} for (let key in props) { if (hasOwn.call(props, key)) { @@ -81,8 +83,8 @@ const Insertion = ({ cache, serialized, isStringTag }) => { return null } -let Emotion = /* #__PURE__ */ withEmotionCache( - (props, cache, ref) => { +let Emotion = /* #__PURE__ */ withEmotionCache( + /* */ (props, cache, ref) => { let cssProp = props.css // so that using `css` from `emotion` and passing the result to the css prop works diff --git a/packages/react/src/get-label-from-stack-trace.js b/packages/react/src/get-label-from-stack-trace.js index c356b14e16..5d0dcd5bcb 100644 --- a/packages/react/src/get-label-from-stack-trace.js +++ b/packages/react/src/get-label-from-stack-trace.js @@ -1,13 +1,11 @@ -// @flow - -const getLastPart = (functionName: string): string => { +const getLastPart = (functionName /* : string */) /* : string */ => { // The match may be something like 'Object.createEmotionProps' or // 'Loader.prototype.render' const parts = functionName.split('.') return parts[parts.length - 1] } -const getFunctionNameFromStackTraceLine = (line: string): ?string => { +const getFunctionNameFromStackTraceLine = (line /*: string*/) /*: ?string*/ => { // V8 let match = /^\s+at\s+([A-Za-z0-9$.]+)\s/.exec(line) if (match) return getLastPart(match[1]) @@ -29,10 +27,9 @@ const internalReactFunctionNames = /* #__PURE__ */ new Set([ // These identifiers come from error stacks, so they have to be valid JS // identifiers, thus we only need to replace what is a valid character for JS, // but not for CSS. -const sanitizeIdentifier = (identifier: string) => - identifier.replace(/\$/g, '-') +const sanitizeIdentifier = identifier => identifier.replace(/\$/g, '-') -export const getLabelFromStackTrace = (stackTrace: string): ?string => { +export const getLabelFromStackTrace = stackTrace => { if (!stackTrace) return undefined const lines = stackTrace.split('\n') diff --git a/packages/react/src/global.js b/packages/react/src/global.js index bcbbbd2b04..48041e96ec 100644 --- a/packages/react/src/global.js +++ b/packages/react/src/global.js @@ -1,4 +1,3 @@ -// @flow import * as React from 'react' import { withEmotionCache } from './context' import { ThemeContext } from './theming' @@ -8,11 +7,13 @@ import { useInsertionEffectWithLayoutFallback } from '@emotion/use-insertion-eff import { serializeStyles } from '@emotion/serialize' +/* type Styles = Object | Array type GlobalProps = { +styles: Styles | (Object => Styles) } +*/ let warnedAboutCssPropForGlobal = false @@ -20,123 +21,123 @@ let warnedAboutCssPropForGlobal = false // initial render from browser, insertBefore context.sheet.tags[0] or if a style hasn't been inserted there yet, appendChild // initial client-side render from SSR, use place of hydrating tag -export let Global: React.AbstractComponent = - /* #__PURE__ */ withEmotionCache((props: GlobalProps, cache) => { - if ( - process.env.NODE_ENV !== 'production' && - !warnedAboutCssPropForGlobal && // check for className as well since the user is - // probably using the custom createElement which - // means it will be turned into a className prop - // $FlowFixMe I don't really want to add it to the type since it shouldn't be used - (props.className || props.css) - ) { - console.error( - "It looks like you're using the css prop on Global, did you mean to use the styles prop instead?" - ) - warnedAboutCssPropForGlobal = true +export let Global /*: React.AbstractComponent< + GlobalProps +> */ = /* #__PURE__ */ withEmotionCache((props /*: GlobalProps */, cache) => { + if ( + process.env.NODE_ENV !== 'production' && + !warnedAboutCssPropForGlobal && // check for className as well since the user is + // probably using the custom createElement which + // means it will be turned into a className prop + // I don't really want to add it to the type since it shouldn't be used + (props.className || props.css) + ) { + console.error( + "It looks like you're using the css prop on Global, did you mean to use the styles prop instead?" + ) + warnedAboutCssPropForGlobal = true + } + let styles = props.styles + + let serialized = serializeStyles( + [styles], + undefined, + React.useContext(ThemeContext) + ) + + if (!isBrowser) { + let serializedNames = serialized.name + let serializedStyles = serialized.styles + let next = serialized.next + while (next !== undefined) { + serializedNames += ' ' + next.name + serializedStyles += next.styles + next = next.next + } + + let shouldCache = cache.compat === true + + let rules = cache.insert( + ``, + { name: serializedNames, styles: serializedStyles }, + cache.sheet, + shouldCache + ) + + if (shouldCache) { + return null } - let styles = props.styles - let serialized = serializeStyles( - [styles], - undefined, - React.useContext(ThemeContext) + return ( + ` } diff --git a/packages/server/src/index.js b/packages/server/src/index.js index 94000e3e6d..9e00e4424e 100644 --- a/packages/server/src/index.js +++ b/packages/server/src/index.js @@ -1,4 +1,3 @@ -// @flow import createEmotionServer from './create-instance' import { cache } from '@emotion/css' diff --git a/packages/server/test/extract-critical-to-chunks.test.js b/packages/server/test/extract-critical-to-chunks.test.js index b035592fc7..f68eb679d3 100644 --- a/packages/server/test/extract-critical-to-chunks.test.js +++ b/packages/server/test/extract-critical-to-chunks.test.js @@ -1,11 +1,10 @@ /** * @jest-environment node - * @flow */ import React from 'react' import { renderToString } from 'react-dom/server' -import type { Emotion } from '@emotion/css/create-instance' +/* import type { Emotion } from '@emotion/css/create-instance' */ import { prettifyCriticalChunks } from './util' let emotion = require('@emotion/css') @@ -13,8 +12,8 @@ let reactEmotion = require('@emotion/styled') let emotionServer = require('@emotion/server') export const getComponents = ( - emotion: Emotion, - { default: styled }: { default: Function } + emotion /*: Emotion */, + { default: styled } /*: { default: Function } */ ) => { let Provider = require('@emotion/react').CacheProvider let Global = require('@emotion/react').Global diff --git a/packages/server/test/index.test.js b/packages/server/test/index.test.js index 98f647c509..6c7b3fd3c9 100644 --- a/packages/server/test/index.test.js +++ b/packages/server/test/index.test.js @@ -57,11 +57,12 @@ describe('extractCritical', () => { ) ) - expect((console.error: any).mock.calls).toMatchObject([]) + expect(console.error.mock.calls).toMatchObject([]) }) }) }) }) + describe('hydration', () => { test('only rules that are not in the critical css are inserted', async () => { const { html, ids, css } = await disableBrowserEnvTemporarily(() => { diff --git a/packages/server/test/util.js b/packages/server/test/util.js index 0f5df444d2..31c68c85f2 100644 --- a/packages/server/test/util.js +++ b/packages/server/test/util.js @@ -1,12 +1,11 @@ -// @flow /* eslint-env jest */ import * as React from 'react' import prettify from '@emotion/css-prettifier' -import type { Emotion } from '@emotion/css/create-instance' -// $FlowFixMe +/* import type { Emotion } from '@emotion/css/create-instance' */ import { renderToNodeStream } from 'react-dom/server' import HTMLSerializer from 'jest-serializer-html' +/* type EmotionServer = { renderStylesToNodeStream: () => *, extractCritical: string => { @@ -16,12 +15,13 @@ type EmotionServer = { }, renderStylesToString: string => string } +*/ expect.addSnapshotSerializer(HTMLSerializer) export const getComponents = ( - emotion: Emotion, - { default: styled }: { default: Function } + emotion /*: Emotion */, + { default: styled } /*: { default: Function } */ ) => { let Provider = require('@emotion/react').CacheProvider let { injectGlobal, keyframes, css } = emotion @@ -131,8 +131,8 @@ export const getComponents = ( const maxColors = Math.pow(16, 6) -export const createBigComponent = ({ injectGlobal, css }: Emotion) => { - const BigComponent = ({ count }: { count: number }) => { +export const createBigComponent = ({ injectGlobal, css } /*: Emotion */) => { + const BigComponent = ({ count } /*: { count: number } */) => { if (count === 0) return null injectGlobal` .some-global-${count} { @@ -158,15 +158,13 @@ export const createBigComponent = ({ injectGlobal, css }: Emotion) => { return BigComponent } -export const prettifyCritical = ({ - html, - css, - ids -}: { +export const prettifyCritical = ( + { html, css, ids } /*: { html: string, css: string, ids: Array -}) => { +} */ +) => { return { css: prettify(css), ids, @@ -174,17 +172,17 @@ export const prettifyCritical = ({ } } -export const prettifyCriticalChunks = ({ - html, - styles -}: { +export const prettifyCriticalChunks = ( + { html, styles } /*: { html: string, styles: Array<{ key: string, css: string, ids: Array }> -}) => { +} */ +) => { return { - // $FlowFixMe - styles: styles.map<{ key: string, css: string, ids: Array }>( - (item): { key: string, css: string, ids: Array } => { + styles: styles.map( + /* <{ key: string, css: string, ids: Array }> */ ( + item + ) /*: { key: string, css: string, ids: Array } */ => { return { css: prettify(item.css || ''), ids: item.ids, key: item.key } } ), @@ -193,20 +191,16 @@ export const prettifyCriticalChunks = ({ } const isSSRedStyle = node => { - const attrib = ((node.getAttribute(`data-emotion`): any): string).split(' ') + const attrib = node.getAttribute(`data-emotion`).split(' ') // SSRed styles have also serialized names set here return attrib.length > 1 } -export const getCssFromChunks = (emotion: Emotion) => { +export const getCssFromChunks = (emotion /*: Emotion*/) => { const chunks = Array.from( - // $FlowFixMe emotion.sheet.tags[0].parentNode.querySelectorAll(`[data-emotion]`) ).filter(isSSRedStyle) - expect( - // $FlowFixMe - document.body.querySelector(`[data-emotion]`) - ).toBeNull() + expect(document.body.querySelector(`[data-emotion]`)).toBeNull() let css = chunks.map(chunk => chunk.textContent || '').join('') return prettify(css) } @@ -220,9 +214,9 @@ export const getInjectedRules = () => ) export const renderToStringWithStream = ( - element: React.Element<*>, - { renderStylesToNodeStream }: EmotionServer -): Promise => + element /*: React.Element<*> */, + { renderStylesToNodeStream } /*: EmotionServer */ +) /*: Promise */ => new Promise((resolve, reject) => { const stream = renderToNodeStream(element).pipe(renderStylesToNodeStream()) let html = '' diff --git a/packages/server/types/tsconfig.json b/packages/server/types/tsconfig.json index d7f5174a6e..5f5a3d15e2 100644 --- a/packages/server/types/tsconfig.json +++ b/packages/server/types/tsconfig.json @@ -3,7 +3,12 @@ "baseUrl": "../", "forceConsistentCasingInFileNames": true, "jsx": "react", - "lib": ["es6"], + "lib": [ + "es6", + // dom is needed here because @emotion/server depends on @emotion/css + // which depends on @emotion/sheet, which depends on DOM types + "dom" + ], "module": "commonjs", "noEmit": true, "strict": true, diff --git a/packages/sheet/__tests__/index.js b/packages/sheet/__tests__/index.js index 5cebf0b8c6..cb99f89779 100644 --- a/packages/sheet/__tests__/index.js +++ b/packages/sheet/__tests__/index.js @@ -1,4 +1,3 @@ -// @flow import { safeQuerySelector } from 'test-utils' import { StyleSheet } from '@emotion/sheet' @@ -10,7 +9,6 @@ let defaultOptions = { container: safeQuerySelector('head') } -// $FlowFixMe console.error = jest.fn() afterEach(() => { @@ -49,7 +47,6 @@ describe('StyleSheet', () => { sheet.insert(rule) expect(document.documentElement).toMatchSnapshot() expect( - // $FlowFixMe document.querySelector('[data-emotion]').getAttribute('data-emotion') ).toBe(key) sheet.flush() @@ -67,7 +64,6 @@ describe('StyleSheet', () => { sheet.insert(rule) expect(document.documentElement).toMatchSnapshot() expect(sheet.tags).toHaveLength(1) - // $FlowFixMe expect(sheet.tags[0].sheet.cssRules).toMatchSnapshot() sheet.flush() }) @@ -76,7 +72,7 @@ describe('StyleSheet', () => { const sheet = new StyleSheet({ ...defaultOptions, speedy: true }) sheet.insert('.asdfasdf4###112121211{') expect(console.error).toHaveBeenCalledTimes(1) - expect((console.error: any).mock.calls[0][0]).toBe( + expect(console.error.mock.calls[0][0]).toBe( 'There was a problem inserting the following rule: ".asdfasdf4###112121211{"' ) sheet.flush() @@ -94,7 +90,6 @@ describe('StyleSheet', () => { it("should use the container option instead of document.head to insert style elements into if it's passed", () => { const container = document.createElement('div') - // $FlowFixMe document.body.appendChild(container) const sheet = new StyleSheet({ ...defaultOptions, container }) expect(sheet.container).toBe(container) diff --git a/packages/sheet/package.json b/packages/sheet/package.json index 738ac6945f..64838c1bf8 100644 --- a/packages/sheet/package.json +++ b/packages/sheet/package.json @@ -7,6 +7,7 @@ "browser": { "./dist/emotion-sheet.esm.js": "./dist/emotion-sheet.browser.esm.js" }, + "types": "dist/emotion-sheet.cjs.d.ts", "exports": { ".": { "module": { @@ -18,7 +19,6 @@ }, "./package.json": "./package.json" }, - "types": "types/index.d.ts", "license": "MIT", "scripts": { "test:typescript": "dtslint types" @@ -29,8 +29,7 @@ }, "files": [ "src", - "dist", - "types/*.d.ts" + "dist" ], "devDependencies": { "@definitelytyped/dtslint": "0.0.112", diff --git a/packages/sheet/src/index.d.ts b/packages/sheet/src/index.d.ts deleted file mode 100644 index 9e46093759..0000000000 --- a/packages/sheet/src/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from '../types' -export { default } from '../types' diff --git a/packages/sheet/src/index.js b/packages/sheet/src/index.ts similarity index 82% rename from packages/sheet/src/index.js rename to packages/sheet/src/index.ts index 4fa90fbb66..b2592a4b02 100644 --- a/packages/sheet/src/index.js +++ b/packages/sheet/src/index.ts @@ -1,4 +1,3 @@ -// @flow /* Based off glamor's StyleSheet, thanks Sunil ❤️ @@ -22,10 +21,8 @@ styleSheet.flush() */ -// $FlowFixMe function sheetForTag(tag: HTMLStyleElement): CSSStyleSheet { if (tag.sheet) { - // $FlowFixMe return tag.sheet } @@ -33,25 +30,25 @@ function sheetForTag(tag: HTMLStyleElement): CSSStyleSheet { /* istanbul ignore next */ for (let i = 0; i < document.styleSheets.length; i++) { if (document.styleSheets[i].ownerNode === tag) { - // $FlowFixMe return document.styleSheets[i] } } + + // this function should always return with a value + // TS can't understand it though so we make it stop complaining here + return undefined as any } export type Options = { - nonce?: string, - key: string, - container: Node, - speedy?: boolean, - prepend?: boolean, + nonce?: string + key: string + container: Node + speedy?: boolean + prepend?: boolean insertionPoint?: HTMLElement } -function createStyleElement(options: { - key: string, - nonce: string | void -}): HTMLStyleElement { +function createStyleElement(options: Options): HTMLStyleElement { let tag = document.createElement('style') tag.setAttribute('data-emotion', options.key) if (options.nonce !== undefined) { @@ -69,10 +66,13 @@ export class StyleSheet { // Using Node instead of HTMLElement since container may be a ShadowRoot container: Node key: string - nonce: string | void - prepend: boolean | void + nonce: string | undefined + prepend: boolean | undefined before: Element | null - insertionPoint: HTMLElement | void + insertionPoint: HTMLElement | undefined + + private _alreadyInsertedOrderInsensitiveRule: boolean | undefined + constructor(options: Options) { this.isSpeedy = options.speedy === undefined @@ -89,7 +89,7 @@ export class StyleSheet { this.before = null } - _insertTag = (tag: HTMLStyleElement) => { + private _insertTag = (tag: HTMLStyleElement): void => { let before if (this.tags.length === 0) { if (this.insertionPoint) { @@ -106,11 +106,11 @@ export class StyleSheet { this.tags.push(tag) } - hydrate(nodes: HTMLStyleElement[]) { + hydrate(nodes: HTMLStyleElement[]): void { nodes.forEach(this._insertTag) } - insert(rule: string) { + insert(rule: string): void { // the max length is how many rules we have per style tag, it's 65000 in speedy mode // it's 1 in dev because we insert source maps that map a single rule to a location // and you can only have one source map per style tag @@ -123,7 +123,7 @@ export class StyleSheet { const isImportRule = rule.charCodeAt(0) === 64 && rule.charCodeAt(1) === 105 - if (isImportRule && (this: any)._alreadyInsertedOrderInsensitiveRule) { + if (isImportRule && this._alreadyInsertedOrderInsensitiveRule) { // this would only cause problem in speedy mode // but we don't want enabling speedy to affect the observable behavior // so we report this error at all times @@ -134,8 +134,8 @@ export class StyleSheet { ) } - ;(this: any)._alreadyInsertedOrderInsensitiveRule = - (this: any)._alreadyInsertedOrderInsensitiveRule || !isImportRule + this._alreadyInsertedOrderInsensitiveRule = + this._alreadyInsertedOrderInsensitiveRule || !isImportRule } if (this.isSpeedy) { @@ -163,13 +163,12 @@ export class StyleSheet { this.ctr++ } - flush() { - // $FlowFixMe - this.tags.forEach(tag => tag.parentNode && tag.parentNode.removeChild(tag)) + flush(): void { + this.tags.forEach(tag => tag.parentNode?.removeChild(tag)) this.tags = [] this.ctr = 0 if (process.env.NODE_ENV !== 'production') { - ;(this: any)._alreadyInsertedOrderInsensitiveRule = false + this._alreadyInsertedOrderInsensitiveRule = false } } } diff --git a/packages/sheet/types/index.d.ts b/packages/sheet/types/index.d.ts index 4e0c258e22..bfaefa68e7 100644 --- a/packages/sheet/types/index.d.ts +++ b/packages/sheet/types/index.d.ts @@ -1,26 +1,5 @@ -// Definitions by: Junyoung Clare Jang // TypeScript Version: 2.0 -export interface Options { - nonce?: string - key: string - container: Node - speedy?: boolean - /** @deprecate use `insertionPoint` instead */ - prepend?: boolean - insertionPoint?: HTMLElement -} +/// -export class StyleSheet { - isSpeedy: boolean - ctr: number - tags: Array - container: Node - key: string - nonce?: string - before?: ChildNode | null - constructor(options?: Options) - insert(rule: string): void - flush(): void - hydrate(nodes: Array): void -} +export * from '..' diff --git a/packages/sheet/types/tests.ts b/packages/sheet/types/tests.ts index 68dcab673d..b68facc59b 100644 --- a/packages/sheet/types/tests.ts +++ b/packages/sheet/types/tests.ts @@ -32,7 +32,16 @@ const styleSheet0 = new StyleSheet({ container: document.createElement('div') }) const styleSheet1: StyleSheet = styleSheet0 +// $ExpectError const styleSheet2: StyleSheet = new StyleSheet() +// $ExpectError +const styleSheet3: StyleSheet = new StyleSheet({}) +// $ExpectError +const styleSheet4: StyleSheet = new StyleSheet({ key: 'mykey' }) +// $ExpectError +const styleSheet5: StyleSheet = new StyleSheet({ + container: document.createElement('div') +}) const styleSheet = new StyleSheet({ key: 'abc', diff --git a/packages/styled/__tests__/as-prop.js b/packages/styled/__tests__/as-prop.js index 26bfd10496..69c57c4375 100644 --- a/packages/styled/__tests__/as-prop.js +++ b/packages/styled/__tests__/as-prop.js @@ -1,4 +1,3 @@ -// @flow import 'test-utils/next-env' import React from 'react' import { render, cleanup } from '@testing-library/react' diff --git a/packages/styled/__tests__/edge-cases.js b/packages/styled/__tests__/edge-cases.js index ec10703750..3bf21f72f2 100644 --- a/packages/styled/__tests__/edge-cases.js +++ b/packages/styled/__tests__/edge-cases.js @@ -1,4 +1,3 @@ -// @flow import 'test-utils/next-env' import * as React from 'react' import renderer from 'react-test-renderer' diff --git a/packages/styled/__tests__/styled-dom.js b/packages/styled/__tests__/styled-dom.js index cd5b54cb04..91d35fae08 100644 --- a/packages/styled/__tests__/styled-dom.js +++ b/packages/styled/__tests__/styled-dom.js @@ -1,4 +1,3 @@ -// @flow import * as React from 'react' import styled from '@emotion/styled' import { render, cleanup } from '@testing-library/react' diff --git a/packages/styled/__tests__/styled.js b/packages/styled/__tests__/styled.js index 853e79f619..ee3da1d64d 100644 --- a/packages/styled/__tests__/styled.js +++ b/packages/styled/__tests__/styled.js @@ -1,4 +1,3 @@ -// @flow /** @jsx jsx */ import 'test-utils/next-env' import renderer from 'react-test-renderer' @@ -590,7 +589,6 @@ describe('styled', () => { test('throws if undefined is passed as the component', () => { expect( () => - // $FlowFixMe styled(undefined)` display: flex; ` diff --git a/packages/styled/__tests__/warnings.js b/packages/styled/__tests__/warnings.js index dd81036c20..893a73a28a 100644 --- a/packages/styled/__tests__/warnings.js +++ b/packages/styled/__tests__/warnings.js @@ -1,11 +1,9 @@ -// @flow import 'test-utils/legacy-env' import * as React from 'react' import { css } from '@emotion/react' import styled from '@emotion/styled' import { render } from '@testing-library/react' -// $FlowFixMe console.error = jest.fn() afterEach(() => { @@ -19,7 +17,7 @@ it('warns about illegal escape sequences inside first quasi of template literal' } ` - expect((console.error: any).mock.calls[0]).toMatchInlineSnapshot(` + expect(console.error.mock.calls[0]).toMatchInlineSnapshot(` [ "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';". @@ -41,7 +39,7 @@ it('warns about illegal escape sequences inside non-first quasi of template lite } ` - expect((console.error: any).mock.calls[0]).toMatchInlineSnapshot(` + expect(console.error.mock.calls[0]).toMatchInlineSnapshot(` [ "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';". @@ -53,12 +51,11 @@ it('warns about illegal escape sequences inside non-first quasi of template lite it("warns about undefined being passed as object style's key", () => { let ListItem - // $FlowFixMe const List = styled.ul({ [ListItem]: { color: 'hotpink' } }) render() - expect((console.error: any).mock.calls[0]).toMatchInlineSnapshot(` + expect(console.error.mock.calls[0]).toMatchInlineSnapshot(` [ "You have passed in falsy value as style object's key (can happen when in example you pass unexported component as computed key).", ] diff --git a/packages/styled/flow-tests/base.js b/packages/styled/flow-tests/base.js deleted file mode 100644 index 9ab45ca9f1..0000000000 --- a/packages/styled/flow-tests/base.js +++ /dev/null @@ -1,21 +0,0 @@ -/* eslint-disable no-unused-vars */ -// @flow -import React from 'react' -import createStyled from '../src/base' -import type { CreateStyledComponent, StyledComponent } from '../src/utils' - -const valid: StyledComponent = createStyled('div')({ - color: 'red' -}) - -// $FlowFixMe: expect error - we can't cast a StyledComponent to string -const invalid: string = createStyled('div')({ color: 'red' }) - -const styled = createStyled('div') - -// $FlowFixMe: expect error - we don't expose the private StyledComponent properties -const invalidPropAccess = styled().__emotion_base - -// We allow styled components not to specify their props types -// NOTE: this is allowed only if you don't attempt to export it! -const untyped: StyledComponent = styled({}) diff --git a/packages/styled/flow-tests/index.js b/packages/styled/flow-tests/index.js deleted file mode 100644 index f941917ae2..0000000000 --- a/packages/styled/flow-tests/index.js +++ /dev/null @@ -1,20 +0,0 @@ -/* eslint-disable no-unused-vars */ -// @flow -import * as React from 'react' -import styled from '../src' - -type Props = { color: string } -const Foo = styled.div({ - color: 'red' -}) - -const valid = - -// $FlowFixMe: expect error - color must be string -const invalid = - -// components defined using the root method should be identical -// to the ones generated using the shortcuts -const root: typeof Foo = styled('div')` - colors: red; -` diff --git a/packages/styled/flow-tests/styled.js b/packages/styled/flow-tests/styled.js deleted file mode 100644 index 7ede72471c..0000000000 --- a/packages/styled/flow-tests/styled.js +++ /dev/null @@ -1,25 +0,0 @@ -/* eslint-disable no-unused-vars */ -// @flow -import React from 'react' -import styled from '../src' -import type { CreateStyledComponent, StyledComponent } from '../src/utils' - -type Props = { color: string } -const Div = styled.div({ color: 'red' }) - -const validProp =
- -// $FlowFixMe: expect error - color property should be a string -const invalidProp =
- -styled(props =>
{props.color}
)` - color: ${props => props.color}; -` - -styled(props => { - const color: string = props.color - const className: string = props.className - // $FlowFixMe: expect error - color should be a string - const colorTest: number = props.color - return
{props.color}
-})`` diff --git a/packages/styled/macro.js.flow b/packages/styled/macro.js.flow deleted file mode 100644 index b2d58a66c4..0000000000 --- a/packages/styled/macro.js.flow +++ /dev/null @@ -1,3 +0,0 @@ -// @flow -export * from './src/index.js' -export { default } from './src/index.js' diff --git a/packages/styled/src/base.js b/packages/styled/src/base.js index 29f3a43a36..992a97772b 100644 --- a/packages/styled/src/base.js +++ b/packages/styled/src/base.js @@ -1,12 +1,13 @@ -// @flow import * as React from 'react' import { getDefaultShouldForwardProp, - composeShouldForwardProps, + composeShouldForwardProps + /* type StyledOptions, type CreateStyled, type PrivateStyledComponent, type StyledElementType + */ } from './utils' import { withEmotionCache, ThemeContext } from '@emotion/react' import { @@ -51,7 +52,10 @@ const Insertion = ({ cache, serialized, isStringTag }) => { return null } -let createStyled: CreateStyled = (tag: any, options?: StyledOptions) => { +let createStyled /*: CreateStyled */ = ( + tag /*: any */, + options /* ?: StyledOptions */ +) => { if (process.env.NODE_ENV !== 'production') { if (tag === undefined) { throw new Error( @@ -74,7 +78,8 @@ let createStyled: CreateStyled = (tag: any, options?: StyledOptions) => { shouldForwardProp || getDefaultShouldForwardProp(baseTag) const shouldUseAs = !defaultShouldForwardProp('as') - return function (): PrivateStyledComponent { + /* return function(): PrivateStyledComponent { */ + return function () { let args = arguments let styles = isReal && tag.__emotion_styles !== undefined @@ -101,8 +106,7 @@ let createStyled: CreateStyled = (tag: any, options?: StyledOptions) => { } } - // $FlowFixMe: we need to cast StatelessFunctionalComponent to our PrivateStyledComponent class - const Styled: PrivateStyledComponent = withEmotionCache( + const Styled /*: PrivateStyledComponent */ = withEmotionCache( (props, cache, ref) => { const FinalTag = (shouldUseAs && props.as) || baseTag @@ -147,10 +151,7 @@ let createStyled: CreateStyled = (tag: any, options?: StyledOptions) => { for (let key in props) { if (shouldUseAs && key === 'as') continue - if ( - // $FlowFixMe - finalShouldForwardProp(key) - ) { + if (finalShouldForwardProp(key)) { newProps[key] = props[key] } } @@ -194,18 +195,16 @@ let createStyled: CreateStyled = (tag: any, options?: StyledOptions) => { ) { return 'NO_COMPONENT_SELECTOR' } - // $FlowFixMe: coerce undefined to string return `.${targetClassName}` } }) Styled.withComponent = ( - nextTag: StyledElementType, - nextOptions?: StyledOptions + nextTag /*: StyledElementType */, + nextOptions /* ?: StyledOptions */ ) => { return createStyled(nextTag, { ...options, - // $FlowFixMe ...nextOptions, shouldForwardProp: composeShouldForwardProps(Styled, nextOptions, true) })(...styles) diff --git a/packages/styled/src/index.js b/packages/styled/src/index.js index 420f7f4764..dd11a7c906 100644 --- a/packages/styled/src/index.js +++ b/packages/styled/src/index.js @@ -1,4 +1,3 @@ -// @flow import styled from './base' import { tags } from './tags' @@ -6,7 +5,6 @@ import { tags } from './tags' const newStyled = styled.bind() tags.forEach(tagName => { - // $FlowFixMe: we can ignore this because its exposed type is defined by the CreateStyled type newStyled[tagName] = newStyled(tagName) }) diff --git a/packages/styled/src/tags.js b/packages/styled/src/tags.js index e33db9d7e8..19bd402366 100644 --- a/packages/styled/src/tags.js +++ b/packages/styled/src/tags.js @@ -1,4 +1,3 @@ -// @flow export const tags = [ 'a', 'abbr', diff --git a/packages/styled/src/utils.js b/packages/styled/src/utils.js index 1ae27ebfc7..83a999d19a 100644 --- a/packages/styled/src/utils.js +++ b/packages/styled/src/utils.js @@ -1,11 +1,11 @@ -// @flow -import type { +/* import type { ElementType, StatelessFunctionalComponent, AbstractComponent -} from 'react' +} from 'react' */ import isPropValid from '@emotion/is-prop-valid' +/* export type Interpolations = Array export type StyledElementType = @@ -33,11 +33,12 @@ export type PrivateStyledComponent = StyledComponent & { __emotion_styles: any, __emotion_forwardProp: any } +*/ const testOmitPropsOnStringTag = isPropValid -const testOmitPropsOnComponent = (key: string) => key !== 'theme' +const testOmitPropsOnComponent = (key /*: string */) => key !== 'theme' -export const getDefaultShouldForwardProp = (tag: ElementType) => +export const getDefaultShouldForwardProp = (tag /*: ElementType */) => typeof tag === 'string' && // 96 is one less than the char code // for "a" so this is checking that @@ -47,16 +48,16 @@ export const getDefaultShouldForwardProp = (tag: ElementType) => : testOmitPropsOnComponent export const composeShouldForwardProps = ( - tag: PrivateStyledComponent, - options: StyledOptions | void, - isReal: boolean + tag /*: PrivateStyledComponent */, + options /*: StyledOptions | void */, + isReal /*: boolean */ ) => { let shouldForwardProp if (options) { const optionsShouldForwardProp = options.shouldForwardProp shouldForwardProp = tag.__emotion_forwardProp && optionsShouldForwardProp - ? (propName: string) => + ? (propName /*: string */) => tag.__emotion_forwardProp(propName) && optionsShouldForwardProp(propName) : optionsShouldForwardProp @@ -69,6 +70,7 @@ export const composeShouldForwardProps = ( return shouldForwardProp } +/* export type CreateStyledComponent = ( ...args: Interpolations ) => StyledComponent @@ -81,3 +83,4 @@ export type CreateStyled = { [key: string]: CreateStyledComponent, bind: () => CreateStyled } +*/ diff --git a/packages/styled/test/__snapshots__/source-map.test.js.snap b/packages/styled/test/__snapshots__/source-map.test.js.snap index f165bb74b2..5f1f21cf4d 100644 --- a/packages/styled/test/__snapshots__/source-map.test.js.snap +++ b/packages/styled/test/__snapshots__/source-map.test.js.snap @@ -8,7 +8,7 @@ exports[`inserts source map 1`] = ` data-s="" > - .css-1igngve-Comp{color:hotpink;}/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNvdXJjZS1tYXAudGVzdC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFNdUIiLCJmaWxlIjoic291cmNlLW1hcC50ZXN0LmpzIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQGZsb3dcbmltcG9ydCBSZWFjdCBmcm9tICdyZWFjdCdcbmltcG9ydCBzdHlsZWQgZnJvbSAnQGVtb3Rpb24vc3R5bGVkJ1xuaW1wb3J0IHJlbmRlcmVyIGZyb20gJ3JlYWN0LXRlc3QtcmVuZGVyZXInXG5cbnRlc3QoJ2luc2VydHMgc291cmNlIG1hcCcsICgpID0+IHtcbiAgbGV0IENvbXAgPSBzdHlsZWQuZGl2YFxuICAgIGNvbG9yOiBob3RwaW5rO1xuICBgXG4gIHJlbmRlcmVyLmNyZWF0ZSg8Q29tcCAvPilcbiAgZXhwZWN0KGRvY3VtZW50LmRvY3VtZW50RWxlbWVudCkudG9NYXRjaFNuYXBzaG90KClcbn0pXG4iXX0= */ + .css-1igngve-Comp{color:hotpink;}/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInNvdXJjZS1tYXAudGVzdC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFLdUIiLCJmaWxlIjoic291cmNlLW1hcC50ZXN0LmpzIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IFJlYWN0IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHN0eWxlZCBmcm9tICdAZW1vdGlvbi9zdHlsZWQnXG5pbXBvcnQgcmVuZGVyZXIgZnJvbSAncmVhY3QtdGVzdC1yZW5kZXJlcidcblxudGVzdCgnaW5zZXJ0cyBzb3VyY2UgbWFwJywgKCkgPT4ge1xuICBsZXQgQ29tcCA9IHN0eWxlZC5kaXZgXG4gICAgY29sb3I6IGhvdHBpbms7XG4gIGBcbiAgcmVuZGVyZXIuY3JlYXRlKDxDb21wIC8+KVxuICBleHBlY3QoZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50KS50b01hdGNoU25hcHNob3QoKVxufSlcbiJdfQ== */ diff --git a/packages/styled/test/babel-plugin.test.js b/packages/styled/test/babel-plugin.test.js index fc8cbdbe33..c1c9492f20 100644 --- a/packages/styled/test/babel-plugin.test.js +++ b/packages/styled/test/babel-plugin.test.js @@ -1,4 +1,3 @@ -// @flow import 'test-utils/legacy-env' import React from 'react' import * as renderer from 'react-test-renderer' diff --git a/packages/styled/test/composition.test.js b/packages/styled/test/composition.test.js index 6a8703c041..208ac0fd19 100644 --- a/packages/styled/test/composition.test.js +++ b/packages/styled/test/composition.test.js @@ -1,4 +1,3 @@ -// @flow /** @jsx jsx */ import 'test-utils/legacy-env' import * as renderer from 'react-test-renderer' diff --git a/packages/styled/test/index.test.js b/packages/styled/test/index.test.js index e73594200c..84aac65bc0 100644 --- a/packages/styled/test/index.test.js +++ b/packages/styled/test/index.test.js @@ -1,4 +1,3 @@ -// @flow import 'test-utils/legacy-env' import React from 'react' import * as renderer from 'react-test-renderer' @@ -301,7 +300,6 @@ describe('styled', () => { test('throws if undefined is passed as the component', () => { expect( () => - // $FlowFixMe styled(undefined)` display: flex; ` @@ -391,7 +389,7 @@ describe('styled', () => { }) test('name with class component', () => { - class SomeComponent extends React.Component<{ className: string }> { + class SomeComponent extends React.Component /* <{ className: string }> */ { render() { return
} diff --git a/packages/styled/test/prop-filtering.test.js b/packages/styled/test/prop-filtering.test.js index 34e4be0e77..7d776bf19a 100644 --- a/packages/styled/test/prop-filtering.test.js +++ b/packages/styled/test/prop-filtering.test.js @@ -1,4 +1,3 @@ -// @flow import 'test-utils/legacy-env' import React from 'react' import * as renderer from 'react-test-renderer' diff --git a/packages/styled/test/source-map.test.js b/packages/styled/test/source-map.test.js index 380bb69bd0..41b9284cb2 100644 --- a/packages/styled/test/source-map.test.js +++ b/packages/styled/test/source-map.test.js @@ -1,4 +1,3 @@ -// @flow import React from 'react' import styled from '@emotion/styled' import renderer from 'react-test-renderer' diff --git a/packages/styled/test/theming.dom.test.js b/packages/styled/test/theming.dom.test.js index fcb219edd7..bae7d46f71 100644 --- a/packages/styled/test/theming.dom.test.js +++ b/packages/styled/test/theming.dom.test.js @@ -1,4 +1,3 @@ -// @flow import 'test-utils/legacy-env' import React from 'react' import styled from '@emotion/styled' diff --git a/packages/styled/test/theming.test.js b/packages/styled/test/theming.test.js index da9578b42a..69a1431d66 100644 --- a/packages/styled/test/theming.test.js +++ b/packages/styled/test/theming.test.js @@ -1,4 +1,3 @@ -// @flow import 'test-utils/legacy-env' import React from 'react' import * as renderer from 'react-test-renderer' diff --git a/packages/unitless/package.json b/packages/unitless/package.json index 30da6a1d05..25a3a6d6ac 100644 --- a/packages/unitless/package.json +++ b/packages/unitless/package.json @@ -4,6 +4,7 @@ "description": "An object of css properties that don't accept values with units", "main": "dist/emotion-unitless.cjs.js", "module": "dist/emotion-unitless.esm.js", + "types": "dist/emotion-unitless.cjs.d.ts", "license": "MIT", "repository": "https://github.com/emotion-js/emotion/tree/main/packages/unitless", "publishConfig": { diff --git a/packages/unitless/src/index.d.ts b/packages/unitless/src/index.d.ts deleted file mode 100644 index 9e46093759..0000000000 --- a/packages/unitless/src/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from '../types' -export { default } from '../types' diff --git a/packages/unitless/src/index.js b/packages/unitless/src/index.ts similarity index 94% rename from packages/unitless/src/index.js rename to packages/unitless/src/index.ts index 66bc957a5a..478252a6b0 100644 --- a/packages/unitless/src/index.js +++ b/packages/unitless/src/index.ts @@ -1,6 +1,4 @@ -// @flow - -let unitlessKeys: { [key: string]: 1 } = { +let unitlessKeys: Record = { animationIterationCount: 1, aspectRatio: 1, borderImageOutset: 1, diff --git a/packages/utils/package.json b/packages/utils/package.json index 880221abd5..0132182aa9 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -4,6 +4,7 @@ "description": "internal utils for emotion", "main": "dist/emotion-utils.cjs.js", "module": "dist/emotion-utils.esm.js", + "types": "dist/emotion-utils.cjs.d.ts", "browser": { "./dist/emotion-utils.esm.js": "./dist/emotion-utils.browser.esm.js" }, @@ -19,7 +20,6 @@ }, "./package.json": "./package.json" }, - "types": "types/index.d.ts", "license": "MIT", "scripts": { "test:typescript": "dtslint types" @@ -30,8 +30,7 @@ }, "files": [ "src", - "dist", - "types/*.d.ts" + "dist" ], "devDependencies": { "@definitelytyped/dtslint": "0.0.112", diff --git a/packages/utils/src/index.d.ts b/packages/utils/src/index.d.ts deleted file mode 100644 index 51a3b4100a..0000000000 --- a/packages/utils/src/index.d.ts +++ /dev/null @@ -1 +0,0 @@ -export * from '../types' diff --git a/packages/utils/src/index.js b/packages/utils/src/index.ts similarity index 93% rename from packages/utils/src/index.js rename to packages/utils/src/index.ts index e43a688806..009e9fba20 100644 --- a/packages/utils/src/index.js +++ b/packages/utils/src/index.ts @@ -1,5 +1,4 @@ -// @flow -import type { RegisteredCache, EmotionCache, SerializedStyles } from './types' +import { RegisteredCache, EmotionCache, SerializedStyles } from './types' const isBrowser = typeof document !== 'undefined' @@ -7,7 +6,7 @@ export function getRegisteredStyles( registered: RegisteredCache, registeredStyles: string[], classNames: string -) { +): string { let rawClassName = '' classNames.split(' ').forEach(className => { @@ -24,7 +23,7 @@ export const registerStyles = ( cache: EmotionCache, serialized: SerializedStyles, isStringTag: boolean -) => { +): void => { let className = `${cache.key}-${serialized.name}` if ( // we only need to add the styles to the registered cache if the @@ -55,7 +54,7 @@ export const insertStyles = ( if (cache.inserted[serialized.name] === undefined) { let stylesForSSR = '' - let current = serialized + let current: SerializedStyles | undefined = serialized do { let maybeStyles = cache.insert( serialized === current ? `.${className}` : '', diff --git a/packages/utils/src/types.js b/packages/utils/src/types.js deleted file mode 100644 index 173b5063eb..0000000000 --- a/packages/utils/src/types.js +++ /dev/null @@ -1,28 +0,0 @@ -// @flow -import type { StyleSheet } from '@emotion/sheet' - -export type RegisteredCache = { [string]: string } - -export type Interpolation = any - -export type SerializedStyles = {| - name: string, - styles: string, - map?: string, - next?: SerializedStyles -|} - -export type EmotionCache = { - inserted: { [string]: string | true }, - registered: RegisteredCache, - sheet: StyleSheet, - key: string, - compat?: true, - nonce?: string, - insert: ( - selector: string, - serialized: SerializedStyles, - sheet: StyleSheet, - shouldCache: boolean - ) => string | void -} diff --git a/packages/utils/src/types.ts b/packages/utils/src/types.ts new file mode 100644 index 0000000000..bb76f91981 --- /dev/null +++ b/packages/utils/src/types.ts @@ -0,0 +1,27 @@ +import type { StyleSheet } from '@emotion/sheet' + +export type { StyleSheet } + +export type RegisteredCache = Record + +export type SerializedStyles = { + name: string + styles: string + map?: string + next?: SerializedStyles +} + +export type EmotionCache = { + inserted: Record + registered: RegisteredCache + sheet: StyleSheet + key: string + compat?: true + nonce?: string + insert: ( + selector: string, + serialized: SerializedStyles, + sheet: StyleSheet, + shouldCache: boolean + ) => string | void +} diff --git a/packages/utils/types/index.d.ts b/packages/utils/types/index.d.ts index f44c0f534c..d0d62d34ab 100644 --- a/packages/utils/types/index.d.ts +++ b/packages/utils/types/index.d.ts @@ -1,59 +1,5 @@ -// Definitions by: Junyoung Clare Jang // TypeScript Version: 2.2 -export interface RegisteredCache { - [key: string]: string -} +/// -export interface StyleSheet { - container: HTMLElement - nonce?: string - key: string - insert(rule: string): void - flush(): void - tags: Array -} - -export interface EmotionCache { - inserted: { - [key: string]: string | true - } - registered: RegisteredCache - sheet: StyleSheet - key: string - compat?: true - nonce?: string - insert( - selector: string, - serialized: SerializedStyles, - sheet: StyleSheet, - shouldCache: boolean - ): string | void -} - -export interface SerializedStyles { - name: string - styles: string - map?: string - next?: SerializedStyles -} - -export const isBrowser: boolean - -export function getRegisteredStyles( - registered: RegisteredCache, - registeredStyles: Array, - classNames: string -): string - -export function registerStyles( - cache: EmotionCache, - serialized: SerializedStyles, - isStringTag: boolean -): void - -export function insertStyles( - cache: EmotionCache, - serialized: SerializedStyles, - isStringTag: boolean -): string | void +export * from '..' diff --git a/packages/utils/types/tests.ts b/packages/utils/types/tests.ts index c0c9b2b0ea..3033719a12 100644 --- a/packages/utils/types/tests.ts +++ b/packages/utils/types/tests.ts @@ -1,11 +1,8 @@ import { EmotionCache, RegisteredCache, - SerializedStyles, - StyleSheet, getRegisteredStyles, - insertStyles, - isBrowser + insertStyles } from '@emotion/utils' declare const testCache: EmotionCache @@ -39,7 +36,3 @@ insertStyles(testCache, { name: 'abc', styles: 'font-size: 18px;' }) - -const test0: boolean = isBrowser -// $ExpectError -const test1: number = isBrowser diff --git a/packages/weak-memoize/package.json b/packages/weak-memoize/package.json index 4d384abcca..d85548bb6d 100644 --- a/packages/weak-memoize/package.json +++ b/packages/weak-memoize/package.json @@ -4,7 +4,7 @@ "description": "A memoization function that uses a WeakMap", "main": "dist/emotion-weak-memoize.cjs.js", "module": "dist/emotion-weak-memoize.esm.js", - "types": "types/index.d.ts", + "types": "dist/emotion-weak-memoize.cjs.d.ts", "license": "MIT", "repository": "https://github.com/emotion-js/emotion/tree/main/packages/weak-memoize", "scripts": { @@ -19,8 +19,7 @@ }, "files": [ "src", - "dist", - "types/*.d.ts" + "dist" ], "exports": { ".": { diff --git a/packages/weak-memoize/src/index.d.ts b/packages/weak-memoize/src/index.d.ts deleted file mode 100644 index 9e46093759..0000000000 --- a/packages/weak-memoize/src/index.d.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from '../types' -export { default } from '../types' diff --git a/packages/weak-memoize/src/index.js b/packages/weak-memoize/src/index.js deleted file mode 100644 index 83c9379d9f..0000000000 --- a/packages/weak-memoize/src/index.js +++ /dev/null @@ -1,16 +0,0 @@ -// @flow -let weakMemoize = function (func: Arg => Return): Arg => Return { - // $FlowFixMe flow doesn't include all non-primitive types as allowed for weakmaps - let cache: WeakMap = new WeakMap() - return arg => { - if (cache.has(arg)) { - // $FlowFixMe - return cache.get(arg) - } - let ret = func(arg) - cache.set(arg, ret) - return ret - } -} - -export default weakMemoize diff --git a/packages/weak-memoize/src/index.ts b/packages/weak-memoize/src/index.ts new file mode 100644 index 0000000000..ba4c5bc555 --- /dev/null +++ b/packages/weak-memoize/src/index.ts @@ -0,0 +1,17 @@ +let weakMemoize = function ( + func: (arg: Arg) => Return +): (arg: Arg) => Return { + let cache = new WeakMap() + return (arg: Arg) => { + if (cache.has(arg)) { + // Use non-null assertion because we just checked that the cache `has` it + // This allows us to remove `undefined` from the return value + return cache.get(arg)! + } + let ret = func(arg) + cache.set(arg, ret) + return ret + } +} + +export default weakMemoize diff --git a/packages/weak-memoize/types/index.d.ts b/packages/weak-memoize/types/index.d.ts index b5344615a0..91fafac0bd 100644 --- a/packages/weak-memoize/types/index.d.ts +++ b/packages/weak-memoize/types/index.d.ts @@ -1,7 +1,3 @@ // TypeScript Version: 2.2 -type UnaryFn = (arg: Arg) => Return - -export default function weakMemoize( - func: UnaryFn -): UnaryFn +export { default } from '..' diff --git a/packages/weak-memoize/types/tslint.json b/packages/weak-memoize/types/tslint.json index 2ab14e84ff..20bc577159 100644 --- a/packages/weak-memoize/types/tslint.json +++ b/packages/weak-memoize/types/tslint.json @@ -18,6 +18,7 @@ ], "no-unnecessary-generics": false, - "strict-export-declare-modifiers": false + "strict-export-declare-modifiers": false, + "no-default-import": false } } diff --git a/scripts/babel-preset-emotion-dev/package.json b/scripts/babel-preset-emotion-dev/package.json index 904888f53f..cf9723419c 100644 --- a/scripts/babel-preset-emotion-dev/package.json +++ b/scripts/babel-preset-emotion-dev/package.json @@ -5,6 +5,7 @@ "private": true, "dependencies": { "@babel/plugin-proposal-class-properties": "^7.17.12", - "@babel/plugin-transform-flow-strip-types": "^7.17.12" + "babel-plugin-add-basic-constructor-for-react-components": "^0.1.0", + "babel-plugin-fix-dce-for-classes-with-statics": "^0.1.0" } } diff --git a/scripts/babel-preset-emotion-dev/src/index.js b/scripts/babel-preset-emotion-dev/src/index.js index 803cd40265..c6f3c28124 100644 --- a/scripts/babel-preset-emotion-dev/src/index.js +++ b/scripts/babel-preset-emotion-dev/src/index.js @@ -14,7 +14,10 @@ module.exports = (api, options = {}) => { ] ], plugins: [ - require.resolve('@babel/plugin-transform-flow-strip-types'), + require.resolve( + 'babel-plugin-add-basic-constructor-for-react-components' + ), + require.resolve('babel-plugin-fix-dce-for-classes-with-statics'), require.resolve('babel-plugin-codegen'), [ require.resolve('@babel/plugin-transform-runtime'), diff --git a/scripts/babel-tester/babel-check-duplicated-nodes.d.ts b/scripts/babel-tester/babel-check-duplicated-nodes.d.ts new file mode 100644 index 0000000000..3db965bb9e --- /dev/null +++ b/scripts/babel-tester/babel-check-duplicated-nodes.d.ts @@ -0,0 +1,6 @@ +declare module 'babel-check-duplicated-nodes' { + export default function checkDuplicatedNodes( + babel: typeof import('@babel/core'), + ast: import('@babel/core').types.File + ): void +} diff --git a/scripts/babel-tester/package.json b/scripts/babel-tester/package.json index b8e2378cc1..3dd089d587 100644 --- a/scripts/babel-tester/package.json +++ b/scripts/babel-tester/package.json @@ -1,10 +1,14 @@ { "name": "babel-tester", - "main": "src/index.js", + "main": "src/index.ts", "version": "0.4.5", "private": true, "dependencies": { "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3" + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "babel-check-duplicated-nodes": "^1.0.0" + }, + "devDependencies": { + "@types/jest-in-case": "^1.0.5" } } diff --git a/scripts/babel-tester/src/index.js b/scripts/babel-tester/src/index.ts similarity index 65% rename from scripts/babel-tester/src/index.js rename to scripts/babel-tester/src/index.ts index 95020ad68c..78dffe8a5e 100644 --- a/scripts/babel-tester/src/index.js +++ b/scripts/babel-tester/src/index.ts @@ -1,4 +1,3 @@ -// @flow /* eslint-env jest */ import jestInCase from 'jest-in-case' import * as babel from '@babel/core' @@ -7,19 +6,40 @@ import path from 'path' import { promisify } from 'util' import checkDuplicatedNodes from 'babel-check-duplicated-nodes' +type FixtureTestCase = { + filename: string + babelFileName: string + only: boolean + skip: boolean +} + +type TestCase = { + code?: string + filename?: string + babelFileName?: string + plugins?: any[] +} + +type TesterOptions = { + plugins?: any[] + presets?: any[] + transform?: (code: string) => string + filename?: string +} + const readFile = promisify(fs.readFile) const separator = '\n\n ↓ ↓ ↓ ↓ ↓ ↓\n\n' -const tester = allOpts => async opts => { +const tester = (allOpts: TesterOptions) => async (opts: TestCase) => { let rawCode = opts.code if (!opts.code && opts.filename) { rawCode = await readFile(opts.filename, 'utf-8') } if (allOpts.transform) { - rawCode = allOpts.transform(rawCode) + rawCode = allOpts.transform(rawCode!) } - const { code, ast } = babel.transformSync(rawCode, { + const { code, ast } = babel.transformSync(rawCode!, { plugins: [ 'macros', '@babel/plugin-syntax-jsx', @@ -33,13 +53,13 @@ const tester = allOpts => async opts => { configFile: false, ast: true, filename: 'babelFileName' in opts ? opts.babelFileName : 'emotion.js' - }) - expect(() => checkDuplicatedNodes(babel, ast)).not.toThrow() + })! + expect(() => checkDuplicatedNodes(babel, ast!)).not.toThrow() expect(`${rawCode}${separator}${code}`).toMatchSnapshot() } -function doThing(dirname) { +function readFixturesDir(dirname: string): string[] { const fixturesFolder = path.join(dirname, '__fixtures__') return fs .readdirSync(fixturesFolder) @@ -49,23 +69,14 @@ function doThing(dirname) { export default ( name: string, cases: - | { - [key: string]: { - code: string, - plugins?: any[], - babelFileName?: string - } - } - | string, - opts?: { - plugins?: Array<*>, - presets?: Array<*>, - transform?: string => string, - filename?: string - } = {} + | string + | Record, + opts: TesterOptions = {} ) => { if (typeof cases === 'string') { - cases = doThing(cases).reduce((accum, filename) => { + const fixtureCases = readFixturesDir(cases).reduce< + Record + >((accum, filename) => { let skip = false let only = false let testTitle = filename @@ -84,8 +95,8 @@ export default ( } return accum }, {}) + return jestInCase(name, tester(opts), fixtureCases) } - // $FlowFixMe return jestInCase(name, tester(opts), cases) } diff --git a/scripts/benchmarks/.babelrc b/scripts/benchmarks/.babelrc index 8fecfd4cf0..4e025bd5bd 100644 --- a/scripts/benchmarks/.babelrc +++ b/scripts/benchmarks/.babelrc @@ -1,7 +1,6 @@ { "presets": [ ["@babel/env", { "modules": false, "loose": true }], - "@babel/flow", "@babel/react" ], "plugins": [ diff --git a/scripts/benchmarks/run.js b/scripts/benchmarks/run.js index 76a50c9dd0..a78a6d32bb 100644 --- a/scripts/benchmarks/run.js +++ b/scripts/benchmarks/run.js @@ -1,5 +1,5 @@ // some of this is from https://github.com/styled-components/styled-components/blob/master/benchmarks/run-headless.js -// @flow + const path = require('path') const puppeteer = require('puppeteer') const { createServer } = require('http-server') diff --git a/scripts/benchmarks/src/app/App.js b/scripts/benchmarks/src/app/App.js index 55e2468e68..552d0f0780 100644 --- a/scripts/benchmarks/src/app/App.js +++ b/scripts/benchmarks/src/app/App.js @@ -16,7 +16,7 @@ import { colors } from './theme' const Overlay = () => -export default class App extends Component<{}> { +export default class App extends Component { static displayName = '@app/App' constructor(props, context) { diff --git a/scripts/benchmarks/src/app/Benchmark/index.js b/scripts/benchmarks/src/app/Benchmark/index.js index a5b74eb000..bf11aff079 100644 --- a/scripts/benchmarks/src/app/Benchmark/index.js +++ b/scripts/benchmarks/src/app/Benchmark/index.js @@ -4,19 +4,17 @@ * https://github.com/paularmstrong/react-component-benchmark */ -/* global $Values */ -/** - * @flow - */ import * as Timing from './timing' import React, { Component } from 'react' import { getMean, getMedian, getStdDev } from './math' +/* import type { BenchResultsType, FullSampleTimingType, SampleTimingType } from './types' +*/ export const BenchmarkType = { MOUNT: 'mount', @@ -25,9 +23,9 @@ export const BenchmarkType = { } const shouldRender = ( - cycle: number, - type: $Values -): boolean => { + cycle /*: number */, + type /*: $Values */ +) /*: boolean */ => { switch (type) { // Render every odd iteration (first, third, etc) // Mounts and unmounts the component @@ -43,9 +41,9 @@ const shouldRender = ( } const shouldRecord = ( - cycle: number, - type: $Values -): boolean => { + cycle /*: number */, + type /*: $Values */ +) /*: boolean */ => { switch (type) { // Record every odd iteration (when mounted: first, third, etc) case BenchmarkType.MOUNT: @@ -62,10 +60,10 @@ const shouldRecord = ( } const isDone = ( - cycle: number, - sampleCount: number, - type: $Values -): boolean => { + cycle /*: number */, + sampleCount /*: number */, + type /*: $Values */ +) /*: boolean */ => { switch (type) { case BenchmarkType.MOUNT: return cycle >= sampleCount * 2 - 1 @@ -78,8 +76,9 @@ const isDone = ( } } -const sortNumbers = (a: number, b: number): number => a - b +const sortNumbers = (a /*: number */, b /*: number */) /*: number */ => a - b +/* type BenchmarkPropsType = { component: typeof React.Component, forceLayout?: boolean, @@ -95,19 +94,19 @@ type BenchmarkStateType = { cycle: number, running: boolean } +*/ /** * Benchmark * TODO: documentation */ -export default class Benchmark extends Component< +export default class Benchmark extends Component /* < BenchmarkPropsType, BenchmarkStateType -> { - _raf: ?Function - _startTime: number - _samples: Array - +> */ { + _raf /*: ?Function */ + _startTime /*: number */ + _samples /*: Array */ static displayName = 'Benchmark' static defaultProps = { @@ -118,7 +117,7 @@ export default class Benchmark extends Component< static Type = BenchmarkType - constructor(props: BenchmarkPropsType, context?: {}) { + constructor(props /*: BenchmarkPropsType */, context /* ?: {} */) { super(props, context) const cycle = 0 const componentProps = props.getComponentProps({ cycle }) @@ -131,7 +130,7 @@ export default class Benchmark extends Component< this._samples = [] } - componentWillReceiveProps(nextProps: BenchmarkPropsType) { + componentWillReceiveProps(nextProps /*: BenchmarkPropsType */) { if (nextProps) { this.setState(state => ({ componentProps: nextProps.getComponentProps(state.cycle) @@ -140,8 +139,8 @@ export default class Benchmark extends Component< } componentWillUpdate( - nextProps: BenchmarkPropsType, - nextState: BenchmarkStateType + nextProps /*: BenchmarkPropsType */, + nextState /*: BenchmarkStateType */ ) { if (nextState.running && !this.state.running) { this._startTime = Timing.now() @@ -217,24 +216,24 @@ export default class Benchmark extends Component< } this._raf = window.requestAnimationFrame(() => { - this.setState((state: BenchmarkStateType) => ({ + this.setState((state /*: BenchmarkStateType */) => ({ cycle: state.cycle + 1, componentProps })) }) } - getSamples(): Array { + getSamples() /*: Array */ { return this._samples.reduce( ( - memo: Array, + memo /*: Array */, { scriptingStart, scriptingEnd, layoutStart, layoutEnd - }: SampleTimingType - ): Array => { + } /*: SampleTimingType */ + ) /*: Array */ => { memo.push({ start: scriptingStart, end: layoutEnd || scriptingEnd || 0, @@ -249,7 +248,7 @@ export default class Benchmark extends Component< ) } - _handleComplete(endTime: number) { + _handleComplete(endTime /*: number */) { const { onComplete } = this.props const samples = this.getSamples() diff --git a/scripts/benchmarks/src/app/Benchmark/math.js b/scripts/benchmarks/src/app/Benchmark/math.js index 2104930261..efd1213653 100644 --- a/scripts/benchmarks/src/app/Benchmark/math.js +++ b/scripts/benchmarks/src/app/Benchmark/math.js @@ -1,11 +1,9 @@ -// @flow import stats from 'stats-analysis' -type ValuesType = Array -export const getStdDev = (values: ValuesType): number => { +export const getStdDev = values => { const avg = getMean(values) - const squareDiffs = values.map((value: number) => { + const squareDiffs = values.map(value => { const diff = value - avg return diff * diff }) @@ -13,7 +11,7 @@ export const getStdDev = (values: ValuesType): number => { return Math.sqrt(getMean(squareDiffs)) } -export const getMean = (values: ValuesType): number => { +export const getMean = values => { let valuesWithoutOutliers = stats.filterMADoutliers(values) return stats.mean(valuesWithoutOutliers) } diff --git a/scripts/benchmarks/src/app/Benchmark/timing.js b/scripts/benchmarks/src/app/Benchmark/timing.js index 297efcc177..de7d507ef3 100644 --- a/scripts/benchmarks/src/app/Benchmark/timing.js +++ b/scripts/benchmarks/src/app/Benchmark/timing.js @@ -1,10 +1,8 @@ -// @flow - const NS_PER_MS = 1e6 const MS_PER_S = 1e3 // Returns a high resolution time (if possible) in milliseconds -export function now(): number { +export function now() { if (window && window.performance) { return window.performance.now() } else if (process && process.hrtime) { diff --git a/scripts/benchmarks/src/app/Benchmark/types.js b/scripts/benchmarks/src/app/Benchmark/types.js index 8bbc5a2333..abba17c3bd 100644 --- a/scripts/benchmarks/src/app/Benchmark/types.js +++ b/scripts/benchmarks/src/app/Benchmark/types.js @@ -1,32 +1,30 @@ -/** - * @flow - */ - +/* export type FullSampleTimingType = { - start: number, - end: number, - scriptingStart: number, - scriptingEnd: number, - layoutStart?: number, + start: number + end: number + scriptingStart: number + scriptingEnd: number + layoutStart?: number layoutEnd?: number } export type BenchResultsType = { - startTime: number, - endTime: number, - runTime: number, - sampleCount: number, - samples: Array, - max: number, - min: number, - median: number, - mean: number, + startTime: number + endTime: number + runTime: number + sampleCount: number + samples: Array + max: number + min: number + median: number + mean: number stdDev: number } export type SampleTimingType = { - scriptingStart: number, - scriptingEnd?: number, - layoutStart?: number, + scriptingStart: number + scriptingEnd?: number + layoutStart?: number layoutEnd?: number } +*/ diff --git a/scripts/benchmarks/src/app/Button.js b/scripts/benchmarks/src/app/Button.js index 51902e3b6b..619f87e78f 100644 --- a/scripts/benchmarks/src/app/Button.js +++ b/scripts/benchmarks/src/app/Button.js @@ -2,7 +2,7 @@ import { StyleSheet, TouchableHighlight, Text } from 'react-native' import React, { Component } from 'react' import { bool, func, string, any } from 'prop-types' -export default class Button extends Component<*> { +export default class Button extends Component { static displayName = '@app/Button' static propTypes = { diff --git a/scripts/benchmarks/src/app/ReportCard.js b/scripts/benchmarks/src/app/ReportCard.js index 94a4826c30..112c63b0f1 100644 --- a/scripts/benchmarks/src/app/ReportCard.js +++ b/scripts/benchmarks/src/app/ReportCard.js @@ -2,12 +2,12 @@ import Text from './Text' import { StyleSheet, View } from 'react-native' import React from 'react' -const fmt = (time: number) => { +const fmt = (time /*: number */) => { const i = Number(Math.round(time + 'e2') + 'e-2').toFixed(2) return 10 / i > 1 ? `0${i}` : i } -class ReportCard extends React.PureComponent<{||}> { +class ReportCard extends React.PureComponent { render() { const { benchmarkName, diff --git a/scripts/benchmarks/src/impl.js b/scripts/benchmarks/src/impl.js index d489a76c42..c618a176f2 100644 --- a/scripts/benchmarks/src/impl.js +++ b/scripts/benchmarks/src/impl.js @@ -1,4 +1,3 @@ -// @flow import * as React from 'react' import * as EmotionCssFunc from './implementations/emotion-css-func' @@ -11,19 +10,21 @@ const impls = { 'emotion-styled': EmotionStyled } +/* type ComponentsType = { - Box: React.ElementType, - Dot: React.ElementType, - Provider: React.ElementType, + Box: React.ElementType + Dot: React.ElementType + Provider: React.ElementType View: React.ElementType } type ImplementationType = { - components: ComponentsType, + components: ComponentsType name: string } +*/ -const implementations: Array = Object.keys(impls).map( +const implementations /*: Array */ = Object.keys(impls).map( name => { const components = impls[name] return { components, name } @@ -31,8 +32,8 @@ const implementations: Array = Object.keys(impls).map( ) const toObject = ( - impls: Array -): { [name: string]: ImplementationType } => + impls /*: Array */ +) /*: { [name: string]: ImplementationType } */ => impls.reduce((acc, impl) => { acc[impl.name] = impl return acc diff --git a/scripts/benchmarks/src/implementations/emotion-css-prop/Provider.js b/scripts/benchmarks/src/implementations/emotion-css-prop/Provider.js index a625d2e8aa..9cbeedb277 100644 --- a/scripts/benchmarks/src/implementations/emotion-css-prop/Provider.js +++ b/scripts/benchmarks/src/implementations/emotion-css-prop/Provider.js @@ -1,10 +1,9 @@ -// @flow import * as React from 'react' import { CacheProvider } from '@emotion/react' import createCache from '@emotion/cache' let cache = createCache({ key: 'emo' }) -export default (props: { children: React.Node }) => { +export default props => { return {props.children} } diff --git a/scripts/benchmarks/src/implementations/emotion-styled/Provider.js b/scripts/benchmarks/src/implementations/emotion-styled/Provider.js index a625d2e8aa..9cbeedb277 100644 --- a/scripts/benchmarks/src/implementations/emotion-styled/Provider.js +++ b/scripts/benchmarks/src/implementations/emotion-styled/Provider.js @@ -1,10 +1,9 @@ -// @flow import * as React from 'react' import { CacheProvider } from '@emotion/react' import createCache from '@emotion/cache' let cache = createCache({ key: 'emo' }) -export default (props: { children: React.Node }) => { +export default props => { return {props.children} } diff --git a/scripts/benchmarks/src/index.js b/scripts/benchmarks/src/index.js index 45dfa5e087..36e828fa7a 100644 --- a/scripts/benchmarks/src/index.js +++ b/scripts/benchmarks/src/index.js @@ -1,4 +1,3 @@ -// @flow import App from './app/App' import implementations from './impl' import Tree from './cases/Tree' diff --git a/scripts/ssr-benchmarks/bench.js b/scripts/ssr-benchmarks/bench.js index d9790e143f..6cabeb3b64 100644 --- a/scripts/ssr-benchmarks/bench.js +++ b/scripts/ssr-benchmarks/bench.js @@ -75,7 +75,6 @@ let CssFuncTriangle = createTriangle(({ x, y, size, color, ...props }) => { ...props }) }) -// $FlowFixMe let CacheContext = CacheProvider._context let hasOwnProperty = Object.prototype.hasOwnProperty diff --git a/scripts/test-utils/enzyme-env.js b/scripts/test-utils/enzyme-env.js index 69078bc17f..88c8c3b323 100644 --- a/scripts/test-utils/enzyme-env.js +++ b/scripts/test-utils/enzyme-env.js @@ -1,4 +1,3 @@ -// @flow import Enzyme from 'enzyme' import Adapter from 'enzyme-adapter-react-16' diff --git a/scripts/test-utils/legacy-env.js b/scripts/test-utils/legacy-env.js index 21a64fb4cb..6810e1cbc9 100644 --- a/scripts/test-utils/legacy-env.js +++ b/scripts/test-utils/legacy-env.js @@ -1,7 +1,5 @@ -// @flow /* eslint-env jest */ import 'test-utils/enzyme-env' import { createEnzymeSerializer } from '@emotion/jest/enzyme' -// $FlowFixMe jest flow type definitions don't include new plugin API expect.addSnapshotSerializer(createEnzymeSerializer()) diff --git a/scripts/test-utils/next-env.js b/scripts/test-utils/next-env.js index c8cc860692..1ad2699748 100644 --- a/scripts/test-utils/next-env.js +++ b/scripts/test-utils/next-env.js @@ -1,6 +1,4 @@ -// @flow /* eslint-env jest */ import { createSerializer } from '@emotion/jest' -// $FlowFixMe jest flow type definitions don't include new plugin API expect.addSnapshotSerializer(createSerializer()) diff --git a/scripts/test-utils/src/index.js b/scripts/test-utils/src/index.js index fd7ad875aa..0321886503 100644 --- a/scripts/test-utils/src/index.js +++ b/scripts/test-utils/src/index.js @@ -1,27 +1,24 @@ -// @flow /* eslint-env jest */ -export function throwIfFalsy(something: *) { +export function throwIfFalsy(something) { if (something) { return something } throw new Error('something is falsy') } -export function ignoreConsoleErrors(cb: () => mixed) { +export function ignoreConsoleErrors(cb /*: () => mixed */) { let oldConsoleError = console.error - // $FlowFixMe console.error = jest.fn() try { cb() } finally { - // $FlowFixMe console.error = oldConsoleError } } -export let safeQuerySelector = (selector: string): HTMLElement => { +export let safeQuerySelector = (selector /*: string */) /*: HTMLElement */ => { let element = document.querySelector(selector) if (!element) { throw new Error(`Could not find element matching selector "${selector}"`) @@ -31,7 +28,7 @@ export let safeQuerySelector = (selector: string): HTMLElement => { // React 18 doesn't use this attribute anymore // we normalize this to avoid snapshot mismatches between React versions -export let stripDataReactRoot = (html: string): string => +export let stripDataReactRoot = (html /*: string*/) /*: string*/ => html.replace(' data-reactroot=""', '') const removeGlobalProp = prop => { @@ -45,7 +42,8 @@ const removeGlobalProp = prop => { return () => Object.defineProperty(global, prop, descriptor) } -export async function disableBrowserEnvTemporarily(fn: () => T): Promise { +// TODO: export async function disableBrowserEnvTemporarily(fn: () => T): Promise { +export async function disableBrowserEnvTemporarily(fn) { let restoreDocument = removeGlobalProp('document') let restoreWindow = removeGlobalProp('window') let restoreHTMLElement = removeGlobalProp('HTMLElement') diff --git a/test/pretty-css.js b/test/pretty-css.js index 22a11a5196..8a8694b420 100644 --- a/test/pretty-css.js +++ b/test/pretty-css.js @@ -1,19 +1,20 @@ -// @flow import prettify from '@emotion/css-prettifier' +/* type StyleSheet = { tags: Array } +*/ export default { - test: (val: any) => val && val.tags !== undefined && Array.isArray(val.tags), + test: val => val && val.tags !== undefined && Array.isArray(val.tags), serialize( - val: StyleSheet, - config: *, - indentation: string, - depth: number, - refs: *, - printer: Function + val /* : StyleSheet */, + config, + indentation /* : string */, + depth /* : number */, + refs, + printer /* : Function */ ) { let styles = val.tags.map(tag => tag.textContent || '').join('') return printer( diff --git a/test/testSetup.js b/test/testSetup.js index b5f40dbcd2..1a4a965964 100644 --- a/test/testSetup.js +++ b/test/testSetup.js @@ -1,11 +1,9 @@ -// @flow /* eslint-env jest */ import 'raf/polyfill' import prettyCSS from './pretty-css' if (typeof Node !== 'undefined') { let oldInsertBefore = Node.prototype.insertBefore - // $FlowFixMe Node.prototype.insertBefore = function (node, refNode) { if (refNode instanceof Node || refNode === null) { return oldInsertBefore.call(this, node, refNode) @@ -16,5 +14,4 @@ if (typeof Node !== 'undefined') { } } -// $FlowFixMe jest flow type definitions don't include new plugin API expect.addSnapshotSerializer(prettyCSS) diff --git a/tsconfig.json b/tsconfig.json index b955ce77e6..d7de73673e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -14,7 +14,7 @@ "target": "es5", "types": [] }, - "include": ["packages", "scripts", "site", "test", "playgrounds"], + "include": ["packages", "scripts", "test", "playgrounds"], "exclude": [ "node_modules", "packages/*/types/test/*", diff --git a/yarn.lock b/yarn.lock index 55ac358195..fdb377f426 100644 --- a/yarn.lock +++ b/yarn.lock @@ -300,7 +300,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-create-class-features-plugin@npm:^7.12.1, @babel/helper-create-class-features-plugin@npm:^7.18.6": +"@babel/helper-create-class-features-plugin@npm:^7.12.1, @babel/helper-create-class-features-plugin@npm:^7.18.6, @babel/helper-create-class-features-plugin@npm:^7.18.9": version: 7.18.9 resolution: "@babel/helper-create-class-features-plugin@npm:7.18.9" dependencies: @@ -1214,7 +1214,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-transform-flow-strip-types@npm:^7.0.0, @babel/plugin-transform-flow-strip-types@npm:^7.17.12, @babel/plugin-transform-flow-strip-types@npm:^7.18.6": +"@babel/plugin-transform-flow-strip-types@npm:^7.0.0": version: 7.18.9 resolution: "@babel/plugin-transform-flow-strip-types@npm:7.18.9" dependencies: @@ -1609,6 +1609,19 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-typescript@npm:^7.18.6": + version: 7.18.12 + resolution: "@babel/plugin-transform-typescript@npm:7.18.12" + dependencies: + "@babel/helper-create-class-features-plugin": ^7.18.9 + "@babel/helper-plugin-utils": ^7.18.9 + "@babel/plugin-syntax-typescript": ^7.18.6 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 87e9b783ef712697a9d3bd72d0345ea4ea71b4676f9b88da0a30fe4b8a81f453a5badee788bb4dc849616af84d674d728a6ec4248f14a75bfb0b4de5bcce7431 + languageName: node + linkType: hard + "@babel/plugin-transform-unicode-escapes@npm:^7.12.1, @babel/plugin-transform-unicode-escapes@npm:^7.18.6": version: 7.18.6 resolution: "@babel/plugin-transform-unicode-escapes@npm:7.18.6" @@ -1793,19 +1806,6 @@ __metadata: languageName: node linkType: hard -"@babel/preset-flow@npm:^7.17.12": - version: 7.18.6 - resolution: "@babel/preset-flow@npm:7.18.6" - dependencies: - "@babel/helper-plugin-utils": ^7.18.6 - "@babel/helper-validator-option": ^7.18.6 - "@babel/plugin-transform-flow-strip-types": ^7.18.6 - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 9100d4eab3402e6601e361a5b235e46d90cfd389c12db19e2a071e1082ca2a00c04bd47eb185ce68d8979e7c8f3e548cd5d61b86dcd701135468fb929c3aecb6 - languageName: node - linkType: hard - "@babel/preset-modules@npm:^0.1.3, @babel/preset-modules@npm:^0.1.5": version: 0.1.5 resolution: "@babel/preset-modules@npm:0.1.5" @@ -1866,6 +1866,19 @@ __metadata: languageName: node linkType: hard +"@babel/preset-typescript@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/preset-typescript@npm:7.18.6" + dependencies: + "@babel/helper-plugin-utils": ^7.18.6 + "@babel/helper-validator-option": ^7.18.6 + "@babel/plugin-transform-typescript": ^7.18.6 + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 7fe0da5103eb72d3cf39cf3e138a794c8cdd19c0b38e3e101507eef519c46a87a0d6d0e8bc9e28a13ea2364001ebe7430b9d75758aab4c3c3a8db9a487b9dc7c + languageName: node + linkType: hard + "@babel/register@npm:^7.0.0, @babel/register@npm:^7.17.7": version: 7.18.9 resolution: "@babel/register@npm:7.18.9" @@ -2339,6 +2352,7 @@ __metadata: dependencies: "@babel/core": ^7.18.5 "@babel/plugin-syntax-jsx": ^7.17.12 + "@types/babel__core": ^7.1.18 peerDependencies: "@babel/core": ^7.0.0 languageName: unknown @@ -2420,7 +2434,10 @@ __metadata: version: 0.0.0-use.local resolution: "@emotion/eslint-plugin@workspace:packages/eslint-plugin" dependencies: + "@types/eslint": ^7.0.0 + "@typescript-eslint/utils": ^5.25.0 eslint: ^7.10.0 + resolve-from: ^5.0.0 peerDependencies: eslint: 6 || 7 || 8 languageName: unknown @@ -2526,6 +2543,7 @@ __metadata: resolution: "@emotion/primitives-core@workspace:packages/primitives-core" dependencies: "@emotion/react": 11.11.4 + "@types/css-to-react-native": ^3.0.0 css-to-react-native: ^3.0.0 react: 16.14.0 peerDependencies: @@ -3144,6 +3162,15 @@ __metadata: languageName: node linkType: hard +"@jest/schemas@npm:^28.1.3": + version: 28.1.3 + resolution: "@jest/schemas@npm:28.1.3" + dependencies: + "@sinclair/typebox": ^0.24.1 + checksum: 3cf1d4b66c9c4ffda58b246de1ddcba8e6ad085af63dccdf07922511f13b68c0cc480a7bc620cb4f3099a6f134801c747e1df7bfc7a4ef4dceefbdea3e31e1de + languageName: node + linkType: hard + "@jest/source-map@npm:^24.9.0": version: 24.9.0 resolution: "@jest/source-map@npm:24.9.0" @@ -4884,6 +4911,13 @@ __metadata: languageName: node linkType: hard +"@sinclair/typebox@npm:^0.24.1": + version: 0.24.27 + resolution: "@sinclair/typebox@npm:0.24.27" + checksum: c283de9158c0206da3d1ebd7c5f994da0b1cf86df89674da7709850300ecdceb0d4c9680dccce84b60cdcc3d8858f54df8235b250ba092726fadb2bebe720bd1 + languageName: node + linkType: hard + "@sindresorhus/is@npm:^0.14.0": version: 0.14.0 resolution: "@sindresorhus/is@npm:0.14.0" @@ -5400,6 +5434,19 @@ __metadata: languageName: node linkType: hard +"@types/babel__core@npm:^7.1.18": + version: 7.1.19 + resolution: "@types/babel__core@npm:7.1.19" + dependencies: + "@babel/parser": ^7.1.0 + "@babel/types": ^7.0.0 + "@types/babel__generator": "*" + "@types/babel__template": "*" + "@types/babel__traverse": "*" + checksum: 8c9fa87a1c2224cbec251683a58bebb0d74c497118034166aaa0491a4e2627998a6621fc71f8a60ffd27d9c0c52097defedf7637adc6618d0331c15adb302338 + languageName: node + linkType: hard + "@types/babel__generator@npm:*": version: 7.6.2 resolution: "@types/babel__generator@npm:7.6.2" @@ -5455,6 +5502,13 @@ __metadata: languageName: node linkType: hard +"@types/css-to-react-native@npm:^3.0.0": + version: 3.0.0 + resolution: "@types/css-to-react-native@npm:3.0.0" + checksum: 85870135513b523601270cafa8479086c4f65cef7f00d4d633cb0849efa3083ae6e3c2673dc4e8743036ad0a3f4081c507f1e96e40bb2a62e7550f765246e58a + languageName: node + linkType: hard + "@types/debug@npm:^4.0.0": version: 4.1.7 resolution: "@types/debug@npm:4.1.7" @@ -5464,6 +5518,16 @@ __metadata: languageName: node linkType: hard +"@types/eslint@npm:^7.0.0": + version: 7.29.0 + resolution: "@types/eslint@npm:7.29.0" + dependencies: + "@types/estree": "*" + "@types/json-schema": "*" + checksum: df13991c554954353ce8f3bb03e19da6cc71916889443d68d178d4f858b561ba4cc4a4f291c6eb9eebb7f864b12b9b9313051b3a8dfea3e513dadf3188a77bdf + languageName: node + linkType: hard + "@types/eslint@npm:^7.2.6": version: 7.28.2 resolution: "@types/eslint@npm:7.28.2" @@ -5605,6 +5669,26 @@ __metadata: languageName: node linkType: hard +"@types/jest-in-case@npm:^1.0.5": + version: 1.0.6 + resolution: "@types/jest-in-case@npm:1.0.6" + dependencies: + "@types/jest": "*" + "@types/node": "*" + checksum: 6bf79f5d12747247e88e65c2bf3473455e81c49c8f9512f8293611cc3d3c4e10df08e1a81bedd6e09518c1ab91f774a180d0dbdeeafb9c7dc5b19d978bc4bdbe + languageName: node + linkType: hard + +"@types/jest@npm:*": + version: 28.1.6 + resolution: "@types/jest@npm:28.1.6" + dependencies: + jest-matcher-utils: ^28.0.0 + pretty-format: ^28.0.0 + checksum: f2ba5fbefc8f44d1c16ee19d8d2811bca75754a2846e222287f2788d96062801c568215e6b81eb532a48e8cb2a7282729da1d4f6fb496831da8269c5abaad4c5 + languageName: node + linkType: hard + "@types/jest@npm:^27.0.3": version: 27.0.3 resolution: "@types/jest@npm:27.0.3" @@ -5636,6 +5720,13 @@ __metadata: languageName: node linkType: hard +"@types/json-schema@npm:^7.0.9": + version: 7.0.11 + resolution: "@types/json-schema@npm:7.0.11" + checksum: 527bddfe62db9012fccd7627794bd4c71beb77601861055d87e3ee464f2217c85fca7a4b56ae677478367bbd248dbde13553312b7d4dbc702a2f2bbf60c4018d + languageName: node + linkType: hard + "@types/json5@npm:^0.0.29": version: 0.0.29 resolution: "@types/json5@npm:0.0.29" @@ -5972,7 +6063,7 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:^4.5.0": +"@typescript-eslint/eslint-plugin@npm:^4.22.0, @typescript-eslint/eslint-plugin@npm:^4.5.0": version: 4.33.0 resolution: "@typescript-eslint/eslint-plugin@npm:4.33.0" dependencies: @@ -6025,7 +6116,7 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/parser@npm:^4.5.0": +"@typescript-eslint/parser@npm:^4.22.0, @typescript-eslint/parser@npm:^4.5.0": version: 4.33.0 resolution: "@typescript-eslint/parser@npm:4.33.0" dependencies: @@ -6052,6 +6143,16 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/scope-manager@npm:5.32.0": + version: 5.32.0 + resolution: "@typescript-eslint/scope-manager@npm:5.32.0" + dependencies: + "@typescript-eslint/types": 5.32.0 + "@typescript-eslint/visitor-keys": 5.32.0 + checksum: 69bdeb029f39d1112299dc0cb0ddef30e51bdb782fdb79cc4e72fa448e00d71e39938d3bff3fa4ee43b3416c2e3b4564de2c37252914772b07eeedafb14412d6 + languageName: node + linkType: hard + "@typescript-eslint/types@npm:3.10.1": version: 3.10.1 resolution: "@typescript-eslint/types@npm:3.10.1" @@ -6066,6 +6167,13 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/types@npm:5.32.0": + version: 5.32.0 + resolution: "@typescript-eslint/types@npm:5.32.0" + checksum: 6758f54d8d7763893cd7c1753f525ef1777eee8b558bf3d54fd2a2ce691ca0cf813c68a26e4db83a1deae4e4a62b247f1195e15a1f3577f1293849f9e55a232c + languageName: node + linkType: hard + "@typescript-eslint/typescript-estree@npm:3.10.1": version: 3.10.1 resolution: "@typescript-eslint/typescript-estree@npm:3.10.1" @@ -6103,6 +6211,40 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/typescript-estree@npm:5.32.0": + version: 5.32.0 + resolution: "@typescript-eslint/typescript-estree@npm:5.32.0" + dependencies: + "@typescript-eslint/types": 5.32.0 + "@typescript-eslint/visitor-keys": 5.32.0 + debug: ^4.3.4 + globby: ^11.1.0 + is-glob: ^4.0.3 + semver: ^7.3.7 + tsutils: ^3.21.0 + peerDependenciesMeta: + typescript: + optional: true + checksum: 6aee08be5d36603d038fb8340f324f5cb38519150c9b37c012f0c1ff2a4d8cf22fbc6835de31d069949c2b3d8ed3e729076a724ef29db4289d9fe73b97c9d310 + languageName: node + linkType: hard + +"@typescript-eslint/utils@npm:^5.25.0": + version: 5.32.0 + resolution: "@typescript-eslint/utils@npm:5.32.0" + dependencies: + "@types/json-schema": ^7.0.9 + "@typescript-eslint/scope-manager": 5.32.0 + "@typescript-eslint/types": 5.32.0 + "@typescript-eslint/typescript-estree": 5.32.0 + eslint-scope: ^5.1.1 + eslint-utils: ^3.0.0 + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + checksum: cfd88d93508c8fb0db17d2726691e1383db390357fa0637bd8111558fbe72da5130d995294001d71b1d929d620fbce3f20a70b277a77ca21a4241b3b470dc758 + languageName: node + linkType: hard + "@typescript-eslint/visitor-keys@npm:3.10.1": version: 3.10.1 resolution: "@typescript-eslint/visitor-keys@npm:3.10.1" @@ -6122,6 +6264,16 @@ __metadata: languageName: node linkType: hard +"@typescript-eslint/visitor-keys@npm:5.32.0": + version: 5.32.0 + resolution: "@typescript-eslint/visitor-keys@npm:5.32.0" + dependencies: + "@typescript-eslint/types": 5.32.0 + eslint-visitor-keys: ^3.3.0 + checksum: 1f9b756d648c2346a6e8538ffde729d3d9ce6621fded3d9f15c96aa0ebf8f511daf8232470423fb36359c2113538a4daaf3336181be78a0cfbfd297af91ce9ba + languageName: node + linkType: hard + "@webassemblyjs/ast@npm:1.9.0": version: 1.9.0 resolution: "@webassemblyjs/ast@npm:1.9.0" @@ -7523,13 +7675,6 @@ __metadata: languageName: node linkType: hard -"babel-flow-types@npm:^1.2.3": - version: 1.2.3 - resolution: "babel-flow-types@npm:1.2.3" - checksum: dd3b87fd429a835372b6012d2c437855ff103a909d0fe8538b809ddccd5cd5bf6a840d84af915bc25e1b8c6f000a2cf6f51ab737c79cb8cd980ef461e4577084 - languageName: node - linkType: hard - "babel-jest@npm:^26.6.0, babel-jest@npm:^26.6.3": version: 26.6.3 resolution: "babel-jest@npm:26.6.3" @@ -7582,6 +7727,13 @@ __metadata: languageName: node linkType: hard +"babel-plugin-add-basic-constructor-for-react-components@npm:^0.1.0": + version: 0.1.0 + resolution: "babel-plugin-add-basic-constructor-for-react-components@npm:0.1.0" + checksum: bfe84200e1738939b8a7a8114a8be2df8fdf35634d3d6a3b02bcca746a7a79855baa2f3f33662b4b4158ef28677d2bc5fd020c46219ec8229e43aab5bea49f31 + languageName: node + linkType: hard + "babel-plugin-codegen@npm:^4.1.5": version: 4.1.5 resolution: "babel-plugin-codegen@npm:4.1.5" @@ -7602,6 +7754,13 @@ __metadata: languageName: node linkType: hard +"babel-plugin-fix-dce-for-classes-with-statics@npm:^0.1.0": + version: 0.1.0 + resolution: "babel-plugin-fix-dce-for-classes-with-statics@npm:0.1.0" + checksum: 83413bb185cfeeb219beecccdf5ed2b2db81a9e800aa8ecbe5ec36bb3d151022f2e052408515b216b25014ceaa75ad64de6e83909842c98631b0462d15eefc8b + languageName: node + linkType: hard + "babel-plugin-istanbul@npm:^6.0.0": version: 6.0.0 resolution: "babel-plugin-istanbul@npm:6.0.0" @@ -7798,7 +7957,8 @@ __metadata: resolution: "babel-preset-emotion-dev@workspace:scripts/babel-preset-emotion-dev" dependencies: "@babel/plugin-proposal-class-properties": ^7.17.12 - "@babel/plugin-transform-flow-strip-types": ^7.17.12 + babel-plugin-add-basic-constructor-for-react-components: ^0.1.0 + babel-plugin-fix-dce-for-classes-with-statics: ^0.1.0 languageName: unknown linkType: soft @@ -7939,6 +8099,8 @@ __metadata: dependencies: "@babel/plugin-syntax-class-properties": ^7.12.13 "@babel/plugin-syntax-object-rest-spread": ^7.8.3 + "@types/jest-in-case": ^1.0.5 + babel-check-duplicated-nodes: ^1.0.0 languageName: unknown linkType: soft @@ -10726,7 +10888,7 @@ __metadata: languageName: node linkType: hard -"debug@npm:^4.0.0, debug@npm:^4.3.3": +"debug@npm:^4.0.0, debug@npm:^4.3.3, debug@npm:^4.3.4": version: 4.3.4 resolution: "debug@npm:4.3.4" dependencies: @@ -11079,6 +11241,13 @@ __metadata: languageName: node linkType: hard +"diff-sequences@npm:^28.1.1": + version: 28.1.1 + resolution: "diff-sequences@npm:28.1.1" + checksum: e2529036505567c7ca5a2dea86b6bcd1ca0e3ae63bf8ebf529b8a99cfa915bbf194b7021dc1c57361a4017a6d95578d4ceb29fabc3232a4f4cb866a2726c7690 + languageName: node + linkType: hard + "diff@npm:^3.2.0": version: 3.5.0 resolution: "diff@npm:3.5.0" @@ -11544,11 +11713,10 @@ __metadata: "@babel/helper-module-imports": ^7.16.7 "@babel/plugin-proposal-class-properties": ^7.17.12 "@babel/plugin-syntax-jsx": ^7.17.12 - "@babel/plugin-transform-flow-strip-types": ^7.17.12 "@babel/plugin-transform-react-jsx": ^7.17.12 "@babel/preset-env": ^7.18.2 - "@babel/preset-flow": ^7.17.12 "@babel/preset-react": ^7.17.12 + "@babel/preset-typescript": ^7.18.6 "@babel/register": ^7.17.7 "@babel/runtime": ^7.18.3 "@changesets/changelog-github": ^0.4.0 @@ -11559,9 +11727,10 @@ __metadata: "@types/jest": ^27.0.3 "@types/node": ^12.20.37 "@types/react": ^18.0.9 + "@typescript-eslint/eslint-plugin": ^4.22.0 + "@typescript-eslint/parser": ^4.22.0 babel-check-duplicated-nodes: ^1.0.0 babel-eslint: ^10.1.0 - babel-flow-types: ^1.2.3 babel-jest: ^27.4.5 babel-plugin-codegen: ^4.1.5 babel-plugin-jsx-pragmatic: ^1.0.2 @@ -11576,17 +11745,11 @@ __metadata: eslint: ^7.10.0 eslint-config-prettier: ^8.3.0 eslint-config-react: ^1.1.7 - eslint-config-standard: ^14.1.1 - eslint-config-standard-react: ^9.2.0 - eslint-plugin-flowtype: ^5.2.0 - eslint-plugin-import: ^2.22.1 eslint-plugin-node: ^11.1.0 eslint-plugin-prettier: ^3.4.0 eslint-plugin-promise: ^4.2.1 eslint-plugin-react: ^7.21.3 eslint-plugin-react-hooks: ^4.1.2 - eslint-plugin-standard: ^4.0.1 - flow-bin: ^0.128.0 html-tag-names: ^1.1.2 husky: ^3.0.9 jest: ^27.4.5 @@ -11614,6 +11777,7 @@ __metadata: react18-test-renderer: "npm:react-test-renderer@18.0.0-rc.0-next-aa8f2bdbc-20211215" svg-tag-names: ^1.1.1 through: ^2.3.8 + typescript: ^4.5.5 unified: ^6.1.6 webpack-bundle-analyzer: 3.3.2 languageName: unknown @@ -12220,41 +12384,6 @@ __metadata: languageName: node linkType: hard -"eslint-config-standard-jsx@npm:^8.0.0": - version: 8.1.0 - resolution: "eslint-config-standard-jsx@npm:8.1.0" - peerDependencies: - eslint: ">=6.2.2" - eslint-plugin-react: ">=7.14.2" - checksum: 004fae82a0671598808578c3e218b6ca2ed192312e07bbc7fc88df005d35a7d0f734628089149d40997e0a0629ee05a9828d1f3a6521568ba5abf4c092907dea - languageName: node - linkType: hard - -"eslint-config-standard-react@npm:^9.2.0": - version: 9.2.0 - resolution: "eslint-config-standard-react@npm:9.2.0" - dependencies: - eslint-config-standard-jsx: ^8.0.0 - peerDependencies: - eslint: ">=6.2.2" - eslint-plugin-react: ">=7.6.1" - checksum: fc1024001ffa67fc1cbf770f1ba519ffc646e7ad9a7aa99811b1ca6f0535324960416a20f57e626c5f11f66dc83167da1f10a255b99a89deba6123c0c266dc12 - languageName: node - linkType: hard - -"eslint-config-standard@npm:^14.1.1": - version: 14.1.1 - resolution: "eslint-config-standard@npm:14.1.1" - peerDependencies: - eslint: ">=6.2.2" - eslint-plugin-import: ">=2.18.0" - eslint-plugin-node: ">=9.1.0" - eslint-plugin-promise: ">=4.2.1" - eslint-plugin-standard: ">=4.0.0" - checksum: 0eee1117e848d9d0d80f1e5d789ad426efa629d71b599711e382c05ebb9fa3ae11ef6d4e34947a0a7ce59bfc3c7f522a047b7fa34ab2eedf7702576ac5cf3d74 - languageName: node - linkType: hard - "eslint-import-resolver-node@npm:^0.3.4": version: 0.3.4 resolution: "eslint-import-resolver-node@npm:0.3.4" @@ -12459,15 +12588,6 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-standard@npm:^4.0.1": - version: 4.0.1 - resolution: "eslint-plugin-standard@npm:4.0.1" - peerDependencies: - eslint: ">=5.0.0" - checksum: 84d6a82d583b33c59602d7b787cd044d6d41ea91ea2e6494fd0fa053e5e7673a977b2028836e5d33f6a1c80da182d5ceb886e42b1455e24704eadd529388830e - languageName: node - linkType: hard - "eslint-plugin-testing-library@npm:^3.9.2": version: 3.10.2 resolution: "eslint-plugin-testing-library@npm:3.10.2" @@ -12540,6 +12660,13 @@ __metadata: languageName: node linkType: hard +"eslint-visitor-keys@npm:^3.3.0": + version: 3.3.0 + resolution: "eslint-visitor-keys@npm:3.3.0" + checksum: d59e68a7c5a6d0146526b0eec16ce87fbf97fe46b8281e0d41384224375c4e52f5ffb9e16d48f4ea50785cde93f766b0c898e31ab89978d88b0e1720fbfb7808 + languageName: node + linkType: hard + "eslint-webpack-plugin@npm:^2.5.2": version: 2.5.4 resolution: "eslint-webpack-plugin@npm:2.5.4" @@ -13243,7 +13370,7 @@ __metadata: languageName: node linkType: hard -"fast-glob@npm:^3.2.4": +"fast-glob@npm:^3.2.4, fast-glob@npm:^3.2.9": version: 3.2.11 resolution: "fast-glob@npm:3.2.11" dependencies: @@ -13657,15 +13784,6 @@ __metadata: languageName: node linkType: hard -"flow-bin@npm:^0.128.0": - version: 0.128.0 - resolution: "flow-bin@npm:0.128.0" - bin: - flow: cli.js - checksum: ef0ed9af0e8756ba31253ff1c299d12d55fd5d2350f5ab69589133be4d99504218b61fded7a08d96379ea6b1e80caab564f88b148f4bf07bda01eb2a5b357907 - languageName: node - linkType: hard - "flush-write-stream@npm:^1.0.0": version: 1.1.1 resolution: "flush-write-stream@npm:1.1.1" @@ -14421,6 +14539,20 @@ __metadata: languageName: node linkType: hard +"globby@npm:^11.1.0": + version: 11.1.0 + resolution: "globby@npm:11.1.0" + dependencies: + array-union: ^2.1.0 + dir-glob: ^3.0.1 + fast-glob: ^3.2.9 + ignore: ^5.2.0 + merge2: ^1.4.1 + slash: ^3.0.0 + checksum: b4be8885e0cfa018fc783792942d53926c35c50b3aefd3fdcfb9d22c627639dc26bd2327a40a0b74b074100ce95bb7187bfeae2f236856aa3de183af7a02aea6 + languageName: node + linkType: hard + "globby@npm:^6.1.0": version: 6.1.0 resolution: "globby@npm:6.1.0" @@ -15483,6 +15615,13 @@ __metadata: languageName: node linkType: hard +"ignore@npm:^5.2.0": + version: 5.2.0 + resolution: "ignore@npm:5.2.0" + checksum: 6b1f926792d614f64c6c83da3a1f9c83f6196c2839aa41e1e32dd7b8d174cef2e329d75caabb62cb61ce9dc432f75e67d07d122a037312db7caa73166a1bdb77 + languageName: node + linkType: hard + "image-size@npm:^0.6.0": version: 0.6.3 resolution: "image-size@npm:0.6.3" @@ -16210,6 +16349,15 @@ __metadata: languageName: node linkType: hard +"is-glob@npm:^4.0.3": + version: 4.0.3 + resolution: "is-glob@npm:4.0.3" + dependencies: + is-extglob: ^2.1.1 + checksum: d381c1319fcb69d341cc6e6c7cd588e17cd94722d9a32dbd60660b993c4fb7d0f19438674e68dfec686d09b7c73139c9166b47597f846af387450224a8101ab4 + languageName: node + linkType: hard + "is-hexadecimal@npm:^1.0.0": version: 1.0.3 resolution: "is-hexadecimal@npm:1.0.3" @@ -17008,6 +17156,18 @@ __metadata: languageName: node linkType: hard +"jest-diff@npm:^28.1.3": + version: 28.1.3 + resolution: "jest-diff@npm:28.1.3" + dependencies: + chalk: ^4.0.0 + diff-sequences: ^28.1.1 + jest-get-type: ^28.0.2 + pretty-format: ^28.1.3 + checksum: fa8583e0ccbe775714ce850b009be1b0f6b17a4b6759f33ff47adef27942ebc610dbbcc8a5f7cfb7f12b3b3b05afc9fb41d5f766674616025032ff1e4f9866e0 + languageName: node + linkType: hard + "jest-docblock@npm:^26.0.0": version: 26.0.0 resolution: "jest-docblock@npm:26.0.0" @@ -17138,6 +17298,13 @@ __metadata: languageName: node linkType: hard +"jest-get-type@npm:^28.0.2": + version: 28.0.2 + resolution: "jest-get-type@npm:28.0.2" + checksum: 5281d7c89bc8156605f6d15784f45074f4548501195c26e9b188742768f72d40948252d13230ea905b5349038865a1a8eeff0e614cc530ff289dfc41fe843abd + languageName: node + linkType: hard + "jest-haste-map@npm:^24.7.1": version: 24.9.0 resolution: "jest-haste-map@npm:24.9.0" @@ -17325,6 +17492,18 @@ __metadata: languageName: node linkType: hard +"jest-matcher-utils@npm:^28.0.0": + version: 28.1.3 + resolution: "jest-matcher-utils@npm:28.1.3" + dependencies: + chalk: ^4.0.0 + jest-diff: ^28.1.3 + jest-get-type: ^28.0.2 + pretty-format: ^28.1.3 + checksum: 6b34f0cf66f6781e92e3bec97bf27796bd2ba31121e5c5997218d9adba6deea38a30df5203937d6785b68023ed95cbad73663cc9aad6fb0cb59aeb5813a58daf + languageName: node + linkType: hard + "jest-message-util@npm:^24.9.0": version: 24.9.0 resolution: "jest-message-util@npm:24.9.0" @@ -19653,7 +19832,7 @@ __metadata: languageName: node linkType: hard -"merge2@npm:^1.3.0": +"merge2@npm:^1.3.0, merge2@npm:^1.4.1": version: 1.4.1 resolution: "merge2@npm:1.4.1" checksum: 7268db63ed5169466540b6fb947aec313200bcf6d40c5ab722c22e242f651994619bcd85601602972d3c85bd2cc45a358a4c61937e9f11a061919a1da569b0c2 @@ -24597,6 +24776,18 @@ __metadata: languageName: node linkType: hard +"pretty-format@npm:^28.0.0, pretty-format@npm:^28.1.3": + version: 28.1.3 + resolution: "pretty-format@npm:28.1.3" + dependencies: + "@jest/schemas": ^28.1.3 + ansi-regex: ^5.0.1 + ansi-styles: ^5.0.0 + react-is: ^18.0.0 + checksum: e69f857358a3e03d271252d7524bec758c35e44680287f36c1cb905187fbc82da9981a6eb07edfd8a03bc3cbeebfa6f5234c13a3d5b59f2bbdf9b4c4053e0a7f + languageName: node + linkType: hard + "prettycli@npm:^1.3.0": version: 1.4.3 resolution: "prettycli@npm:1.4.3" @@ -25162,6 +25353,13 @@ __metadata: languageName: node linkType: hard +"react-is@npm:^18.0.0": + version: 18.2.0 + resolution: "react-is@npm:18.2.0" + checksum: e72d0ba81b5922759e4aff17e0252bd29988f9642ed817f56b25a3e217e13eea8a7f2322af99a06edb779da12d5d636e9fda473d620df9a3da0df2a74141d53e + languageName: node + linkType: hard + "react-native-web@npm:0.17.5": version: 0.17.5 resolution: "react-native-web@npm:0.17.5"