refactor(build): lint build scripts

This commit is contained in:
Daniel 2018-03-23 10:57:54 +01:00
parent d7829e4012
commit c15b78bab2
12 changed files with 201 additions and 121 deletions

View File

@ -5,12 +5,13 @@ import { camelCase, clone } from 'lodash';
import { Logger } from '../logger';
export const ROOT = path.resolve(__dirname, '../../');
// tslint:disable-next-line:no-var-requires
export const TS_CONFIG = clone(require(path.resolve(ROOT, 'tsconfig.json')));
export const COMPILER_OPTIONS = TS_CONFIG.compilerOptions;
export const PLUGINS_ROOT = path.join(ROOT, 'src/@ionic-native/plugins/');
export const PLUGIN_PATHS = fs.readdirSync(PLUGINS_ROOT).map(d => path.join(PLUGINS_ROOT, d, 'index.ts'));
export function getDecorator(node: ts.Node, index: number = 0): ts.Decorator {
export function getDecorator(node: ts.Node, index = 0): ts.Decorator {
if (node.decorators && node.decorators[index])
return node.decorators[index];
}
@ -59,7 +60,7 @@ export function getDecoratorArgs(decorator: any) {
default:
Logger.debug('Unexpected property value type: ' + prop.initializer.kind);
throw 'Unexpected property value type << helpers.ts >>';
throw new Error('Unexpected property value type << helpers.ts >>');
}
args[prop.name.text] = val;

View File

@ -1,6 +1,7 @@
import * as ts from 'typescript';
import * as fs from 'fs-extra';
import * as path from 'path';
import * as ts from 'typescript';
import { hasDecorator, ROOT } from '../helpers';
export interface InjectableClassEntry {
@ -24,7 +25,9 @@ export function extractInjectables() {
return (ctx: ts.TransformationContext) => {
return tsSourceFile => {
if (tsSourceFile.fileName.indexOf('src/@ionic-native/plugins') > -1) {
ts.visitEachChild(tsSourceFile, node => {
ts.visitEachChild(
tsSourceFile,
node => {
if (node.kind !== ts.SyntaxKind.ClassDeclaration) {
return node;
}
@ -37,11 +40,13 @@ export function extractInjectables() {
dirName: tsSourceFile.path.split(/[\\\/]+/).reverse()[1]
});
}
}, ctx);
},
ctx
);
}
return tsSourceFile;
}
};
};
}

View File

