create-esmx 3.0.0-rc.35 → 3.0.0-rc.36

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.
package/dist/cli.d.ts CHANGED
@@ -1,2 +1,5 @@
1
- #!/usr/bin/env node
2
- export {};
1
+ import type { CliOptions } from './types';
2
+ /**
3
+ * Main function to create a project
4
+ */
5
+ export declare function cli(options?: CliOptions): Promise<void>;
@@ -1,9 +1,11 @@
1
1
  import { existsSync } from "node:fs";
2
+ import { readFileSync } from "node:fs";
2
3
  import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises";
3
4
  import { tmpdir } from "node:os";
4
5
  import { join } from "node:path";
5
6
  import { afterEach, beforeEach, describe, expect, it } from "vitest";
6
- import { createProject } from "./index.mjs";
7
+ import { cli } from "./cli.mjs";
8
+ import { getAvailableTemplates } from "./template.mjs";
7
9
  async function createTempDir(prefix = "esmx-test-") {
8
10
  return mkdtemp(join(tmpdir(), prefix));
9
11
  }
@@ -14,7 +16,75 @@ async function cleanupTempDir(tempDir) {
14
16
  console.warn(`Failed to cleanup temp directory: ${tempDir}`, error);
15
17
  }
16
18
  }
17
- describe("create-esmx integration tests", () => {
19
+ async function verifyProjectStructure(projectPath, projectName) {
20
+ expect(existsSync(projectPath)).toBe(true);
21
+ expect(existsSync(join(projectPath, "src"))).toBe(true);
22
+ const requiredFiles = [
23
+ "package.json",
24
+ "tsconfig.json",
25
+ "README.md",
26
+ "src/entry.client.ts",
27
+ "src/entry.node.ts",
28
+ "src/create-app.ts"
29
+ ];
30
+ for (const file of requiredFiles) {
31
+ expect(existsSync(join(projectPath, file))).toBe(true);
32
+ if (!existsSync(join(projectPath, file))) {
33
+ throw new Error(`Missing required file: ${file}`);
34
+ }
35
+ }
36
+ const packageJson = JSON.parse(
37
+ readFileSync(join(projectPath, "package.json"), "utf-8")
38
+ );
39
+ const typeCheckCommands = ["vue-tsc --noEmit", "tsc --noEmit"];
40
+ const typeGenCommands = [
41
+ "vue-tsc --declaration --emitDeclarationOnly --noEmit false --outDir dist/src && tsc-alias -p tsconfig.json --outDir dist/src",
42
+ "tsc --declaration --emitDeclarationOnly --outDir dist/src && tsc-alias -p tsconfig.json --outDir dist/src"
43
+ ];
44
+ expect(packageJson).toMatchObject({
45
+ name: projectName,
46
+ type: "module",
47
+ private: true,
48
+ scripts: {
49
+ dev: "esmx dev",
50
+ build: "esmx build",
51
+ preview: "esmx preview",
52
+ start: "NODE_ENV=production node dist/index.mjs"
53
+ },
54
+ dependencies: {
55
+ "@esmx/core": expect.any(String)
56
+ },
57
+ devDependencies: {
58
+ typescript: expect.any(String),
59
+ "@types/node": expect.any(String),
60
+ "tsc-alias": expect.any(String)
61
+ }
62
+ });
63
+ expect(packageJson.scripts["lint:type"]).toBeOneOf(typeCheckCommands);
64
+ expect(packageJson.scripts["build:type"]).toBeOneOf(typeGenCommands);
65
+ const tsconfig = JSON.parse(
66
+ readFileSync(join(projectPath, "tsconfig.json"), "utf-8")
67
+ );
68
+ expect(tsconfig).toMatchObject({
69
+ compilerOptions: {
70
+ module: "ESNext",
71
+ moduleResolution: "node",
72
+ target: "ESNext",
73
+ strict: true,
74
+ baseUrl: ".",
75
+ paths: {
76
+ [`${projectName}/src/*`]: ["./src/*"],
77
+ [`${projectName}/*`]: ["./*"]
78
+ }
79
+ },
80
+ include: ["src"],
81
+ exclude: ["dist", "node_modules"]
82
+ });
83
+ const readmeContent = readFileSync(join(projectPath, "README.md"), "utf-8");
84
+ expect(readmeContent.length).toBeGreaterThan(0);
85
+ expect(readmeContent).toContain(projectName);
86
+ }
87
+ describe("create-esmx CLI integration tests", () => {
18
88
  let tmpDir;
19
89
  beforeEach(async () => {
20
90
  tmpDir = await createTempDir();
@@ -22,32 +92,29 @@ describe("create-esmx integration tests", () => {
22
92
  afterEach(async () => {
23
93
  await cleanupTempDir(tmpDir);
24
94
  });
25
- it("should create project with vue2 template", async () => {
26
- const projectPath = join(tmpDir, "test-project");
27
- await createProject({
28
- argv: ["test-project", "--template", "vue2"],
29
- cwd: tmpDir,
30
- userAgent: "npm/test"
31
- });
32
- expect(existsSync(projectPath)).toBe(true);
33
- expect(existsSync(join(projectPath, "package.json"))).toBe(true);
34
- expect(existsSync(join(projectPath, "tsconfig.json"))).toBe(true);
35
- expect(existsSync(join(projectPath, "README.md"))).toBe(true);
36
- expect(existsSync(join(projectPath, "src"))).toBe(true);
37
- expect(existsSync(join(projectPath, "src/entry.client.ts"))).toBe(true);
38
- expect(existsSync(join(projectPath, "src/entry.node.ts"))).toBe(true);
39
- expect(existsSync(join(projectPath, "src/entry.server.ts"))).toBe(true);
40
- expect(existsSync(join(projectPath, "src/create-app.ts"))).toBe(true);
95
+ it("should create project with all available templates", async () => {
96
+ const templates = getAvailableTemplates();
97
+ expect(templates.length).toBeGreaterThan(0);
98
+ for (const template of templates) {
99
+ const projectName = `test-${template.folder}`;
100
+ const projectPath = join(tmpDir, projectName);
101
+ await cli({
102
+ argv: [projectName, "--template", template.folder],
103
+ cwd: tmpDir,
104
+ userAgent: "npm/test"
105
+ });
106
+ await verifyProjectStructure(projectPath, projectName);
107
+ }
41
108
  });
42
109
  it("should handle --force parameter correctly", async () => {
43
110
  const projectPath = join(tmpDir, "test-project");
44
- await createProject({
111
+ await cli({
45
112
  argv: ["test-project", "--template", "vue2"],
46
113
  cwd: tmpDir,
47
114
  userAgent: "npm/test"
48
115
  });
49
116
  expect(existsSync(join(projectPath, "package.json"))).toBe(true);
50
- await createProject({
117
+ await cli({
51
118
  argv: ["test-project", "--template", "vue2", "--force"],
52
119
  cwd: tmpDir,
53
120
  userAgent: "npm/test"
@@ -66,7 +133,7 @@ describe("create-esmx integration tests", () => {
66
133
  logOutput.push(args.join(" "));
67
134
  };
68
135
  try {
69
- await createProject({
136
+ await cli({
70
137
  argv: ["--help"],
71
138
  cwd: tmpDir,
72
139
  userAgent: "npm/test"
@@ -86,7 +153,7 @@ describe("create-esmx integration tests", () => {
86
153
  logOutput.push(args.join(" "));
87
154
  };
88
155
  try {
89
- await createProject({
156
+ await cli({
90
157
  argv: ["--version"],
91
158
  cwd: tmpDir,
92
159
  userAgent: "npm/test"
@@ -99,7 +166,7 @@ describe("create-esmx integration tests", () => {
99
166
  });
100
167
  it("should handle creating directory when target directory does not exist", async () => {
101
168
  const projectPath = join(tmpDir, "non-existent-parent", "test-project");
102
- await createProject({
169
+ await cli({
103
170
  argv: ["non-existent-parent/test-project", "--template", "vue2"],
104
171
  cwd: tmpDir,
105
172
  userAgent: "npm/test"
@@ -115,7 +182,7 @@ describe("create-esmx integration tests", () => {
115
182
  join(projectPath, "existing-file.txt"),
116
183
  "existing content"
117
184
  );
118
- await createProject({
185
+ await cli({
119
186
  argv: ["test-project", "--template", "vue2", "--force"],
120
187
  cwd: tmpDir,
121
188
  userAgent: "npm/test"
@@ -126,7 +193,7 @@ describe("create-esmx integration tests", () => {
126
193
  it("should handle force overwrite in current directory", async () => {
127
194
  const testFile = join(tmpDir, "existing-file.txt");
128
195
  await writeFile(testFile, "existing content");
129
- await createProject({
196
+ await cli({
130
197
  argv: [".", "--template", "vue2", "--force"],
131
198
  cwd: tmpDir,
132
199
  userAgent: "npm/test"
@@ -136,7 +203,7 @@ describe("create-esmx integration tests", () => {
136
203
  expect(existsSync(join(tmpDir, "src/entry.client.ts"))).toBe(true);
137
204
  });
138
205
  it('should create project in current directory when target is "."', async () => {
139
- await createProject({
206
+ await cli({
140
207
  argv: [".", "--template", "vue2"],
141
208
  cwd: tmpDir,
142
209
  userAgent: "npm/test"
@@ -153,7 +220,7 @@ describe("create-esmx integration tests", () => {
153
220
  ];
154
221
  for (const projectName of testCases) {
155
222
  const projectPath = join(tmpDir, projectName);
156
- await createProject({
223
+ await cli({
157
224
  argv: [projectName, "--template", "vue2"],
158
225
  cwd: tmpDir,
159
226
  userAgent: "npm/test"
package/dist/cli.mjs CHANGED
@@ -1,6 +1,156 @@
1
- #!/usr/bin/env node
2
- import { createProject } from "./index.mjs";
3
- createProject().catch((error) => {
4
- console.error("Error creating project:", error);
5
- process.exit(1);
6
- });
1
+ import {
2
+ cancel,
3
+ intro,
4
+ isCancel,
5
+ note,
6
+ outro,
7
+ select,
8
+ text
9
+ } from "@clack/prompts";
10
+ import minimist from "minimist";
11
+ import color from "picocolors";
12
+ import { createProjectFromTemplate } from "./project.mjs";
13
+ import { getAvailableTemplates, getEsmxVersion } from "./template.mjs";
14
+ import { formatProjectName, getCommand } from "./utils/index.mjs";
15
+ function showHelp(userAgent) {
16
+ const createCmd = getCommand("create", userAgent);
17
+ console.log(`
18
+ ${color.reset(color.bold(color.blue("\u{1F680} Create Esmx Project")))}
19
+
20
+ ${color.bold("Usage:")}
21
+ ${createCmd} [project-name]
22
+ ${createCmd} [project-name] [options]
23
+
24
+ ${color.bold("Options:")}
25
+ -t, --template <template> Template to use (default: vue2)
26
+ -n, --name <name> Project name or path
27
+ -f, --force Force overwrite existing directory
28
+ -h, --help Show help information
29
+ -v, --version Show version number
30
+
31
+ ${color.bold("Examples:")}
32
+ ${createCmd} my-project
33
+ ${createCmd} my-project -t vue2
34
+ ${createCmd} my-project --force
35
+ ${createCmd} . -f -t vue2
36
+
37
+ ${color.bold("Available Templates:")}
38
+ ${getAvailableTemplates().map((t) => ` ${t.folder.padEnd(25)} ${t.description}`).join("\n")}
39
+
40
+ For more information, visit: ${color.cyan("https://esmnext.com")}
41
+ `);
42
+ }
43
+ async function getProjectName(argName, positionalName) {
44
+ const providedName = argName || positionalName;
45
+ if (providedName) {
46
+ return providedName;
47
+ }
48
+ const projectName = await text({
49
+ message: "Project name or path:",
50
+ placeholder: "my-esmx-project",
51
+ validate: (value) => {
52
+ if (!value.trim()) {
53
+ return "Project name or path is required";
54
+ }
55
+ if (!/^[a-zA-Z0-9_.\/@-]+$/.test(value.trim())) {
56
+ return "Project name or path should only contain letters, numbers, hyphens, underscores, dots, and slashes";
57
+ }
58
+ }
59
+ });
60
+ return String(projectName).trim();
61
+ }
62
+ async function getTemplateType(argTemplate) {
63
+ const availableTemplates = getAvailableTemplates();
64
+ if (argTemplate && availableTemplates.some((t) => t.folder === argTemplate)) {
65
+ return argTemplate;
66
+ }
67
+ const options = availableTemplates.map((t) => ({
68
+ label: color.reset(color.gray(`${t.folder} - `) + color.bold(t.name)),
69
+ value: t.folder,
70
+ hint: t.description
71
+ }));
72
+ const template = await select({
73
+ message: "Select a template:",
74
+ options
75
+ });
76
+ return template;
77
+ }
78
+ export async function cli(options = {}) {
79
+ const { argv, cwd, userAgent } = options;
80
+ const commandLineArgs = argv || process.argv.slice(2);
81
+ const workingDir = cwd || process.cwd();
82
+ const parsedArgs = minimist(commandLineArgs, {
83
+ string: ["template", "name"],
84
+ boolean: ["help", "version", "force"],
85
+ alias: {
86
+ t: "template",
87
+ n: "name",
88
+ f: "force",
89
+ h: "help",
90
+ v: "version"
91
+ }
92
+ });
93
+ if (parsedArgs.help) {
94
+ showHelp(userAgent);
95
+ return;
96
+ }
97
+ if (parsedArgs.version) {
98
+ console.log(getEsmxVersion());
99
+ return;
100
+ }
101
+ console.log();
102
+ intro(
103
+ color.reset(
104
+ color.bold(color.blue("\u{1F680} Welcome to Esmx Project Creator!"))
105
+ )
106
+ );
107
+ const projectNameInput = await getProjectName(
108
+ parsedArgs.name,
109
+ parsedArgs._[0]
110
+ );
111
+ if (isCancel(projectNameInput)) {
112
+ cancel("Operation cancelled");
113
+ return;
114
+ }
115
+ const { packageName, targetDir } = formatProjectName(
116
+ projectNameInput,
117
+ workingDir
118
+ );
119
+ const templateType = await getTemplateType(parsedArgs.template);
120
+ if (isCancel(templateType)) {
121
+ cancel("Operation cancelled");
122
+ return;
123
+ }
124
+ const installCommand = getCommand("install", userAgent);
125
+ const devCommand = getCommand("dev", userAgent);
126
+ const buildCommand = getCommand("build", userAgent);
127
+ const startCommand = getCommand("start", userAgent);
128
+ const buildTypeCommand = getCommand("build:type", userAgent);
129
+ const lintTypeCommand = getCommand("lint:type", userAgent);
130
+ await createProjectFromTemplate(
131
+ targetDir,
132
+ templateType,
133
+ workingDir,
134
+ parsedArgs.force,
135
+ {
136
+ projectName: packageName,
137
+ esmxVersion: getEsmxVersion(),
138
+ installCommand,
139
+ devCommand,
140
+ buildCommand,
141
+ startCommand,
142
+ buildTypeCommand,
143
+ lintTypeCommand
144
+ }
145
+ );
146
+ const installCmd = installCommand;
147
+ const devCmd = devCommand;
148
+ const nextSteps = [
149
+ color.reset(`1. ${color.cyan(`cd ${targetDir}`)}`),
150
+ color.reset(`2. ${color.cyan(installCmd)}`),
151
+ color.reset(`3. ${color.cyan("git init")} ${color.gray("(optional)")}`),
152
+ color.reset(`4. ${color.cyan(devCmd)}`)
153
+ ];
154
+ note(nextSteps.join("\n"), "Next steps");
155
+ outro(color.reset(color.green("Happy coding! \u{1F389}")));
156
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env node
2
+ import { cli } from "./cli.mjs";
3
+ cli().catch((error) => {
4
+ console.error("Error creating project:", error);
5
+ process.exit(1);
6
+ });
package/dist/index.d.ts CHANGED
@@ -1,8 +1 @@
1
- #!/usr/bin/env node
2
- interface CreateProjectOptions {
3
- argv?: string[];
4
- cwd?: string;
5
- userAgent?: string;
6
- }
7
- export declare function createProject(options?: CreateProjectOptions): Promise<void>;
8
- export default createProject;
1
+ export { cli } from './cli';
package/dist/index.mjs CHANGED
@@ -1,276 +1 @@
1
- #!/usr/bin/env node
2
- import {
3
- existsSync,
4
- mkdirSync,
5
- readFileSync,
6
- readdirSync,
7
- statSync,
8
- writeFileSync
9
- } from "node:fs";
10
- import { dirname, join, resolve } from "node:path";
11
- import { fileURLToPath } from "node:url";
12
- import {
13
- cancel,
14
- confirm,
15
- intro,
16
- isCancel,
17
- note,
18
- outro,
19
- select,
20
- text
21
- } from "@clack/prompts";
22
- import minimist from "minimist";
23
- import color from "picocolors";
24
- import {
25
- formatProjectName,
26
- getCommand,
27
- replaceTemplateVariables
28
- } from "./utils/index.mjs";
29
- const __dirname = dirname(fileURLToPath(import.meta.url));
30
- function getEsmxVersion() {
31
- try {
32
- const packageJsonPath = resolve(__dirname, "../package.json");
33
- const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
34
- return packageJson.version || "latest";
35
- } catch (error) {
36
- console.warn("Failed to read esmx version, using latest version");
37
- return "latest";
38
- }
39
- }
40
- function getAvailableTemplates() {
41
- const templateDir = resolve(__dirname, "../template");
42
- const templates = [];
43
- const templateFolders = readdirSync(templateDir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => dirent.name);
44
- for (const folder of templateFolders) {
45
- const name = folder;
46
- const packageJsonPath = resolve(templateDir, folder, "package.json");
47
- let description = `${name} template`;
48
- if (existsSync(packageJsonPath)) {
49
- try {
50
- const packageJson = JSON.parse(
51
- readFileSync(packageJsonPath, "utf-8")
52
- );
53
- if (packageJson.description) {
54
- description = packageJson.description;
55
- }
56
- templates.push({
57
- folder,
58
- name,
59
- description
60
- });
61
- } catch (error) {
62
- console.warn(
63
- `Warning: Failed to parse package.json for template '${folder}', skipping.`
64
- );
65
- }
66
- }
67
- }
68
- return templates.sort((a, b) => a.name.localeCompare(b.name));
69
- }
70
- function showHelp(userAgent) {
71
- const createCmd = getCommand("create", userAgent);
72
- console.log(`
73
- ${color.reset(color.bold(color.blue("\u{1F680} Create Esmx Project")))}
74
-
75
- ${color.bold("Usage:")}
76
- ${createCmd} [project-name]
77
- ${createCmd} [project-name] [options]
78
-
79
- ${color.bold("Options:")}
80
- -t, --template <template> Template to use (default: vue2)
81
- -n, --name <name> Project name or path
82
- -f, --force Force overwrite existing directory
83
- -h, --help Show help information
84
- -v, --version Show version number
85
-
86
- ${color.bold("Examples:")}
87
- ${createCmd} my-project
88
- ${createCmd} my-project -t vue2
89
- ${createCmd} my-project --force
90
- ${createCmd} . -f -t vue2
91
-
92
- ${color.bold("Available Templates:")}
93
- ${getAvailableTemplates().map((t) => ` ${t.folder.padEnd(25)} ${t.description}`).join("\n")}
94
-
95
- For more information, visit: ${color.cyan("https://esmnext.com")}
96
- `);
97
- }
98
- export async function createProject(options = {}) {
99
- const { argv, cwd, userAgent } = options;
100
- const commandLineArgs = argv || process.argv.slice(2);
101
- const workingDir = cwd || process.cwd();
102
- const parsedArgs = minimist(commandLineArgs, {
103
- string: ["template", "name"],
104
- boolean: ["help", "version", "force"],
105
- alias: {
106
- t: "template",
107
- n: "name",
108
- f: "force",
109
- h: "help",
110
- v: "version"
111
- }
112
- });
113
- if (parsedArgs.help) {
114
- showHelp(userAgent);
115
- return;
116
- }
117
- if (parsedArgs.version) {
118
- console.log(getEsmxVersion());
119
- return;
120
- }
121
- console.log();
122
- intro(
123
- color.reset(
124
- color.bold(color.blue("\u{1F680} Welcome to Esmx Project Creator!"))
125
- )
126
- );
127
- const projectNameInput = await getProjectName(
128
- parsedArgs.name,
129
- parsedArgs._[0]
130
- );
131
- if (isCancel(projectNameInput)) {
132
- cancel("Operation cancelled");
133
- return;
134
- }
135
- const { packageName, targetDir } = formatProjectName(
136
- projectNameInput,
137
- workingDir
138
- );
139
- const templateType = await getTemplateType(parsedArgs.template);
140
- if (isCancel(templateType)) {
141
- cancel("Operation cancelled");
142
- return;
143
- }
144
- const installCommand = getCommand("install", userAgent);
145
- const devCommand = getCommand("dev", userAgent);
146
- const buildCommand = getCommand("build", userAgent);
147
- const startCommand = getCommand("start", userAgent);
148
- const buildTypeCommand = getCommand("build:type", userAgent);
149
- const lintTypeCommand = getCommand("lint:type", userAgent);
150
- await createProjectFromTemplate(
151
- targetDir,
152
- templateType,
153
- workingDir,
154
- parsedArgs.force,
155
- {
156
- projectName: packageName,
157
- esmxVersion: getEsmxVersion(),
158
- installCommand,
159
- devCommand,
160
- buildCommand,
161
- startCommand,
162
- buildTypeCommand,
163
- lintTypeCommand
164
- }
165
- );
166
- const installCmd = installCommand;
167
- const devCmd = devCommand;
168
- const nextSteps = [
169
- color.reset(`1. ${color.cyan(`cd ${targetDir}`)}`),
170
- color.reset(`2. ${color.cyan(installCmd)}`),
171
- color.reset(`3. ${color.cyan("git init")} ${color.gray("(optional)")}`),
172
- color.reset(`4. ${color.cyan(devCmd)}`)
173
- ];
174
- note(nextSteps.join("\n"), "Next steps");
175
- outro(color.reset(color.green("Happy coding! \u{1F389}")));
176
- }
177
- async function getProjectName(argName, positionalName) {
178
- const providedName = argName || positionalName;
179
- if (providedName) {
180
- return providedName;
181
- }
182
- const projectName = await text({
183
- message: "Project name or path:",
184
- placeholder: "my-esmx-project",
185
- validate: (value) => {
186
- if (!value.trim()) {
187
- return "Project name or path is required";
188
- }
189
- if (!/^[a-zA-Z0-9_.\/@-]+$/.test(value.trim())) {
190
- return "Project name or path should only contain letters, numbers, hyphens, underscores, dots, and slashes";
191
- }
192
- }
193
- });
194
- return String(projectName).trim();
195
- }
196
- async function getTemplateType(argTemplate) {
197
- const availableTemplates = getAvailableTemplates();
198
- if (argTemplate && availableTemplates.some((t) => t.folder === argTemplate)) {
199
- return argTemplate;
200
- }
201
- const options = availableTemplates.map((t) => ({
202
- label: color.reset(color.gray(`${t.folder} - `) + color.bold(t.name)),
203
- value: t.folder,
204
- hint: t.description
205
- }));
206
- const template = await select({
207
- message: "Select a template:",
208
- options
209
- });
210
- return template;
211
- }
212
- function isDirectoryEmpty(dirPath) {
213
- if (!existsSync(dirPath)) {
214
- return true;
215
- }
216
- const files = readdirSync(dirPath);
217
- const nonHiddenFiles = files.filter((file) => !file.startsWith("."));
218
- return nonHiddenFiles.length === 0;
219
- }
220
- async function createProjectFromTemplate(targetDir, templateType, workingDir, force, variables) {
221
- const templatePath = resolve(__dirname, "../template", templateType);
222
- const targetPath = targetDir === "." ? workingDir : resolve(workingDir, targetDir);
223
- if (!existsSync(templatePath)) {
224
- throw new Error(`Template "${templateType}" not found`);
225
- }
226
- if (targetDir !== "." && existsSync(targetPath)) {
227
- if (!isDirectoryEmpty(targetPath)) {
228
- if (!force) {
229
- const shouldOverwrite = await confirm({
230
- message: `Directory "${targetDir}" is not empty. Do you want to overwrite it?`
231
- });
232
- if (isCancel(shouldOverwrite)) {
233
- cancel("Operation cancelled");
234
- return;
235
- }
236
- if (!shouldOverwrite) {
237
- throw new Error("Operation cancelled by user");
238
- }
239
- }
240
- }
241
- } else if (targetDir !== ".") {
242
- mkdirSync(targetPath, { recursive: true });
243
- }
244
- if (targetDir === "." && !isDirectoryEmpty(targetPath)) {
245
- if (!force) {
246
- const shouldOverwrite = await confirm({
247
- message: "Current directory is not empty. Do you want to overwrite existing files?"
248
- });
249
- if (isCancel(shouldOverwrite)) {
250
- cancel("Operation cancelled");
251
- return;
252
- }
253
- if (!shouldOverwrite) {
254
- throw new Error("Operation cancelled by user");
255
- }
256
- }
257
- }
258
- copyTemplateFiles(templatePath, targetPath, variables);
259
- }
260
- function copyTemplateFiles(templatePath, targetPath, variables) {
261
- const files = readdirSync(templatePath);
262
- for (const file of files) {
263
- const filePath = join(templatePath, file);
264
- const targetFilePath = join(targetPath, file);
265
- const stat = statSync(filePath);
266
- if (stat.isDirectory()) {
267
- mkdirSync(targetFilePath, { recursive: true });
268
- copyTemplateFiles(filePath, targetFilePath, variables);
269
- } else {
270
- let content = readFileSync(filePath, "utf-8");
271
- content = replaceTemplateVariables(content, variables);
272
- writeFileSync(targetFilePath, content);
273
- }
274
- }
275
- }
276
- export default createProject;
1
+ export { cli } from "./cli.mjs";
@@ -0,0 +1,5 @@
1
+ import type { TemplateVariables } from './types';
2
+ /**
3
+ * Create a project from template
4
+ */
5
+ export declare function createProjectFromTemplate(targetDir: string, templateType: string, workingDir: string, force: boolean, variables: TemplateVariables): Promise<void>;