diff --git a/scripts/build/helpers.ts b/scripts/build/helpers.ts index a26cb4d0..ea6615cf 100644 --- a/scripts/build/helpers.ts +++ b/scripts/build/helpers.ts @@ -1,7 +1,20 @@ import { readdirSync } from 'fs-extra'; import { camelCase, clone } from 'lodash'; import { join, resolve } from 'path'; -import * as ts from 'typescript'; +import { + ArrayLiteralExpression, + createArrayLiteral, + createLiteral, + createNumericLiteral, + createObjectLiteral, + createPropertyAssignment, + Decorator, + Expression, + Node, + ObjectLiteralElementLike, + ObjectLiteralExpression, + SyntaxKind, +} from 'typescript'; import { Logger } from '../logger'; @@ -12,13 +25,13 @@ export const COMPILER_OPTIONS = TS_CONFIG.compilerOptions; export const PLUGINS_ROOT = join(ROOT, 'src/@awesome-cordova-plugins/plugins/'); export const PLUGIN_PATHS = readdirSync(PLUGINS_ROOT).map(d => join(PLUGINS_ROOT, d, 'index.ts')); -export function getDecorator(node: ts.Node, index = 0): ts.Decorator { +export function getDecorator(node: Node, index = 0): Decorator { if (node.decorators && node.decorators[index]) { return node.decorators[index]; } } -export function hasDecorator(decoratorName: string, node: ts.Node): boolean { +export function hasDecorator(decoratorName: string, node: Node): boolean { return ( node.decorators && node.decorators.length && @@ -43,24 +56,24 @@ export function getDecoratorArgs(decorator: any) { let val: number | boolean; switch (prop.initializer.kind) { - case ts.SyntaxKind.StringLiteral: - case ts.SyntaxKind.Identifier: + case SyntaxKind.StringLiteral: + case SyntaxKind.Identifier: val = prop.initializer.text; break; - case ts.SyntaxKind.ArrayLiteralExpression: + case SyntaxKind.ArrayLiteralExpression: val = prop.initializer.elements.map((e: any) => e.text); break; - case ts.SyntaxKind.TrueKeyword: + case SyntaxKind.TrueKeyword: val = true; break; - case ts.SyntaxKind.FalseKeyword: + case SyntaxKind.FalseKeyword: val = false; break; - case ts.SyntaxKind.NumericLiteral: + case SyntaxKind.NumericLiteral: val = Number(prop.initializer.text); break; @@ -89,9 +102,9 @@ export function convertValueToLiteral(val: any) { return objectToObjectLiteral(val); } if (typeof val === 'number') { - return ts.createNumericLiteral(String(val)); + return createNumericLiteral(String(val)); } - return ts.createLiteral(val); + return createLiteral(val); } /** @@ -100,14 +113,12 @@ export function convertValueToLiteral(val: any) { * @param obj key value object * @returns Typescript Object Literal Expression */ -function objectToObjectLiteral(obj: { [key: string]: any }): ts.ObjectLiteralExpression { - const newProperties: ts.ObjectLiteralElementLike[] = Object.keys(obj).map( - (key: string): ts.ObjectLiteralElementLike => { - return ts.createPropertyAssignment(ts.createLiteral(key), convertValueToLiteral(obj[key]) as ts.Expression); - } - ); +function objectToObjectLiteral(obj: { [key: string]: any }): ObjectLiteralExpression { + const newProperties: ObjectLiteralElementLike[] = Object.keys(obj).map((key: string): ObjectLiteralElementLike => { + return createPropertyAssignment(createLiteral(key), convertValueToLiteral(obj[key]) as Expression); + }); - return ts.createObjectLiteral(newProperties); + return createObjectLiteral(newProperties); } /** @@ -116,9 +127,9 @@ function objectToObjectLiteral(obj: { [key: string]: any }): ts.ObjectLiteralExp * @param list array * @returns Typescript Array Literal Expression */ -function arrayToArrayLiteral(list: any[]): ts.ArrayLiteralExpression { +function arrayToArrayLiteral(list: any[]): ArrayLiteralExpression { const newList: any[] = list.map(convertValueToLiteral); - return ts.createArrayLiteral(newList); + return createArrayLiteral(newList); } export function getMethodsForDecorator(decoratorName: string) { diff --git a/scripts/build/ngx.ts b/scripts/build/ngx.ts index a9cc9fba..22bc0f94 100644 --- a/scripts/build/ngx.ts +++ b/scripts/build/ngx.ts @@ -4,7 +4,7 @@ import { clone } from 'lodash'; import { dirname, join, resolve } from 'path'; import * as rimraf from 'rimraf'; import * as rollup from 'rollup'; -import * as ts from 'typescript'; +import { ModuleKind, ModuleResolutionKind, ScriptTarget } from 'typescript'; import { COMPILER_OPTIONS, PLUGIN_PATHS, ROOT } from './helpers'; import { importsTransformer } from './transformers/imports'; @@ -14,9 +14,9 @@ import { generateDeclarations } from './transpile'; export function getProgram(rootNames: string[] = createSourceFiles()) { const options: CompilerOptions = clone(COMPILER_OPTIONS); options.basePath = ROOT; - options.moduleResolution = ts.ModuleResolutionKind.NodeJs; - options.module = ts.ModuleKind.ES2015; - options.target = ts.ScriptTarget.ES5; + options.moduleResolution = ModuleResolutionKind.NodeJs; + options.module = ModuleKind.ES2015; + options.target = ScriptTarget.ES5; options.lib = ['dom', 'es2017']; options.inlineSourceMap = true; options.importHelpers = true; diff --git a/scripts/build/transformers/extract-injectables.ts b/scripts/build/transformers/extract-injectables.ts index b66c17b3..b3f002e7 100644 --- a/scripts/build/transformers/extract-injectables.ts +++ b/scripts/build/transformers/extract-injectables.ts @@ -1,6 +1,6 @@ import { unlinkSync, writeJSONSync } from 'fs-extra'; import { resolve } from 'path'; -import * as ts from 'typescript'; +import { ClassDeclaration, SyntaxKind, TransformationContext, visitEachChild } from 'typescript'; import { hasDecorator, ROOT } from '../helpers'; @@ -22,13 +22,13 @@ export const EMIT_PATH = resolve(ROOT, 'injectable-classes.json'); * window['IonicNative'] object. */ export function extractInjectables() { - return (ctx: ts.TransformationContext) => { + return (ctx: TransformationContext) => { return tsSourceFile => { if (tsSourceFile.fileName.indexOf('src/@awesome-cordova-plugins/plugins') > -1) { - ts.visitEachChild( + visitEachChild( tsSourceFile, node => { - if (node.kind !== ts.SyntaxKind.ClassDeclaration) { + if (node.kind !== SyntaxKind.ClassDeclaration) { return node; } @@ -36,7 +36,7 @@ export function extractInjectables() { if (isInjectable) { injectableClasses.push({ file: tsSourceFile.path, - className: (node as ts.ClassDeclaration).name.text, + className: (node as ClassDeclaration).name.text, dirName: tsSourceFile.path.split(/[\\\/]+/).reverse()[1], }); } diff --git a/scripts/build/transformers/imports.ts b/scripts/build/transformers/imports.ts index ff1c324c..0a2503ce 100644 --- a/scripts/build/transformers/imports.ts +++ b/scripts/build/transformers/imports.ts @@ -1,18 +1,19 @@ -import * as ts from 'typescript'; +import { createIdentifier, SourceFile, SyntaxKind, TransformationContext } from 'typescript'; + import { getMethodsForDecorator } from '../helpers'; -function transformImports(file: ts.SourceFile, ctx: ts.TransformationContext, ngcBuild?: boolean) { +function transformImports(file: SourceFile, ctx: TransformationContext, ngcBuild?: boolean) { // remove angular imports if (!ngcBuild) { // @ts-expect-error file.statements = (file.statements as any).filter( - (s: any) => !(s.kind === ts.SyntaxKind.ImportDeclaration && s.moduleSpecifier.text === '@angular/core') + (s: any) => !(s.kind === SyntaxKind.ImportDeclaration && s.moduleSpecifier.text === '@angular/core') ); } // find the @awesome-cordova-plugins/core import statement const importStatement = (file.statements as any).find((s: any) => { - return s.kind === ts.SyntaxKind.ImportDeclaration && s.moduleSpecifier.text === '@awesome-cordova-plugins/core'; + return s.kind === SyntaxKind.ImportDeclaration && s.moduleSpecifier.text === '@awesome-cordova-plugins/core'; }); // we're only interested in files containing @awesome-cordova-plugins/core import statement @@ -40,11 +41,11 @@ function transformImports(file: ts.SourceFile, ctx: ts.TransformationContext, ng decorators.forEach(d => (methods = getMethodsForDecorator(d).concat(methods))); - const methodElements = methods.map(m => ts.createIdentifier(m)); + const methodElements = methods.map(m => createIdentifier(m)); const methodNames = methodElements.map(el => el.escapedText); importStatement.importClause.namedBindings.elements = [ - ts.createIdentifier('AwesomeCordovaNativePlugin'), + createIdentifier('AwesomeCordovaNativePlugin'), ...methodElements, ...importStatement.importClause.namedBindings.elements.filter( el => keep.indexOf(el.name.text) !== -1 && methodNames.indexOf(el.name.text) === -1 @@ -69,7 +70,7 @@ function transformImports(file: ts.SourceFile, ctx: ts.TransformationContext, ng } export function importsTransformer(ngcBuild?: boolean) { - return (ctx: ts.TransformationContext) => { + return (ctx: TransformationContext) => { return tsSourceFile => { return transformImports(tsSourceFile, ctx, ngcBuild); }; diff --git a/scripts/build/transformers/members.ts b/scripts/build/transformers/members.ts index cb212386..662e7385 100644 --- a/scripts/build/transformers/members.ts +++ b/scripts/build/transformers/members.ts @@ -1,8 +1,9 @@ -import * as ts from 'typescript'; +import { ClassDeclaration, createConstructor, SyntaxKind } from 'typescript'; + import { transformMethod } from './methods'; import { transformProperty } from './properties'; -export function transformMembers(cls: ts.ClassDeclaration) { +export function transformMembers(cls: ClassDeclaration) { const propertyIndices: number[] = []; const members = cls.members.map((member: any, index: number) => { @@ -10,13 +11,13 @@ export function transformMembers(cls: ts.ClassDeclaration) { if (!member.decorators || !member.decorators.length) return member; switch (member.kind) { - case ts.SyntaxKind.MethodDeclaration: + case SyntaxKind.MethodDeclaration: return transformMethod(member); - case ts.SyntaxKind.PropertyDeclaration: + case SyntaxKind.PropertyDeclaration: propertyIndices.push(index); return member; - case ts.SyntaxKind.Constructor: - return ts.createConstructor(undefined, undefined, member.parameters, member.body); + case SyntaxKind.Constructor: + return createConstructor(undefined, undefined, member.parameters, member.body); default: return member; // in case anything gets here by accident... } diff --git a/scripts/build/transformers/methods.ts b/scripts/build/transformers/methods.ts index 32e1d413..09117a01 100644 --- a/scripts/build/transformers/methods.ts +++ b/scripts/build/transformers/methods.ts @@ -1,4 +1,20 @@ -import * as ts from 'typescript'; +import { + createBinary, + createBlock, + createCall, + createIdentifier, + createIf, + createImmediatelyInvokedArrowFunction, + createLiteral, + createMethod, + createReturn, + createThis, + createTrue, + Expression, + MethodDeclaration, + SyntaxKind, +} from 'typescript'; + import { Logger } from '../../logger'; import { convertValueToLiteral, @@ -8,7 +24,7 @@ import { getMethodsForDecorator, } from '../helpers'; -export function transformMethod(method: ts.MethodDeclaration) { +export function transformMethod(method: MethodDeclaration) { if (!method) return; const decorator = getDecorator(method), @@ -16,7 +32,7 @@ export function transformMethod(method: ts.MethodDeclaration) { decoratorArgs = getDecoratorArgs(decorator); try { - return ts.createMethod( + return createMethod( undefined, undefined, undefined, @@ -25,7 +41,7 @@ export function transformMethod(method: ts.MethodDeclaration) { method.typeParameters, method.parameters, method.type, - ts.createBlock([ts.createReturn(getMethodBlock(method, decoratorName, decoratorArgs))]) + createBlock([createReturn(getMethodBlock(method, decoratorName, decoratorArgs))]) ); } catch (e) { Logger.error('Error transforming method: ' + (method.name as any).text); @@ -33,30 +49,30 @@ export function transformMethod(method: ts.MethodDeclaration) { } } -function getMethodBlock(method: ts.MethodDeclaration, decoratorName: string, decoratorArgs: any): ts.Expression { +function getMethodBlock(method: MethodDeclaration, decoratorName: string, decoratorArgs: any): Expression { const decoratorMethod = getMethodsForDecorator(decoratorName)[0]; switch (decoratorName) { case 'CordovaCheck': case 'InstanceCheck': // TODO remove function wrapper - return ts.createImmediatelyInvokedArrowFunction([ - ts.createIf( - ts.createBinary( - ts.createCall(ts.createIdentifier(decoratorMethod), undefined, [ts.createThis()]), - ts.SyntaxKind.EqualsEqualsEqualsToken, - ts.createTrue() + return createImmediatelyInvokedArrowFunction([ + createIf( + createBinary( + createCall(createIdentifier(decoratorMethod), undefined, [createThis()]), + SyntaxKind.EqualsEqualsEqualsToken, + createTrue() ), method.body ), ]); default: - return ts.createCall(ts.createIdentifier(decoratorMethod), undefined, [ - ts.createThis(), - ts.createLiteral(decoratorArgs?.methodName || (method.name as any).text), + return createCall(createIdentifier(decoratorMethod), undefined, [ + createThis(), + createLiteral(decoratorArgs?.methodName || (method.name as any).text), convertValueToLiteral(decoratorArgs), - ts.createIdentifier('arguments'), + createIdentifier('arguments'), ]); } } diff --git a/scripts/build/transformers/plugin-class.ts b/scripts/build/transformers/plugin-class.ts index 2dde23f2..45f146d4 100644 --- a/scripts/build/transformers/plugin-class.ts +++ b/scripts/build/transformers/plugin-class.ts @@ -1,4 +1,14 @@ -import * as ts from 'typescript'; +import { + createClassDeclaration, + createIdentifier, + createProperty, + createToken, + SourceFile, + SyntaxKind, + TransformationContext, + TransformerFactory, + visitEachChild, +} from 'typescript'; import { Logger } from '../../logger'; import { convertValueToLiteral, getDecorator, getDecoratorArgs, getDecoratorName } from '../helpers'; @@ -16,10 +26,10 @@ function transformClass(cls: any, ngcBuild?: boolean) { // add plugin decorator args as static properties of the plugin's class for (const prop in pluginDecoratorArgs) { pluginStatics.push( - ts.createProperty( + createProperty( undefined, - [ts.createToken(ts.SyntaxKind.StaticKeyword)], - ts.createIdentifier(prop), + [createToken(SyntaxKind.StaticKeyword)], + createIdentifier(prop), undefined, undefined, convertValueToLiteral(pluginDecoratorArgs[prop]) @@ -28,11 +38,11 @@ function transformClass(cls: any, ngcBuild?: boolean) { } } - cls = ts.createClassDeclaration( + cls = createClassDeclaration( ngcBuild && cls.decorators && cls.decorators.length ? cls.decorators.filter(d => getDecoratorName(d) === 'Injectable') : undefined, // remove Plugin and Injectable decorators - [ts.createToken(ts.SyntaxKind.ExportKeyword)], + [createToken(SyntaxKind.ExportKeyword)], cls.name, cls.typeParameters, cls.heritageClauses, @@ -43,14 +53,14 @@ function transformClass(cls: any, ngcBuild?: boolean) { return cls; } -function transformClasses(file: ts.SourceFile, ctx: ts.TransformationContext, ngcBuild?: boolean) { +function transformClasses(file: SourceFile, ctx: TransformationContext, ngcBuild?: boolean) { Logger.silly('Transforming file: ' + file.fileName); - return ts.visitEachChild( + return visitEachChild( file, node => { if ( - node.kind !== ts.SyntaxKind.ClassDeclaration || - (node.modifiers && node.modifiers.find(v => v.kind === ts.SyntaxKind.DeclareKeyword)) + node.kind !== SyntaxKind.ClassDeclaration || + (node.modifiers && node.modifiers.find(v => v.kind === SyntaxKind.DeclareKeyword)) ) { return node; } @@ -60,11 +70,12 @@ function transformClasses(file: ts.SourceFile, ctx: ts.TransformationContext, ng ); } -export function pluginClassTransformer(ngcBuild?: boolean): ts.TransformerFactory { - return (ctx: ts.TransformationContext) => { +export function pluginClassTransformer(ngcBuild?: boolean): TransformerFactory { + return (ctx: TransformationContext) => { return tsSourceFile => { - if (tsSourceFile.fileName.indexOf('src/@awesome-cordova-plugins/plugins') > -1) + if (tsSourceFile.fileName.indexOf('src/@awesome-cordova-plugins/plugins') > -1) { return transformClasses(tsSourceFile, ctx, ngcBuild); + } return tsSourceFile; }; }; diff --git a/scripts/build/transformers/properties.ts b/scripts/build/transformers/properties.ts index 94566578..11b5a4a7 100644 --- a/scripts/build/transformers/properties.ts +++ b/scripts/build/transformers/properties.ts @@ -1,9 +1,21 @@ -import * as ts from 'typescript'; +import { + createBlock, + createCall, + createGetAccessor, + createIdentifier, + createLiteral, + createParameter, + createReturn, + createSetAccessor, + createStatement, + createThis, + PropertyDeclaration, +} from 'typescript'; import { getDecorator, getDecoratorName } from '../helpers'; export function transformProperty(members: any[], index: number) { - const property = members[index] as ts.PropertyDeclaration, + const property = members[index] as PropertyDeclaration, decorator = getDecorator(property), decoratorName = getDecoratorName(decorator); @@ -22,33 +34,33 @@ export function transformProperty(members: any[], index: number) { return property; } - const getter = ts.createGetAccessor( + const getter = createGetAccessor( undefined, undefined, property.name, undefined, property.type, - ts.createBlock([ - ts.createReturn( - ts.createCall(ts.createIdentifier(type + 'PropertyGet'), undefined, [ - ts.createThis(), - ts.createLiteral((property.name as any).text), + createBlock([ + createReturn( + createCall(createIdentifier(type + 'PropertyGet'), undefined, [ + createThis(), + createLiteral((property.name as any).text), ]) ), ]) ); - const setter = ts.createSetAccessor( + const setter = createSetAccessor( undefined, undefined, property.name, - [ts.createParameter(undefined, undefined, undefined, 'value', undefined, property.type)], - ts.createBlock([ - ts.createStatement( - ts.createCall(ts.createIdentifier(type + 'PropertySet'), undefined, [ - ts.createThis(), - ts.createLiteral((property.name as any).text), - ts.createIdentifier('value'), + [createParameter(undefined, undefined, undefined, 'value', undefined, property.type)], + createBlock([ + createStatement( + createCall(createIdentifier(type + 'PropertySet'), undefined, [ + createThis(), + createLiteral((property.name as any).text), + createIdentifier('value'), ]) ), ]) diff --git a/scripts/build/transpile.ts b/scripts/build/transpile.ts index 5f1c2490..f6d044bf 100644 --- a/scripts/build/transpile.ts +++ b/scripts/build/transpile.ts @@ -1,28 +1,37 @@ -import * as ts from 'typescript'; -import { pluginClassTransformer } from './transformers/plugin-class'; -import { importsTransformer } from './transformers/imports'; import { clone } from 'lodash'; -import { emitInjectableClasses, extractInjectables } from './transformers/extract-injectables'; -import { COMPILER_OPTIONS, PLUGIN_PATHS, TS_CONFIG } from './helpers'; +import { + CompilerHost, + CompilerOptions, + createCompilerHost, + createProgram, + ModuleKind, + ModuleResolutionKind, + ScriptTarget, +} from 'typescript'; -let host: ts.CompilerHost; +import { COMPILER_OPTIONS, PLUGIN_PATHS, TS_CONFIG } from './helpers'; +import { emitInjectableClasses, extractInjectables } from './transformers/extract-injectables'; +import { importsTransformer } from './transformers/imports'; +import { pluginClassTransformer } from './transformers/plugin-class'; + +let host: CompilerHost; export function getCompilerHost() { - if (!host) host = ts.createCompilerHost(TS_CONFIG); + if (!host) host = createCompilerHost(TS_CONFIG); return host; } export function getProgram(declaration = false, pluginPaths: string[] = PLUGIN_PATHS) { - const compilerOptions: ts.CompilerOptions = clone(COMPILER_OPTIONS); + const compilerOptions: CompilerOptions = clone(COMPILER_OPTIONS); compilerOptions.declaration = declaration; - compilerOptions.moduleResolution = ts.ModuleResolutionKind.NodeJs; - compilerOptions.target = ts.ScriptTarget.ES5; - compilerOptions.module = ts.ModuleKind.ES2015; + compilerOptions.moduleResolution = ModuleResolutionKind.NodeJs; + compilerOptions.target = ScriptTarget.ES5; + compilerOptions.module = ModuleKind.ES2015; compilerOptions.inlineSourceMap = true; compilerOptions.inlineSources = true; compilerOptions.lib = ['lib.dom.d.ts', 'lib.es5.d.ts', 'lib.es2015.d.ts', 'lib.es2016.d.ts', 'lib.es2017.d.ts']; - return ts.createProgram(pluginPaths, compilerOptions, getCompilerHost()); + return createProgram(pluginPaths, compilerOptions, getCompilerHost()); } export function generateDeclarations(sourceFiles?: string[]) {