@ -15,7 +15,7 @@ function transformImports(file: ts.SourceFile, ctx: ts.TransformationContext, ng
// we're only interested in files containing @ionic-native/core import statement
if (!importStatement) return file;
let decorators: string[] = [];
const decorators: string[] = [];
const decoratorRegex: RegExp = /@([a-zA-Z]+)\(/g;
@ -48,6 +48,6 @@ export function importsTransformer(ngcBuild?: boolean) {
return (ctx: ts.TransformationContext) => {
return tsSourceFile => {
return transformImports(tsSourceFile, ctx, ngcBuild);
}
};
};
}

View File

@ -5,7 +5,7 @@ import { transformProperty } from './properties';
export function transformMembers(cls: ts.ClassDeclaration) {
const propertyIndices: number[] = [];
let members = cls.members.map((member: any, index: number) => {
const members = cls.members.map((member: any, index: number) => {
// only process decorated members
if (!member.decorators || !member.decorators.length) return member;

View File

@ -1,10 +1,15 @@
import * as ts from 'typescript';
import { Logger } from '../../logger';
import { convertValueToLiteral, getDecorator, getDecoratorArgs, getDecoratorName } from '../helpers';
import {
convertValueToLiteral,
getDecorator,
getDecoratorArgs,
getDecoratorName
} from '../helpers';
import { transformMembers } from './members';
function transformClass(cls: any, ngcBuild?: boolean) {
Logger.profile('transformClass: ' + cls.name.text);
const pluginStatics = [];
@ -14,45 +19,56 @@ function transformClass(cls: any, ngcBuild?: boolean) {
const pluginDecoratorArgs = getDecoratorArgs(dec);
// add plugin decorator args as static properties of the plugin's class
for (let prop in pluginDecoratorArgs) {
pluginStatics.push(ts.createProperty(
for (const prop in pluginDecoratorArgs) {
pluginStatics.push(
ts.createProperty(
undefined,
[ts.createToken(ts.SyntaxKind.StaticKeyword)],
ts.createIdentifier(prop),
undefined,
undefined,
convertValueToLiteral(pluginDecoratorArgs[prop])
));
)
);
}
}
cls = ts.createClassDeclaration(
ngcBuild && cls.decorators && cls.decorators.length? cls.decorators.filter(d => getDecoratorName(d) === 'Injectable') : undefined, // remove Plugin and Injectable decorators
ngcBuild && cls.decorators && cls.decorators.length
? cls.decorators.filter(d => getDecoratorName(d) === 'Injectable')
: undefined, // remove Plugin and Injectable decorators
[ts.createToken(ts.SyntaxKind.ExportKeyword)],
cls.name,
cls.typeParameters,
cls.heritageClauses,
[
...transformMembers(cls),
...pluginStatics
]
[...transformMembers(cls), ...pluginStatics]
);
Logger.profile('transformClass: ' + cls.name.text, { level: 'verbose' });
return cls;
}
function transformClasses(file: ts.SourceFile, ctx: ts.TransformationContext, ngcBuild?: boolean) {
function transformClasses(
file: ts.SourceFile,
ctx: ts.TransformationContext,
ngcBuild?: boolean
) {
Logger.silly('Transforming file: ' + file.fileName);
return ts.visitEachChild(file, node => {
return ts.visitEachChild(
file,
node => {
if (node.kind !== ts.SyntaxKind.ClassDeclaration) {
return node;
}
return transformClass(node, ngcBuild);
}, ctx);
},
ctx
);
}
export function pluginClassTransformer(ngcBuild?: boolean): ts.TransformerFactory<ts.SourceFile> {
export function pluginClassTransformer(
ngcBuild?: boolean
): ts.TransformerFactory<ts.SourceFile> {
return (ctx: ts.TransformationContext) => {
return tsSourceFile => {
if (tsSourceFile.fileName.indexOf('src/@ionic-native/plugins') > -1)

View File

@ -1,8 +1,8 @@
import * as ts from 'typescript';
import { getDecorator, getDecoratorName } from '../helpers';
export function transformProperty(members: any[], index: number) {
const property = members[index] as ts.PropertyDeclaration,
decorator = getDecorator(property),
decoratorName = getDecoratorName(decorator);
@ -18,36 +18,50 @@ export function transformProperty(members: any[], index: number) {
type = 'instance';
break;
default: return property;
default:
return property;
}
const getter = ts.createGetAccessor(undefined, undefined, property.name, undefined, property.type, ts.createBlock([
ts.createReturn(
ts.createCall(
ts.createIdentifier(type + 'PropertyGet'),
const getter = ts.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)
]
])
)
)
]));
])
);
const setter = ts.createSetAccessor(undefined, undefined, property.name, [ts.createParameter(undefined, undefined, undefined, 'value', undefined, property.type)], ts.createBlock([
ts.createStatement(
ts.createCall(
ts.createIdentifier(type + 'PropertySet'),
const setter = ts.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')
]
])
)
)
]));
])
);
return [getter, setter];
}

View File

