import { basename } from 'path' ; import { declare } from '@babel/helper-plugin-utils' ; import jsxSyntax from '@babel/plugin-syntax-jsx' ; import template from '@babel/template' ; import * as t from '@babel/types' ; import { unique } from '@compiled/utils' ; import { visitClassNamesPath } from './class-names' ; import { visitCssPropPath } from './css-prop' ; import { visitStyledPath } from './styled' ; import type { State } from './types' ; import { appendRuntimeImports } from './utils/append-runtime-imports' ; import { Cache } from './utils/cache' ; import { isCompiledCSSCallExpression , isCompiledCSSTaggedTemplateExpression , isCompiledKeyframesCallExpression , isCompiledKeyframesTaggedTemplateExpression , isCompiledStyledCallExpression , isCompiledStyledTaggedTemplateExpression , } from './utils/is-compiled' ; const packageJson = require ( '../package.json' ) ; const JSX_SOURCE_ANNOTATION_REGEX = /\*?\s*@jsxImportSource\s+([^\s]+)/ ; const JSX_ANNOTATION_REGEX = /\*?\s*@jsx\s+([^\s]+)/ ; const COMPILED_MODULE = '@compiled/react' ; let globalCache ; export default declare < State > ( ( api ) => { api . assertVersion ( 7 ) ; return { name : packageJson . name , inherits : jsxSyntax , pre ( ) { this . sheets = { } ; let cache ; if ( this . opts . cache === true ) { globalCache = new Cache ( ) ; cache = globalCache ; } else { cache = new Cache ( ) ; } cache . initialize ( { ... this . opts , cache : ! ! this . opts . cache } ) ; this . cache = cache ; this . includedFiles = [ ] ; this . pathsToCleanup = [ ] ; this . pragma = { } ; } , visitor : { Program : { enter ( _ , state ) { const { file } = state ; if ( file . ast . comments ) { for ( const comment of file . ast . comments ) { const jsxSourceMatches = JSX_SOURCE_ANNOTATION_REGEX . exec ( comment . value ) ; const jsxMatches = JSX_ANNOTATION_REGEX . exec ( comment . value ) ; if ( jsxSourceMatches && jsxSourceMatches [ 1 ] === COMPILED_MODULE ) { state . compiledImports = { } ; state . pragma . jsxImportSource = true ; } if ( jsxMatches && jsxMatches [ 1 ] === 'jsx' ) { state . pragma . jsx = true ; } } } } , exit ( path , state ) { if ( ! state . compiledImports ) { return ; } const { pragma , opts : { importReact : shouldImportReact = true } , } = state ; appendRuntimeImports ( path ) ; const hasPragma = pragma . jsxImportSource || pragma . jsx ; if ( ! hasPragma && shouldImportReact && ! path . scope . getBinding ( 'React' ) ) { path . unshiftContainer ( 'body' , template . ast ( `import * as React from 'react'` ) ) ; } if ( state . compiledImports . styled && ! path . scope . getBinding ( 'forwardRef' ) ) { path . unshiftContainer ( 'body' , template . ast ( `import { forwardRef } from 'react'` ) ) ; } const filename = basename ( state . filename ?? '' ) || 'File' ; const version = process . env . TEST_PKG_VERSION || packageJson . version ; path . addComment ( 'leading' , ` ${ filename } generated by ${ packageJson . name } v${ version } ` ) ; path . unshiftContainer ( 'body' , t . noop ( ) ) ; if ( this . includedFiles . length && this . opts . onIncludedFiles ) { this . opts . onIncludedFiles ( unique ( this . includedFiles ) ) ; } state . pathsToCleanup . forEach ( ( clean ) => { switch ( clean . action ) { case 'remove' : { clean . path . remove ( ) ; return ; } case 'replace' : { clean . path . replaceWith ( t . nullLiteral ( ) ) ; return ; } default : return ; } } ) ; } , } , ImportDeclaration ( path , state ) { if ( path . node . source . value !== COMPILED_MODULE ) { return ; } state . compiledImports = state . compiledImports || { } ; path . get ( 'specifiers' ) . forEach ( ( specifier ) => { if ( ! state . compiledImports || ! specifier . isImportSpecifier ( ) ) { return ; } ( [ 'styled' , 'ClassNames' , 'css' , 'keyframes' ] as const ) . forEach ( ( apiName ) => { if ( state . compiledImports && t . isIdentifier ( specifier . node ?. imported ) && specifier . node ?. imported . name === apiName ) { state . compiledImports [ apiName ] = specifier . node . local . name ; specifier . remove ( ) ; } } ) ; } ) ; if ( path . node . specifiers . length === 0 ) { path . remove ( ) ; } } , TaggedTemplateExpression ( path , state ) { if ( isCompiledCSSTaggedTemplateExpression ( path . node , state ) || isCompiledKeyframesTaggedTemplateExpression ( path . node , state ) ) { state . pathsToCleanup . push ( { path , action : 'replace' } ) ; return ; } if ( isCompiledStyledTaggedTemplateExpression ( path . node , state ) ) { visitStyledPath ( path , { context : 'root' , state , parentPath : path } ) ; return ; } } , CallExpression ( path , state ) { if ( isCompiledCSSCallExpression ( path . node , state ) || isCompiledKeyframesCallExpression ( path . node , state ) ) { state . pathsToCleanup . push ( { path , action : 'replace' } ) ; return ; } if ( isCompiledStyledCallExpression ( path . node , state ) ) { visitStyledPath ( path , { context : 'root' , state , parentPath : path } ) ; return ; } } , JSXElement ( path , state ) { if ( ! state . compiledImports ?. ClassNames ) { return ; } visitClassNamesPath ( path , { context : 'root' , state , parentPath : path } ) ; } , JSXOpeningElement ( path , state ) { if ( ! state . compiledImports ) { return ; } visitCssPropPath ( path , { context : 'root' , state , parentPath : path } ) ; } , } , } ; } ) ;