@doyuli/create-vue 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/bin/index.js +2 -0
  2. package/dist/index.js +1223 -0
  3. package/package.json +32 -0
  4. package/template/base/.editorconfig +8 -0
  5. package/template/base/.gitattributes +1 -0
  6. package/template/base/.prettierrc.json +7 -0
  7. package/template/base/.vscode/extensions.json +3 -0
  8. package/template/base/index.html +14 -0
  9. package/template/base/package.json +32 -0
  10. package/template/base/public/favicon.ico +0 -0
  11. package/template/base/src/App.vue +26 -0
  12. package/template/base/src/layouts/DefaultLayout.vue +11 -0
  13. package/template/base/src/main.ts +14 -0
  14. package/template/base/src/pages/about/index.vue +43 -0
  15. package/template/base/src/pages/home/index.vue +38 -0
  16. package/template/base/src/stores/counter.ts +12 -0
  17. package/template/base/types/env.d.ts.ejs +12 -0
  18. package/template/base/unocss.config.ts +21 -0
  19. package/template/base/vite.config.ts.ejs +42 -0
  20. package/template/eslint/eslint.config.ts +8 -0
  21. package/template/eslint/package.json +12 -0
  22. package/template/git-hooks/package.json +17 -0
  23. package/template/git-hooks/scripts/verify-commit.js +29 -0
  24. package/template/router/default/package.json +6 -0
  25. package/template/router/default/src/router/index.ts +19 -0
  26. package/template/router/unplugin/package.json +9 -0
  27. package/template/router/unplugin/src/router/index.ts +13 -0
  28. package/template/tsconfig/tsconfig.app.json +20 -0
  29. package/template/tsconfig/tsconfig.node.json +19 -0
  30. package/template/vitest/.vscode/extensions.json +3 -0
  31. package/template/vitest/package.json +14 -0
  32. package/template/vitest/src/components/__tests__/HelloWorld.spec.js +11 -0
  33. package/template/vitest/tsconfig.vitest.json +11 -0
  34. package/template/vitest/vitest.config.js +14 -0
