diff --git a/packages/umi-build-dev/src/PluginAPI.js b/packages/umi-build-dev/src/PluginAPI.js index 52428c2a4f1f..380dad7f603e 100644 --- a/packages/umi-build-dev/src/PluginAPI.js +++ b/packages/umi-build-dev/src/PluginAPI.js @@ -100,6 +100,9 @@ export default class PluginAPI { '_modifyHelpInfo', 'addRuntimePlugin', 'addRuntimePluginKey', + '_modifyBlockPackageJSONPath', + '_modifyBlockDependencies', + '_modifyBlockFile', ].forEach(method => { if (Array.isArray(method)) { this.registerMethod(...method); diff --git a/packages/umi-build-dev/src/constants.js b/packages/umi-build-dev/src/constants.js index 10a74fe3a700..13e87b69eff8 100644 --- a/packages/umi-build-dev/src/constants.js +++ b/packages/umi-build-dev/src/constants.js @@ -1,3 +1,13 @@ export const CONFIG_FILES = ['.umirc.js', 'config/config.js']; export const EXT_LIST = ['.js', '.jsx', '.ts', '.tsx']; + +export const SINGULAR_SENSLTIVE = [ + 'pages', + 'components', + 'models', + 'locales', + 'utils', + 'services', + 'layouts', +]; diff --git a/packages/umi-build-dev/src/plugins/commands/block/block.js b/packages/umi-build-dev/src/plugins/commands/block/block.js index 1a2415f48bec..f9e1948f2ab4 100644 --- a/packages/umi-build-dev/src/plugins/commands/block/block.js +++ b/packages/umi-build-dev/src/plugins/commands/block/block.js @@ -1,9 +1,9 @@ -import { existsSync } from 'fs'; -import { join } from 'path'; +import { existsSync, readdirSync, statSync } from 'fs'; +import { join, dirname } from 'path'; import semver from 'semver'; import chalk from 'chalk'; import clipboardy from 'clipboardy'; -import { CONFIG_FILES } from '../../../constants'; +import { CONFIG_FILES, SINGULAR_SENSLTIVE } from '../../../constants'; import writeNewRoute from '../../../utils/writeNewRoute'; const debug = require('debug')('umi-build-dev:MaterialGenerator'); @@ -27,23 +27,41 @@ export function dependenciesConflictCheck( blockPkgDeps = {}, projectPkgDeps = {}, ) { - const lackDeps = []; - const conflictDeps = []; + const lacks = []; + const conflicts = []; Object.keys(blockPkgDeps).forEach(dep => { if (!projectPkgDeps[dep]) { - lackDeps.push([dep, blockPkgDeps[dep]]); + lacks.push([dep, blockPkgDeps[dep]]); } else if (!semver.intersects(projectPkgDeps[dep], blockPkgDeps[dep])) { - conflictDeps.push([dep, blockPkgDeps[dep], projectPkgDeps[dep]]); + conflicts.push([dep, blockPkgDeps[dep], projectPkgDeps[dep]]); } }); return { - conflictDeps, - lackDeps, + conflicts, + lacks, }; } +const singularReg = new RegExp( + `[\'\"]@\/(${SINGULAR_SENSLTIVE.join('|')})\/`, + 'g', +); + +export function parseContentToSingular(content) { + return content.replace(singularReg, (all, match) => { + return all.replace(match, match.replace(/s$/, '')); + }); +} + +export function getSingularName(name) { + if (SINGULAR_SENSLTIVE.includes(name)) { + name = name.replace(/s$/, ''); + } + return name; +} + export default api => { - const { paths, log, Generator, config } = api; + const { paths, log, Generator, config, applyPlugins } = api; return class MaterialGenerator extends Generator { constructor(args, opts) { @@ -92,7 +110,7 @@ export default api => { // get block package.json data const pkgPath = join(this.sourcePath, 'package.json'); if (!existsSync(pkgPath)) { - return log.error(`not find package.json in ${this.sourcePath}`); + throw new Error(`not find package.json in ${this.sourcePath}`); } else { // eslint-disable-next-line this.pkg = require(pkgPath); @@ -112,7 +130,9 @@ export default api => { log.info('skip dependencies'); } else { // read project package.json - const projectPkgPath = join(paths.cwd, 'package.json'); + const projectPkgPath = applyPlugins('_modifyBlockPackageJSONPath', { + initialValue: join(paths.cwd, 'package.json'), + }); if (!existsSync(projectPkgPath)) { throw new Error(`not find package.json in your project ${paths.cwd}`); } @@ -120,17 +140,19 @@ export default api => { const projectPkg = require(projectPkgPath); // get confilict dependencies and lack dependencies - const { conflictDeps, lackDeps } = dependenciesConflictCheck( - this.pkg.dependencies, - projectPkg.dependencies, - ); - debug(`conflictDeps ${conflictDeps}, lackDeps ${lackDeps}`); + const { conflicts, lacks } = applyPlugins('_modifyBlockDependencies', { + initialValue: dependenciesConflictCheck( + this.pkg.dependencies, + projectPkg.dependencies, + ), + }); + debug(`conflictDeps ${conflicts}, lackDeps ${lacks}`); // find confilict dependencies throw error - if (conflictDeps.length) { + if (conflicts.length) { throw new Error(` find dependencies conflict between block and your project: - ${conflictDeps + ${conflicts .map(info => { return `* ${info[0]}: ${info[2]}(your project) not compatible with ${ info[1] @@ -142,17 +164,17 @@ export default api => { // find lack confilict, auto install if (this.dryRun) { log.log('dryRun is true, skip install dependencies'); - } else if (lackDeps.length) { - log.info(`install dependencies ${lackDeps} with ${this.npmClient}`); + } else if (lacks.length) { + log.info(`install dependencies ${lacks} with ${this.npmClient}`); // install block dependencies this.scheduleInstallTask( this.npmClient, - lackDeps.map(dep => `${dep[0]}@${dep[1]}`), + lacks.map(dep => `${dep[0]}@${dep[1]}`), { save: true, }, { - cwd: paths.cwd, + cwd: dirname(projectPkgPath), }, ); } @@ -179,11 +201,33 @@ export default api => { return; } + // you can find the copy api detail in https://github.com/SBoudrias/mem-fs-editor/blob/master/lib/actions/copy.js log.info('start copy block file to your project...'); - this.fs.copy(join(this.sourcePath, 'src'), targetPath); + this.fs.copy(join(this.sourcePath, 'src'), targetPath, { + process(content) { + content = String(content); + if (config.singular) { + content = parseContentToSingular(content); + } + return applyPlugins('_modifyBlockFile', { + initialValue: content, + }); + }, + }); const commonPath = join(this.sourcePath, '@'); if (existsSync(commonPath)) { - this.fs.copy(commonPath, paths.absSrcPath); + if (config.singular) { + // @/components/ => @/src/component/ + readdirSync(commonPath).forEach(name => { + const thePath = join(commonPath, name); + if (statSync(thePath).isDirectory()) { + name = getSingularName(name); + } + this.fs.copy(thePath, join(paths.absSrcPath, name)); + }); + } else { + this.fs.copy(commonPath, paths.absSrcPath); + } } } }; diff --git a/packages/umi-build-dev/src/plugins/commands/block/block.test.js b/packages/umi-build-dev/src/plugins/commands/block/block.test.js index eb61cd57b35c..53afd3aa1cc9 100644 --- a/packages/umi-build-dev/src/plugins/commands/block/block.test.js +++ b/packages/umi-build-dev/src/plugins/commands/block/block.test.js @@ -1,8 +1,13 @@ -import { dependenciesConflictCheck, getNameFromPkg } from './block'; +import { + dependenciesConflictCheck, + getNameFromPkg, + parseContentToSingular, + getSingularName, +} from './block'; describe('test block generate', () => { it('dependenciesConflictCheck', () => { - const { conflictDeps, lackDeps } = dependenciesConflictCheck( + const { conflicts, lacks } = dependenciesConflictCheck( { react: '>=16.0.0', antd: '^3.0.0', @@ -13,8 +18,8 @@ describe('test block generate', () => { moment: '2.1.0', }, ); - expect(conflictDeps).toEqual([['moment', '^2.3.0', '2.1.0']]); - expect(lackDeps).toEqual([['antd', '^3.0.0']]); + expect(conflicts).toEqual([['moment', '^2.3.0', '2.1.0']]); + expect(lacks).toEqual([['antd', '^3.0.0']]); }); it('getNameFromPkg', () => { @@ -34,4 +39,46 @@ describe('test block generate', () => { }), ).toEqual('demo'); }); + + it('parseContentToSingular', () => { + expect( + parseContentToSingular(` +import test from '@/utils/test'; +import '@/models/global'; +import '@/components/CompTest/index.js'; +import "@/locales/zh_CN"; +import { api } from '@/services/yes'; +import { ok } from '@/page/ttt'; +import test2 from '@/goos/test'; +import types from '@types/yes'; + +// test comment +export default() { + return