mirror of
https://github.com/danielsogl/awesome-cordova-plugins.git
synced 2026-05-20 00:06:24 +08:00
refactor: replace build dependencies with native Node.js APIs
Replace fs-extra/rimraf with native node:fs, lodash with structuredClone/spread, ts-node with tsx, minimist with node:util parseArgs, winston with console logger, async-promise-queue with native Promise concurrency. Use promisify for child_process.exec. Normalize all imports to use node: protocol. Extract Jest config to jest.config.ts and replace ts-jest with @swc/jest.
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
import type { Config } from 'jest';
|
||||
|
||||
const config: Config = {
|
||||
testEnvironment: 'jsdom',
|
||||
transform: {
|
||||
'^.+\\.tsx?$': '@swc/jest',
|
||||
},
|
||||
testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.(js?|ts?)$',
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'],
|
||||
};
|
||||
|
||||
export default config;
|
||||
+12
-13
@@ -1,11 +1,13 @@
|
||||
import { readdirSync } from 'fs-extra';
|
||||
import { camelCase, clone } from 'lodash';
|
||||
import { join, resolve } from 'path';
|
||||
import { readdirSync } from 'node:fs';
|
||||
import { readFileSync } from 'node:fs';
|
||||
import { join, resolve } from 'node:path';
|
||||
import {
|
||||
ArrayLiteralExpression,
|
||||
canHaveDecorators,
|
||||
Decorator,
|
||||
Expression,
|
||||
factory,
|
||||
getDecorators as tsGetDecorators,
|
||||
Node,
|
||||
ObjectLiteralElementLike,
|
||||
ObjectLiteralExpression,
|
||||
@@ -15,24 +17,21 @@ import {
|
||||
import { Logger } from '../logger';
|
||||
|
||||
export const ROOT = resolve(__dirname, '../../');
|
||||
// tslint:disable-next-line:no-var-requires
|
||||
export const TS_CONFIG = clone(require(resolve(ROOT, 'tsconfig.json')));
|
||||
export const TS_CONFIG = JSON.parse(readFileSync(resolve(ROOT, 'tsconfig.json'), 'utf-8'));
|
||||
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: Node, index = 0): Decorator {
|
||||
if (node.decorators && node.decorators[index]) {
|
||||
return node.decorators[index];
|
||||
const decorators = canHaveDecorators(node) ? tsGetDecorators(node) : undefined;
|
||||
if (decorators && decorators[index]) {
|
||||
return decorators[index];
|
||||
}
|
||||
}
|
||||
|
||||
export function hasDecorator(decoratorName: string, node: Node): boolean {
|
||||
return (
|
||||
node.decorators &&
|
||||
node.decorators.length &&
|
||||
node.decorators.findIndex((d) => getDecoratorName(d) === decoratorName) > -1
|
||||
);
|
||||
const decorators = canHaveDecorators(node) ? tsGetDecorators(node) : undefined;
|
||||
return decorators && decorators.length > 0 && decorators.findIndex((d) => getDecoratorName(d) === decoratorName) > -1;
|
||||
}
|
||||
|
||||
export function getDecoratorName(decorator: any) {
|
||||
@@ -148,5 +147,5 @@ export function getMethodsForDecorator(decoratorName: string) {
|
||||
return ['instanceAvailability'];
|
||||
}
|
||||
|
||||
return [camelCase(decoratorName)];
|
||||
return [decoratorName.charAt(0).toLowerCase() + decoratorName.slice(1)];
|
||||
}
|
||||
|
||||
+12
-13
@@ -1,8 +1,6 @@
|
||||
import { CompilerHost, CompilerOptions, createCompilerHost, createProgram, EmitFlags } from '@angular/compiler-cli';
|
||||
import { copyFileSync, mkdirpSync, readJSONSync, writeJSONSync } from 'fs-extra';
|
||||
import { clone } from 'lodash';
|
||||
import { dirname, join, resolve } from 'path';
|
||||
import { sync } from 'rimraf';
|
||||
import { copyFileSync, mkdirSync, rmSync } from 'node:fs';
|
||||
import { dirname, join, resolve } from 'node:path';
|
||||
import { rollup } from 'rollup';
|
||||
import { ModuleKind, ModuleResolutionKind, ScriptTarget } from 'typescript';
|
||||
|
||||
@@ -12,16 +10,15 @@ import { pluginClassTransformer } from './transformers/plugin-class';
|
||||
import { generateDeclarations } from './transpile';
|
||||
|
||||
export function getProgram(rootNames: string[] = createSourceFiles()) {
|
||||
const options: CompilerOptions = clone(COMPILER_OPTIONS);
|
||||
const options: CompilerOptions = structuredClone(COMPILER_OPTIONS);
|
||||
options.basePath = ROOT;
|
||||
options.moduleResolution = ModuleResolutionKind.NodeJs;
|
||||
options.module = ModuleKind.ES2015;
|
||||
options.target = ScriptTarget.ES5;
|
||||
options.lib = ['dom', 'es2017'];
|
||||
options.moduleResolution = ModuleResolutionKind.Node16;
|
||||
options.module = ModuleKind.ES2022;
|
||||
options.target = ScriptTarget.ES2022;
|
||||
options.lib = ['dom', 'es2022'];
|
||||
options.inlineSourceMap = true;
|
||||
options.importHelpers = true;
|
||||
options.inlineSources = true;
|
||||
options.enableIvy = true;
|
||||
options.compilationMode = 'partial';
|
||||
|
||||
delete options.baseUrl;
|
||||
@@ -84,8 +81,8 @@ function createSourceFiles(): string[] {
|
||||
newPath = resolve(ngxPath, 'index.ts');
|
||||
|
||||
// delete directory
|
||||
sync(ngxPath);
|
||||
mkdirpSync(ngxPath);
|
||||
rmSync(ngxPath, { recursive: true, force: true });
|
||||
mkdirSync(ngxPath, { recursive: true });
|
||||
copyFileSync(indexPath, newPath);
|
||||
|
||||
return newPath;
|
||||
@@ -93,5 +90,7 @@ function createSourceFiles(): string[] {
|
||||
}
|
||||
|
||||
export function cleanupNgx() {
|
||||
PLUGIN_PATHS.forEach((indexPath: string) => sync(indexPath.replace('index.ts', 'ngx')));
|
||||
PLUGIN_PATHS.forEach((indexPath: string) =>
|
||||
rmSync(indexPath.replace('index.ts', 'ngx'), { recursive: true, force: true })
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
// removes the __extends method that is added automatically by typescript
|
||||
module.exports = (source) => source.replace(/var\s__extends\s=\s\(this\s&&[\sa-z\._\(\)\|{}=:\[\]&,;?]+}\)\(\);/i, '');
|
||||
@@ -1,5 +1,5 @@
|
||||
import { unlinkSync, writeJSONSync } from 'fs-extra';
|
||||
import { resolve } from 'path';
|
||||
import { unlinkSync, writeFileSync } from 'node:fs';
|
||||
import { resolve } from 'node:path';
|
||||
import { ClassDeclaration, SyntaxKind, TransformationContext, visitEachChild } from 'typescript';
|
||||
|
||||
import { hasDecorator, ROOT } from '../helpers';
|
||||
@@ -51,7 +51,7 @@ export function extractInjectables() {
|
||||
}
|
||||
|
||||
export function emitInjectableClasses() {
|
||||
writeJSONSync(EMIT_PATH, injectableClasses);
|
||||
writeFileSync(EMIT_PATH, JSON.stringify(injectableClasses, null, 2));
|
||||
}
|
||||
|
||||
export function cleanEmittedData() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ClassDeclaration, factory, SyntaxKind } from 'typescript';
|
||||
import { canHaveDecorators, ClassDeclaration, factory, getDecorators as tsGetDecorators, SyntaxKind } from 'typescript';
|
||||
|
||||
import { transformMethod } from './methods';
|
||||
import { transformProperty } from './properties';
|
||||
@@ -8,7 +8,8 @@ export function transformMembers(cls: ClassDeclaration) {
|
||||
|
||||
const members = cls.members.map((member: any, index: number) => {
|
||||
// only process decorated members
|
||||
if (!member.decorators || !member.decorators.length) return member;
|
||||
const memberDecorators = canHaveDecorators(member) ? tsGetDecorators(member) : undefined;
|
||||
if (!memberDecorators || !memberDecorators.length) return member;
|
||||
|
||||
switch (member.kind) {
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
@@ -17,7 +18,7 @@ export function transformMembers(cls: ClassDeclaration) {
|
||||
propertyIndices.push(index);
|
||||
return member;
|
||||
case SyntaxKind.Constructor:
|
||||
return factory.createConstructorDeclaration(undefined, undefined, member.parameters, member.body);
|
||||
return factory.createConstructorDeclaration(undefined, member.parameters, member.body);
|
||||
default:
|
||||
return member; // in case anything gets here by accident...
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ export function transformMethod(method: MethodDeclaration) {
|
||||
|
||||
try {
|
||||
return factory.createMethodDeclaration(
|
||||
undefined,
|
||||
undefined,
|
||||
undefined,
|
||||
method.name,
|
||||
@@ -40,7 +39,6 @@ function getMethodBlock(method: MethodDeclaration, decoratorName: string, decora
|
||||
switch (decoratorName) {
|
||||
case 'CordovaCheck':
|
||||
case 'InstanceCheck':
|
||||
// TODO remove function wrapper
|
||||
return factory.createImmediatelyInvokedArrowFunction([
|
||||
factory.createIfStatement(
|
||||
factory.createBinaryExpression(
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import {
|
||||
canHaveDecorators,
|
||||
canHaveModifiers,
|
||||
Decorator,
|
||||
factory,
|
||||
getDecorators as tsGetDecorators,
|
||||
getModifiers as tsGetModifiers,
|
||||
SourceFile,
|
||||
SyntaxKind,
|
||||
TransformationContext,
|
||||
@@ -25,7 +29,6 @@ function transformClass(cls: any, ngcBuild?: boolean) {
|
||||
for (const prop in pluginDecoratorArgs) {
|
||||
pluginStatics.push(
|
||||
factory.createPropertyDeclaration(
|
||||
undefined,
|
||||
[factory.createToken(SyntaxKind.StaticKeyword)],
|
||||
factory.createIdentifier(prop),
|
||||
undefined,
|
||||
@@ -36,11 +39,14 @@ function transformClass(cls: any, ngcBuild?: boolean) {
|
||||
}
|
||||
}
|
||||
|
||||
const clsDecorators = canHaveDecorators(cls) ? tsGetDecorators(cls) : undefined;
|
||||
const keepDecorators =
|
||||
ngcBuild && clsDecorators && clsDecorators.length
|
||||
? clsDecorators.filter((d: Decorator) => getDecoratorName(d) === 'Injectable')
|
||||
: [];
|
||||
|
||||
cls = factory.createClassDeclaration(
|
||||
ngcBuild && cls.decorators && cls.decorators.length
|
||||
? cls.decorators.filter((d) => getDecoratorName(d) === 'Injectable')
|
||||
: undefined, // remove Plugin and Injectable decorators
|
||||
[factory.createToken(SyntaxKind.ExportKeyword)],
|
||||
[...keepDecorators, factory.createToken(SyntaxKind.ExportKeyword)],
|
||||
cls.name,
|
||||
cls.typeParameters,
|
||||
cls.heritageClauses,
|
||||
@@ -58,7 +64,7 @@ function transformClasses(file: SourceFile, ctx: TransformationContext, ngcBuild
|
||||
(node) => {
|
||||
if (
|
||||
node.kind !== SyntaxKind.ClassDeclaration ||
|
||||
(node.modifiers && node.modifiers.find((v) => v.kind === SyntaxKind.DeclareKeyword))
|
||||
(canHaveModifiers(node) ? tsGetModifiers(node) : undefined)?.find((v) => v.kind === SyntaxKind.DeclareKeyword)
|
||||
) {
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -23,10 +23,9 @@ export function transformProperty(members: any[], index: number) {
|
||||
}
|
||||
|
||||
const getter = factory.createGetAccessorDeclaration(
|
||||
undefined,
|
||||
undefined,
|
||||
property.name,
|
||||
undefined,
|
||||
[],
|
||||
property.type,
|
||||
factory.createBlock([
|
||||
factory.createReturnStatement(
|
||||
@@ -39,10 +38,9 @@ export function transformProperty(members: any[], index: number) {
|
||||
);
|
||||
|
||||
const setter = factory.createSetAccessorDeclaration(
|
||||
undefined,
|
||||
undefined,
|
||||
property.name,
|
||||
[factory.createParameterDeclaration(undefined, undefined, undefined, 'value', undefined, property.type)],
|
||||
[factory.createParameterDeclaration(undefined, undefined, 'value', undefined, property.type)],
|
||||
factory.createBlock([
|
||||
factory.createExpressionStatement(
|
||||
factory.createCallExpression(factory.createIdentifier(type + 'PropertySet'), undefined, [
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { clone } from 'lodash';
|
||||
import {
|
||||
CompilerHost,
|
||||
CompilerOptions,
|
||||
@@ -22,14 +21,14 @@ export function getCompilerHost() {
|
||||
}
|
||||
|
||||
export function getProgram(declaration = false, pluginPaths: string[] = PLUGIN_PATHS) {
|
||||
const compilerOptions: CompilerOptions = clone(COMPILER_OPTIONS);
|
||||
const compilerOptions: CompilerOptions = structuredClone(COMPILER_OPTIONS);
|
||||
compilerOptions.declaration = declaration;
|
||||
compilerOptions.moduleResolution = ModuleResolutionKind.NodeJs;
|
||||
compilerOptions.target = ScriptTarget.ES5;
|
||||
compilerOptions.module = ModuleKind.ES2015;
|
||||
compilerOptions.moduleResolution = ModuleResolutionKind.Node16;
|
||||
compilerOptions.target = ScriptTarget.ES2022;
|
||||
compilerOptions.module = ModuleKind.ES2022;
|
||||
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'];
|
||||
compilerOptions.lib = ['lib.dom.d.ts', 'lib.es2022.d.ts'];
|
||||
|
||||
return createProgram(pluginPaths, compilerOptions, getCompilerHost());
|
||||
}
|
||||
|
||||
+29
-10
@@ -1,11 +1,30 @@
|
||||
import { createLogger, format, transports } from 'winston';
|
||||
const profiles = new Map<string, number>();
|
||||
|
||||
const { combine, colorize, simple } = format;
|
||||
|
||||
const LOG_LEVEL = 'verbose';
|
||||
|
||||
export const Logger = createLogger({
|
||||
level: LOG_LEVEL,
|
||||
format: combine(colorize(), simple()),
|
||||
transports: [new transports.Console({ level: LOG_LEVEL })],
|
||||
});
|
||||
export const Logger = {
|
||||
error(...args: unknown[]) {
|
||||
console.error('[error]', ...args);
|
||||
},
|
||||
info(...args: unknown[]) {
|
||||
console.info('[info]', ...args);
|
||||
},
|
||||
verbose(...args: unknown[]) {
|
||||
console.log('[verbose]', ...args);
|
||||
},
|
||||
debug(...args: unknown[]) {
|
||||
console.debug('[debug]', ...args);
|
||||
},
|
||||
silly(...args: unknown[]) {
|
||||
console.debug('[silly]', ...args);
|
||||
},
|
||||
profile(label: string) {
|
||||
const now = performance.now();
|
||||
const start = profiles.get(label);
|
||||
if (start !== undefined) {
|
||||
const durationMs = Math.round(now - start);
|
||||
console.info(`[info] ${label} {"durationMs":${durationMs}}`);
|
||||
profiles.delete(label);
|
||||
} else {
|
||||
profiles.set(label, now);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
import { readJSONSync, writeFileSync } from 'fs-extra';
|
||||
import { resolve } from 'path';
|
||||
import * as TerserPlugin from 'terser-webpack-plugin';
|
||||
import * as unminifiedPlugin from 'unminified-webpack-plugin';
|
||||
import { Configuration, DefinePlugin, ProvidePlugin, webpack } from 'webpack';
|
||||
|
||||
import { ROOT } from '../build/helpers';
|
||||
import { cleanEmittedData, EMIT_PATH, InjectableClassEntry } from '../build/transformers/extract-injectables';
|
||||
import { Logger } from '../logger';
|
||||
|
||||
const DIST = resolve(ROOT, 'dist');
|
||||
const INDEX_PATH = resolve(DIST, 'index.js');
|
||||
const INJECTABLE_CLASSES = readJSONSync(EMIT_PATH).map((item: InjectableClassEntry) => {
|
||||
item.file =
|
||||
'./' +
|
||||
item.file
|
||||
.split(/[\/\\]+/)
|
||||
.slice(-4, -1)
|
||||
.join('/');
|
||||
return item;
|
||||
});
|
||||
|
||||
const webpackConfig: Configuration = {
|
||||
mode: 'production',
|
||||
entry: INDEX_PATH,
|
||||
devtool: 'source-map',
|
||||
target: 'web',
|
||||
output: {
|
||||
path: DIST,
|
||||
filename: 'awesome-cordova-plugins.min.js',
|
||||
},
|
||||
resolve: {
|
||||
modules: ['node_modules'],
|
||||
extensions: ['.js'],
|
||||
alias: {
|
||||
'@awesome-cordova-plugins/core': resolve(DIST, '@awesome-cordova-plugins/core/index.js'),
|
||||
},
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
use: resolve(ROOT, 'scripts/build/remove-tslib-helpers.js'),
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new ProvidePlugin({
|
||||
__extends: ['tslib', '__extends'],
|
||||
}),
|
||||
new DefinePlugin({
|
||||
'process.env.NODE_ENV': JSON.stringify('production'),
|
||||
}),
|
||||
new unminifiedPlugin(),
|
||||
],
|
||||
optimization: {
|
||||
minimize: true,
|
||||
minimizer: [new TerserPlugin()],
|
||||
},
|
||||
};
|
||||
|
||||
function getPluginImport(entry: InjectableClassEntry) {
|
||||
return `import { ${entry.className} } from '${entry.file}';`;
|
||||
}
|
||||
|
||||
function createIndexFile() {
|
||||
let fileContent = '';
|
||||
fileContent += INJECTABLE_CLASSES.map(getPluginImport).join('\n');
|
||||
fileContent += `\nwindow.IonicNative = {\n`;
|
||||
fileContent += INJECTABLE_CLASSES.map((e) => e.className).join(',\n');
|
||||
fileContent += '\n};\n';
|
||||
fileContent += `require('./@awesome-cordova-plugins/core/bootstrap').checkReady();\n`;
|
||||
fileContent += `require('./@awesome-cordova-plugins/core/ng1').initAngular1(window.IonicNative);`;
|
||||
|
||||
writeFileSync(INDEX_PATH, fileContent, { encoding: 'utf-8' });
|
||||
}
|
||||
|
||||
function compile() {
|
||||
Logger.profile('build-es5');
|
||||
webpack(webpackConfig, (err, stats) => {
|
||||
Logger.profile('build-es5');
|
||||
if (err) Logger.error('Error occurred while compiling with Webpack', err);
|
||||
else {
|
||||
Logger.info('Compiled ES5 file with Webpack successfully.');
|
||||
}
|
||||
cleanEmittedData();
|
||||
});
|
||||
}
|
||||
|
||||
createIndexFile();
|
||||
compile();
|
||||
@@ -1,5 +1,5 @@
|
||||
import { readFileSync, readJSONSync, writeFileSync } from 'fs-extra';
|
||||
import { join } from 'path';
|
||||
import { readFileSync, writeFileSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
|
||||
import { PLUGIN_PATHS, ROOT } from '../build/helpers';
|
||||
import { EMIT_PATH } from '../build/transformers/extract-injectables';
|
||||
@@ -9,7 +9,7 @@ generateDeclarations();
|
||||
transpile();
|
||||
|
||||
const outDirs = PLUGIN_PATHS.map((p) => p.replace(join(ROOT, 'src'), join(ROOT, 'dist')).replace(/[\\/]index.ts/, ''));
|
||||
const injectableClasses = readJSONSync(EMIT_PATH);
|
||||
const injectableClasses = JSON.parse(readFileSync(EMIT_PATH, 'utf-8'));
|
||||
|
||||
outDirs.forEach((dir) => {
|
||||
const classes = injectableClasses.filter((entry) => entry.dirName === dir.split(/[\\/]+/).pop());
|
||||
|
||||
@@ -1,55 +0,0 @@
|
||||
import { writeFileSync } from 'fs-extra';
|
||||
import { resolve } from 'path';
|
||||
import { PLUGIN_PATHS, ROOT } from '../build/helpers';
|
||||
|
||||
// Base configuration for release-please
|
||||
const baseConfig = {
|
||||
$schema: 'https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json',
|
||||
'release-type': 'node',
|
||||
'bump-minor-pre-major': false,
|
||||
'bump-patch-for-minor-pre-major': false,
|
||||
draft: false,
|
||||
prerelease: false,
|
||||
'changelog-sections': [
|
||||
{ type: 'feat', section: 'Features' },
|
||||
{ type: 'fix', section: 'Bug Fixes' },
|
||||
{ type: 'chore', section: 'Miscellaneous Chores', hidden: false },
|
||||
{ type: 'docs', section: 'Documentation' },
|
||||
{ type: 'style', section: 'Styles', hidden: true },
|
||||
{ type: 'refactor', section: 'Code Refactoring' },
|
||||
{ type: 'perf', section: 'Performance Improvements' },
|
||||
{ type: 'test', section: 'Tests', hidden: true },
|
||||
{ type: 'build', section: 'Build System', hidden: true },
|
||||
{ type: 'ci', section: 'Continuous Integration', hidden: true },
|
||||
],
|
||||
packages: {},
|
||||
};
|
||||
|
||||
function generateReleaseConfig() {
|
||||
const config = { ...baseConfig };
|
||||
|
||||
// Add core package
|
||||
config.packages['src/@awesome-cordova-plugins/core'] = {
|
||||
'package-name': '@awesome-cordova-plugins/core',
|
||||
};
|
||||
|
||||
// Add all plugin packages dynamically
|
||||
PLUGIN_PATHS.forEach((pluginPath: string) => {
|
||||
const pluginName = pluginPath.split(/[\/\\]+/).slice(-2)[0];
|
||||
const packagePath = `src/@awesome-cordova-plugins/plugins/${pluginName}`;
|
||||
|
||||
config.packages[packagePath] = {
|
||||
'package-name': `@awesome-cordova-plugins/${pluginName}`,
|
||||
};
|
||||
});
|
||||
|
||||
// Write the configuration file
|
||||
const configPath = resolve(ROOT, 'release-please-config.json');
|
||||
writeFileSync(configPath, JSON.stringify(config, null, 2));
|
||||
|
||||
console.log(`Generated release-please-config.json with ${Object.keys(config.packages).length} packages`);
|
||||
console.log(`- 1 core package`);
|
||||
console.log(`- ${Object.keys(config.packages).length - 1} plugin packages`);
|
||||
}
|
||||
|
||||
generateReleaseConfig();
|
||||
@@ -1,32 +0,0 @@
|
||||
import { writeFileSync } from 'fs-extra';
|
||||
import { resolve } from 'path';
|
||||
import { PLUGIN_PATHS, ROOT } from '../build/helpers';
|
||||
|
||||
// Get the current version from package.json
|
||||
const MAIN_PACKAGE_JSON = require('../../package.json');
|
||||
const VERSION = MAIN_PACKAGE_JSON.version;
|
||||
|
||||
function generateReleaseManifest() {
|
||||
const manifest = {};
|
||||
|
||||
// Add core package with current version
|
||||
manifest['src/@awesome-cordova-plugins/core'] = VERSION;
|
||||
|
||||
// Add all plugin packages with current version
|
||||
PLUGIN_PATHS.forEach((pluginPath: string) => {
|
||||
const pluginName = pluginPath.split(/[\/\\]+/).slice(-2)[0];
|
||||
const packagePath = `src/@awesome-cordova-plugins/plugins/${pluginName}`;
|
||||
|
||||
manifest[packagePath] = VERSION;
|
||||
});
|
||||
|
||||
// Write the manifest file
|
||||
const manifestPath = resolve(ROOT, '.release-please-manifest.json');
|
||||
writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
|
||||
|
||||
console.log(
|
||||
`Generated .release-please-manifest.json with version ${VERSION} for ${Object.keys(manifest).length} packages`
|
||||
);
|
||||
}
|
||||
|
||||
generateReleaseManifest();
|
||||
@@ -0,0 +1,46 @@
|
||||
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
||||
import { join, resolve } from 'node:path';
|
||||
import { parseArgs } from 'node:util';
|
||||
|
||||
const ROOT = resolve(__dirname, '../..');
|
||||
const PLUGINS_DIR = join(ROOT, 'src/@awesome-cordova-plugins/plugins');
|
||||
const TEMPLATES_DIR = join(ROOT, 'scripts/templates');
|
||||
|
||||
const { values } = parseArgs({
|
||||
args: process.argv.slice(2),
|
||||
options: {
|
||||
n: { type: 'string', short: 'n' },
|
||||
m: { type: 'boolean', short: 'm', default: false },
|
||||
},
|
||||
});
|
||||
|
||||
if (!values.n) {
|
||||
console.log('Usage: tsx scripts/tasks/plugin-create -n PluginName [-m]');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const pluginName: string = values.n;
|
||||
const useMinimal: boolean = !!values.m;
|
||||
|
||||
// Convert PascalCase to variants
|
||||
const spaced = pluginName.replace(/(?!^)([A-Z])/g, ' $1');
|
||||
const kebabCase = pluginName
|
||||
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
|
||||
.replace(/([A-Z])([A-Z][a-z])/g, '$1-$2')
|
||||
.toLowerCase();
|
||||
const camelCase = pluginName.charAt(0).toLowerCase() + pluginName.slice(1);
|
||||
|
||||
const templateFile = useMinimal ? 'wrap-min.tmpl' : 'wrap.tmpl';
|
||||
const templatePath = join(TEMPLATES_DIR, templateFile);
|
||||
|
||||
let content = readFileSync(templatePath, 'utf-8');
|
||||
content = content.replace(/\{\{ PluginName \}\}/g, pluginName);
|
||||
content = content.replace(/\{\{ Plugin_Name \}\}/g, spaced);
|
||||
content = content.replace(/\{\{ pluginName \}\}/g, camelCase);
|
||||
content = content.replace(/\{\{ plugin-name \}\}/g, kebabCase);
|
||||
|
||||
const outDir = join(PLUGINS_DIR, kebabCase);
|
||||
mkdirSync(outDir, { recursive: true });
|
||||
writeFileSync(join(outDir, 'index.ts'), content, 'utf-8');
|
||||
|
||||
console.log(`Plugin created at: src/@awesome-cordova-plugins/plugins/${kebabCase}/index.ts`);
|
||||
+57
-38
@@ -1,24 +1,38 @@
|
||||
import * as Queue from 'async-promise-queue';
|
||||
import { exec } from 'child_process';
|
||||
import { writeJSONSync } from 'fs-extra';
|
||||
import { merge } from 'lodash';
|
||||
import { cpus } from 'os';
|
||||
import { join, resolve } from 'path';
|
||||
import { exec as execCb } from 'node:child_process';
|
||||
import { readFileSync, writeFileSync } from 'node:fs';
|
||||
import { availableParallelism } from 'node:os';
|
||||
import { join, resolve } from 'node:path';
|
||||
import { promisify } from 'node:util';
|
||||
|
||||
const exec = promisify(execCb);
|
||||
|
||||
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 MAIN_PACKAGE_JSON = JSON.parse(readFileSync(resolve(__dirname, '../../package.json'), 'utf-8'));
|
||||
const VERSION = MAIN_PACKAGE_JSON.version;
|
||||
const FLAGS = '--access public';
|
||||
|
||||
const PACKAGE_JSON_BASE = {
|
||||
description: 'Awesome Cordova Plugins - Native plugins for ionic apps',
|
||||
main: 'index.js',
|
||||
module: 'index.js',
|
||||
typings: 'index.d.ts',
|
||||
author: 'ionic',
|
||||
type: 'module',
|
||||
main: './index.js',
|
||||
module: './index.js',
|
||||
types: './index.d.ts',
|
||||
exports: {
|
||||
'.': {
|
||||
types: './index.d.ts',
|
||||
import: './index.js',
|
||||
default: './index.js',
|
||||
},
|
||||
'./ngx': {
|
||||
types: './ngx/index.d.ts',
|
||||
import: './ngx/index.js',
|
||||
default: './ngx/index.js',
|
||||
},
|
||||
},
|
||||
sideEffects: false,
|
||||
author: 'Daniel Sogl',
|
||||
license: 'MIT',
|
||||
repository: {
|
||||
type: 'git',
|
||||
@@ -39,22 +53,30 @@ const PLUGIN_PEER_DEPENDENCIES = {
|
||||
};
|
||||
|
||||
function getPackageJsonContent(name: string, peerDependencies = {}, dependencies = {}) {
|
||||
return merge(PACKAGE_JSON_BASE, {
|
||||
const pkg = {
|
||||
...structuredClone(PACKAGE_JSON_BASE),
|
||||
name: '@awesome-cordova-plugins/' + name,
|
||||
dependencies,
|
||||
peerDependencies,
|
||||
version: VERSION,
|
||||
});
|
||||
};
|
||||
|
||||
// Core package has no ngx subfolder
|
||||
if (name === 'core') {
|
||||
delete pkg.exports['./ngx'];
|
||||
}
|
||||
|
||||
return pkg;
|
||||
}
|
||||
|
||||
function writePackageJson(data: any, dir: string) {
|
||||
const filePath = resolve(dir, 'package.json');
|
||||
writeJSONSync(filePath, data);
|
||||
writeFileSync(filePath, JSON.stringify(data, null, 2));
|
||||
PACKAGES.push(dir);
|
||||
}
|
||||
function writeNGXPackageJson(data: any, dir: string) {
|
||||
const filePath = resolve(dir, 'package.json');
|
||||
writeJSONSync(filePath, data);
|
||||
writeFileSync(filePath, JSON.stringify(data, null, 2));
|
||||
}
|
||||
function prepare() {
|
||||
// write @awesome-cordova-plugins/core package.json
|
||||
@@ -74,32 +96,29 @@ function prepare() {
|
||||
});
|
||||
}
|
||||
|
||||
async function publishPackage(pkg: string, ignoreErrors: boolean): Promise<void> {
|
||||
try {
|
||||
const { stdout } = await exec(`npm publish ${pkg} ${FLAGS}`);
|
||||
if (stdout) Logger.verbose(stdout.trim());
|
||||
} catch (err: any) {
|
||||
if (err.message?.includes('You cannot publish over the previously published version')) {
|
||||
Logger.verbose('Ignoring duplicate version error.');
|
||||
return;
|
||||
}
|
||||
if (!ignoreErrors) throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async function publish(ignoreErrors = false) {
|
||||
Logger.profile('Publishing');
|
||||
// upload 1 package per CPU thread at a time
|
||||
const worker = Queue.async.asyncify(
|
||||
(pkg: any) =>
|
||||
new Promise<string | void>((resolve, reject) => {
|
||||
exec(`npm publish ${pkg} ${FLAGS}`, (err, stdout) => {
|
||||
if (stdout) {
|
||||
Logger.verbose(stdout.trim());
|
||||
resolve(stdout);
|
||||
}
|
||||
if (err) {
|
||||
if (!ignoreErrors) {
|
||||
if (err.message.includes('You cannot publish over the previously published version')) {
|
||||
Logger.verbose('Ignoring duplicate version error.');
|
||||
return resolve();
|
||||
}
|
||||
reject(err);
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
);
|
||||
const concurrency = availableParallelism();
|
||||
const queue = [...PACKAGES];
|
||||
|
||||
try {
|
||||
await Queue(worker, PACKAGES, cpus().length);
|
||||
while (queue.length > 0) {
|
||||
const batch = queue.splice(0, concurrency);
|
||||
await Promise.all(batch.map((pkg) => publishPackage(pkg, ignoreErrors)));
|
||||
}
|
||||
Logger.info('Done publishing!');
|
||||
} catch (e) {
|
||||
Logger.error('Error publishing!');
|
||||
|
||||
Reference in New Issue
Block a user