diff --git a/lib/core/package.json b/lib/core/package.json index 1018824def..b992ad25a8 100644 --- a/lib/core/package.json +++ b/lib/core/package.json @@ -41,8 +41,7 @@ "@alfresco/js-api": ">=9.1.1", "@alfresco/adf-extensions": ">=8.2.0", "minimatch": ">=10.0.0", - "pdfjs-dist": ">=3.3.122", - "ts-morph": ">=20.0.0" + "pdfjs-dist": ">=3.3.122" }, "keywords": [ "core", diff --git a/lib/core/schematics/migrations/7_0_0/index.ts b/lib/core/schematics/migrations/7_0_0/index.ts index a6c6d43de5..b397719479 100644 --- a/lib/core/schematics/migrations/7_0_0/index.ts +++ b/lib/core/schematics/migrations/7_0_0/index.ts @@ -15,8 +15,8 @@ * limitations under the License. */ -import { Rule, SchematicContext, SchematicsException, Tree } from '@angular-devkit/schematics'; -import { Project, NamedImports, SourceFile, ImportSpecifier, ImportDeclaration } from 'ts-morph'; +import * as ts from 'typescript'; +import { Rule, SchematicsException, Tree } from '@angular-devkit/schematics'; interface MigrationData { change: { @@ -68,17 +68,13 @@ const migrations: MigrationData[] = [alfrescoApiServiceMigration, alfrescoApiMoc * @returns Schematic rule for updating imports */ export function updateAlfrescoApiImports(): Rule { - const project = new Project(); - - // eslint-disable-next-line @typescript-eslint/no-unused-vars - return (tree: Tree, _context: SchematicContext) => { - tree.visit((filePath: string) => visitor(filePath, tree, project)); - + return (tree: Tree) => { + tree.visit((filePath: string) => visitor(filePath, tree)); return tree; }; } -export const visitor = (filePath: string, tree: Pick, project: Project) => { +export const visitor = (filePath: string, tree: Pick): void => { if ( !filePath.includes('/.git/') && !filePath.includes('/node_modules/') && @@ -92,8 +88,11 @@ export const visitor = (filePath: string, tree: Pick throw new SchematicsException(`Could not read file: ${filePath}`); } + const fileContent = bufferFileContent.toString(); + const sourceFile = ts.createSourceFile(filePath, fileContent, ts.ScriptTarget.Latest, true); + migrations.forEach((migrationData) => { - const fileWithUpdatedImport = moveImport(filePath, bufferFileContent, project, migrationData); + const fileWithUpdatedImport = moveImport(bufferFileContent, sourceFile, migrationData); if (fileWithUpdatedImport) { tree.overwrite(filePath, fileWithUpdatedImport); @@ -102,88 +101,62 @@ export const visitor = (filePath: string, tree: Pick } }; -const moveImport = (filePath: string, bufferFileContent: Buffer, project: Project, migrationData: MigrationData): string | undefined => { +const moveImport = (bufferFileContent: Buffer, sourceFile: ts.SourceFile, migrationData: MigrationData): string | undefined => { const fileContent = bufferFileContent.toString(); const predictImport = fileContent.includes(migrationData.change.importedValue); + if (!predictImport) { + return undefined; + } + const moduleImports = sourceFile.statements.filter(ts.isImportDeclaration); - if (predictImport) { - const sourceFile = project.getSourceFile(`migration-${filePath}`) ?? project.createSourceFile(`migration-${filePath}`, fileContent); + const importDeclaration = moduleImports.find((moduleImport) => { + const currentImportSource = moduleImport.moduleSpecifier.getText().replace(/['"]/g, ''); + return currentImportSource === migrationData.change.importSource; + }); - const alfrescoApiImportResult = getImportedValueFromSource(sourceFile, { - importedIdentifier: migrationData.change.importedValue, - from: migrationData.change.importSource + if (!importDeclaration?.importClause?.namedBindings) { + return undefined; + } + + if (!ts.isNamedImports(importDeclaration.importClause.namedBindings)) { + return undefined; + } + + const namedImportsElements = importDeclaration.importClause.namedBindings.elements; + const importedValue = namedImportsElements.find((binding) => binding.name.text === migrationData.change.importedValue); + + if (importedValue) { + let updatedContent = + namedImportsElements.length === 1 + ? removeTextRange(fileContent, importDeclaration.getFullStart(), importDeclaration.getEnd()) + : removeTextRange(fileContent, importedValue.getFullStart(), importedValue.getEnd()); + const alreadyImported = moduleImports.some((moduleImport) => { + const currentImportSource = moduleImport.moduleSpecifier.getText().replace(/['"]/g, ''); + return ( + currentImportSource === migrationData.to.importSource && + moduleImport.importClause?.namedBindings && + ts.isNamedImports(moduleImport.importClause.namedBindings) && + moduleImport.importClause.namedBindings.elements.some((element) => element.name.text === migrationData.to.importedValue) + ); }); - if (alfrescoApiImportResult?.importedValue) { - if (alfrescoApiImportResult.allImportedValuesCount === 1) { - // There is only one import e.g. import { A } from 'A'; - // Therefore, we need to remove whole import statement - alfrescoApiImportResult.importSource?.remove(); - } else { - alfrescoApiImportResult.importedValue?.remove(); - } + if (!alreadyImported) { + const firstNonImport = sourceFile.statements.find((statement) => !ts.isImportDeclaration(statement)); + const insertPosition = firstNonImport ? firstNonImport.getFullStart() : fileContent.length; - const alfrescoContentServiceImport = getSourceImport(sourceFile, migrationData.to.importSource); - - if (alfrescoContentServiceImport) { - alfrescoContentServiceImport.addNamedImport(migrationData.to.importedValue); - } else { - sourceFile.insertStatements( - sourceFile.getImportDeclarations().length + 1, - `import { ${migrationData.to.importedValue} } from '${migrationData.to.importSource}';` - ); - } - - return sourceFile.getFullText(); + updatedContent = + updatedContent.slice(0, insertPosition).trimEnd() + + `\nimport { ${migrationData.to.importedValue} } from '${migrationData.to.importSource}';\n` + + updatedContent.slice(insertPosition); } + updatedContent = updatedContent.replace(/^\s*\n+/g, '').replace(/\n{3,}/g, '\n\n'); + + return updatedContent; } return undefined; }; -const getSourceImport = (sourceFile: SourceFile, from: string): ImportDeclaration | undefined => { - const moduleImports = sourceFile.getImportDeclarations(); - - const importDeclaration = moduleImports.find((moduleImport) => { - const currentImportSource = moduleImport.getModuleSpecifierValue(); - return currentImportSource === from; - }); - - return importDeclaration; -}; - -const getImportedValueFromSource = ( - sourceFile: SourceFile, - searchedImport: { - importedIdentifier: string; - from: string; - } -): { - importedValue: ImportSpecifier | undefined; - importSource: ImportDeclaration | undefined; - allImportedValuesCount: number | undefined; -} => { - const importSource = getSourceImport(sourceFile, searchedImport.from); - - if (!importSource) { - return { - importedValue: undefined, - importSource: undefined, - allImportedValuesCount: undefined - }; - } - - const importedValues = importSource?.getImportClause(); - const namedImports = importedValues?.getNamedBindings() as NamedImports; - const namedImportsElements = namedImports?.getElements() ?? []; - - const importedValue = namedImportsElements.find((binding) => binding.getName() === searchedImport.importedIdentifier); - - return { - importedValue, - importSource, - allImportedValuesCount: namedImportsElements.length - }; -}; +const removeTextRange = (text: string, start: number, end: number): string => text.slice(0, start) + text.slice(end); export default updateAlfrescoApiImports; diff --git a/lib/core/schematics/migrations/collection.json b/lib/core/schematics/migrations/collection.json index 56436c6df5..34e94b44cf 100644 --- a/lib/core/schematics/migrations/collection.json +++ b/lib/core/schematics/migrations/collection.json @@ -11,11 +11,6 @@ "move-out-alfresco-api": { "version": "7.0.0", "packages": { - "ts-morph": { - "version": "^20.0.0", - "alwaysAddToPackageJson": true, - "addToPackageJson": "devDependencies" - }, "@alfresco/adf-content-services": { "version": "7.0.0", "alwaysAddToPackageJson": false diff --git a/package-lock.json b/package-lock.json index 8238143053..d5b9160694 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,7 +43,6 @@ "raphael": "2.3.0", "rxjs": "7.8.2", "superagent": "^9.0.1", - "ts-morph": "^26.0.0", "tslib": "2.8.1", "zone.js": "0.15.0" }, @@ -5259,6 +5258,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", + "dev": true, "license": "MIT", "engines": { "node": "20 || >=22" @@ -5268,6 +5268,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", + "dev": true, "license": "MIT", "dependencies": { "@isaacs/balanced-match": "^4.0.1" @@ -15968,32 +15969,6 @@ "node": ">=10.13.0" } }, - "node_modules/@ts-morph/common": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.27.0.tgz", - "integrity": "sha512-Wf29UqxWDpc+i61k3oIOzcUfQt79PIT9y/MWfAGlrkjg6lBC1hwDECLXPVJAhWjiGbfBCxZd65F/LIZF3+jeJQ==", - "license": "MIT", - "dependencies": { - "fast-glob": "^3.3.3", - "minimatch": "^10.0.1", - "path-browserify": "^1.0.1" - } - }, - "node_modules/@ts-morph/common/node_modules/minimatch": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz", - "integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==", - "license": "ISC", - "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@tsconfig/node10": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", @@ -20326,12 +20301,6 @@ "node": ">= 0.12.0" } }, - "node_modules/code-block-writer": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-13.0.3.tgz", - "integrity": "sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==", - "license": "MIT" - }, "node_modules/collapse-white-space": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-1.0.6.tgz", @@ -32667,6 +32636,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, "license": "MIT" }, "node_modules/path-exists": { @@ -38525,16 +38495,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/ts-morph": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-26.0.0.tgz", - "integrity": "sha512-ztMO++owQnz8c/gIENcM9XfCEzgoGphTv+nKpYNM1bgsdOVC/jRZuEBf6N+mLLDNg68Kl+GgUZfOySaRiG1/Ug==", - "license": "MIT", - "dependencies": { - "@ts-morph/common": "~0.27.0", - "code-block-writer": "^13.0.3" - } - }, "node_modules/ts-node": { "version": "10.9.2", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", diff --git a/package.json b/package.json index fb4378d84f..1ee8626d40 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,6 @@ "raphael": "2.3.0", "rxjs": "7.8.2", "superagent": "^9.0.1", - "ts-morph": "^26.0.0", "tslib": "2.8.1", "zone.js": "0.15.0" }, diff --git a/scripts/github/release/set-migrations.js b/scripts/github/release/set-migrations.js index c6d70ec716..94c0cd11bd 100644 --- a/scripts/github/release/set-migrations.js +++ b/scripts/github/release/set-migrations.js @@ -48,10 +48,6 @@ const setMigration = () => { const packagesToUpdate = packageJsonUpdates[migration.name]['packages']; Object.keys(packagesToUpdate).forEach((packageName) => { - if (packageName === 'ts-morph') { - return; - } - if (packageName === '@alfresco/js-api') { packagesToUpdate[packageName]['version'] = jsApiPackage.version; } else {