1+ const { babel } = require ( "@rollup/plugin-babel" )
2+
3+
4+ const functionVisitor = types => ( path , { opts } ) => {
5+ {
6+ const { mode = 'ts' } = opts
7+
8+ if ( mode !== 'ts' && mode !== 'vanilla-js' )
9+ throw new Error ( "Invalid configuration: mode must be 'ts' or 'vanilla-js'." )
10+
11+ const type = path ?. type
12+
13+ if ( mode === 'ts' ) {
14+ if ( type !== "ArrowFunctionExpression" ) return
15+ if ( path . parent ?. type !== "VariableDeclarator" ) return
16+ const bindings = path . context ?. scope ?. bindings
17+ if ( ! path . parent ?. id ?. typeAnnotation ) return
18+ const typeAnnotation = path . parent . id . typeAnnotation . typeAnnotation
19+ if ( typeAnnotation ?. type !== "TSTypeReference" ) return
20+ if ( typeAnnotation ?. typeName ?. type === "Identifier" ) {
21+ const typeName = typeAnnotation . typeName . name
22+ const typeBinding = bindings ?. [ typeName ]
23+ if ( ! typeBinding ) return
24+ const importSpecifier = typeBinding . path ?. node
25+ if ( importSpecifier ?. type !== "ImportSpecifier" ) return
26+ if ( importSpecifier ?. imported ?. name !== "Component" ) return
27+ if ( typeBinding ?. path ?. parent ?. source ?. value !== "solid-js" ) return
28+ }
29+ else if ( typeAnnotation ?. typeName ?. type === "TSQualifiedName" ) {
30+ if ( typeAnnotation . typeName ?. right ?. name !== "Component" ) return
31+ const typeQualification = typeAnnotation . typeName ?. left
32+ if ( typeQualification ?. type !== "Identifier" ) return
33+ const typeQualificationName = typeQualification ?. name
34+ const typeQualificationBinding = bindings ?. [ typeQualificationName ]
35+ if ( ! typeQualificationBinding ) return
36+ const importSpecifier = typeQualificationBinding ?. path ?. node
37+ if ( importSpecifier ?. type !== "ImportDefaultSpecifier" ) return
38+ if ( typeQualificationBinding ?. path ?. parent ?. source ?. value !== "solid-js" ) return
39+ }
40+ else return
41+ }
42+
43+ if ( mode === 'vanilla-js' ) {
44+ if ( path . parent ?. type !== "CallExpression" ) return
45+ const wrappingFunctionName = path . parent . callee ?. name
46+ const bindings = path . context ?. scope ?. bindings
47+ const wrappingFunctionBinding = bindings ?. [ wrappingFunctionName ]
48+ if ( ! wrappingFunctionBinding ) return
49+ const importSpecifier = wrappingFunctionBinding . path ?. node
50+ if ( importSpecifier ?. type !== "ImportSpecifier" ) return
51+ if ( importSpecifier ?. imported ?. name !== "component" ) return
52+
53+ if ( wrappingFunctionBinding . path . parent ?. source ?. value !== 'babel-plugin-solid-undestructure' ) return
54+ wrappingFunctionBinding . path . parentPath . remove ( )
55+ path . parentPath . replaceWith ( path )
56+ }
57+ }
58+
59+ const firstParam = path . node ?. params ?. [ 0 ]
60+ if ( ! firstParam || firstParam . type !== "ObjectPattern" ) return
61+
62+ const program = path ?. findParent ( path => path . isProgram ( ) )
63+ const newPropsIdentifier =
64+ program ?. scope ?. generateUidIdentifier ( "props" )
65+
66+ const propsDestructredProperties = firstParam ?. properties
67+ const componentScopeBindings = path . scope ?. bindings
68+
69+ for ( const DestructredProperty of propsDestructredProperties )
70+ if ( ! DestructredProperty ?. value ?. name ) return
71+
72+ for ( const DestructredProperty of propsDestructredProperties ) {
73+ const DestructredKeyIdentifier = DestructredProperty . key
74+ const undestructuredPropExpression =
75+ types . memberExpression ( newPropsIdentifier , DestructredKeyIdentifier )
76+
77+ const DestructredName = DestructredProperty . value ?. name
78+
79+ const { referencePaths, constantViolations } = componentScopeBindings ?. [ DestructredName ]
80+
81+ for ( const referencePath of referencePaths )
82+ referencePath ?. replaceWith ( undestructuredPropExpression )
83+
84+ for ( const constantViolation of constantViolations )
85+ constantViolation . node && ( constantViolation . node . left = undestructuredPropExpression )
86+ }
87+
88+ path . node . params [ 0 ] = newPropsIdentifier
89+ }
90+
91+
92+ module . exports = function babelPluginUndestructure ( { types } ) {
93+ const visitor = {
94+ FunctionDeclaration : functionVisitor ( types ) ,
95+ FunctionExpression : functionVisitor ( types ) ,
96+ ArrowFunctionExpression : functionVisitor ( types )
97+ }
98+
99+ return {
100+ name : "babel-plugin-solid-undestructure" ,
101+ visitor
102+ }
103+ }
104+
105+
106+ module . exports . undestructurePlugin = mode => {
107+ if ( ! mode || mode === 'ts' ) return [
108+ {
109+ ...babel ( {
110+ plugins : [
111+ [ "@babel/plugin-syntax-typescript" , { isTSX : true } ] ,
112+ "babel-plugin-solid-undestructure" ,
113+ ] ,
114+ extensions : [ ".tsx" ]
115+ } ) ,
116+ enforce : 'pre'
117+ } ,
118+ {
119+ ...babel ( {
120+ plugins : [
121+ "@babel/plugin-syntax-typescript" ,
122+ "babel-plugin-solid-undestructure" ,
123+ ] ,
124+ extensions : [ ".ts" ]
125+ } ) ,
126+ enforce : 'pre'
127+ }
128+ ]
129+
130+ else if ( mode === "vanilla-js" )
131+ return [ "babel-plugin-solid-undestructure" , { mode : "vanilla-js" } ]
132+
133+ else throw new Error ( "babel-plugin-solid-undestructure error: Invalid mode. Mode must be either 'ts' or 'vanilla-js'" )
134+ }
0 commit comments