mirror of
https://gitee.com/nocobase/nocobase.git
synced 2025-05-05 05:29:26 +08:00
* fix: add license code * fix: bug * fix: bug * fix: upgrade * fix: improve * chore: add copyright information to the file header * fix: d.ts bug * fix: bug * fix: e2e bug * fix: merge main --------- Co-authored-by: chenos <chenlinxh@gmail.com>
175 lines
5.5 KiB
TypeScript
175 lines
5.5 KiB
TypeScript
/**
|
|
* This file is part of the NocoBase (R) project.
|
|
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
* Authors: NocoBase Team.
|
|
*
|
|
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
*/
|
|
|
|
import fs from 'fs';
|
|
import chalk from 'chalk';
|
|
import { builtinModules } from 'module';
|
|
import path from 'path';
|
|
|
|
const requireRegex = /require\s*\(['"`](.*?)['"`]\)/g;
|
|
const importRegex = /^import(?:['"\s]*([\w*${}\s,]+)from\s*)?['"\s]['"\s](.*[@\w_-]+)['"\s].*/gm;
|
|
|
|
type Log = (msg: string, ...args: any) => void;
|
|
|
|
export function isNotBuiltinModule(packageName: string) {
|
|
return !builtinModules.includes(packageName);
|
|
}
|
|
|
|
export const isValidPackageName = (str: string) => {
|
|
const pattern = /^(?:@[a-zA-Z0-9_-]+\/)?[a-zA-Z0-9_-]+$/;
|
|
return pattern.test(str);
|
|
};
|
|
|
|
/**
|
|
* get package name from string
|
|
* @example
|
|
* getPackageNameFromString('lodash') => lodash
|
|
* getPackageNameFromString('lodash/xx') => lodash
|
|
* getPackageNameFromString('@aa/bb') => @aa/bb
|
|
* getPackageNameFromString('aa/${lang}') => aa
|
|
*
|
|
* getPackageNameFromString('./xx') => null
|
|
* getPackageNameFromString('../xx') => null
|
|
* getPackageNameFromString($file) => null
|
|
* getPackageNameFromString(`${file}`) => null
|
|
* getPackageNameFromString($file + './xx') => null
|
|
*/
|
|
export function getPackageNameFromString(str: string) {
|
|
// ./xx or ../xx
|
|
if (str.startsWith('.')) return null;
|
|
|
|
const arr = str.split('/');
|
|
let packageName: string;
|
|
if (arr[0].startsWith('@')) {
|
|
// @aa/bb/ccFile => @aa/bb
|
|
packageName = arr.slice(0, 2).join('/');
|
|
} else {
|
|
// aa/bbFile => aa
|
|
packageName = arr[0];
|
|
}
|
|
|
|
packageName = packageName.trim();
|
|
|
|
return isValidPackageName(packageName) ? packageName : null;
|
|
}
|
|
|
|
export function getPackagesFromFiles(files: string[]): string[] {
|
|
const packageNames = files
|
|
.map((item) => [
|
|
...[...item.matchAll(importRegex)].map((item) => item[2]),
|
|
...[...item.matchAll(requireRegex)].map((item) => item[1]),
|
|
])
|
|
.flat()
|
|
.map(getPackageNameFromString)
|
|
.filter(Boolean)
|
|
.filter(isNotBuiltinModule);
|
|
|
|
return [...new Set(packageNames)];
|
|
}
|
|
|
|
export function getSourcePackages(fileSources: string[]): string[] {
|
|
return getPackagesFromFiles(fileSources);
|
|
}
|
|
|
|
export function getIncludePackages(sourcePackages: string[], external: string[], pluginPrefix: string[]): string[] {
|
|
return sourcePackages
|
|
.filter((packageName) => !external.includes(packageName)) // exclude external
|
|
.filter((packageName) => !pluginPrefix.some((prefix) => packageName.startsWith(prefix))); // exclude other plugin
|
|
}
|
|
|
|
export function getExcludePackages(sourcePackages: string[], external: string[], pluginPrefix: string[]): string[] {
|
|
const includePackages = getIncludePackages(sourcePackages, external, pluginPrefix);
|
|
return sourcePackages.filter((packageName) => !includePackages.includes(packageName));
|
|
}
|
|
|
|
export function getPackageJsonPackages(packageJson: Record<string, any>): string[] {
|
|
return [
|
|
...new Set([...Object.keys(packageJson.devDependencies || {}), ...Object.keys(packageJson.dependencies || {})]),
|
|
];
|
|
}
|
|
|
|
export function checkEntryExists(cwd: string, entry: 'server' | 'client', log: Log) {
|
|
const srcDir = path.join(cwd, 'src', entry);
|
|
if (!fs.existsSync(srcDir)) {
|
|
log('Missing %s. Please create it.', chalk.red(`src/${entry}`));
|
|
process.exit(-1);
|
|
}
|
|
|
|
return srcDir;
|
|
}
|
|
|
|
export function checkDependencies(packageJson: Record<string, any>, log: Log) {
|
|
const packages = Object.keys(packageJson.dependencies || {});
|
|
if (!packages.length) return;
|
|
log(
|
|
"The build tool will package all dependencies into the dist directory, so you don't need to put them in %s. Instead, they should be placed in %s. For more information, please refer to: %s.",
|
|
chalk.yellow(packages.join(', ')),
|
|
chalk.yellow('dependencies'),
|
|
chalk.yellow('devDependencies'),
|
|
chalk.blue(chalk.blue('https://docs.nocobase.com/development/deps')),
|
|
);
|
|
}
|
|
|
|
type CheckOptions = {
|
|
cwd: string;
|
|
log: Log;
|
|
entry: 'server' | 'client';
|
|
files: string[];
|
|
packageJson: Record<string, any>;
|
|
};
|
|
|
|
export function getFileSize(filePath: string) {
|
|
const stat = fs.statSync(filePath);
|
|
return stat.size;
|
|
}
|
|
|
|
export function formatFileSize(fileSize: number) {
|
|
const kb = fileSize / 1024;
|
|
return kb.toFixed(2) + ' KB';
|
|
}
|
|
|
|
export function buildCheck(options: CheckOptions) {
|
|
const { cwd, log, entry, files, packageJson } = options;
|
|
checkEntryExists(cwd, entry, log);
|
|
|
|
// checkRequirePackageJson(files, log);
|
|
checkDependencies(packageJson, log);
|
|
}
|
|
|
|
export function checkRequire(sourceFiles: string[], log: Log) {
|
|
const requireArr = sourceFiles
|
|
.map((filePath) => {
|
|
const code = fs.readFileSync(filePath, 'utf-8');
|
|
return [...code.matchAll(requireRegex)].map((item) => ({
|
|
filePath: filePath,
|
|
code: item[0],
|
|
}));
|
|
})
|
|
.flat();
|
|
if (requireArr.length) {
|
|
log('%s not allowed. Please use %s instead.', chalk.red('require()'), chalk.red('import'));
|
|
requireArr.forEach((item, index) => {
|
|
console.log('%s. %s in %s;', index + 1, chalk.red(item.code), chalk.red(item.filePath));
|
|
});
|
|
console.log('\n');
|
|
process.exit(-1);
|
|
}
|
|
}
|
|
|
|
export function checkFileSize(outDir: string, log: Log) {
|
|
const files = fs.readdirSync(outDir);
|
|
|
|
files.forEach(file => {
|
|
const fileSize = getFileSize(path.join(outDir, file));
|
|
if (fileSize > 1024 * 1024) {
|
|
log(`The %s size %s exceeds 1MB. You can use dynamic import \`import()\` for lazy loading content.`, chalk.red(file), chalk.red(formatFileSize(fileSize)));
|
|
}
|
|
});
|
|
}
|