package/dist/index.js ADDED
@@ -0,0 +1,1223 @@
1
+ import { createRequire } from "node:module";
2
+ import * as fs from "node:fs";
3
+ import { writeFileSync } from "node:fs";
4
+ import * as path from "node:path";
5
+ import { relative, resolve } from "node:path";
6
+ import process from "node:process";
7
+ import { fileURLToPath, pathToFileURL } from "node:url";
8
+ import { parseArgs } from "node:util";
9
+ import { cancel, confirm, intro, isCancel, multiselect, outro, text } from "@clack/prompts";
10
+ import pico from "picocolors";
11
+
12
+ //#region rolldown:runtime
13
+ var __create = Object.create;
14
+ var __defProp = Object.defineProperty;
15
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
16
+ var __getOwnPropNames = Object.getOwnPropertyNames;
17
+ var __getProtoOf = Object.getPrototypeOf;
18
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
19
+ var __commonJS = (cb, mod) => function() {
20
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
21
+ };
22
+ var __copyProps = (to, from, except, desc) => {
23
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
24
+ key = keys[i];
25
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
26
+ get: ((k) => from[k]).bind(null, key),
27
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
28
+ });
29
+ }
30
+ return to;
31
+ };
32
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
33
+ value: mod,
34
+ enumerable: true
35
+ }) : target, mod));
36
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
37
+
38
+ //#endregion
39
+ //#region ../kits-core/src/utils/command.ts
40
+ function getPackageManager() {
41
+ const userAgent = process.env.npm_config_user_agent ?? "";
42
+ return /pnpm/.test(userAgent) ? "pnpm" : /yarn/.test(userAgent) ? "yarn" : /bun/.test(userAgent) ? "bun" : "npm";
43
+ }
44
+ function getPackageCommand(packageManager, scriptName, args) {
45
+ if (scriptName === "install") return packageManager === "yarn" ? "yarn" : `${packageManager} install`;
46
+ if (scriptName === "build") return packageManager === "npm" || packageManager === "bun" ? `${packageManager} run build` : `${packageManager} build`;
47
+ if (args) return packageManager === "npm" ? `npm run ${scriptName} -- ${args}` : `${packageManager} ${scriptName} ${args}`;
48
+ else return packageManager === "npm" ? `npm run ${scriptName}` : `${packageManager} ${scriptName}`;
49
+ }
50
+ function getOutroMessage(root, cwd) {
51
+ const packageManager = getPackageManager();
52
+ let message = `项目初始化完成,可执行以下命令:\n\n`;
53
+ if (root !== cwd) {
54
+ const cdProjectName = relative(cwd, root);
55
+ message += ` ${pico.bold(pico.green(`cd ${cdProjectName.includes(" ") ? `"${cdProjectName}"` : cdProjectName}`))}\n`;
56
+ }
57
+ message += ` ${pico.bold(pico.green(getPackageCommand(packageManager, "install")))}\n`;
58
+ message += ` ${pico.bold(pico.green(getPackageCommand(packageManager, "lint:fix")))}\n`;
59
+ message += ` ${pico.bold(pico.green(getPackageCommand(packageManager, "dev")))}\n`;
60
+ return message;
61
+ }
62
+
63
+ //#endregion
64
+ //#region ../kits-core/src/utils/directoryTraverse.ts
65
+ function preOrderDirectoryTraverse(dir, dirCallback, fileCallback) {
66
+ for (const filename of fs.readdirSync(dir)) {
67
+ if (filename === ".git") continue;
68
+ const fullpath = path.resolve(dir, filename);
69
+ if (fs.lstatSync(fullpath).isDirectory()) {
70
+ dirCallback(fullpath);
71
+ if (fs.existsSync(fullpath)) preOrderDirectoryTraverse(fullpath, dirCallback, fileCallback);
72
+ continue;
73
+ }
74
+ fileCallback(fullpath);
75
+ }
76
+ }
77
+ const dotGitDirectoryState = { hasDotGitDirectory: false };
78
+ function postOrderDirectoryTraverse(dir, dirCallback, fileCallback) {
79
+ for (const filename of fs.readdirSync(dir)) {
80
+ if (filename === ".git") {
81
+ dotGitDirectoryState.hasDotGitDirectory = true;
82
+ continue;
83
+ }
84
+ const fullpath = path.resolve(dir, filename);
85
+ if (fs.lstatSync(fullpath).isDirectory()) {
86
+ postOrderDirectoryTraverse(fullpath, dirCallback, fileCallback);
87
+ dirCallback(fullpath);
88
+ continue;
89
+ }
90
+ fileCallback(fullpath);
91
+ }
92
+ }
93
+ function canSkipEmptying(dir) {
94
+ if (!fs.existsSync(dir)) return true;
95
+ const files = fs.readdirSync(dir);
96
+ if (files.length === 0) return true;
97
+ if (files.length === 1 && files[0] === ".git") {
98
+ dotGitDirectoryState.hasDotGitDirectory = true;
99
+ return true;
100
+ }
101
+ return false;
102
+ }
103
+ function emptyDir(dir) {
104
+ if (!fs.existsSync(dir)) return;
105
+ postOrderDirectoryTraverse(dir, (dir$1) => fs.rmdirSync(dir$1), (file) => fs.unlinkSync(file));
106
+ }
107
+
108
+ //#endregion
109
+ //#region ../kits-core/src/utils/prompts.ts
110
+ async function unwrapPrompt(maybeCancelPromise) {
111
+ const result = await maybeCancelPromise;
112
+ if (isCancel(result)) {
113
+ cancel(`${pico.red("✖")} 操作取消`);
114
+ process.exit(0);
115
+ }
116
+ return result;
117
+ }
118
+
119
+ //#endregion
120
+ //#region ../kits-core/src/utils/deepMerge.ts
121
+ const isObject = (val) => val && typeof val === "object";
122
+ const mergeArrayWithDedupe = (a, b) => Array.from(new Set([...a, ...b]));
123
+ /**
124
+ * Recursively merge the content of the new object to the existing one
125
+ * @param {object} target the existing object
126
+ * @param {object} obj the new object
127
+ */
128
+ function deepMerge(target, obj) {
129
+ for (const key of Object.keys(obj)) {
130
+ const oldVal = target[key];
131
+ const newVal = obj[key];
132
+ if (Array.isArray(oldVal) && Array.isArray(newVal)) target[key] = mergeArrayWithDedupe(oldVal, newVal);
133
+ else if (isObject(oldVal) && isObject(newVal)) target[key] = deepMerge(oldVal, newVal);
134
+ else target[key] = newVal;
135
+ }
136
+ return target;
137
+ }
138
+ var deepMerge_default = deepMerge;
139
+
140
+ //#endregion
141
+ //#region ../kits-core/src/utils/sortDependencies.ts
142
+ function sortDependencies(packageJson) {
143
+ const sorted = {};
144
+ const depTypes = [
145
+ "dependencies",
146
+ "devDependencies",
147
+ "peerDependencies",
148
+ "optionalDependencies"
149
+ ];
150
+ for (const depType of depTypes) if (packageJson[depType]) {
151
+ sorted[depType] = {};
152
+ Object.keys(packageJson[depType]).sort().forEach((name) => {
153
+ sorted[depType][name] = packageJson[depType][name];
154
+ });
155
+ }
156
+ return {
157
+ ...packageJson,
158
+ ...sorted
159
+ };
160
+ }
161
+
162
+ //#endregion
163
+ //#region ../kits-core/src/utils/renderTemplate.ts
164
+ /**
165
+ * Renders a template folder/file to the file system,
166
+ * by recursively copying all files under the `src` directory,
167
+ * with the following exception:
168
+ * - `_filename` should be renamed to `.filename`
169
+ * - Fields in `package.json` should be recursively merged
170
+ * @param {string} src source filename to copy
171
+ * @param {string} dest destination filename of the copy operation
172
+ */
173
+ function renderTemplate(src, dest, callbacks) {
174
+ if (fs.statSync(src).isDirectory()) {
175
+ if (path.basename(src) === "node_modules") return;
176
+ fs.mkdirSync(dest, { recursive: true });
177
+ for (const file of fs.readdirSync(src)) renderTemplate(path.resolve(src, file), path.resolve(dest, file), callbacks);
178
+ return;
179
+ }
180
+ const filename = path.basename(src);
181
+ if (filename === "package.json" && fs.existsSync(dest)) {
182
+ const existing = JSON.parse(fs.readFileSync(dest, "utf8"));
183
+ const newPackage = JSON.parse(fs.readFileSync(src, "utf8"));
184
+ const pkg = sortDependencies(deepMerge_default(existing, newPackage));
185
+ fs.writeFileSync(dest, `${JSON.stringify(pkg, null, 2)}\n`);
186
+ return;
187
+ }
188
+ if (filename === "extensions.json" && fs.existsSync(dest)) {
189
+ const existing = JSON.parse(fs.readFileSync(dest, "utf8"));
190
+ const newExtensions = JSON.parse(fs.readFileSync(src, "utf8"));
191
+ const extensions = deepMerge_default(existing, newExtensions);
192
+ fs.writeFileSync(dest, `${JSON.stringify(extensions, null, 2)}\n`);
193
+ return;
194
+ }
195
+ if (filename === "settings.json" && fs.existsSync(dest)) {
196
+ const existing = JSON.parse(fs.readFileSync(dest, "utf8"));
197
+ const newSettings = JSON.parse(fs.readFileSync(src, "utf8"));
198
+ const settings = deepMerge_default(existing, newSettings);
199
+ fs.writeFileSync(dest, `${JSON.stringify(settings, null, 2)}\n`);
200
+ return;
201
+ }
202
+ if (filename.startsWith("_")) dest = path.resolve(path.dirname(dest), filename.replace(/^_/, "."));
203
+ if (filename === "_gitignore" && fs.existsSync(dest)) {
204
+ const existing = fs.readFileSync(dest, "utf8");
205
+ const newGitignore = fs.readFileSync(src, "utf8");
206
+ fs.writeFileSync(dest, `${existing}\n${newGitignore}`);
207
+ return;
208
+ }
209
+ if (filename.endsWith(".data.mjs")) {
210
+ dest = dest.replace(/\.data\.mjs$/, "");
211
+ callbacks.push(async (dataStore) => {
212
+ const getData = (await import(pathToFileURL(src).toString())).default;
213
+ dataStore[dest] = await getData({ oldData: dataStore[dest] || {} });
214
+ });
215
+ return;
216
+ }
217
+ fs.copyFileSync(src, dest);
218
+ }
219
+
220
+ //#endregion
221
+ //#region ../kits-core/src/utils/render.ts
222
+ function renderFile(root, fileName, content) {
223
+ writeFileSync(resolve(root, fileName), content, "utf-8");
224
+ }
225
+
226
+ //#endregion
227
+ //#region ../../node_modules/.pnpm/ejs@3.1.10/node_modules/ejs/lib/utils.js
228
+ var require_utils = /* @__PURE__ */ __commonJS({ "../../node_modules/.pnpm/ejs@3.1.10/node_modules/ejs/lib/utils.js": ((exports) => {
229
+ var regExpChars = /[|\\{}()[\]^$+*?.]/g;
230
+ var hasOwnProperty = Object.prototype.hasOwnProperty;
231
+ var hasOwn = function(obj, key) {
232
+ return hasOwnProperty.apply(obj, [key]);
233
+ };
234
+ /**
235
+ * Escape characters reserved in regular expressions.
236
+ *
237
+ * If `string` is `undefined` or `null`, the empty string is returned.
238
+ *
239
+ * @param {String} string Input string
240
+ * @return {String} Escaped string
241
+ * @static
242
+ * @private
243
+ */
244
+ exports.escapeRegExpChars = function(string) {
245
+ // istanbul ignore if
246
+ if (!string) return "";
247
+ return String(string).replace(regExpChars, "\\$&");
248
+ };
249
+ var _ENCODE_HTML_RULES = {
250
+ "&": "&amp;",
251
+ "<": "&lt;",
252
+ ">": "&gt;",
253
+ "\"": "&#34;",
254
+ "'": "&#39;"
255
+ };
256
+ var _MATCH_HTML = /[&<>'"]/g;
257
+ function encode_char(c) {
258
+ return _ENCODE_HTML_RULES[c] || c;
259
+ }
260
+ /**
261
+ * Stringified version of constants used by {@link module:utils.escapeXML}.
262
+ *
263
+ * It is used in the process of generating {@link ClientFunction}s.
264
+ *
265
+ * @readonly
266
+ * @type {String}
267
+ */
268
+ var escapeFuncStr = "var _ENCODE_HTML_RULES = {\n \"&\": \"&amp;\"\n , \"<\": \"&lt;\"\n , \">\": \"&gt;\"\n , '\"': \"&#34;\"\n , \"'\": \"&#39;\"\n }\n , _MATCH_HTML = /[&<>'\"]/g;\nfunction encode_char(c) {\n return _ENCODE_HTML_RULES[c] || c;\n};\n";
269
+ /**
270
+ * Escape characters reserved in XML.
271
+ *
272
+ * If `markup` is `undefined` or `null`, the empty string is returned.
273
+ *
274
+ * @implements {EscapeCallback}
275
+ * @param {String} markup Input string
276
+ * @return {String} Escaped string
277
+ * @static
278
+ * @private
279
+ */
280
+ exports.escapeXML = function(markup) {
281
+ return markup == void 0 ? "" : String(markup).replace(_MATCH_HTML, encode_char);
282
+ };
283
+ function escapeXMLToString() {
284
+ return Function.prototype.toString.call(this) + ";\n" + escapeFuncStr;
285
+ }
286
+ try {
287
+ if (typeof Object.defineProperty === "function") Object.defineProperty(exports.escapeXML, "toString", { value: escapeXMLToString });
288
+ else exports.escapeXML.toString = escapeXMLToString;
289
+ } catch (err) {
290
+ console.warn("Unable to set escapeXML.toString (is the Function prototype frozen?)");
291
+ }
292
+ /**
293
+ * Naive copy of properties from one object to another.
294
+ * Does not recurse into non-scalar properties
295
+ * Does not check to see if the property has a value before copying
296
+ *
297
+ * @param {Object} to Destination object
298
+ * @param {Object} from Source object
299
+ * @return {Object} Destination object
300
+ * @static
301
+ * @private
302
+ */
303
+ exports.shallowCopy = function(to, from) {
304
+ from = from || {};
305
+ if (to !== null && to !== void 0) for (var p in from) {
306
+ if (!hasOwn(from, p)) continue;
307
+ if (p === "__proto__" || p === "constructor") continue;
308
+ to[p] = from[p];
309
+ }
310
+ return to;
311
+ };
312
+ /**
313
+ * Naive copy of a list of key names, from one object to another.
314
+ * Only copies property if it is actually defined
315
+ * Does not recurse into non-scalar properties
316
+ *
317
+ * @param {Object} to Destination object
318
+ * @param {Object} from Source object
319
+ * @param {Array} list List of properties to copy
320
+ * @return {Object} Destination object
321
+ * @static
322
+ * @private
323
+ */
324
+ exports.shallowCopyFromList = function(to, from, list) {
325
+ list = list || [];
326
+ from = from || {};
327
+ if (to !== null && to !== void 0) for (var i = 0; i < list.length; i++) {
328
+ var p = list[i];
329
+ if (typeof from[p] != "undefined") {
330
+ if (!hasOwn(from, p)) continue;
331
+ if (p === "__proto__" || p === "constructor") continue;
332
+ to[p] = from[p];
333
+ }
334
+ }
335
+ return to;
336
+ };
337
+ /**
338
+ * Simple in-process cache implementation. Does not implement limits of any
339
+ * sort.
340
+ *
341
+ * @implements {Cache}
342
+ * @static
343
+ * @private
344
+ */
345
+ exports.cache = {
346
+ _data: {},
347
+ set: function(key, val) {
348
+ this._data[key] = val;
349
+ },
350
+ get: function(key) {
351
+ return this._data[key];
352
+ },
353
+ remove: function(key) {
354
+ delete this._data[key];
355
+ },
356
+ reset: function() {
357
+ this._data = {};
358
+ }
359
+ };
360
+ /**
361
+ * Transforms hyphen case variable into camel case.
362
+ *
363
+ * @param {String} string Hyphen case string
364
+ * @return {String} Camel case string
365
+ * @static
366
+ * @private
367
+ */
368
+ exports.hyphenToCamel = function(str) {
369
+ return str.replace(/-[a-z]/g, function(match) {
370
+ return match[1].toUpperCase();
371
+ });
372
+ };
373
+ /**
374
+ * Returns a null-prototype object in runtimes that support it
375
+ *
376
+ * @return {Object} Object, prototype will be set to null where possible
377
+ * @static
378
+ * @private
379
+ */
380
+ exports.createNullProtoObjWherePossible = (function() {
381
+ if (typeof Object.create == "function") return function() {
382
+ return Object.create(null);
383
+ };
384
+ return function() {
385
+ return {};
386
+ };
387
+ })();
388
+ exports.hasOwnOnlyObject = function(obj) {
389
+ var o = exports.createNullProtoObjWherePossible();
390
+ for (var p in obj) if (hasOwn(obj, p)) o[p] = obj[p];
391
+ return o;
392
+ };
393
+ }) });
394
+
395
+ //#endregion
396
+ //#region ../../node_modules/.pnpm/ejs@3.1.10/node_modules/ejs/package.json
397
+ var require_package = /* @__PURE__ */ __commonJS({ "../../node_modules/.pnpm/ejs@3.1.10/node_modules/ejs/package.json": ((exports, module) => {
398
+ module.exports = {
399
+ "name": "ejs",
400
+ "description": "Embedded JavaScript templates",
401
+ "keywords": [
402
+ "template",
403
+ "engine",
404
+ "ejs"
405
+ ],
406
+ "version": "3.1.10",
407
+ "author": "Matthew Eernisse <mde@fleegix.org> (http://fleegix.org)",
408
+ "license": "Apache-2.0",
409
+ "bin": { "ejs": "./bin/cli.js" },
410
+ "main": "./lib/ejs.js",
411
+ "jsdelivr": "ejs.min.js",
412
+ "unpkg": "ejs.min.js",
413
+ "repository": {
414
+ "type": "git",
415
+ "url": "git://github.com/mde/ejs.git"
416
+ },
417
+ "bugs": "https://github.com/mde/ejs/issues",
418
+ "homepage": "https://github.com/mde/ejs",
419
+ "dependencies": { "jake": "^10.8.5" },
420
+ "devDependencies": {
421
+ "browserify": "^16.5.1",
422
+ "eslint": "^6.8.0",
423
+ "git-directory-deploy": "^1.5.1",
424
+ "jsdoc": "^4.0.2",
425
+ "lru-cache": "^4.0.1",
426
+ "mocha": "^10.2.0",
427
+ "uglify-js": "^3.3.16"
428
+ },
429
+ "engines": { "node": ">=0.10.0" },
430
+ "scripts": { "test": "npx jake test" }
431
+ };
432
+ }) });
433
+
434
+ //#endregion
435
+ //#region ../../node_modules/.pnpm/ejs@3.1.10/node_modules/ejs/lib/ejs.js
436
+ var require_ejs = /* @__PURE__ */ __commonJS({ "../../node_modules/.pnpm/ejs@3.1.10/node_modules/ejs/lib/ejs.js": ((exports) => {
437
+ /**
438
+ * @file Embedded JavaScript templating engine. {@link http://ejs.co}
439
+ * @author Matthew Eernisse <mde@fleegix.org>
440
+ * @author Tiancheng "Timothy" Gu <timothygu99@gmail.com>
441
+ * @project EJS
442
+ * @license {@link http://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0}
443
+ */
444
+ /**
445
+ * EJS internal functions.
446
+ *
447
+ * Technically this "module" lies in the same file as {@link module:ejs}, for
448
+ * the sake of organization all the private functions re grouped into this
449
+ * module.
450
+ *
451
+ * @module ejs-internal
452
+ * @private
453
+ */
454
+ /**
455
+ * Embedded JavaScript templating engine.
456
+ *
457
+ * @module ejs
458
+ * @public
459
+ */
460
+ var fs$1 = __require("fs");
461
+ var path$1 = __require("path");
462
+ var utils = require_utils();
463
+ var scopeOptionWarned = false;
464
+ /** @type {string} */
465
+ var _VERSION_STRING = require_package().version;
466
+ var _DEFAULT_OPEN_DELIMITER = "<";
467
+ var _DEFAULT_CLOSE_DELIMITER = ">";
468
+ var _DEFAULT_DELIMITER = "%";
469
+ var _DEFAULT_LOCALS_NAME = "locals";
470
+ var _NAME = "ejs";
471
+ var _REGEX_STRING = "(<%%|%%>|<%=|<%-|<%_|<%#|<%|%>|-%>|_%>)";
472
+ var _OPTS_PASSABLE_WITH_DATA = [
473
+ "delimiter",
474
+ "scope",
475
+ "context",
476
+ "debug",
477
+ "compileDebug",
478
+ "client",
479
+ "_with",
480
+ "rmWhitespace",
481
+ "strict",
482
+ "filename",
483
+ "async"
484
+ ];
485
+ var _OPTS_PASSABLE_WITH_DATA_EXPRESS = _OPTS_PASSABLE_WITH_DATA.concat("cache");
486
+ var _BOM = /^\uFEFF/;
487
+ var _JS_IDENTIFIER = /^[a-zA-Z_$][0-9a-zA-Z_$]*$/;
488
+ /**
489
+ * EJS template function cache. This can be a LRU object from lru-cache NPM
490
+ * module. By default, it is {@link module:utils.cache}, a simple in-process
491
+ * cache that grows continuously.
492
+ *
493
+ * @type {Cache}
494
+ */
495
+ exports.cache = utils.cache;
496
+ /**
497
+ * Custom file loader. Useful for template preprocessing or restricting access
498
+ * to a certain part of the filesystem.
499
+ *
500
+ * @type {fileLoader}
501
+ */
502
+ exports.fileLoader = fs$1.readFileSync;
503
+ /**
504
+ * Name of the object containing the locals.
505
+ *
506
+ * This variable is overridden by {@link Options}`.localsName` if it is not
507
+ * `undefined`.
508
+ *
509
+ * @type {String}
510
+ * @public
511
+ */
512
+ exports.localsName = _DEFAULT_LOCALS_NAME;
513
+ /**
514
+ * Promise implementation -- defaults to the native implementation if available
515
+ * This is mostly just for testability
516
+ *
517
+ * @type {PromiseConstructorLike}
518
+ * @public
519
+ */
520
+ exports.promiseImpl = new Function("return this;")().Promise;
521
+ /**
522
+ * Get the path to the included file from the parent file path and the
523
+ * specified path.
524
+ *
525
+ * @param {String} name specified path
526
+ * @param {String} filename parent file path
527
+ * @param {Boolean} [isDir=false] whether the parent file path is a directory
528
+ * @return {String}
529
+ */
530
+ exports.resolveInclude = function(name, filename, isDir) {
531
+ var dirname = path$1.dirname;
532
+ var extname = path$1.extname;
533
+ var resolve$1 = path$1.resolve;
534
+ var includePath = resolve$1(isDir ? filename : dirname(filename), name);
535
+ if (!extname(name)) includePath += ".ejs";
536
+ return includePath;
537
+ };
538
+ /**
539
+ * Try to resolve file path on multiple directories
540
+ *
541
+ * @param {String} name specified path
542
+ * @param {Array<String>} paths list of possible parent directory paths
543
+ * @return {String}
544
+ */
545
+ function resolvePaths(name, paths) {
546
+ var filePath;
547
+ if (paths.some(function(v) {
548
+ filePath = exports.resolveInclude(name, v, true);
549
+ return fs$1.existsSync(filePath);
550
+ })) return filePath;
551
+ }
552
+ /**
553
+ * Get the path to the included file by Options
554
+ *
555
+ * @param {String} path specified path
556
+ * @param {Options} options compilation options
557
+ * @return {String}
558
+ */
559
+ function getIncludePath(path$2, options) {
560
+ var includePath;
561
+ var filePath;
562
+ var views = options.views;
563
+ var match = /^[A-Za-z]+:\\|^\//.exec(path$2);
564
+ if (match && match.length) {
565
+ path$2 = path$2.replace(/^\/*/, "");
566
+ if (Array.isArray(options.root)) includePath = resolvePaths(path$2, options.root);
567
+ else includePath = exports.resolveInclude(path$2, options.root || "/", true);
568
+ } else {
569
+ if (options.filename) {
570
+ filePath = exports.resolveInclude(path$2, options.filename);
571
+ if (fs$1.existsSync(filePath)) includePath = filePath;
572
+ }
573
+ if (!includePath && Array.isArray(views)) includePath = resolvePaths(path$2, views);
574
+ if (!includePath && typeof options.includer !== "function") throw new Error("Could not find the include file \"" + options.escapeFunction(path$2) + "\"");
575
+ }
576
+ return includePath;
577
+ }
578
+ /**
579
+ * Get the template from a string or a file, either compiled on-the-fly or
580
+ * read from cache (if enabled), and cache the template if needed.
581
+ *
582
+ * If `template` is not set, the file specified in `options.filename` will be
583
+ * read.
584
+ *
585
+ * If `options.cache` is true, this function reads the file from
586
+ * `options.filename` so it must be set prior to calling this function.
587
+ *
588
+ * @memberof module:ejs-internal
589
+ * @param {Options} options compilation options
590
+ * @param {String} [template] template source
591
+ * @return {(TemplateFunction|ClientFunction)}
592
+ * Depending on the value of `options.client`, either type might be returned.
593
+ * @static
594
+ */
595
+ function handleCache(options, template) {
596
+ var func;
597
+ var filename = options.filename;
598
+ var hasTemplate = arguments.length > 1;
599
+ if (options.cache) {
600
+ if (!filename) throw new Error("cache option requires a filename");
601
+ func = exports.cache.get(filename);
602
+ if (func) return func;
603
+ if (!hasTemplate) template = fileLoader(filename).toString().replace(_BOM, "");
604
+ } else if (!hasTemplate) {
605
+ // istanbul ignore if: should not happen at all
606
+ if (!filename) throw new Error("Internal EJS error: no file name or template provided");
607
+ template = fileLoader(filename).toString().replace(_BOM, "");
608
+ }
609
+ func = exports.compile(template, options);
610
+ if (options.cache) exports.cache.set(filename, func);
611
+ return func;
612
+ }
613
+ /**
614
+ * Try calling handleCache with the given options and data and call the
615
+ * callback with the result. If an error occurs, call the callback with
616
+ * the error. Used by renderFile().
617
+ *
618
+ * @memberof module:ejs-internal
619
+ * @param {Options} options compilation options
620
+ * @param {Object} data template data
621
+ * @param {RenderFileCallback} cb callback
622
+ * @static
623
+ */
624
+ function tryHandleCache(options, data, cb) {
625
+ var result;
626
+ if (!cb) if (typeof exports.promiseImpl == "function") return new exports.promiseImpl(function(resolve$1, reject) {
627
+ try {
628
+ result = handleCache(options)(data);
629
+ resolve$1(result);
630
+ } catch (err) {
631
+ reject(err);
632
+ }
633
+ });
634
+ else throw new Error("Please provide a callback function");
635
+ else {
636
+ try {
637
+ result = handleCache(options)(data);
638
+ } catch (err) {
639
+ return cb(err);
640
+ }
641
+ cb(null, result);
642
+ }
643
+ }
644
+ /**
645
+ * fileLoader is independent
646
+ *
647
+ * @param {String} filePath ejs file path.
648
+ * @return {String} The contents of the specified file.
649
+ * @static
650
+ */
651
+ function fileLoader(filePath) {
652
+ return exports.fileLoader(filePath);
653
+ }
654
+ /**
655
+ * Get the template function.
656
+ *
657
+ * If `options.cache` is `true`, then the template is cached.
658
+ *
659
+ * @memberof module:ejs-internal
660
+ * @param {String} path path for the specified file
661
+ * @param {Options} options compilation options
662
+ * @return {(TemplateFunction|ClientFunction)}
663
+ * Depending on the value of `options.client`, either type might be returned
664
+ * @static
665
+ */
666
+ function includeFile(path$2, options) {
667
+ var opts = utils.shallowCopy(utils.createNullProtoObjWherePossible(), options);
668
+ opts.filename = getIncludePath(path$2, opts);
669
+ if (typeof options.includer === "function") {
670
+ var includerResult = options.includer(path$2, opts.filename);
671
+ if (includerResult) {
672
+ if (includerResult.filename) opts.filename = includerResult.filename;
673
+ if (includerResult.template) return handleCache(opts, includerResult.template);
674
+ }
675
+ }
676
+ return handleCache(opts);
677
+ }
678
+ /**
679
+ * Re-throw the given `err` in context to the `str` of ejs, `filename`, and
680
+ * `lineno`.
681
+ *
682
+ * @implements {RethrowCallback}
683
+ * @memberof module:ejs-internal
684
+ * @param {Error} err Error object
685
+ * @param {String} str EJS source
686
+ * @param {String} flnm file name of the EJS file
687
+ * @param {Number} lineno line number of the error
688
+ * @param {EscapeCallback} esc
689
+ * @static
690
+ */
691
+ function rethrow(err, str, flnm, lineno, esc) {
692
+ var lines = str.split("\n");
693
+ var start = Math.max(lineno - 3, 0);
694
+ var end = Math.min(lines.length, lineno + 3);
695
+ var filename = esc(flnm);
696
+ var context = lines.slice(start, end).map(function(line, i) {
697
+ var curr = i + start + 1;
698
+ return (curr == lineno ? " >> " : " ") + curr + "| " + line;
699
+ }).join("\n");
700
+ err.path = filename;
701
+ err.message = (filename || "ejs") + ":" + lineno + "\n" + context + "\n\n" + err.message;
702
+ throw err;
703
+ }
704
+ function stripSemi(str) {
705
+ return str.replace(/;(\s*$)/, "$1");
706
+ }
707
+ /**
708
+ * Compile the given `str` of ejs into a template function.
709
+ *
710
+ * @param {String} template EJS template
711
+ *
712
+ * @param {Options} [opts] compilation options
713
+ *
714
+ * @return {(TemplateFunction|ClientFunction)}
715
+ * Depending on the value of `opts.client`, either type might be returned.
716
+ * Note that the return type of the function also depends on the value of `opts.async`.
717
+ * @public
718
+ */
719
+ exports.compile = function compile(template, opts) {
720
+ var templ;
721
+ if (opts && opts.scope) {
722
+ if (!scopeOptionWarned) {
723
+ console.warn("`scope` option is deprecated and will be removed in EJS 3");
724
+ scopeOptionWarned = true;
725
+ }
726
+ if (!opts.context) opts.context = opts.scope;
727
+ delete opts.scope;
728
+ }
729
+ templ = new Template(template, opts);
730
+ return templ.compile();
731
+ };
732
+ /**
733
+ * Render the given `template` of ejs.
734
+ *
735
+ * If you would like to include options but not data, you need to explicitly
736
+ * call this function with `data` being an empty object or `null`.
737
+ *
738
+ * @param {String} template EJS template
739
+ * @param {Object} [data={}] template data
740
+ * @param {Options} [opts={}] compilation and rendering options
741
+ * @return {(String|Promise<String>)}
742
+ * Return value type depends on `opts.async`.
743
+ * @public
744
+ */
745
+ exports.render = function(template, d, o) {
746
+ var data = d || utils.createNullProtoObjWherePossible();
747
+ var opts = o || utils.createNullProtoObjWherePossible();
748
+ if (arguments.length == 2) utils.shallowCopyFromList(opts, data, _OPTS_PASSABLE_WITH_DATA);
749
+ return handleCache(opts, template)(data);
750
+ };
751
+ /**
752
+ * Render an EJS file at the given `path` and callback `cb(err, str)`.
753
+ *
754
+ * If you would like to include options but not data, you need to explicitly
755
+ * call this function with `data` being an empty object or `null`.
756
+ *
757
+ * @param {String} path path to the EJS file
758
+ * @param {Object} [data={}] template data
759
+ * @param {Options} [opts={}] compilation and rendering options
760
+ * @param {RenderFileCallback} cb callback
761
+ * @public
762
+ */
763
+ exports.renderFile = function() {
764
+ var args = Array.prototype.slice.call(arguments);
765
+ var filename = args.shift();
766
+ var cb;
767
+ var opts = { filename };
768
+ var data;
769
+ var viewOpts;
770
+ if (typeof arguments[arguments.length - 1] == "function") cb = args.pop();
771
+ if (args.length) {
772
+ data = args.shift();
773
+ if (args.length) utils.shallowCopy(opts, args.pop());
774
+ else {
775
+ if (data.settings) {
776
+ if (data.settings.views) opts.views = data.settings.views;
777
+ if (data.settings["view cache"]) opts.cache = true;
778
+ viewOpts = data.settings["view options"];
779
+ if (viewOpts) utils.shallowCopy(opts, viewOpts);
780
+ }
781
+ utils.shallowCopyFromList(opts, data, _OPTS_PASSABLE_WITH_DATA_EXPRESS);
782
+ }
783
+ opts.filename = filename;
784
+ } else data = utils.createNullProtoObjWherePossible();
785
+ return tryHandleCache(opts, data, cb);
786
+ };
787
+ /**
788
+ * Clear intermediate JavaScript cache. Calls {@link Cache#reset}.
789
+ * @public
790
+ */
791
+ /**
792
+ * EJS template class
793
+ * @public
794
+ */
795
+ exports.Template = Template;
796
+ exports.clearCache = function() {
797
+ exports.cache.reset();
798
+ };
799
+ function Template(text$1, optsParam) {
800
+ var opts = utils.hasOwnOnlyObject(optsParam);
801
+ var options = utils.createNullProtoObjWherePossible();
802
+ this.templateText = text$1;
803
+ /** @type {string | null} */
804
+ this.mode = null;
805
+ this.truncate = false;
806
+ this.currentLine = 1;
807
+ this.source = "";
808
+ options.client = opts.client || false;
809
+ options.escapeFunction = opts.escape || opts.escapeFunction || utils.escapeXML;
810
+ options.compileDebug = opts.compileDebug !== false;
811
+ options.debug = !!opts.debug;
812
+ options.filename = opts.filename;
813
+ options.openDelimiter = opts.openDelimiter || exports.openDelimiter || _DEFAULT_OPEN_DELIMITER;
814
+ options.closeDelimiter = opts.closeDelimiter || exports.closeDelimiter || _DEFAULT_CLOSE_DELIMITER;
815
+ options.delimiter = opts.delimiter || exports.delimiter || _DEFAULT_DELIMITER;
816
+ options.strict = opts.strict || false;
817
+ options.context = opts.context;
818
+ options.cache = opts.cache || false;
819
+ options.rmWhitespace = opts.rmWhitespace;
820
+ options.root = opts.root;
821
+ options.includer = opts.includer;
822
+ options.outputFunctionName = opts.outputFunctionName;
823
+ options.localsName = opts.localsName || exports.localsName || _DEFAULT_LOCALS_NAME;
824
+ options.views = opts.views;
825
+ options.async = opts.async;
826
+ options.destructuredLocals = opts.destructuredLocals;
827
+ options.legacyInclude = typeof opts.legacyInclude != "undefined" ? !!opts.legacyInclude : true;
828
+ if (options.strict) options._with = false;
829
+ else options._with = typeof opts._with != "undefined" ? opts._with : true;
830
+ this.opts = options;
831
+ this.regex = this.createRegex();
832
+ }
833
+ Template.modes = {
834
+ EVAL: "eval",
835
+ ESCAPED: "escaped",
836
+ RAW: "raw",
837
+ COMMENT: "comment",
838
+ LITERAL: "literal"
839
+ };
840
+ Template.prototype = {
841
+ createRegex: function() {
842
+ var str = _REGEX_STRING;
843
+ var delim = utils.escapeRegExpChars(this.opts.delimiter);
844
+ var open = utils.escapeRegExpChars(this.opts.openDelimiter);
845
+ var close = utils.escapeRegExpChars(this.opts.closeDelimiter);
846
+ str = str.replace(/%/g, delim).replace(/</g, open).replace(/>/g, close);
847
+ return new RegExp(str);
848
+ },
849
+ compile: function() {
850
+ /** @type {string} */
851
+ var src;
852
+ /** @type {ClientFunction} */
853
+ var fn;
854
+ var opts = this.opts;
855
+ var prepended = "";
856
+ var appended = "";
857
+ /** @type {EscapeCallback} */
858
+ var escapeFn = opts.escapeFunction;
859
+ /** @type {FunctionConstructor} */
860
+ var ctor;
861
+ /** @type {string} */
862
+ var sanitizedFilename = opts.filename ? JSON.stringify(opts.filename) : "undefined";
863
+ if (!this.source) {
864
+ this.generateSource();
865
+ prepended += " var __output = \"\";\n function __append(s) { if (s !== undefined && s !== null) __output += s }\n";
866
+ if (opts.outputFunctionName) {
867
+ if (!_JS_IDENTIFIER.test(opts.outputFunctionName)) throw new Error("outputFunctionName is not a valid JS identifier.");
868
+ prepended += " var " + opts.outputFunctionName + " = __append;\n";
869
+ }
870
+ if (opts.localsName && !_JS_IDENTIFIER.test(opts.localsName)) throw new Error("localsName is not a valid JS identifier.");
871
+ if (opts.destructuredLocals && opts.destructuredLocals.length) {
872
+ var destructuring = " var __locals = (" + opts.localsName + " || {}),\n";
873
+ for (var i = 0; i < opts.destructuredLocals.length; i++) {
874
+ var name = opts.destructuredLocals[i];
875
+ if (!_JS_IDENTIFIER.test(name)) throw new Error("destructuredLocals[" + i + "] is not a valid JS identifier.");
876
+ if (i > 0) destructuring += ",\n ";
877
+ destructuring += name + " = __locals." + name;
878
+ }
879
+ prepended += destructuring + ";\n";
880
+ }
881
+ if (opts._with !== false) {
882
+ prepended += " with (" + opts.localsName + " || {}) {\n";
883
+ appended += " }\n";
884
+ }
885
+ appended += " return __output;\n";
886
+ this.source = prepended + this.source + appended;
887
+ }
888
+ if (opts.compileDebug) src = "var __line = 1\n , __lines = " + JSON.stringify(this.templateText) + "\n , __filename = " + sanitizedFilename + ";\ntry {\n" + this.source + "} catch (e) {\n rethrow(e, __lines, __filename, __line, escapeFn);\n}\n";
889
+ else src = this.source;
890
+ if (opts.client) {
891
+ src = "escapeFn = escapeFn || " + escapeFn.toString() + ";\n" + src;
892
+ if (opts.compileDebug) src = "rethrow = rethrow || " + rethrow.toString() + ";\n" + src;
893
+ }
894
+ if (opts.strict) src = "\"use strict\";\n" + src;
895
+ if (opts.debug) console.log(src);
896
+ if (opts.compileDebug && opts.filename) src = src + "\n//# sourceURL=" + sanitizedFilename + "\n";
897
+ try {
898
+ if (opts.async) try {
899
+ ctor = new Function("return (async function(){}).constructor;")();
900
+ } catch (e) {
901
+ if (e instanceof SyntaxError) throw new Error("This environment does not support async/await");
902
+ else throw e;
903
+ }
904
+ else ctor = Function;
905
+ fn = new ctor(opts.localsName + ", escapeFn, include, rethrow", src);
906
+ } catch (e) {
907
+ // istanbul ignore else
908
+ if (e instanceof SyntaxError) {
909
+ if (opts.filename) e.message += " in " + opts.filename;
910
+ e.message += " while compiling ejs\n\n";
911
+ e.message += "If the above error is not helpful, you may want to try EJS-Lint:\n";
912
+ e.message += "https://github.com/RyanZim/EJS-Lint";
913
+ if (!opts.async) {
914
+ e.message += "\n";
915
+ e.message += "Or, if you meant to create an async function, pass `async: true` as an option.";
916
+ }
917
+ }
918
+ throw e;
919
+ }
920
+ var returnedFn = opts.client ? fn : function anonymous(data) {
921
+ var include = function(path$2, includeData) {
922
+ var d = utils.shallowCopy(utils.createNullProtoObjWherePossible(), data);
923
+ if (includeData) d = utils.shallowCopy(d, includeData);
924
+ return includeFile(path$2, opts)(d);
925
+ };
926
+ return fn.apply(opts.context, [
927
+ data || utils.createNullProtoObjWherePossible(),
928
+ escapeFn,
929
+ include,
930
+ rethrow
931
+ ]);
932
+ };
933
+ if (opts.filename && typeof Object.defineProperty === "function") {
934
+ var filename = opts.filename;
935
+ var basename = path$1.basename(filename, path$1.extname(filename));
936
+ try {
937
+ Object.defineProperty(returnedFn, "name", {
938
+ value: basename,
939
+ writable: false,
940
+ enumerable: false,
941
+ configurable: true
942
+ });
943
+ } catch (e) {}
944
+ }
945
+ return returnedFn;
946
+ },
947
+ generateSource: function() {
948
+ if (this.opts.rmWhitespace) this.templateText = this.templateText.replace(/[\r\n]+/g, "\n").replace(/^\s+|\s+$/gm, "");
949
+ this.templateText = this.templateText.replace(/[ \t]*<%_/gm, "<%_").replace(/_%>[ \t]*/gm, "_%>");
950
+ var self = this;
951
+ var matches = this.parseTemplateText();
952
+ var d = this.opts.delimiter;
953
+ var o = this.opts.openDelimiter;
954
+ var c = this.opts.closeDelimiter;
955
+ if (matches && matches.length) matches.forEach(function(line, index) {
956
+ var closing;
957
+ if (line.indexOf(o + d) === 0 && line.indexOf(o + d + d) !== 0) {
958
+ closing = matches[index + 2];
959
+ if (!(closing == d + c || closing == "-" + d + c || closing == "_" + d + c)) throw new Error("Could not find matching close tag for \"" + line + "\".");
960
+ }
961
+ self.scanLine(line);
962
+ });
963
+ },
964
+ parseTemplateText: function() {
965
+ var str = this.templateText;
966
+ var pat = this.regex;
967
+ var result = pat.exec(str);
968
+ var arr = [];
969
+ var firstPos;
970
+ while (result) {
971
+ firstPos = result.index;
972
+ if (firstPos !== 0) {
973
+ arr.push(str.substring(0, firstPos));
974
+ str = str.slice(firstPos);
975
+ }
976
+ arr.push(result[0]);
977
+ str = str.slice(result[0].length);
978
+ result = pat.exec(str);
979
+ }
980
+ if (str) arr.push(str);
981
+ return arr;
982
+ },
983
+ _addOutput: function(line) {
984
+ if (this.truncate) {
985
+ line = line.replace(/^(?:\r\n|\r|\n)/, "");
986
+ this.truncate = false;
987
+ }
988
+ if (!line) return line;
989
+ line = line.replace(/\\/g, "\\\\");
990
+ line = line.replace(/\n/g, "\\n");
991
+ line = line.replace(/\r/g, "\\r");
992
+ line = line.replace(/"/g, "\\\"");
993
+ this.source += " ; __append(\"" + line + "\")\n";
994
+ },
995
+ scanLine: function(line) {
996
+ var self = this;
997
+ var d = this.opts.delimiter;
998
+ var o = this.opts.openDelimiter;
999
+ var c = this.opts.closeDelimiter;
1000
+ var newLineCount = 0;
1001
+ newLineCount = line.split("\n").length - 1;
1002
+ switch (line) {
1003
+ case o + d:
1004
+ case o + d + "_":
1005
+ this.mode = Template.modes.EVAL;
1006
+ break;
1007
+ case o + d + "=":
1008
+ this.mode = Template.modes.ESCAPED;
1009
+ break;
1010
+ case o + d + "-":
1011
+ this.mode = Template.modes.RAW;
1012
+ break;
1013
+ case o + d + "#":
1014
+ this.mode = Template.modes.COMMENT;
1015
+ break;
1016
+ case o + d + d:
1017
+ this.mode = Template.modes.LITERAL;
1018
+ this.source += " ; __append(\"" + line.replace(o + d + d, o + d) + "\")\n";
1019
+ break;
1020
+ case d + d + c:
1021
+ this.mode = Template.modes.LITERAL;
1022
+ this.source += " ; __append(\"" + line.replace(d + d + c, d + c) + "\")\n";
1023
+ break;
1024
+ case d + c:
1025
+ case "-" + d + c:
1026
+ case "_" + d + c:
1027
+ if (this.mode == Template.modes.LITERAL) this._addOutput(line);
1028
+ this.mode = null;
1029
+ this.truncate = line.indexOf("-") === 0 || line.indexOf("_") === 0;
1030
+ break;
1031
+ default: if (this.mode) {
1032
+ switch (this.mode) {
1033
+ case Template.modes.EVAL:
1034
+ case Template.modes.ESCAPED:
1035
+ case Template.modes.RAW: if (line.lastIndexOf("//") > line.lastIndexOf("\n")) line += "\n";
1036
+ }
1037
+ switch (this.mode) {
1038
+ case Template.modes.EVAL:
1039
+ this.source += " ; " + line + "\n";
1040
+ break;
1041
+ case Template.modes.ESCAPED:
1042
+ this.source += " ; __append(escapeFn(" + stripSemi(line) + "))\n";
1043
+ break;
1044
+ case Template.modes.RAW:
1045
+ this.source += " ; __append(" + stripSemi(line) + ")\n";
1046
+ break;
1047
+ case Template.modes.COMMENT: break;
1048
+ case Template.modes.LITERAL:
1049
+ this._addOutput(line);
1050
+ break;
1051
+ }
1052
+ } else this._addOutput(line);
1053
+ }
1054
+ if (self.opts.compileDebug && newLineCount) {
1055
+ this.currentLine += newLineCount;
1056
+ this.source += " ; __line = " + this.currentLine + "\n";
1057
+ }
1058
+ }
1059
+ };
1060
+ /**
1061
+ * Escape characters reserved in XML.
1062
+ *
1063
+ * This is simply an export of {@link module:utils.escapeXML}.
1064
+ *
1065
+ * If `markup` is `undefined` or `null`, the empty string is returned.
1066
+ *
1067
+ * @param {String} markup Input string
1068
+ * @return {String} Escaped string
1069
+ * @public
1070
+ * @func
1071
+ * */
1072
+ exports.escapeXML = utils.escapeXML;
1073
+ /**
1074
+ * Express.js support.
1075
+ *
1076
+ * This is an alias for {@link module:ejs.renderFile}, in order to support
1077
+ * Express.js out-of-the-box.
1078
+ *
1079
+ * @func
1080
+ */
1081
+ exports.__express = exports.renderFile;
1082
+ /**
1083
+ * Version of EJS.
1084
+ *
1085
+ * @readonly
1086
+ * @type {String}
1087
+ * @public
1088
+ */
1089
+ exports.VERSION = _VERSION_STRING;
1090
+ /**
1091
+ * Name for detection of EJS.
1092
+ *
1093
+ * @readonly
1094
+ * @type {String}
1095
+ * @public
1096
+ */
1097
+ exports.name = _NAME;
1098
+ /* istanbul ignore if */
1099
+ if (typeof window != "undefined") window.ejs = exports;
1100
+ }) });
1101
+
1102
+ //#endregion
1103
+ //#region src/constants.ts
1104
+ var import_ejs = /* @__PURE__ */ __toESM(require_ejs(), 1);
1105
+ const DEFAULT_BANNER = "Template-Kits - 快速生成你的模板代码";
1106
+ const FEATURE_OPTIONS = [
1107
+ {
1108
+ value: "unplugin-vue-router",
1109
+ label: "Unplugin Vue Router(约定式路由)"
1110
+ },
1111
+ {
1112
+ value: "simple-git-hooks",
1113
+ label: "Simple Git Hooks(Git Commit 检查)"
1114
+ },
1115
+ {
1116
+ value: "vitest",
1117
+ label: "Vitest(单元测试)"
1118
+ }
1119
+ ];
1120
+
1121
+ //#endregion
1122
+ //#region src/index.ts
1123
+ async function promptUser() {
1124
+ const { positionals } = parseArgs({
1125
+ strict: true,
1126
+ allowPositionals: true
1127
+ });
1128
+ let targetDir = positionals[0];
1129
+ const defaultProjectName = targetDir || "Template-Kits";
1130
+ const result = {
1131
+ projectName: defaultProjectName,
1132
+ packageName: defaultProjectName,
1133
+ shouldOverwrite: false,
1134
+ features: []
1135
+ };
1136
+ if (!targetDir) targetDir = result.projectName = result.packageName = (await unwrapPrompt(text({
1137
+ message: "请输入项目名称:",
1138
+ placeholder: defaultProjectName,
1139
+ defaultValue: "",
1140
+ validate: (value) => value.trim().length === 0 ? "不能为空" : ""
1141
+ }))).trim();
1142
+ if (!canSkipEmptying(targetDir)) {
1143
+ result.shouldOverwrite = await unwrapPrompt(confirm({
1144
+ message: `${targetDir === "." ? "当前目录" : `目标文件夹 "${targetDir}"`} 非空,是否覆盖?`,
1145
+ initialValue: false
1146
+ }));
1147
+ if (!result.shouldOverwrite) {
1148
+ cancel(`${pico.red("✖")} 操作取消`);
1149
+ process.exit(0);
1150
+ }
1151
+ }
1152
+ result.features = await unwrapPrompt(multiselect({
1153
+ message: `请选择要包含的功能: ${pico.dim("(↑/↓ 切换,空格选择,a 全选,回车确认)")}`,
1154
+ options: FEATURE_OPTIONS,
1155
+ required: false
1156
+ }));
1157
+ return {
1158
+ result,
1159
+ targetDir
1160
+ };
1161
+ }
1162
+ function setupProjectDir(cwd, result, targetDir) {
1163
+ const root = path.join(cwd, targetDir);
1164
+ if (fs.existsSync(root) && result.shouldOverwrite) emptyDir(root);
1165
+ else if (!fs.existsSync(root)) fs.mkdirSync(root);
1166
+ console.log(`\n正在初始化项目 ${root}...`);
1167
+ const pkg = {
1168
+ name: result.packageName,
1169
+ version: "0.0.0"
1170
+ };
1171
+ renderFile(root, "tsconfig.json", JSON.stringify(pkg, null, 2));
1172
+ return root;
1173
+ }
1174
+ function renderTemplates(root, result) {
1175
+ const { features = [] } = result;
1176
+ const needsAutoRouter = features.includes("unplugin-vue-router");
1177
+ const needsGitHooks = features.includes("simple-git-hooks");
1178
+ const needsVitest = features.includes("vitest");
1179
+ const templateRoot = fileURLToPath(new URL("../template", import.meta.url));
1180
+ const callbacks = [];
1181
+ const render = (templateName) => {
1182
+ const templateDir = path.resolve(templateRoot, templateName);
1183
+ renderTemplate(templateDir, root, callbacks);
1184
+ };
1185
+ render("base");
1186
+ render("eslint");
1187
+ render("tsconfig");
1188
+ render(needsAutoRouter ? "router/unplugin" : "router/default");
1189
+ if (needsGitHooks) render("git-hooks");
1190
+ const rootTsConfig = {
1191
+ files: [],
1192
+ references: [{ path: "./tsconfig.node.json" }, { path: "./tsconfig.app.json" }]
1193
+ };
1194
+ if (needsVitest) {
1195
+ render("vitest");
1196
+ rootTsConfig.references.push({ path: "./tsconfig.vitest.json" });
1197
+ }
1198
+ renderFile(root, "tsconfig.json", `${JSON.stringify(rootTsConfig, null, 2)}\n`);
1199
+ renderFile(root, ".env", `VITE_APP_TITLE = ${result.packageName}\n`);
1200
+ preOrderDirectoryTraverse(root, () => {}, (filepath) => {
1201
+ if (filepath.endsWith(".ejs")) {
1202
+ const template = fs.readFileSync(filepath, "utf-8");
1203
+ const dest = filepath.replace(/\.ejs$/, "");
1204
+ const content = import_ejs.render(template, {
1205
+ needsAutoRouter,
1206
+ needsGitHooks
1207
+ });
1208
+ fs.writeFileSync(dest, content);
1209
+ fs.unlinkSync(filepath);
1210
+ }
1211
+ });
1212
+ }
1213
+ (async function() {
1214
+ const cwd = process.cwd();
1215
+ intro(pico.magenta(DEFAULT_BANNER));
1216
+ const { result, targetDir } = await promptUser();
1217
+ const root = setupProjectDir(cwd, result, targetDir);
1218
+ renderTemplates(root, result);
1219
+ outro(getOutroMessage(root, cwd));
1220
+ })();
1221
+
1222
+ //#endregion
1223
+ export { };