@tanstack/create-start 1.92.0
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/LICENSE +21 -0
- package/README.md +0 -0
- package/dist/cli-entry.d.ts +1 -0
- package/dist/cli-entry.mjs +5 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.mjs +92 -0
- package/dist/constants.d.ts +3 -0
- package/dist/constants.mjs +7 -0
- package/dist/directory.d.ts +3 -0
- package/dist/directory.mjs +62 -0
- package/dist/index.d.ts +2446 -0
- package/dist/index.mjs +15 -0
- package/dist/logo.d.ts +1 -0
- package/dist/logo.mjs +28 -0
- package/dist/module.d.ts +67 -0
- package/dist/module.mjs +168 -0
- package/dist/modules/core/index.d.ts +1446 -0
- package/dist/modules/core/index.mjs +218 -0
- package/dist/modules/core/template/app/client.tsx +10 -0
- package/dist/modules/core/template/app/router.tsx +18 -0
- package/dist/modules/core/template/app/routes/__root.tsx +50 -0
- package/dist/modules/core/template/app/ssr.tsx +15 -0
- package/dist/modules/core/template/app.config.ts +5 -0
- package/dist/modules/core/template/tsconfig.json +10 -0
- package/dist/modules/git.d.ts +231 -0
- package/dist/modules/git.mjs +114 -0
- package/dist/modules/ide.d.ts +92 -0
- package/dist/modules/ide.mjs +70 -0
- package/dist/modules/packageJson.d.ts +541 -0
- package/dist/modules/packageJson.mjs +153 -0
- package/dist/modules/packageManager.d.ts +139 -0
- package/dist/modules/packageManager.mjs +89 -0
- package/dist/modules/vscode/index.d.ts +33 -0
- package/dist/modules/vscode/index.mjs +35 -0
- package/dist/modules/vscode/template/_dot_vscode/settings.json +11 -0
- package/dist/templates/barebones/index.d.ts +1507 -0
- package/dist/templates/barebones/index.mjs +60 -0
- package/dist/templates/barebones/template/app/routes/index.tsx +11 -0
- package/dist/templates/index.d.ts +13 -0
- package/dist/templates/index.mjs +60 -0
- package/dist/types.d.ts +2 -0
- package/dist/types.mjs +0 -0
- package/dist/utils/debug.d.ts +11 -0
- package/dist/utils/debug.mjs +71 -0
- package/dist/utils/getPackageManager.d.ts +2 -0
- package/dist/utils/getPackageManager.mjs +11 -0
- package/dist/utils/helpers/helperFactory.d.ts +15 -0
- package/dist/utils/helpers/helperFactory.mjs +3 -0
- package/dist/utils/helpers/index.d.ts +51 -0
- package/dist/utils/helpers/index.mjs +227 -0
- package/dist/utils/runCmd.d.ts +1 -0
- package/dist/utils/runCmd.mjs +4 -0
- package/dist/utils/runPackageManagerCommand.d.ts +4 -0
- package/dist/utils/runPackageManagerCommand.mjs +17 -0
- package/dist/utils/spawnCmd.d.ts +1 -0
- package/dist/utils/spawnCmd.mjs +30 -0
- package/dist/utils/validateProjectName.d.ts +8 -0
- package/dist/utils/validateProjectName.mjs +14 -0
- package/index.js +3 -0
- package/package.json +66 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url";
|
|
2
|
+
import { dirname } from "node:path";
|
|
3
|
+
import { createModule, runWithSpinner } from "../../module.mjs";
|
|
4
|
+
import { coreModule } from "../../modules/core/index.mjs";
|
|
5
|
+
import { initHelpers } from "../../utils/helpers/index.mjs";
|
|
6
|
+
import { createDebugger } from "../../utils/debug.mjs";
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = dirname(__filename);
|
|
9
|
+
const debug = createDebugger("barebones-template");
|
|
10
|
+
const schema = coreModule._initSchema;
|
|
11
|
+
export const barebonesTemplate = createModule(schema).init((schema2) => schema2).prompt(
|
|
12
|
+
(schema2) => schema2.transform(async (vals) => {
|
|
13
|
+
debug.verbose("Transforming prompt schema", { vals });
|
|
14
|
+
const core = await coreModule._promptSchema.parseAsync(vals);
|
|
15
|
+
debug.verbose("Core module prompt complete");
|
|
16
|
+
return {
|
|
17
|
+
...core
|
|
18
|
+
};
|
|
19
|
+
})
|
|
20
|
+
).validateAndApply({
|
|
21
|
+
validate: async ({ cfg, targetPath }) => {
|
|
22
|
+
debug.verbose("Validating barebones template", { targetPath });
|
|
23
|
+
const _ = initHelpers(__dirname, targetPath);
|
|
24
|
+
const issues = await _.getTemplateFilesThatWouldBeOverwritten({
|
|
25
|
+
file: "**/*",
|
|
26
|
+
templateFolder: "./template",
|
|
27
|
+
targetFolder: targetPath,
|
|
28
|
+
overwrite: false
|
|
29
|
+
});
|
|
30
|
+
debug.verbose("Template file conflicts found", { issues });
|
|
31
|
+
const coreIssues = await coreModule._validateFn?.({ cfg, targetPath }) ?? [];
|
|
32
|
+
debug.verbose("Core module validation issues", { coreIssues });
|
|
33
|
+
issues.push(...coreIssues);
|
|
34
|
+
return issues;
|
|
35
|
+
},
|
|
36
|
+
apply: async ({ cfg, targetPath }) => {
|
|
37
|
+
debug.info("Applying barebones template", { targetPath });
|
|
38
|
+
const _ = initHelpers(__dirname, targetPath);
|
|
39
|
+
await runWithSpinner({
|
|
40
|
+
spinnerOptions: {
|
|
41
|
+
inProgress: "Copying barebones template files",
|
|
42
|
+
error: "Failed to copy barebones template files",
|
|
43
|
+
success: "Copied barebones template files"
|
|
44
|
+
},
|
|
45
|
+
fn: async () => {
|
|
46
|
+
debug.verbose("Copying template files");
|
|
47
|
+
await _.copyTemplateFiles({
|
|
48
|
+
file: "**/*",
|
|
49
|
+
templateFolder: "./template",
|
|
50
|
+
targetFolder: ".",
|
|
51
|
+
overwrite: false
|
|
52
|
+
});
|
|
53
|
+
debug.verbose("Template files copied successfully");
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
debug.verbose("Applying core module");
|
|
57
|
+
await coreModule._applyFn({ cfg, targetPath });
|
|
58
|
+
debug.info("Barebones template applied successfully");
|
|
59
|
+
}
|
|
60
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { coreModule } from '../modules/core';
|
|
2
|
+
import type { z } from 'zod';
|
|
3
|
+
declare const templateIds: "barebones"[];
|
|
4
|
+
export type TEMPLATE_NAME = (typeof templateIds)[number];
|
|
5
|
+
export declare const DEFAULT_TEMPLATE: TEMPLATE_NAME;
|
|
6
|
+
export declare const templateCliOption: import("@commander-js/extra-typings").Option<"--template <string>", undefined, undefined, "barebones", false, undefined>;
|
|
7
|
+
export declare const templatePrompt: () => Promise<"barebones">;
|
|
8
|
+
export declare const scaffoldTemplate: ({ templateId, cfg, targetPath, }: {
|
|
9
|
+
templateId: TEMPLATE_NAME;
|
|
10
|
+
cfg: z.input<typeof coreModule._baseSchema>;
|
|
11
|
+
targetPath: string;
|
|
12
|
+
}) => Promise<void>;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { select } from "@inquirer/prompts";
|
|
2
|
+
import { InvalidArgumentError, createOption } from "@commander-js/extra-typings";
|
|
3
|
+
import invariant from "tiny-invariant";
|
|
4
|
+
import { createDebugger } from "../utils/debug.mjs";
|
|
5
|
+
import { barebonesTemplate } from "./barebones/index.mjs";
|
|
6
|
+
const debug = createDebugger("templates");
|
|
7
|
+
const templates = [
|
|
8
|
+
{
|
|
9
|
+
id: "barebones",
|
|
10
|
+
name: "Barebones",
|
|
11
|
+
module: barebonesTemplate,
|
|
12
|
+
description: "The bare minimum"
|
|
13
|
+
}
|
|
14
|
+
];
|
|
15
|
+
const templateIds = templates.map((t) => t.id);
|
|
16
|
+
export const DEFAULT_TEMPLATE = "barebones";
|
|
17
|
+
export const templateCliOption = createOption(
|
|
18
|
+
"--template <string>",
|
|
19
|
+
"Choose the template to use"
|
|
20
|
+
).argParser((value) => {
|
|
21
|
+
if (!templateIds.includes(value)) {
|
|
22
|
+
debug.error(`Invalid template specified: ${value}`);
|
|
23
|
+
throw new InvalidArgumentError(
|
|
24
|
+
`Invalid Template: ${value}. Only the following are allowed: ${templateIds.join(", ")}`
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
debug.verbose("Template validated from CLI", { template: value });
|
|
28
|
+
return value;
|
|
29
|
+
});
|
|
30
|
+
export const templatePrompt = async () => {
|
|
31
|
+
debug.info("Prompting for template selection");
|
|
32
|
+
const selection = await select({
|
|
33
|
+
message: "Which template would you like to use?",
|
|
34
|
+
choices: templates.map((t) => ({
|
|
35
|
+
name: t.name,
|
|
36
|
+
value: t.id,
|
|
37
|
+
description: t.description
|
|
38
|
+
})),
|
|
39
|
+
default: DEFAULT_TEMPLATE
|
|
40
|
+
});
|
|
41
|
+
debug.verbose("Template selected", { template: selection });
|
|
42
|
+
return selection;
|
|
43
|
+
};
|
|
44
|
+
export const scaffoldTemplate = async ({
|
|
45
|
+
templateId,
|
|
46
|
+
cfg,
|
|
47
|
+
targetPath
|
|
48
|
+
}) => {
|
|
49
|
+
debug.info("Starting template scaffolding", { templateId, targetPath });
|
|
50
|
+
const template = templates[0];
|
|
51
|
+
invariant(template, `The template with ${templateId} is not valid`);
|
|
52
|
+
debug.verbose("Executing template module", { template: template.id });
|
|
53
|
+
await template.module.execute({
|
|
54
|
+
cfg,
|
|
55
|
+
targetPath,
|
|
56
|
+
type: "new-project",
|
|
57
|
+
applyingMessage: `Scaffolding the ${template.name} template`
|
|
58
|
+
});
|
|
59
|
+
debug.info("Template scaffolding complete");
|
|
60
|
+
};
|
package/dist/types.d.ts
ADDED
package/dist/types.mjs
ADDED
|
File without changes
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type Context = string;
|
|
2
|
+
export declare const debugCliOption: import("@commander-js/extra-typings").Option<`--debug <${string}>`, undefined, undefined, "debug" | "trace" | "verbose", false, undefined>;
|
|
3
|
+
export declare const initDebug: (level: undefined | "debug" | "trace" | "verbose") => void;
|
|
4
|
+
export declare const createDebugger: (context: Context) => {
|
|
5
|
+
info: (message: string, data?: Record<string, unknown>) => void;
|
|
6
|
+
warn: (message: string, data?: Record<string, unknown>) => void;
|
|
7
|
+
error: (message: string, error?: Error | unknown, data?: Record<string, unknown>) => void;
|
|
8
|
+
verbose: (message: string, data?: Record<string, unknown>) => void;
|
|
9
|
+
trace: (message: string, data?: Record<string, unknown>) => void;
|
|
10
|
+
};
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { InvalidArgumentError, createOption } from "@commander-js/extra-typings";
|
|
2
|
+
let isDebugMode = false;
|
|
3
|
+
let debugLevel = 0;
|
|
4
|
+
const DEBUG_LEVELS = ["debug", "trace", "verbose"];
|
|
5
|
+
export const debugCliOption = createOption(
|
|
6
|
+
`--debug <${DEBUG_LEVELS.join("|")}>`,
|
|
7
|
+
`Set a debug level (${DEBUG_LEVELS.join(", ")})`
|
|
8
|
+
).argParser((value) => {
|
|
9
|
+
if (!DEBUG_LEVELS.includes(value)) {
|
|
10
|
+
throw new InvalidArgumentError(
|
|
11
|
+
`Invalid IDE: ${value}. Only the following are allowed: ${DEBUG_LEVELS.join(", ")}`
|
|
12
|
+
);
|
|
13
|
+
}
|
|
14
|
+
return value;
|
|
15
|
+
});
|
|
16
|
+
export const initDebug = (level) => {
|
|
17
|
+
if (level === void 0) return;
|
|
18
|
+
isDebugMode = true;
|
|
19
|
+
if (level === "debug") debugLevel = 1;
|
|
20
|
+
if (level === "trace") debugLevel = 2;
|
|
21
|
+
if (level === "verbose") debugLevel = 3;
|
|
22
|
+
};
|
|
23
|
+
const formatData = (data) => {
|
|
24
|
+
if (!data) return "";
|
|
25
|
+
return Object.entries(data).map(([key, value]) => `${key}=${JSON.stringify(value)}`).join(" ");
|
|
26
|
+
};
|
|
27
|
+
const log = (level, message, options) => {
|
|
28
|
+
if (!isDebugMode) return;
|
|
29
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
30
|
+
const dataStr = formatData(options.data);
|
|
31
|
+
const logMessage = `[${timestamp}] [${level}] [${options.context}] ${message} ${dataStr}`;
|
|
32
|
+
switch (level) {
|
|
33
|
+
case "error":
|
|
34
|
+
console.error(logMessage);
|
|
35
|
+
break;
|
|
36
|
+
case "warn":
|
|
37
|
+
console.warn(logMessage);
|
|
38
|
+
break;
|
|
39
|
+
case "info":
|
|
40
|
+
console.log(logMessage);
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
export const createDebugger = (context) => ({
|
|
45
|
+
info: (message, data) => {
|
|
46
|
+
if (debugLevel < 1) return;
|
|
47
|
+
log("info", message, { context, data });
|
|
48
|
+
},
|
|
49
|
+
warn: (message, data) => {
|
|
50
|
+
if (debugLevel < 2) return;
|
|
51
|
+
log("warn", message, { context, data });
|
|
52
|
+
},
|
|
53
|
+
error: (message, error, data) => {
|
|
54
|
+
if (debugLevel < 1) return;
|
|
55
|
+
log("error", message, {
|
|
56
|
+
context,
|
|
57
|
+
data: {
|
|
58
|
+
...data,
|
|
59
|
+
error: error instanceof Error ? error.message : error
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
},
|
|
63
|
+
verbose: (message, data) => {
|
|
64
|
+
if (debugLevel < 2) return;
|
|
65
|
+
log("info", message, { context, data });
|
|
66
|
+
},
|
|
67
|
+
trace: (message, data) => {
|
|
68
|
+
if (debugLevel < 3) return;
|
|
69
|
+
log("info", message, { context, data });
|
|
70
|
+
}
|
|
71
|
+
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { SUPPORTED_PACKAGE_MANAGERS } from "../constants.mjs";
|
|
2
|
+
export function getPackageManager() {
|
|
3
|
+
const userAgent = process.env.npm_config_user_agent;
|
|
4
|
+
if (userAgent === void 0) {
|
|
5
|
+
return void 0;
|
|
6
|
+
}
|
|
7
|
+
const packageManager = SUPPORTED_PACKAGE_MANAGERS.find(
|
|
8
|
+
(manager) => userAgent.startsWith(manager)
|
|
9
|
+
);
|
|
10
|
+
return packageManager;
|
|
11
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type Ctx = {
|
|
2
|
+
getFullModulePath: (relativePath: string) => string;
|
|
3
|
+
getFullTargetPath: (relativePath: string) => string;
|
|
4
|
+
targetFileExists: (relativePath: string) => Promise<boolean>;
|
|
5
|
+
moduleFileExists: (relativePath: string) => Promise<boolean>;
|
|
6
|
+
absoluteTargetFolder: string;
|
|
7
|
+
absoluteModuleFolder: string;
|
|
8
|
+
};
|
|
9
|
+
type HelperFn<T extends (...args: any) => any> = (args: {
|
|
10
|
+
modulePath: string;
|
|
11
|
+
targetPath: string;
|
|
12
|
+
ctx: Ctx;
|
|
13
|
+
}) => T;
|
|
14
|
+
export declare const helperFactory: <T extends (...args: any) => any>(fn: HelperFn<T>) => HelperFn<T>;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { Ctx } from './helperFactory';
|
|
2
|
+
export declare const initHelpers: (modulePath: string, targetPath: string) => {
|
|
3
|
+
readTargetFile: (relativePath: string) => Promise<string>;
|
|
4
|
+
writeTargetfile: (relativePath: string, content: string, overwrite?: boolean) => Promise<void>;
|
|
5
|
+
copyTemplateFiles: ({ file, templateFolder, targetFolder, overwrite, }: {
|
|
6
|
+
file: string;
|
|
7
|
+
templateFolder: string;
|
|
8
|
+
targetFolder: string;
|
|
9
|
+
overwrite: boolean;
|
|
10
|
+
}) => Promise<void>;
|
|
11
|
+
getTemplateFilesThatWouldBeOverwritten: ({ file, templateFolder, targetFolder, overwrite, }: {
|
|
12
|
+
file: string;
|
|
13
|
+
templateFolder: string;
|
|
14
|
+
targetFolder: string;
|
|
15
|
+
overwrite: boolean;
|
|
16
|
+
}) => Promise<string[]>;
|
|
17
|
+
getFullModulePath: (relativePath: string) => string;
|
|
18
|
+
getFullTargetPath: (relativePath: string) => string;
|
|
19
|
+
targetFileExists: (relativePath: string) => Promise<boolean>;
|
|
20
|
+
moduleFileExists: (relativePath: string) => Promise<boolean>;
|
|
21
|
+
absoluteTargetFolder: string;
|
|
22
|
+
absoluteModuleFolder: string;
|
|
23
|
+
};
|
|
24
|
+
export declare const checkFileExists: (path: string) => Promise<boolean>;
|
|
25
|
+
export declare const checkFolderExists: (path: string) => Promise<boolean>;
|
|
26
|
+
export declare const checkFolderIsEmpty: (path: string) => Promise<boolean>;
|
|
27
|
+
export declare const createWriteTargetFile: (args: {
|
|
28
|
+
modulePath: string;
|
|
29
|
+
targetPath: string;
|
|
30
|
+
ctx: Ctx;
|
|
31
|
+
}) => (relativePath: string, content: string, overwrite?: boolean) => Promise<void>;
|
|
32
|
+
export declare const createGetTemplateFilesThatWouldBeOverwritten: (args: {
|
|
33
|
+
modulePath: string;
|
|
34
|
+
targetPath: string;
|
|
35
|
+
ctx: Ctx;
|
|
36
|
+
}) => ({ file, templateFolder, targetFolder, overwrite, }: {
|
|
37
|
+
file: string;
|
|
38
|
+
templateFolder: string;
|
|
39
|
+
targetFolder: string;
|
|
40
|
+
overwrite: boolean;
|
|
41
|
+
}) => Promise<string[]>;
|
|
42
|
+
export declare const createCopyTemplateFiles: (args: {
|
|
43
|
+
modulePath: string;
|
|
44
|
+
targetPath: string;
|
|
45
|
+
ctx: Ctx;
|
|
46
|
+
}) => ({ file, templateFolder, targetFolder, overwrite, }: {
|
|
47
|
+
file: string;
|
|
48
|
+
templateFolder: string;
|
|
49
|
+
targetFolder: string;
|
|
50
|
+
overwrite: boolean;
|
|
51
|
+
}) => Promise<void>;
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import path, { resolve } from "node:path";
|
|
2
|
+
import fs, {
|
|
3
|
+
access,
|
|
4
|
+
copyFile,
|
|
5
|
+
mkdir,
|
|
6
|
+
readFile,
|
|
7
|
+
readdir,
|
|
8
|
+
stat,
|
|
9
|
+
writeFile
|
|
10
|
+
} from "node:fs/promises";
|
|
11
|
+
import invariant from "tiny-invariant";
|
|
12
|
+
import fastGlob from "fast-glob";
|
|
13
|
+
import { createDebugger } from "../debug.mjs";
|
|
14
|
+
import { helperFactory } from "./helperFactory.mjs";
|
|
15
|
+
const debug = createDebugger("helpers");
|
|
16
|
+
export const initHelpers = (modulePath, targetPath) => {
|
|
17
|
+
debug.info("Initializing helpers", { modulePath, targetPath });
|
|
18
|
+
const getFullModulePath = (relativePath) => {
|
|
19
|
+
const fullPath = path.join(modulePath, relativePath);
|
|
20
|
+
debug.trace("Getting full module path", { relativePath, fullPath });
|
|
21
|
+
return fullPath;
|
|
22
|
+
};
|
|
23
|
+
const getFullTargetPath = (relativePath) => {
|
|
24
|
+
const fullPath = path.join(targetPath, relativePath);
|
|
25
|
+
debug.trace("Getting full target path", { relativePath, fullPath });
|
|
26
|
+
return fullPath;
|
|
27
|
+
};
|
|
28
|
+
const targetFileExists = async (relativePath) => {
|
|
29
|
+
const path2 = resolve(targetPath, relativePath);
|
|
30
|
+
debug.trace("Checking if target file exists", { path: path2 });
|
|
31
|
+
return await checkFileExists(path2);
|
|
32
|
+
};
|
|
33
|
+
const moduleFileExists = async (relativePath) => {
|
|
34
|
+
const path2 = resolve(modulePath, relativePath);
|
|
35
|
+
debug.trace("Checking if module file exists", { path: path2 });
|
|
36
|
+
return await checkFileExists(path2);
|
|
37
|
+
};
|
|
38
|
+
const ctx = {
|
|
39
|
+
targetFileExists,
|
|
40
|
+
moduleFileExists,
|
|
41
|
+
absoluteModuleFolder: getFullModulePath(modulePath),
|
|
42
|
+
absoluteTargetFolder: getFullTargetPath(targetPath),
|
|
43
|
+
getFullModulePath,
|
|
44
|
+
getFullTargetPath
|
|
45
|
+
};
|
|
46
|
+
debug.verbose("Created helper context", ctx);
|
|
47
|
+
return {
|
|
48
|
+
...ctx,
|
|
49
|
+
readTargetFile: createReadTargetFile({
|
|
50
|
+
ctx,
|
|
51
|
+
modulePath,
|
|
52
|
+
targetPath
|
|
53
|
+
}),
|
|
54
|
+
writeTargetfile: createWriteTargetFile({
|
|
55
|
+
ctx,
|
|
56
|
+
modulePath,
|
|
57
|
+
targetPath
|
|
58
|
+
}),
|
|
59
|
+
copyTemplateFiles: createCopyTemplateFiles({
|
|
60
|
+
ctx,
|
|
61
|
+
modulePath,
|
|
62
|
+
targetPath
|
|
63
|
+
}),
|
|
64
|
+
getTemplateFilesThatWouldBeOverwritten: createGetTemplateFilesThatWouldBeOverwritten({
|
|
65
|
+
ctx,
|
|
66
|
+
modulePath,
|
|
67
|
+
targetPath
|
|
68
|
+
})
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
export const checkFileExists = async (path2) => {
|
|
72
|
+
debug.trace("Checking if file exists", { path: path2 });
|
|
73
|
+
try {
|
|
74
|
+
await access(path2, fs.constants.F_OK);
|
|
75
|
+
return true;
|
|
76
|
+
} catch {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
export const checkFolderExists = async (path2) => {
|
|
81
|
+
debug.trace("Checking if folder exists", { path: path2 });
|
|
82
|
+
try {
|
|
83
|
+
await access(path2, fs.constants.R_OK);
|
|
84
|
+
return true;
|
|
85
|
+
} catch {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
export const checkFolderIsEmpty = async (path2) => {
|
|
90
|
+
debug.trace("Checking if folder is empty", { path: path2 });
|
|
91
|
+
try {
|
|
92
|
+
const files = await readdir(path2);
|
|
93
|
+
return files.length === 0;
|
|
94
|
+
} catch {
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
const createReadTargetFile = helperFactory(
|
|
99
|
+
({ ctx, targetPath }) => async (relativePath) => {
|
|
100
|
+
debug.trace("Reading target file", { relativePath, targetPath });
|
|
101
|
+
invariant(
|
|
102
|
+
await ctx.targetFileExists(relativePath),
|
|
103
|
+
`The file ${relativePath} doesn't exist`
|
|
104
|
+
);
|
|
105
|
+
const path2 = resolve(targetPath, relativePath);
|
|
106
|
+
return await readFile(path2, "utf-8");
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
export const createWriteTargetFile = helperFactory(
|
|
110
|
+
({ targetPath }) => async (relativePath, content, overwrite = false) => {
|
|
111
|
+
debug.trace("Writing target file", {
|
|
112
|
+
relativePath,
|
|
113
|
+
targetPath,
|
|
114
|
+
overwrite
|
|
115
|
+
});
|
|
116
|
+
const path2 = resolve(targetPath, relativePath);
|
|
117
|
+
invariant(
|
|
118
|
+
!(!overwrite && await checkFileExists(path2)),
|
|
119
|
+
`File ${relativePath} already exists and overwrite is false`
|
|
120
|
+
);
|
|
121
|
+
await writeFile(path2, content);
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
const DOT_PREFIX = "_dot_";
|
|
125
|
+
const removeTsNoCheckHeader = async (filePath) => {
|
|
126
|
+
debug.trace("Removing ts-nocheck header", { filePath });
|
|
127
|
+
const content = await readFile(filePath, "utf-8");
|
|
128
|
+
const lines = content.split("\n");
|
|
129
|
+
let newContent = content;
|
|
130
|
+
if (lines[0]?.trim() === "// @ts-nocheck") {
|
|
131
|
+
newContent = lines.slice(1).join("\n").trimStart();
|
|
132
|
+
}
|
|
133
|
+
await writeFile(filePath, newContent);
|
|
134
|
+
};
|
|
135
|
+
async function copyDir(srcDir, destDir) {
|
|
136
|
+
debug.trace("Copying directory", { srcDir, destDir });
|
|
137
|
+
await mkdir(destDir, { recursive: true });
|
|
138
|
+
const files = await readdir(srcDir);
|
|
139
|
+
for (const file of files) {
|
|
140
|
+
const srcFile = resolve(srcDir, file);
|
|
141
|
+
const destFile = resolve(destDir, file);
|
|
142
|
+
await copy(srcFile, destFile);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
async function copy(src, dest) {
|
|
146
|
+
debug.trace("Copying file", { src, dest });
|
|
147
|
+
const statResult = await stat(src);
|
|
148
|
+
const replacedDest = dest.replaceAll(DOT_PREFIX, ".");
|
|
149
|
+
if (statResult.isDirectory()) {
|
|
150
|
+
await copyDir(src, replacedDest);
|
|
151
|
+
} else {
|
|
152
|
+
await copyFile(src, replacedDest);
|
|
153
|
+
await removeTsNoCheckHeader(replacedDest);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
export const createGetTemplateFilesThatWouldBeOverwritten = helperFactory(
|
|
157
|
+
({ ctx }) => async ({
|
|
158
|
+
file,
|
|
159
|
+
templateFolder,
|
|
160
|
+
targetFolder,
|
|
161
|
+
overwrite
|
|
162
|
+
}) => {
|
|
163
|
+
debug.verbose("Checking for files that would be overwritten", {
|
|
164
|
+
file,
|
|
165
|
+
templateFolder,
|
|
166
|
+
targetFolder,
|
|
167
|
+
overwrite
|
|
168
|
+
});
|
|
169
|
+
const overwrittenFiles = [];
|
|
170
|
+
if (overwrite) [];
|
|
171
|
+
const absoluteTemplateFolder = ctx.getFullModulePath(templateFolder);
|
|
172
|
+
const absoluteTargetFolder = ctx.getFullTargetPath(targetFolder);
|
|
173
|
+
const files = await fastGlob.glob(file, {
|
|
174
|
+
cwd: absoluteTemplateFolder,
|
|
175
|
+
onlyFiles: false
|
|
176
|
+
});
|
|
177
|
+
for (const file2 of files) {
|
|
178
|
+
const exists = await checkFileExists(
|
|
179
|
+
resolve(absoluteTargetFolder, file2)
|
|
180
|
+
);
|
|
181
|
+
if (exists) {
|
|
182
|
+
debug.verbose("Found file that would be overwritten", { file: file2 });
|
|
183
|
+
overwrittenFiles.push(file2);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return overwrittenFiles;
|
|
187
|
+
}
|
|
188
|
+
);
|
|
189
|
+
export const createCopyTemplateFiles = helperFactory(
|
|
190
|
+
({ ctx }) => async ({
|
|
191
|
+
file,
|
|
192
|
+
templateFolder,
|
|
193
|
+
targetFolder,
|
|
194
|
+
overwrite
|
|
195
|
+
}) => {
|
|
196
|
+
debug.verbose("Copying template files", {
|
|
197
|
+
file,
|
|
198
|
+
templateFolder,
|
|
199
|
+
targetFolder,
|
|
200
|
+
overwrite
|
|
201
|
+
});
|
|
202
|
+
const absoluteTemplateFolder = ctx.getFullModulePath(templateFolder);
|
|
203
|
+
const absoluteTargetFolder = ctx.getFullTargetPath(targetFolder);
|
|
204
|
+
const templateFolderExists = checkFolderExists(absoluteTemplateFolder);
|
|
205
|
+
invariant(
|
|
206
|
+
templateFolderExists,
|
|
207
|
+
`The template folder ${templateFolder} doesn't exist`
|
|
208
|
+
);
|
|
209
|
+
const files = await fastGlob.glob(file, {
|
|
210
|
+
cwd: absoluteTemplateFolder,
|
|
211
|
+
onlyFiles: false
|
|
212
|
+
});
|
|
213
|
+
for (const file2 of files) {
|
|
214
|
+
if (overwrite) {
|
|
215
|
+
invariant(
|
|
216
|
+
await checkFileExists(resolve(absoluteTargetFolder, file2)),
|
|
217
|
+
`The file ${file2} couldn't be created because it would overwrite an existing file`
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
debug.trace("Copying template file", { file: file2 });
|
|
221
|
+
await copy(
|
|
222
|
+
resolve(absoluteTemplateFolder, file2),
|
|
223
|
+
resolve(absoluteTargetFolder, file2)
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runCmd(command: string, args: Array<string>, env?: NodeJS.ProcessEnv, cwd?: string): Promise<void>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { PackageManager } from '../constants';
|
|
2
|
+
export declare function runPackageManagerCommand(packageManager: PackageManager, args: Array<string>, env?: NodeJS.ProcessEnv, cwd?: string): Promise<void>;
|
|
3
|
+
export declare function install(packageManager: PackageManager, cwd?: string): Promise<void>;
|
|
4
|
+
export declare function build(packageManager: PackageManager, cwd?: string): Promise<void>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { spawnCommand } from "./spawnCmd.mjs";
|
|
2
|
+
export async function runPackageManagerCommand(packageManager, args, env = {}, cwd) {
|
|
3
|
+
return spawnCommand(packageManager, args, env, cwd);
|
|
4
|
+
}
|
|
5
|
+
export async function install(packageManager, cwd) {
|
|
6
|
+
return runPackageManagerCommand(
|
|
7
|
+
packageManager,
|
|
8
|
+
["install"],
|
|
9
|
+
{
|
|
10
|
+
NODE_ENV: "development"
|
|
11
|
+
},
|
|
12
|
+
cwd
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
export async function build(packageManager, cwd) {
|
|
16
|
+
return runPackageManagerCommand(packageManager, ["run", "build"], {}, cwd);
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function spawnCommand(command: string, args: Array<string>, env?: NodeJS.ProcessEnv, cwd?: string): Promise<void>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import spawn from "cross-spawn";
|
|
2
|
+
export async function spawnCommand(command, args, env = {}, cwd) {
|
|
3
|
+
return new Promise((resolve, reject) => {
|
|
4
|
+
const child = spawn(command, args, {
|
|
5
|
+
env: {
|
|
6
|
+
...process.env,
|
|
7
|
+
...env
|
|
8
|
+
},
|
|
9
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
10
|
+
cwd
|
|
11
|
+
});
|
|
12
|
+
let stderrBuffer = "";
|
|
13
|
+
let stdoutBuffer = "";
|
|
14
|
+
child.stderr?.on("data", (data) => {
|
|
15
|
+
stderrBuffer += data;
|
|
16
|
+
});
|
|
17
|
+
child.stdout?.on("data", (data) => {
|
|
18
|
+
stdoutBuffer += data;
|
|
19
|
+
});
|
|
20
|
+
child.on("close", (code) => {
|
|
21
|
+
if (code !== 0) {
|
|
22
|
+
reject(
|
|
23
|
+
`"${command} ${args.join(" ")}" failed ${stdoutBuffer} ${stderrBuffer}`
|
|
24
|
+
);
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
resolve();
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import validate from "validate-npm-package-name";
|
|
2
|
+
export function validateProjectName(name) {
|
|
3
|
+
const nameValidation = validate(name);
|
|
4
|
+
if (nameValidation.validForNewPackages) {
|
|
5
|
+
return { valid: true };
|
|
6
|
+
}
|
|
7
|
+
return {
|
|
8
|
+
valid: false,
|
|
9
|
+
problems: [
|
|
10
|
+
...nameValidation.errors || [],
|
|
11
|
+
...nameValidation.warnings || []
|
|
12
|
+
]
|
|
13
|
+
};
|
|
14
|
+
}
|
package/index.js
ADDED