@@ -4,9 +4,8 @@ import LinterContext, {RawLintMessage, ResourcePath} from "../linter/LinterConte
44import { MESSAGE } from "../linter/messages.js" ;
55import { ModuleDeclaration } from "../linter/ui5Types/amdTranspiler/parseModuleDeclaration.js" ;
66import generateSolutionNoGlobals from "./solutions/noGlobals.js" ;
7- import { collectModuleIdentifiers } from "./utils.js" ;
87import { getLogger } from "@ui5/logger" ;
9- import { resolveUniqueName } from "../linter/ui5Types/utils/utils .js" ;
8+ import { addDependencies } from "./solutions/amdImports .js" ;
109
1110const log = getLogger ( "linter:autofix" ) ;
1211
@@ -75,7 +74,7 @@ export interface DeprecatedApiAccessNode {
7574 node ?: ts . CallExpression | ts . Identifier | ts . PropertyAccessExpression | ts . ElementAccessExpression ;
7675}
7776
78- type ImportRequests = Map < string , {
77+ export type ImportRequests = Map < string , {
7978 nodeInfos : ( DeprecatedApiAccessNode | GlobalPropertyAccessNodeInfo ) [ ] ;
8079 identifier ?: string ;
8180} > ;
@@ -228,164 +227,6 @@ function applyFixes(
228227 return applyChanges ( content , changeSet ) ;
229228}
230229
231- function addDependencies (
232- defineCall : ts . CallExpression , moduleDeclarationInfo : ExistingModuleDeclarationInfo ,
233- changeSet : ChangeSet [ ]
234- ) {
235- const { moduleDeclaration, importRequests} = moduleDeclarationInfo ;
236-
237- if ( importRequests . size === 0 ) {
238- return ;
239- }
240-
241- const declaredIdentifiers = collectModuleIdentifiers ( moduleDeclaration . factory ) ;
242-
243- const defineCallArgs = defineCall . arguments ;
244- const existingImportModules = defineCall . arguments && ts . isArrayLiteralExpression ( defineCallArgs [ 0 ] ) ?
245- defineCallArgs [ 0 ] . elements . map ( ( el ) => ts . isStringLiteralLike ( el ) ? el . text : "" ) :
246- [ ] ;
247-
248- if ( ! ts . isFunctionLike ( moduleDeclaration . factory ) ) {
249- throw new Error ( "Invalid factory function" ) ;
250- }
251- const existingIdentifiers = moduleDeclaration . factory
252- . parameters . map ( ( param : ts . ParameterDeclaration ) => ( param . name as ts . Identifier ) . text ) ;
253- const existingIdentifiersLength = existingIdentifiers . length ;
254-
255- const imports = [ ...importRequests . keys ( ) ] ;
256-
257- const identifiersForExistingImports : string [ ] = [ ] ;
258- let existingIdentifiersCut = 0 ;
259- existingImportModules . forEach ( ( existingModule , index ) => {
260- const indexOf = imports . indexOf ( existingModule ) ;
261- const identifierName = existingIdentifiers [ index ] ||
262- resolveUniqueName ( existingModule , declaredIdentifiers ) ;
263- declaredIdentifiers . add ( identifierName ) ;
264- identifiersForExistingImports . push ( identifierName ) ;
265- if ( indexOf !== - 1 ) {
266- // If there are defined dependencies, but identifiers for them are missing,
267- // and those identifiers are needed in the code, then we need to find out
268- // up to which index we need to build identifiers and cut the rest.
269- existingIdentifiersCut = index > existingIdentifiersCut ? ( index + 1 ) : existingIdentifiersCut ;
270- imports . splice ( indexOf , 1 ) ;
271- importRequests . get ( existingModule ) ! . identifier = identifierName ;
272- }
273- } ) ;
274-
275- // Cut identifiers that are already there
276- identifiersForExistingImports . splice ( existingIdentifiersCut ) ;
277-
278- const dependencies = imports . map ( ( i ) => `"${ i } "` ) ;
279- const identifiers = [
280- ...identifiersForExistingImports ,
281- ...imports . map ( ( i ) => {
282- const identifier = resolveUniqueName ( i , declaredIdentifiers ) ;
283- declaredIdentifiers . add ( identifier ) ;
284- importRequests . get ( i ) ! . identifier = identifier ;
285- return identifier ;
286- } ) ] ;
287-
288- if ( dependencies . length ) {
289- // Add dependencies
290- if ( moduleDeclaration . dependencies ) {
291- const depsNode = defineCall . arguments [ 0 ] ;
292- const depElementNodes = depsNode && ts . isArrayLiteralExpression ( depsNode ) ? depsNode . elements : [ ] ;
293- const insertAfterElement = depElementNodes [ existingIdentifiersLength - 1 ] ??
294- depElementNodes [ depElementNodes . length - 1 ] ;
295-
296- if ( insertAfterElement ) {
297- changeSet . push ( {
298- action : ChangeAction . INSERT ,
299- start : insertAfterElement . getEnd ( ) ,
300- value : ( existingImportModules . length ? ", " : "" ) + dependencies . join ( ", " ) ,
301- } ) ;
302- } else {
303- changeSet . push ( {
304- action : ChangeAction . REPLACE ,
305- start : depsNode . getFullStart ( ) ,
306- end : depsNode . getEnd ( ) ,
307- value : `[${ dependencies . join ( ", " ) } ]` ,
308- } ) ;
309- }
310- } else {
311- changeSet . push ( {
312- action : ChangeAction . INSERT ,
313- start : defineCall . arguments [ 0 ] . getFullStart ( ) ,
314- value : `[${ dependencies . join ( ", " ) } ], ` ,
315- } ) ;
316- }
317- }
318-
319- if ( identifiers . length ) {
320- const closeParenToken = moduleDeclaration . factory . getChildren ( )
321- . find ( ( c ) => c . kind === ts . SyntaxKind . CloseParenToken ) ;
322- // Factory arguments
323- const syntaxList = moduleDeclaration . factory . getChildren ( )
324- . find ( ( c ) => c . kind === ts . SyntaxKind . SyntaxList ) ;
325- if ( ! syntaxList ) {
326- throw new Error ( "Invalid factory syntax" ) ;
327- }
328-
329- // Patch factory arguments
330- const value = ( existingIdentifiersLength ? ", " : "" ) + identifiers . join ( ", " ) ;
331- if ( ! closeParenToken ) {
332- changeSet . push ( {
333- action : ChangeAction . INSERT ,
334- start : syntaxList . getStart ( ) ,
335- value : "(" ,
336- } ) ;
337- changeSet . push ( {
338- action : ChangeAction . INSERT ,
339- start : syntaxList . getEnd ( ) ,
340- value : `${ value } )` ,
341- } ) ;
342- } else {
343- let start = syntaxList . getEnd ( ) ;
344-
345- // Existing trailing comma: Insert new args before it, to keep the trailing comma
346- const lastSyntaxListChild = syntaxList . getChildAt ( syntaxList . getChildCount ( ) - 1 ) ;
347- if ( lastSyntaxListChild ?. kind === ts . SyntaxKind . CommaToken ) {
348- start = lastSyntaxListChild . getStart ( ) ;
349- }
350-
351- changeSet . push ( {
352- action : ChangeAction . INSERT ,
353- start,
354- value,
355- } ) ;
356- }
357- }
358-
359- // Patch identifiers
360- patchIdentifiers ( importRequests , changeSet ) ;
361- }
362-
363- function patchIdentifiers ( importRequests : ImportRequests , changeSet : ChangeSet [ ] ) {
364- for ( const { nodeInfos, identifier} of importRequests . values ( ) ) {
365- if ( ! identifier ) {
366- throw new Error ( "No identifier found for import" ) ;
367- }
368-
369- for ( const nodeInfo of nodeInfos ) {
370- let node : ts . Node = nodeInfo . node ! ;
371-
372- if ( "namespace" in nodeInfo && nodeInfo . namespace === "sap.ui.getCore" ) {
373- node = node . parent ;
374- }
375- const nodeStart = node . getStart ( ) ;
376- const nodeEnd = node . getEnd ( ) ;
377- const nodeReplacement = `${ identifier } ` ;
378-
379- changeSet . push ( {
380- action : ChangeAction . REPLACE ,
381- start : nodeStart ,
382- end : nodeEnd ,
383- value : nodeReplacement ,
384- } ) ;
385- }
386- }
387- }
388-
389230function applyChanges ( content : string , changeSet : ChangeSet [ ] ) : string {
390231 changeSet . sort ( ( a , b ) => a . start - b . start ) ;
391232 const s = new MagicString ( content ) ;
0 commit comments