@ -12,7 +12,7 @@ export function getCompilerHost() {
return host;
}
export function getProgram(declaration: boolean = false, pluginPaths: string[] = PLUGIN_PATHS) {
export function getProgram(declaration = false, pluginPaths: string[] = PLUGIN_PATHS) {
const compilerOptions: ts.CompilerOptions = clone(COMPILER_OPTIONS);
compilerOptions.declaration = declaration;
compilerOptions.moduleResolution = ts.ModuleResolutionKind.NodeJs;

View File

@ -1,13 +1,11 @@
import { createLogger, transports, format } from 'winston';
import { createLogger, format, transports } from 'winston';
const { label, printf, prettyPrint, combine, colorize, simple } = format;
const LOG_LEVEL = 'silly';
export const Logger = createLogger({
level: LOG_LEVEL,
format: combine(
colorize(),
simple(),
),
format: combine(colorize(), simple()),
transports: [new transports.Console({ level: LOG_LEVEL })]
});

View File

@ -1,16 +1,28 @@
import * as fs from 'fs-extra';
import * as path from 'path';
import * as webpack from 'webpack';
import * as uglifyJsPlugin from 'uglifyjs-webpack-plugin';
import * as unminifiedPlugin from 'unminified-webpack-plugin';
import { cleanEmittedData, EMIT_PATH, InjectableClassEntry } from '../build/transformers/extract-injectables';
import * as webpack from 'webpack';
import { ROOT } from '../build/helpers';
import {
cleanEmittedData,
EMIT_PATH,
InjectableClassEntry
} from '../build/transformers/extract-injectables';
import { Logger } from '../logger';
const DIST = path.resolve(ROOT, 'dist');
const INDEX_PATH = path.resolve(DIST, 'index.js');
const INJECTABLE_CLASSES = fs.readJSONSync(EMIT_PATH).map((item: InjectableClassEntry) => {
item.file = './' + item.file.split(/[\/\\]+/).slice(-4, -1).join('/');
const INJECTABLE_CLASSES = fs
.readJSONSync(EMIT_PATH)
.map((item: InjectableClassEntry) => {
item.file =
'./' +
item.file
.split(/[\/\\]+/)
.slice(-4, -1)
.join('/');
return item;
});
@ -31,14 +43,16 @@ const webpackConfig: webpack.Configuration = {
}
},
module: {
rules: [{
rules: [
{
test: /\.js$/,
use: path.resolve(ROOT, 'scripts/build/remove-tslib-helpers.js')
}]
}
]
},
plugins: [
new webpack.ProvidePlugin({
'__extends': ['tslib', '__extends']
__extends: ['tslib', '__extends']
}),
new webpack.optimize.OccurrenceOrderPlugin(true),
new webpack.DefinePlugin({

View File

@ -1,27 +1,44 @@
import { generateDeclarations, transpile } from '../build/transpile';
import { EMIT_PATH } from '../build/transformers/extract-injectables';
import { PLUGIN_PATHS } from '../build/helpers';
import * as fs from 'fs-extra';
import * as path from 'path';
import { PLUGIN_PATHS } from '../build/helpers';
import { EMIT_PATH } from '../build/transformers/extract-injectables';
import { generateDeclarations, transpile } from '../build/transpile';
generateDeclarations();
transpile();
const outDirs = PLUGIN_PATHS.map(p => p.replace('src', 'dist').replace(/[\\/]index.ts/, ''));
const outDirs = PLUGIN_PATHS.map(p =>
p.replace('src', 'dist').replace(/[\\/]index.ts/, '')
);
const injectableClasses = fs.readJSONSync(EMIT_PATH);
outDirs.forEach(dir => {
const classes = injectableClasses.filter(entry => entry.dirName === dir.split(/[\\/]+/).pop());
const classes = injectableClasses.filter(
entry => entry.dirName === dir.split(/[\\/]+/).pop()
);
let jsFile: string = fs.readFileSync(path.join(dir, 'index.js'), 'utf-8'),
dtsFile: string = fs.readFileSync(path.join(dir, 'index.d.ts'), 'utf-8');
classes.forEach(entry => {
dtsFile = dtsFile.replace(`class ${ entry.className } `, 'class ' + entry.className + 'Original ');
dtsFile += `\nexport declare const ${ entry.className }: ${ entry.className }Original;`;
jsFile = jsFile.replace(new RegExp(`([\\s\\(])${ entry.className }([\\s\\.;\\(,])`, 'g'), '$1' + entry.className + 'Original$2');
jsFile = jsFile.replace(`export { ${ entry.className }Original }`, `var ${ entry.className } = new ${ entry.className }Original();\nexport { ${ entry.className } }`);
dtsFile = dtsFile.replace(
`class ${entry.className} `,
'class ' + entry.className + 'Original '
);
dtsFile += `\nexport declare const ${entry.className}: ${
entry.className
}Original;`;
jsFile = jsFile.replace(
new RegExp(`([\\s\\(])${entry.className}([\\s\\.;\\(,])`, 'g'),
'$1' + entry.className + 'Original$2'
);
jsFile = jsFile.replace(
`export { ${entry.className}Original }`,
`var ${entry.className} = new ${entry.className}Original();\nexport { ${
entry.className
} }`
);
});
fs.writeFileSync(path.join(dir, 'index.js'), jsFile, 'utf-8');

View File

@ -1,4 +1,10 @@
import { generateDeclarationFiles, transpileNgx, transpileNgxCore, modifyMetadata, cleanupNgx } from '../build/ngx';
import {
cleanupNgx,
generateDeclarationFiles,
modifyMetadata,
transpileNgx,
transpileNgxCore
} from '../build/ngx';
transpileNgxCore();
transpileNgx();

View File

@ -1,25 +1,27 @@
import * as fs from 'fs-extra';
import * as path from 'path';
import { merge } from 'lodash';
import { exec } from 'child_process';
import { PLUGIN_PATHS, ROOT } from '../build/helpers';
import { cpus } from 'os';
import * as Queue from 'async-promise-queue';
import { exec } from 'child_process';
import * as fs from 'fs-extra';
import { merge } from 'lodash';
import { cpus } from 'os';
import * as path from 'path';
import { PLUGIN_PATHS, ROOT } from '../build/helpers';
import { Logger } from '../logger';
// tslint:disable-next-line:no-var-requires
const MAIN_PACKAGE_JSON = require('../../package.json');
const VERSION = MAIN_PACKAGE_JSON.version;
const FLAGS = '--access public --tag beta';
const PACKAGE_JSON_BASE = {
'description': 'Ionic Native - Native plugins for ionic apps',
'module': 'index.js',
'typings': 'index.d.ts',
'author': 'ionic',
'license': 'MIT',
'repository': {
'type': 'git',
'url': 'https://github.com/ionic-team/ionic-native.git'
description: 'Ionic Native - Native plugins for ionic apps',
module: 'index.js',
typings: 'index.d.ts',
author: 'ionic',
license: 'MIT',
repository: {
type: 'git',
url: 'https://github.com/ionic-team/ionic-native.git'
}
};
@ -32,7 +34,7 @@ const CORE_VERSION = '^5.0.0';
const PLUGIN_PEER_DEPENDENCIES = {
'@ionic-native/core': VERSION, // TODO change this in production
'rxjs': RXJS_VEERSION
rxjs: RXJS_VEERSION
};
function getPackageJsonContent(name, peerDependencies = {}) {
@ -52,21 +54,24 @@ function writePackageJson(data: any, dir: string) {
function prepare() {
// write @ionic-native/core package.json
writePackageJson(
getPackageJsonContent('core', { 'rxjs': RXJS_VEERSION }),
getPackageJsonContent('core', { rxjs: RXJS_VEERSION }),
path.resolve(DIST, 'core')
);
// write plugin package.json files
PLUGIN_PATHS.forEach((pluginPath: string) => {
const pluginName = pluginPath.split(/[\/\\]+/).slice(-2)[0];
const packageJsonContents = getPackageJsonContent(pluginName, PLUGIN_PEER_DEPENDENCIES);
const packageJsonContents = getPackageJsonContent(
pluginName,
PLUGIN_PEER_DEPENDENCIES
);
const dir = path.resolve(DIST, 'plugins', pluginName);
writePackageJson(packageJsonContents, dir);
});
}
async function publish(ignoreErrors: boolean = false) {
async function publish(ignoreErrors = false) {
Logger.profile('Publishing');
// upload 1 package per CPU thread at a time
const worker = Queue.async.asyncify((pkg: any) => {
@ -78,7 +83,11 @@ async function publish(ignoreErrors: boolean = false) {
}
if (err) {
if (!ignoreErrors) {
if (err.message.includes('You cannot publish over the previously published version')) {
if (
err.message.includes(
'You cannot publish over the previously published version'
)
) {
Logger.verbose('Ignoring duplicate version error.');
return resolve();
}