11// @ts -ignore
22import type * as Liquid from '@shopify/prettier-plugin-liquid/dist/types.js'
3- import * as astTypes from 'ast-types'
4- // @ts -ignore
5- import jsesc from 'jsesc'
63// @ts -ignore
74import lineColumn from 'line-column'
85import * as prettierParserAngular from 'prettier/plugins/angular'
96import * as prettierParserBabel from 'prettier/plugins/babel'
107import * as prettierParserCss from 'prettier/plugins/postcss'
118// @ts -ignore
12- import * as recast from 'recast'
139import { createPlugin } from './create-plugin.js'
1410import type { Matcher } from './options.js'
1511import { sortClasses , sortClassList } from './sorting.js'
@@ -97,115 +93,126 @@ function transformDynamicAngularAttribute(attr: any, env: TransformerEnv) {
9793function transformDynamicJsAttribute ( attr : any , env : TransformerEnv ) {
9894 let { matcher } = env
9995
100- let ast = recast . parse ( ` let __prettier_temp__ = ${ attr . value } ` , {
101- parser : prettierParserBabel . parsers [ 'babel-ts' ] ,
102- } )
96+ let expressionPrefix = ' let __prettier_temp__ = '
97+ let source = ` ${ expressionPrefix } ${ attr . value } `
98+ let ast = prettierParserBabel . parsers [ 'babel-ts' ] . parse ( source , env . options )
10399
104- function * ancestors < N , V > ( path : import ( 'ast-types/lib/node-path' ) . NodePath < N , V > ) {
105- yield path
100+ let didChange = false
101+ let changes : StringChange [ ] = [ ]
106102
107- while ( path . parentPath ) {
108- path = path . parentPath
109- yield path
110- }
103+ function findConcatEntry ( path : Path < any , any > ) {
104+ return path . find (
105+ ( entry ) => entry . parent ?. type === 'BinaryExpression' && entry . parent . operator === '+' ,
106+ )
111107 }
112108
113- let didChange = false
109+ function addChange ( start : number | null | undefined , end : number | null | undefined , after : string ) {
110+ if ( start == null || end == null ) return
114111
115- astTypes . visit ( ast , {
116- visitLiteral ( path ) {
117- let entries = Array . from ( ancestors ( path ) )
118- let concat = entries . find ( ( entry ) => {
119- return (
120- entry . parent &&
121- entry . parent . value &&
122- entry . parent . value . type === 'BinaryExpression' &&
123- entry . parent . value . operator === '+'
124- )
125- } )
112+ let offsetStart = start - expressionPrefix . length
113+ let offsetEnd = end - expressionPrefix . length
126114
127- if ( isStringLiteral ( path . node ) ) {
128- let sorted = sortStringLiteral ( path . node , {
129- env,
130- collapseWhitespace : {
131- start : concat ?. name !== 'right' ,
132- end : concat ?. name !== 'left' ,
133- } ,
134- } )
115+ if ( offsetStart < 0 || offsetEnd < 0 ) return
116+
117+ didChange = true
118+ changes . push ( {
119+ start : offsetStart ,
120+ end : offsetEnd ,
121+ before : attr . value . slice ( offsetStart , offsetEnd ) ,
122+ after,
123+ } )
124+ }
135125
136- if ( sorted ) {
137- didChange = true
138-
139- // https://github.com/benjamn/recast/issues/171#issuecomment-224996336
140- // @ts -ignore
141- let quote = path . node . extra . raw [ 0 ]
142- let value = jsesc ( path . node . value , {
143- quotes : quote === "'" ? 'single' : 'double' ,
144- } )
145- // @ts -ignore
146- path . node . value = new String ( quote + value + quote )
126+ visit ( ast , {
127+ StringLiteral ( node , path ) {
128+ let concat = findConcatEntry ( path )
129+ let sorted = sortStringLiteral ( node , {
130+ env,
131+ collapseWhitespace : {
132+ start : concat ?. key !== 'right' ,
133+ end : concat ?. key !== 'left' ,
134+ } ,
135+ } )
136+
137+ if ( sorted ) {
138+ // @ts -ignore
139+ let raw = node . extra ?. raw ?? node . raw
140+ if ( typeof raw === 'string' ) {
141+ addChange ( node . start , node . end , raw )
147142 }
148143 }
149- this . traverse ( path )
150144 } ,
151145
152- visitTemplateLiteral ( path ) {
153- let entries = Array . from ( ancestors ( path ) )
154- let concat = entries . find ( ( entry ) => {
155- return (
156- entry . parent &&
157- entry . parent . value &&
158- entry . parent . value . type === 'BinaryExpression' &&
159- entry . parent . value . operator === '+'
160- )
161- } )
146+ Literal ( node : any , path ) {
147+ if ( ! isStringLiteral ( node ) ) return
162148
163- let sorted = sortTemplateLiteral ( path . node , {
149+ let concat = findConcatEntry ( path )
150+ let sorted = sortStringLiteral ( node , {
164151 env,
165152 collapseWhitespace : {
166- start : concat ?. name !== 'right' ,
167- end : concat ?. name !== 'left' ,
153+ start : concat ?. key !== 'right' ,
154+ end : concat ?. key !== 'left' ,
168155 } ,
169156 } )
170157
171158 if ( sorted ) {
172- didChange = true
159+ // @ts -ignore
160+ let raw = node . extra ?. raw ?? node . raw
161+ if ( typeof raw === 'string' ) {
162+ addChange ( node . start , node . end , raw )
163+ }
173164 }
174-
175- this . traverse ( path )
176165 } ,
177166
178- visitTaggedTemplateExpression ( path ) {
179- let entries = Array . from ( ancestors ( path ) )
180- let concat = entries . find ( ( entry ) => {
181- return (
182- entry . parent &&
183- entry . parent . value &&
184- entry . parent . value . type === 'BinaryExpression' &&
185- entry . parent . value . operator === '+'
186- )
167+ TemplateLiteral ( node , path ) {
168+ let concat = findConcatEntry ( path )
169+ let originalQuasis = node . quasis . map ( ( quasi ) => quasi . value . raw )
170+ let sorted = sortTemplateLiteral ( node , {
171+ env ,
172+ collapseWhitespace : {
173+ start : concat ?. key !== 'right' ,
174+ end : concat ?. key !== 'left' ,
175+ } ,
187176 } )
188177
189- if ( isSortableTemplateExpression ( path . node , matcher ) ) {
190- let sorted = sortTemplateLiteral ( path . node . quasi , {
191- env,
192- collapseWhitespace : {
193- start : concat ?. name !== 'right' ,
194- end : concat ?. name !== 'left' ,
195- } ,
196- } )
197-
198- if ( sorted ) {
199- didChange = true
178+ if ( sorted ) {
179+ for ( let i = 0 ; i < node . quasis . length ; i ++ ) {
180+ let quasi = node . quasis [ i ]
181+ if ( quasi . value . raw !== originalQuasis [ i ] ) {
182+ addChange ( quasi . start , quasi . end , quasi . value . raw )
183+ }
200184 }
201185 }
186+ } ,
187+
188+ TaggedTemplateExpression ( node , path ) {
189+ if ( ! isSortableTemplateExpression ( node , matcher ) ) {
190+ return
191+ }
192+
193+ let concat = findConcatEntry ( path )
194+ let originalQuasis = node . quasi . quasis . map ( ( quasi ) => quasi . value . raw )
195+ let sorted = sortTemplateLiteral ( node . quasi , {
196+ env,
197+ collapseWhitespace : {
198+ start : concat ?. key !== 'right' ,
199+ end : concat ?. key !== 'left' ,
200+ } ,
201+ } )
202202
203- this . traverse ( path )
203+ if ( sorted ) {
204+ for ( let i = 0 ; i < node . quasi . quasis . length ; i ++ ) {
205+ let quasi = node . quasi . quasis [ i ]
206+ if ( quasi . value . raw !== originalQuasis [ i ] ) {
207+ addChange ( quasi . start , quasi . end , quasi . value . raw )
208+ }
209+ }
210+ }
204211 } ,
205212 } )
206213
207214 if ( didChange ) {
208- attr . value = recast . print ( ast . program . body [ 0 ] . declarations [ 0 ] . init ) . code
215+ attr . value = spliceChangesIntoString ( attr . value , changes )
209216 }
210217}
211218
@@ -510,16 +517,14 @@ function sortTemplateLiteral(
510517}
511518
512519function isSortableTemplateExpression (
513- node :
514- | import ( '@babel/types' ) . TaggedTemplateExpression
515- | import ( 'ast-types' ) . namedTypes . TaggedTemplateExpression ,
520+ node : import ( '@babel/types' ) . TaggedTemplateExpression ,
516521 matcher : Matcher ,
517522) : boolean {
518523 return isSortableExpression ( node . tag , matcher )
519524}
520525
521526function isSortableCallExpression (
522- node : import ( '@babel/types' ) . CallExpression | import ( 'ast-types' ) . namedTypes . CallExpression ,
527+ node : import ( '@babel/types' ) . CallExpression ,
523528 matcher : Matcher ,
524529) : boolean {
525530 if ( ! node . arguments ?. length ) return false
@@ -528,10 +533,7 @@ function isSortableCallExpression(
528533}
529534
530535function isSortableExpression (
531- node :
532- | import ( '@babel/types' ) . Expression
533- | import ( '@babel/types' ) . V8IntrinsicIdentifier
534- | import ( 'ast-types' ) . namedTypes . ASTNode ,
536+ node : import ( '@babel/types' ) . Expression | import ( '@babel/types' ) . V8IntrinsicIdentifier ,
535537 matcher : Matcher ,
536538) : boolean {
537539 // Traverse property accesses and function calls to find the leading ident
0 commit comments