"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.create = create; exports.update = update; const tslib_1 = require("tslib"); const ts = tslib_1.__importStar(require("typescript")); const fs_1 = require("fs"); const { factory } = ts; const file_handle_1 = require("./file-handle"); const enum_1 = require("./enum"); const config_1 = require("./config"); const template_1 = require("./template"); const path_1 = require("path"); const inquirer_1 = tslib_1.__importDefault(require("inquirer")); const axios_1 = tslib_1.__importDefault(require("axios")); const tip_style_1 = require("./tip-style"); const shelljs_1 = tslib_1.__importDefault(require("shelljs")); const rename_1 = require("./rename"); const assert_1 = tslib_1.__importDefault(require("assert")); const DEFAULT_PROJECT_NAME = 'oak_template'; const DEFAULT_PROJECT_TITLE = 'oak template project'; const prompt = [ { type: 'input', name: 'version', message: 'version', default: '1.0.0', }, { type: 'input', name: 'description', message: 'description', }, { name: 'useOgb', type: 'confirm', message: 'add oak-general-business into dependency?', default: true, }, { name: 'moreDeps', type: 'input', message: 'do you have more dependent oak-family libraries? type their names, use comma as separator.', default: '', }, { name: 'example', type: 'confirm', message: 'load an initial example about personal blog? It will load correspond Entities/Pages/Components/Checkers and etc.', default: true, }, ]; /** * 将项目的依赖关系加入 */ function addDependencies(dependencies) { const dependencyFile = (0, path_1.join)(process.cwd(), 'src', 'configuration', 'dependency.ts'); const program = ts.createProgram([ dependencyFile, ], {}); const sourceFile = program.getSourceFile(dependencyFile); const { statements } = sourceFile; const stmt1 = statements[1]; (0, assert_1.default)(ts.isVariableStatement(stmt1)); const { declarationList: { declarations: [vd] } } = stmt1; const { name, initializer } = vd; (0, assert_1.default)(ts.isIdentifier(name) && name.text === 'dependencyConfiguration'); (0, assert_1.default)(ts.isArrayLiteralExpression(initializer)); Object.assign(initializer, { elements: dependencies.map(ele => factory.createStringLiteral(ele)) }); const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed }); const result = printer.printList(ts.ListFormat.SourceFileStatements, factory.createNodeArray(statements), sourceFile); (0, fs_1.writeFileSync)(dependencyFile, result, { flag: 'w' }); (0, tip_style_1.Success)((0, tip_style_1.success)(`${dependencyFile} has been built.`)); } /** * @name 检查项目名是否已存在 * @param dirName */ function checkProjectName(dirName, exists) { // 项目根路径 const rootPath = process.cwd() + '/' + dirName; const isExists = (0, file_handle_1.checkFileExists)(rootPath); if (isExists && !exists) { throw new global.Error(`Cannot create a project named ${(0, tip_style_1.success)(`"${dirName}"`)} because a path with the same name exists.\nPlease choose a different project name.`); } else if (!isExists && exists) { throw new global.Error(`${(0, tip_style_1.success)(dirName)} is not a valid project dir.\nPlease choose a different project name.`); } } /** * @name 获取oak-cli最新版本号 * @returns */ async function getOakCliVersion() { const res = await axios_1.default.get(config_1.CNPM_BASE_URL); return res.data['dist-tags']['latest']; } /** * @name 获取微信小程序稳定基础版本库 * @returns */ async function getMiniVersion() { try { const res = await axios_1.default.get(config_1.MINI_VERSION_URL); const versions = JSON.parse(res.data['json_data'])['total']; const versionsSort = versions.sort((a, b) => { return b['percentage'] - a['percentage']; }); return versionsSort[0]['sdkVer']; } catch (err) { (0, tip_style_1.Warn)((0, tip_style_1.warn)(`can't access a-o-s weixin mini version, using 3.4.1`)); return '3.4.1'; } } async function createWechatMpBoilplate(dir, isDev, isUpdate) { // 获取微信小程序稳定基础版本库 const miniVersion = await getMiniVersion(); // 获取小程序项目app.json内容 const appJsonWithWeChatMp = (0, template_1.appJsonContentWithWeChatMp)(isDev); // 获取小程序项目project.config.json内容 const projectConfigWithWeChatMp = (0, template_1.projectConfigContentWithWeChatMp)(config_1.USER_CONFIG_FILE_NAME, DEFAULT_PROJECT_TITLE, miniVersion); // 获取小程序项目oak.config.json内容 const oakConfigWithWeChatMp = (0, template_1.oakConfigContentWithWeChatMp)(); const appJsonPathWithWeChatMp = (0, path_1.join)(dir, 'src', 'app.json'); // 小程序项目project.config.json路径 const projectConfigPathWithWeChatMp = (0, path_1.join)(dir, 'src', 'project.config.json'); // 小程序项目project.config.json路径 const oakConfigPathWithWeChatMp = (0, path_1.join)(dir, 'src', config_1.USER_CONFIG_FILE_NAME); // 创建小程序项目project.config.json (0, file_handle_1.checkFileExistsAndCreate)(projectConfigPathWithWeChatMp, projectConfigWithWeChatMp, enum_1.checkFileExistsAndCreateType.FILE, isUpdate); // 创建小程序项目app.json (0, file_handle_1.checkFileExistsAndCreate)(appJsonPathWithWeChatMp, appJsonWithWeChatMp, enum_1.checkFileExistsAndCreateType.FILE, isUpdate); // 创建小程序项目oak.config.json (0, file_handle_1.checkFileExistsAndCreate)(oakConfigPathWithWeChatMp, oakConfigWithWeChatMp, enum_1.checkFileExistsAndCreateType.FILE, isUpdate); } async function createWebBoilplate(dir, isDev, isUpdate) { // 获取web项目oak.config.json内容 const oakConfigWithWeb = (0, template_1.oakConfigContentWithWeb)(); // web项目oak.config.json路径 const oakConfigPathWithWeb = (0, path_1.join)(dir, 'src', config_1.USER_CONFIG_FILE_NAME); // 创建web项目oak.config.json (0, file_handle_1.checkFileExistsAndCreate)(oakConfigPathWithWeb, oakConfigWithWeb, enum_1.checkFileExistsAndCreateType.FILE, isUpdate); } async function create(dirName, cmd) { const nameOption = { type: 'input', name: 'name', message: `name`, default: dirName, }; const titleOption = { type: 'input', name: 'title', message: 'title of the project shown in App/Html', default: dirName, }; prompt.unshift(nameOption, titleOption); const isDev = cmd.dev ? true : false; const isModule = cmd.module ? true : false; const { name, version, title, description, useOgb, moreDeps, example } = await inquirer_1.default.prompt(prompt); // 项目根路径 const rootPath = process.cwd() + '/' + dirName; // package.json路径 const packageJsonPath = `${rootPath}/package.json`; // tsconfig.json路径 const tsconfigJsonPath = `${rootPath}/tsconfig.json`; // tsconfig.build.json路径 const tsConfigBuildJsonPath = `${rootPath}/tsconfig.build.json`; // tsconfig.build.paths.json路径 const tsConfigBuildPathsJsonPath = `${rootPath}/tsconfig.build.paths.json`; // tsconfig.paths.json路径 const tsconfigPathsJsonPath = `${rootPath}/tsconfig.paths.json`; // tsconfig.mp.json路径 const tsConfigMpJsonPath = `${rootPath}/tsconfig.mp.json`; // tsconfig.web.json路径 const tsConfigWebJsonPath = `${rootPath}/tsconfig.web.json`; // web项目根路径 const webRootPath = `${rootPath}/web`; // 小程序项目根路径 const weChatMpRootPath = `${rootPath}/wechatMp`; // 被复制的文件夹路径 const emptyTemplatePath = (0, path_1.join)(__dirname, '..', 'template'); const examplePath = (0, path_1.join)(__dirname, '..', 'templateExample'); //检查项目名是否存在 checkProjectName(dirName); try { // 创建根目录 (0, file_handle_1.checkFileExistsAndCreate)(rootPath); // 复制项目文件 if (isModule) { // 模块化的项目,只拷贝 src 下的内容,但跳过 pages 目录;同时拷贝 typings const templateSrc = (0, path_1.join)(emptyTemplatePath, 'src'); const destSrc = (0, path_1.join)(rootPath, 'src'); // 确保目标 src 目录存在 if (!(0, fs_1.existsSync)(destSrc)) { (0, fs_1.mkdirSync)(destSrc, { recursive: true }); } const entries = (0, fs_1.readdirSync)(templateSrc, { withFileTypes: true }); for (const entry of entries) { if (entry.name === 'pages') { continue; // 模块模式下跳过 pages } const from = (0, path_1.join)(templateSrc, entry.name); const to = (0, path_1.join)(destSrc, entry.name); (0, file_handle_1.copyFolder)(from, to); } (0, file_handle_1.copyFolder)((0, path_1.join)(emptyTemplatePath, 'typings'), (0, path_1.join)(rootPath, 'typings')); } else { (0, file_handle_1.copyFolder)(emptyTemplatePath, rootPath); await createWechatMpBoilplate(weChatMpRootPath, isDev); await createWebBoilplate(webRootPath, isDev); /* if (!shell.which('npm')) { Warn(warn('Sorry, this script requires npm! Please install npm!')); shell.exit(1); } Success(`${success(`Waiting...`)}`); Success(`${success(`Dependencies are now being installed`)}`); shell.cd(dirName).exec('npm install'); */ } const deps = []; if (useOgb) { deps.push('oak-general-business'); } if (moreDeps) { deps.push(...(moreDeps.split(',').map(ele => ele.trim()).filter(ele => !!ele))); } // 获取tsconfig.json内容 const tsconfigJson = (0, template_1.tsConfigJsonContent)(); const tsConfigBuildJson = (0, template_1.tsConfigBuildJsonContent)(); const tsConfigBuildPathsJson = (0, template_1.tsConfigPathsJsonContent)(deps); const tsConfigPathsJson = (0, template_1.tsConfigPathsJsonContent)(deps); const tsConfigMpJson = (0, template_1.tsConfigMpJsonContent)(); const tsConfigWebJson = (0, template_1.tsConfigWebJsonContent)(); // 创建tsconfig.json (0, file_handle_1.checkFileExistsAndCreate)(tsconfigJsonPath, tsconfigJson, enum_1.checkFileExistsAndCreateType.FILE); // 创建tsconfig.build.json (0, file_handle_1.checkFileExistsAndCreate)(tsConfigBuildJsonPath, tsConfigBuildJson, enum_1.checkFileExistsAndCreateType.FILE); // 创建tsconfig.build.paths.json (0, file_handle_1.checkFileExistsAndCreate)(tsConfigBuildPathsJsonPath, tsConfigBuildPathsJson, enum_1.checkFileExistsAndCreateType.FILE); // 创建tsconfig.paths.json (0, file_handle_1.checkFileExistsAndCreate)(tsconfigPathsJsonPath, tsConfigPathsJson, enum_1.checkFileExistsAndCreateType.FILE); // 创建tsconfig.mp.json (0, file_handle_1.checkFileExistsAndCreate)(tsConfigMpJsonPath, tsConfigMpJson, enum_1.checkFileExistsAndCreateType.FILE); // 创建tsconfig.web.json (0, file_handle_1.checkFileExistsAndCreate)(tsConfigWebJsonPath, tsConfigWebJson, enum_1.checkFileExistsAndCreateType.FILE); // 复制.gitignore const gitignoreContent = (0, file_handle_1.readFile)((0, path_1.join)(__dirname, '..', 'template', '.gitignore')); (0, file_handle_1.checkFileExistsAndCreate)((0, path_1.join)(rootPath, '.gitignore'), gitignoreContent, enum_1.checkFileExistsAndCreateType.FILE); // 复制oak.config.json const oakConfigContent = (0, file_handle_1.readFile)((0, path_1.join)(__dirname, '..', 'template', config_1.USER_CONFIG_FILE_NAME)); (0, file_handle_1.checkFileExistsAndCreate)((0, path_1.join)(rootPath, config_1.USER_CONFIG_FILE_NAME), oakConfigContent, enum_1.checkFileExistsAndCreateType.FILE); // 更新configuration/compiler.js (仅在非模块化模式下) if (!isModule) { (0, template_1.updateCompilerJsContent)(rootPath, deps); } (0, tip_style_1.Success)(`${(0, tip_style_1.success)(`Successfully created project ${(0, tip_style_1.primary)(name)}, directory name is ${(0, tip_style_1.primary)(dirName)}`)}`); shelljs_1.default.cd(dirName); if (deps.length > 0) { addDependencies(deps); } // 获取package.json内容 const packageJson = (0, template_1.packageJsonContent)({ name: DEFAULT_PROJECT_NAME, // 后面再统一rename version, description, cliName: config_1.CLI_NAME, cliBinName: config_1.CLI_BIN_NAME, isDev, isModule, dependencies: deps, }); // 创建package.json (0, file_handle_1.checkFileExistsAndCreate)(packageJsonPath, packageJson, enum_1.checkFileExistsAndCreateType.FILE); // 只在非模块化模式下重命名整个项目(包括web、wechatMp等) if (!isModule) { (0, rename_1.renameProject)(rootPath, name, title, DEFAULT_PROJECT_NAME, DEFAULT_PROJECT_TITLE); } else { // 模块化模式下只更新 package.json 的 name const packageJsonFilePath = (0, path_1.join)(rootPath, 'package.json'); const packageJsonContent = (0, fs_1.readFileSync)(packageJsonFilePath, 'utf-8'); const packageJsonJson = JSON.parse(packageJsonContent); packageJsonJson.name = name; const newPackageJsonContent = JSON.stringify(packageJsonJson, undefined, 4); (0, fs_1.writeFileSync)(packageJsonFilePath, newPackageJsonContent); (0, tip_style_1.Success)(`${(0, tip_style_1.success)(`Change project name to ${(0, tip_style_1.primary)(name)}`)}`); } if (example && !isModule) { // todo: copy template example files (0, file_handle_1.copyFolder)(examplePath, rootPath, true); } (0, tip_style_1.Success)(`${(0, tip_style_1.success)(`Ok, type 'npm install' to install libs, then start!`)}`); } catch (err) { (0, tip_style_1.Error)((0, tip_style_1.error)('create error')); (0, tip_style_1.Error)((0, tip_style_1.error)(err)); } } async function update(dirName, subDirName, cmd) { const isDev = cmd.dev ? true : false; try { // 需要拷贝的路径 const destPath = (0, path_1.join)(process.cwd(), dirName, subDirName); const templatePath = (0, path_1.join)(__dirname, '..', 'template'); //检查项目名是否存在 checkProjectName(dirName, true); if (subDirName === 'src') { const fromPath = (0, path_1.join)(templatePath, subDirName); (0, file_handle_1.copyFolder)(fromPath, destPath, true); } else if (subDirName.startsWith('wechatMp')) { const fromPath = (0, path_1.join)(templatePath, 'wechatMp'); (0, file_handle_1.copyFolder)(fromPath, destPath, true); await createWechatMpBoilplate(destPath, isDev, true); } else { throw new global.Error(`Cannot recoganize ${(0, tip_style_1.success)(`"${subDirName}"`)} for update.\n Please choose src/wechatMp%.`); } (0, tip_style_1.Success)(`${(0, tip_style_1.success)(`Successfully update directory ${(0, tip_style_1.primary)(subDirName)} for project ${(0, tip_style_1.primary)(dirName)}}`)}`); } catch (err) { console.error((0, tip_style_1.error)(err.message)); } }