@farm.js/create-app 0.1.0-beta.0 → 0.1.0-beta.10
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/README.md +6 -1
- package/bin/create-farm-app.js +1 -0
- package/dist/index.js +52 -12
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +50 -12
- package/dist/index.mjs.map +1 -1
- package/dist/{rolldown-runtime-D6vf50IK.js → rolldown-runtime-VH7oDXx4.js} +1 -1
- package/dist/utils.js +1 -1
- package/package.json +2 -2
- package/templates/basic/farm.config.ts +0 -1
- package/templates/basic/gitignore +23 -0
- package/templates/basic/package.json +9 -6
- package/templates/basic/public/favicon.svg +13 -0
- package/templates/basic/src/app/about/page.tsx +2 -4
- package/templates/basic/src/app/layout.tsx +3 -1
- package/templates/basic/src/app/page.tsx +4 -5
- package/templates/basic/src/farm-images.d.ts +0 -59
package/README.md
CHANGED
|
@@ -5,7 +5,12 @@ Create a new Farm.js application
|
|
|
5
5
|
Farm.js is currently in beta.
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
|
|
8
|
+
pnpm create @farm.js/app my-app
|
|
9
|
+
cd my-app
|
|
10
|
+
pnpm dev
|
|
9
11
|
```
|
|
10
12
|
|
|
13
|
+
The scaffolder installs React, React DOM, Farm.js, TypeScript, and the other starter dependencies
|
|
14
|
+
automatically. Pass `--skip-install` when you only want to generate the project files.
|
|
15
|
+
|
|
11
16
|
See the [Farm.js repository](https://github.com/farming-labs/farm.js) for documentation, examples, and support.
|
package/bin/create-farm-app.js
CHANGED
|
@@ -11,6 +11,7 @@ program
|
|
|
11
11
|
.argument("[project-name]", "Name of the project")
|
|
12
12
|
.option("-t, --template <template>", "Template to use")
|
|
13
13
|
.option("--typescript", "Use TypeScript template")
|
|
14
|
+
.option("--skip-install", "Skip installing dependencies")
|
|
14
15
|
.action(async (projectName, options) => {
|
|
15
16
|
try {
|
|
16
17
|
await createApp(projectName, options);
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_rolldown_runtime = require("./rolldown-runtime-
|
|
2
|
+
const require_rolldown_runtime = require("./rolldown-runtime-VH7oDXx4.js");
|
|
3
3
|
const require_utils = require("./utils.js");
|
|
4
4
|
let prompts = require("prompts");
|
|
5
5
|
prompts = require_rolldown_runtime.__toESM(prompts);
|
|
@@ -7,6 +7,7 @@ let path = require("path");
|
|
|
7
7
|
path = require_rolldown_runtime.__toESM(path);
|
|
8
8
|
let fs_promises = require("fs/promises");
|
|
9
9
|
fs_promises = require_rolldown_runtime.__toESM(fs_promises);
|
|
10
|
+
let node_child_process = require("node:child_process");
|
|
10
11
|
//#region src/index.ts
|
|
11
12
|
async function createApp(projectName, options = {}) {
|
|
12
13
|
require_utils.showBanner();
|
|
@@ -72,6 +73,7 @@ async function createApp(projectName, options = {}) {
|
|
|
72
73
|
useTypeScript = response.typescript;
|
|
73
74
|
}
|
|
74
75
|
const projectPath = path.default.resolve(process.cwd(), projectName);
|
|
76
|
+
const packageManager = detectPackageManager();
|
|
75
77
|
if (await directoryHasFiles(projectPath)) {
|
|
76
78
|
if (!(await (0, prompts.default)({
|
|
77
79
|
type: "confirm",
|
|
@@ -86,13 +88,18 @@ async function createApp(projectName, options = {}) {
|
|
|
86
88
|
require_utils.logger.info(`Creating Farm.js app in ${projectPath}`);
|
|
87
89
|
await fs_promises.default.mkdir(projectPath, { recursive: true });
|
|
88
90
|
await copyTemplate(template, projectPath, useTypeScript);
|
|
89
|
-
await updatePackageJson(projectPath, projectName);
|
|
91
|
+
await updatePackageJson(projectPath, projectName, packageManager);
|
|
90
92
|
require_utils.logger.success(`🚜 Created ${projectName}`);
|
|
93
|
+
if (!options.skipInstall) {
|
|
94
|
+
require_utils.logger.info(`Installing dependencies with ${packageManager.name}...`);
|
|
95
|
+
await installDependencies(projectPath, packageManager);
|
|
96
|
+
require_utils.logger.success("Dependencies installed");
|
|
97
|
+
}
|
|
91
98
|
require_utils.logger.info("");
|
|
92
99
|
require_utils.logger.info("Next steps");
|
|
93
100
|
require_utils.logger.info(` cd ${projectName}`);
|
|
94
|
-
require_utils.logger.info(
|
|
95
|
-
require_utils.logger.info(
|
|
101
|
+
if (options.skipInstall) require_utils.logger.info(` ${packageManager.name} install`);
|
|
102
|
+
require_utils.logger.info(` ${getDevCommand(packageManager.name)}`);
|
|
96
103
|
require_utils.logger.info("");
|
|
97
104
|
require_utils.logger.info("Tailwind is enabled by default. You only need postcss config for custom plugins.");
|
|
98
105
|
}
|
|
@@ -108,7 +115,8 @@ async function copyDir(src, dest) {
|
|
|
108
115
|
const entries = await fs_promises.default.readdir(src, { withFileTypes: true });
|
|
109
116
|
for (const entry of entries) {
|
|
110
117
|
const srcPath = path.default.join(src, entry.name);
|
|
111
|
-
const
|
|
118
|
+
const destinationName = entry.name === "gitignore" ? ".gitignore" : entry.name;
|
|
119
|
+
const destPath = path.default.join(dest, destinationName);
|
|
112
120
|
if (entry.isDirectory()) await copyDir(srcPath, destPath);
|
|
113
121
|
else await fs_promises.default.copyFile(srcPath, destPath);
|
|
114
122
|
}
|
|
@@ -146,21 +154,53 @@ async function getAvailableTemplates() {
|
|
|
146
154
|
const templatesRoot = path.default.join(__dirname, "..", "templates");
|
|
147
155
|
return (await fs_promises.default.readdir(templatesRoot, { withFileTypes: true })).filter((entry) => entry.isDirectory() && !entry.name.startsWith("_")).map((entry) => entry.name).sort();
|
|
148
156
|
}
|
|
149
|
-
async function updatePackageJson(projectPath, projectName) {
|
|
157
|
+
async function updatePackageJson(projectPath, projectName, packageManager) {
|
|
150
158
|
const packageJsonPath = path.default.join(projectPath, "package.json");
|
|
151
|
-
const createAppPackageJsonPath = path.default.join(__dirname, "..", "package.json");
|
|
152
159
|
try {
|
|
153
|
-
const
|
|
160
|
+
const content = await fs_promises.default.readFile(packageJsonPath, "utf-8");
|
|
154
161
|
const packageJson = JSON.parse(content);
|
|
155
|
-
const createAppPackageJson = JSON.parse(createAppContent);
|
|
156
162
|
packageJson.name = projectName;
|
|
157
|
-
packageJson.
|
|
158
|
-
await fs_promises.default.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
159
|
-
} catch
|
|
163
|
+
if (packageManager.version) packageJson.packageManager = `${packageManager.name}@${packageManager.version}`;
|
|
164
|
+
await fs_promises.default.writeFile(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`);
|
|
165
|
+
} catch {
|
|
160
166
|
require_utils.logger.warn("Could not update package.json");
|
|
161
167
|
}
|
|
162
168
|
}
|
|
169
|
+
function detectPackageManager(userAgent = process.env.npm_config_user_agent) {
|
|
170
|
+
const match = userAgent?.match(/^(npm|pnpm|yarn|bun)\/([^\s]+)/);
|
|
171
|
+
if (!match) return { name: "pnpm" };
|
|
172
|
+
const [, name, version] = match;
|
|
173
|
+
return {
|
|
174
|
+
name,
|
|
175
|
+
version: version === "?" ? void 0 : version
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
function installDependencies(projectPath, packageManager) {
|
|
179
|
+
return new Promise((resolve, reject) => {
|
|
180
|
+
const command = process.platform === "win32" ? `${packageManager.name}.cmd` : packageManager.name;
|
|
181
|
+
const child = (0, node_child_process.spawn)(command, ["install"], {
|
|
182
|
+
cwd: projectPath,
|
|
183
|
+
env: process.env,
|
|
184
|
+
stdio: "inherit"
|
|
185
|
+
});
|
|
186
|
+
child.on("error", reject);
|
|
187
|
+
child.on("close", (code, signal) => {
|
|
188
|
+
if (code === 0) {
|
|
189
|
+
resolve();
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const reason = signal ? `signal ${signal}` : `exit code ${code ?? "unknown"}`;
|
|
193
|
+
reject(/* @__PURE__ */ new Error(`${packageManager.name} install failed with ${reason}.`));
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
function getDevCommand(packageManager) {
|
|
198
|
+
if (packageManager === "npm" || packageManager === "bun") return `${packageManager} run dev`;
|
|
199
|
+
return `${packageManager} dev`;
|
|
200
|
+
}
|
|
163
201
|
//#endregion
|
|
164
202
|
exports.createApp = createApp;
|
|
203
|
+
exports.detectPackageManager = detectPackageManager;
|
|
204
|
+
exports.installDependencies = installDependencies;
|
|
165
205
|
|
|
166
206
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["fs","path"],"sources":["../src/index.ts"],"sourcesContent":["import prompts from \"prompts\";\nimport path from \"path\";\nimport fs from \"fs/promises\";\nimport { logger, showBanner } from \"./utils\";\n\ninterface CreateAppOptions {\n template?: string;\n typescript?: boolean;\n}\n\nexport async function createApp(projectName?: string, options: CreateAppOptions = {}) {\n showBanner();\n\n const templates = await getAvailableTemplates();\n if (templates.length === 0) {\n logger.error(\"No templates are available in this package.\");\n process.exit(1);\n }\n\n // Get project name if not provided\n if (!projectName) {\n const response = await prompts({\n type: \"text\",\n name: \"projectName\",\n message: \"What is your project named?\",\n initial: \"my-farm-app\",\n validate: validateProjectName,\n });\n\n if (!response.projectName) {\n logger.error(\"Operation cancelled.\");\n process.exit(1);\n }\n\n projectName = response.projectName;\n } else {\n const validation = validateProjectPathArg(projectName);\n if (validation !== true) {\n logger.error(validation);\n process.exit(1);\n }\n }\n\n // Get template if not provided\n let template = options.template;\n if (!template) {\n const response = await prompts({\n type: \"select\",\n name: \"template\",\n message: \"Which template would you like to use?\",\n choices: templates.map((name) => ({\n title: prettifyTemplateName(name),\n value: name,\n description:\n name === \"basic\" ? \"A simple Farm.js app with built-in Tailwind support\" : undefined,\n })),\n initial: 0,\n });\n\n if (!response.template) {\n logger.error(\"Operation cancelled.\");\n process.exit(1);\n }\n template = response.template;\n } else if (!templates.includes(template)) {\n logger.error(\n `Unknown template \"${template}\". Available: ${templates.map((t) => `\"${t}\"`).join(\", \")}`,\n );\n process.exit(1);\n }\n\n // Check TypeScript preference\n let useTypeScript = options.typescript;\n if (useTypeScript === undefined) {\n const response = await prompts({\n type: \"confirm\",\n name: \"typescript\",\n message: \"Would you like to use TypeScript?\",\n initial: true,\n });\n\n if (response.typescript === undefined) {\n logger.error(\"Operation cancelled.\");\n process.exit(1);\n }\n useTypeScript = response.typescript;\n }\n\n const projectPath = path.resolve(process.cwd(), projectName!);\n const hasExistingFiles = await directoryHasFiles(projectPath);\n if (hasExistingFiles) {\n const overwriteResponse = await prompts({\n type: \"confirm\",\n name: \"overwrite\",\n message: `Directory \"${projectName}\" is not empty. Continue and overwrite conflicting files?`,\n initial: false,\n });\n\n if (!overwriteResponse.overwrite) {\n logger.error(\"Operation cancelled.\");\n process.exit(1);\n }\n }\n\n logger.info(`Creating Farm.js app in ${projectPath}`);\n\n await fs.mkdir(projectPath, { recursive: true });\n\n await copyTemplate(template!, projectPath, useTypeScript!);\n\n await updatePackageJson(projectPath, projectName!);\n\n logger.success(`🚜 Created ${projectName}`);\n logger.info(\"\");\n logger.info(\"Next steps\");\n logger.info(` cd ${projectName}`);\n logger.info(\" pnpm install\");\n logger.info(\" pnpm dev\");\n logger.info(\"\");\n logger.info(\"Tailwind is enabled by default. You only need postcss config for custom plugins.\");\n}\n\nasync function copyTemplate(template: string, projectPath: string, useTypeScript: boolean) {\n const templatePath = path.join(__dirname, \"..\", \"templates\", template);\n\n // Copy base template files\n await copyDir(templatePath, projectPath);\n\n // If TypeScript is requested, copy TS-specific files\n if (useTypeScript) {\n const tsTemplatePath = path.join(__dirname, \"..\", \"templates\", \"_typescript\");\n if (await dirExists(tsTemplatePath)) {\n await copyDir(tsTemplatePath, projectPath);\n }\n }\n}\n\nasync function copyDir(src: string, dest: string) {\n await fs.mkdir(dest, { recursive: true });\n\n const entries = await fs.readdir(src, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcPath = path.join(src, entry.name);\n const destPath = path.join(dest, entry.name);\n\n if (entry.isDirectory()) {\n await copyDir(srcPath, destPath);\n } else {\n await fs.copyFile(srcPath, destPath);\n }\n }\n}\n\nasync function dirExists(path: string): Promise<boolean> {\n try {\n const stat = await fs.stat(path);\n return stat.isDirectory();\n } catch {\n return false;\n }\n}\n\nasync function directoryHasFiles(dirPath: string): Promise<boolean> {\n if (!(await dirExists(dirPath))) {\n return false;\n }\n const files = await fs.readdir(dirPath);\n return files.length > 0;\n}\n\nfunction validateProjectName(value: string): true | string {\n const trimmed = value.trim();\n if (!trimmed) {\n return \"Project name is required\";\n }\n\n // npm package-safe pattern\n if (!/^[a-z0-9._-]+$/i.test(trimmed)) {\n return \"Use letters, numbers, hyphens, underscores, or dots\";\n }\n\n if (trimmed.startsWith(\".\") || trimmed.startsWith(\"_\")) {\n return \"Project name cannot start with '.' or '_'\";\n }\n\n return true;\n}\n\nfunction validateProjectPathArg(value: string): true | string {\n const trimmed = value.trim();\n if (!trimmed) {\n return \"Project name is required\";\n }\n\n const normalized = trimmed.replace(/[\\\\/]+$/, \"\");\n const baseName = path.basename(normalized);\n if (!baseName || baseName === \".\" || baseName === \"..\") {\n return \"Please provide a valid project directory name\";\n }\n\n return validateProjectName(baseName);\n}\n\nfunction prettifyTemplateName(name: string): string {\n return name\n .split(\"-\")\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join(\" \");\n}\n\nasync function getAvailableTemplates(): Promise<string[]> {\n const templatesRoot = path.join(__dirname, \"..\", \"templates\");\n const entries = await fs.readdir(templatesRoot, { withFileTypes: true });\n return entries\n .filter((entry) => entry.isDirectory() && !entry.name.startsWith(\"_\"))\n .map((entry) => entry.name)\n .sort();\n}\n\nasync function updatePackageJson(projectPath: string, projectName: string) {\n const packageJsonPath = path.join(projectPath, \"package.json\");\n const createAppPackageJsonPath = path.join(__dirname, \"..\", \"package.json\");\n\n try {\n const [content, createAppContent] = await Promise.all([\n fs.readFile(packageJsonPath, \"utf-8\"),\n fs.readFile(createAppPackageJsonPath, \"utf-8\"),\n ]);\n const packageJson = JSON.parse(content);\n const createAppPackageJson = JSON.parse(createAppContent);\n\n packageJson.name = projectName;\n packageJson.dependencies[\"@farm.js/core\"] = createAppPackageJson.version;\n\n await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));\n } catch (error) {\n logger.warn(\"Could not update package.json\");\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["fs","path","spawn"],"sources":["../src/index.ts"],"sourcesContent":["import prompts from \"prompts\";\nimport path from \"path\";\nimport fs from \"fs/promises\";\nimport { spawn } from \"node:child_process\";\nimport { logger, showBanner } from \"./utils\";\n\ninterface CreateAppOptions {\n template?: string;\n typescript?: boolean;\n skipInstall?: boolean;\n}\n\nexport type PackageManagerName = \"npm\" | \"pnpm\" | \"yarn\" | \"bun\";\n\nexport interface PackageManager {\n name: PackageManagerName;\n version?: string;\n}\n\nexport async function createApp(projectName?: string, options: CreateAppOptions = {}) {\n showBanner();\n\n const templates = await getAvailableTemplates();\n if (templates.length === 0) {\n logger.error(\"No templates are available in this package.\");\n process.exit(1);\n }\n\n // Get project name if not provided\n if (!projectName) {\n const response = await prompts({\n type: \"text\",\n name: \"projectName\",\n message: \"What is your project named?\",\n initial: \"my-farm-app\",\n validate: validateProjectName,\n });\n\n if (!response.projectName) {\n logger.error(\"Operation cancelled.\");\n process.exit(1);\n }\n\n projectName = response.projectName;\n } else {\n const validation = validateProjectPathArg(projectName);\n if (validation !== true) {\n logger.error(validation);\n process.exit(1);\n }\n }\n\n // Get template if not provided\n let template = options.template;\n if (!template) {\n const response = await prompts({\n type: \"select\",\n name: \"template\",\n message: \"Which template would you like to use?\",\n choices: templates.map((name) => ({\n title: prettifyTemplateName(name),\n value: name,\n description:\n name === \"basic\" ? \"A simple Farm.js app with built-in Tailwind support\" : undefined,\n })),\n initial: 0,\n });\n\n if (!response.template) {\n logger.error(\"Operation cancelled.\");\n process.exit(1);\n }\n template = response.template;\n } else if (!templates.includes(template)) {\n logger.error(\n `Unknown template \"${template}\". Available: ${templates.map((t) => `\"${t}\"`).join(\", \")}`,\n );\n process.exit(1);\n }\n\n // Check TypeScript preference\n let useTypeScript = options.typescript;\n if (useTypeScript === undefined) {\n const response = await prompts({\n type: \"confirm\",\n name: \"typescript\",\n message: \"Would you like to use TypeScript?\",\n initial: true,\n });\n\n if (response.typescript === undefined) {\n logger.error(\"Operation cancelled.\");\n process.exit(1);\n }\n useTypeScript = response.typescript;\n }\n\n const projectPath = path.resolve(process.cwd(), projectName!);\n const packageManager = detectPackageManager();\n const hasExistingFiles = await directoryHasFiles(projectPath);\n if (hasExistingFiles) {\n const overwriteResponse = await prompts({\n type: \"confirm\",\n name: \"overwrite\",\n message: `Directory \"${projectName}\" is not empty. Continue and overwrite conflicting files?`,\n initial: false,\n });\n\n if (!overwriteResponse.overwrite) {\n logger.error(\"Operation cancelled.\");\n process.exit(1);\n }\n }\n\n logger.info(`Creating Farm.js app in ${projectPath}`);\n\n await fs.mkdir(projectPath, { recursive: true });\n\n await copyTemplate(template!, projectPath, useTypeScript!);\n\n await updatePackageJson(projectPath, projectName!, packageManager);\n\n logger.success(`🚜 Created ${projectName}`);\n\n if (!options.skipInstall) {\n logger.info(`Installing dependencies with ${packageManager.name}...`);\n await installDependencies(projectPath, packageManager);\n logger.success(\"Dependencies installed\");\n }\n\n logger.info(\"\");\n logger.info(\"Next steps\");\n logger.info(` cd ${projectName}`);\n if (options.skipInstall) {\n logger.info(` ${packageManager.name} install`);\n }\n logger.info(` ${getDevCommand(packageManager.name)}`);\n logger.info(\"\");\n logger.info(\"Tailwind is enabled by default. You only need postcss config for custom plugins.\");\n}\n\nasync function copyTemplate(template: string, projectPath: string, useTypeScript: boolean) {\n const templatePath = path.join(__dirname, \"..\", \"templates\", template);\n\n // Copy base template files\n await copyDir(templatePath, projectPath);\n\n // If TypeScript is requested, copy TS-specific files\n if (useTypeScript) {\n const tsTemplatePath = path.join(__dirname, \"..\", \"templates\", \"_typescript\");\n if (await dirExists(tsTemplatePath)) {\n await copyDir(tsTemplatePath, projectPath);\n }\n }\n}\n\nasync function copyDir(src: string, dest: string) {\n await fs.mkdir(dest, { recursive: true });\n\n const entries = await fs.readdir(src, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcPath = path.join(src, entry.name);\n // npm excludes .gitignore files from published tarballs. Keep the template\n // file publishable and restore its dot when generating the application.\n const destinationName = entry.name === \"gitignore\" ? \".gitignore\" : entry.name;\n const destPath = path.join(dest, destinationName);\n\n if (entry.isDirectory()) {\n await copyDir(srcPath, destPath);\n } else {\n await fs.copyFile(srcPath, destPath);\n }\n }\n}\n\nasync function dirExists(path: string): Promise<boolean> {\n try {\n const stat = await fs.stat(path);\n return stat.isDirectory();\n } catch {\n return false;\n }\n}\n\nasync function directoryHasFiles(dirPath: string): Promise<boolean> {\n if (!(await dirExists(dirPath))) {\n return false;\n }\n const files = await fs.readdir(dirPath);\n return files.length > 0;\n}\n\nfunction validateProjectName(value: string): true | string {\n const trimmed = value.trim();\n if (!trimmed) {\n return \"Project name is required\";\n }\n\n // npm package-safe pattern\n if (!/^[a-z0-9._-]+$/i.test(trimmed)) {\n return \"Use letters, numbers, hyphens, underscores, or dots\";\n }\n\n if (trimmed.startsWith(\".\") || trimmed.startsWith(\"_\")) {\n return \"Project name cannot start with '.' or '_'\";\n }\n\n return true;\n}\n\nfunction validateProjectPathArg(value: string): true | string {\n const trimmed = value.trim();\n if (!trimmed) {\n return \"Project name is required\";\n }\n\n const normalized = trimmed.replace(/[\\\\/]+$/, \"\");\n const baseName = path.basename(normalized);\n if (!baseName || baseName === \".\" || baseName === \"..\") {\n return \"Please provide a valid project directory name\";\n }\n\n return validateProjectName(baseName);\n}\n\nfunction prettifyTemplateName(name: string): string {\n return name\n .split(\"-\")\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join(\" \");\n}\n\nasync function getAvailableTemplates(): Promise<string[]> {\n const templatesRoot = path.join(__dirname, \"..\", \"templates\");\n const entries = await fs.readdir(templatesRoot, { withFileTypes: true });\n return entries\n .filter((entry) => entry.isDirectory() && !entry.name.startsWith(\"_\"))\n .map((entry) => entry.name)\n .sort();\n}\n\nasync function updatePackageJson(\n projectPath: string,\n projectName: string,\n packageManager: PackageManager,\n) {\n const packageJsonPath = path.join(projectPath, \"package.json\");\n\n try {\n const content = await fs.readFile(packageJsonPath, \"utf-8\");\n const packageJson = JSON.parse(content);\n\n packageJson.name = projectName;\n if (packageManager.version) {\n packageJson.packageManager = `${packageManager.name}@${packageManager.version}`;\n }\n\n await fs.writeFile(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\\n`);\n } catch {\n logger.warn(\"Could not update package.json\");\n }\n}\n\nexport function detectPackageManager(\n userAgent = process.env.npm_config_user_agent,\n): PackageManager {\n const match = userAgent?.match(/^(npm|pnpm|yarn|bun)\\/([^\\s]+)/);\n if (!match) {\n return { name: \"pnpm\" };\n }\n\n const [, name, version] = match;\n return {\n name: name as PackageManagerName,\n version: version === \"?\" ? undefined : version,\n };\n}\n\nexport function installDependencies(\n projectPath: string,\n packageManager: PackageManager,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const command =\n process.platform === \"win32\" ? `${packageManager.name}.cmd` : packageManager.name;\n const child = spawn(command, [\"install\"], {\n cwd: projectPath,\n env: process.env,\n stdio: \"inherit\",\n });\n\n child.on(\"error\", reject);\n child.on(\"close\", (code, signal) => {\n if (code === 0) {\n resolve();\n return;\n }\n\n const reason = signal ? `signal ${signal}` : `exit code ${code ?? \"unknown\"}`;\n reject(new Error(`${packageManager.name} install failed with ${reason}.`));\n });\n });\n}\n\nfunction getDevCommand(packageManager: PackageManagerName) {\n if (packageManager === \"npm\" || packageManager === \"bun\") {\n return `${packageManager} run dev`;\n }\n return `${packageManager} dev`;\n}\n"],"mappings":";;;;;;;;;;;AAmBA,eAAsB,UAAU,aAAsB,UAA4B,CAAC,GAAG;CACpF,cAAA,WAAW;CAEX,MAAM,YAAY,MAAM,sBAAsB;CAC9C,IAAI,UAAU,WAAW,GAAG;EAC1B,cAAA,OAAO,MAAM,6CAA6C;EAC1D,QAAQ,KAAK,CAAC;CAChB;CAGA,IAAI,CAAC,aAAa;EAChB,MAAM,WAAW,OAAA,GAAM,QAAA,QAAA,CAAQ;GAC7B,MAAM;GACN,MAAM;GACN,SAAS;GACT,SAAS;GACT,UAAU;EACZ,CAAC;EAED,IAAI,CAAC,SAAS,aAAa;GACzB,cAAA,OAAO,MAAM,sBAAsB;GACnC,QAAQ,KAAK,CAAC;EAChB;EAEA,cAAc,SAAS;CACzB,OAAO;EACL,MAAM,aAAa,uBAAuB,WAAW;EACrD,IAAI,eAAe,MAAM;GACvB,cAAA,OAAO,MAAM,UAAU;GACvB,QAAQ,KAAK,CAAC;EAChB;CACF;CAGA,IAAI,WAAW,QAAQ;CACvB,IAAI,CAAC,UAAU;EACb,MAAM,WAAW,OAAA,GAAM,QAAA,QAAA,CAAQ;GAC7B,MAAM;GACN,MAAM;GACN,SAAS;GACT,SAAS,UAAU,KAAK,UAAU;IAChC,OAAO,qBAAqB,IAAI;IAChC,OAAO;IACP,aACE,SAAS,UAAU,wDAAwD,KAAA;GAC/E,EAAE;GACF,SAAS;EACX,CAAC;EAED,IAAI,CAAC,SAAS,UAAU;GACtB,cAAA,OAAO,MAAM,sBAAsB;GACnC,QAAQ,KAAK,CAAC;EAChB;EACA,WAAW,SAAS;CACtB,OAAO,IAAI,CAAC,UAAU,SAAS,QAAQ,GAAG;EACxC,cAAA,OAAO,MACL,qBAAqB,SAAS,gBAAgB,UAAU,KAAK,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,GACxF;EACA,QAAQ,KAAK,CAAC;CAChB;CAGA,IAAI,gBAAgB,QAAQ;CAC5B,IAAI,kBAAkB,KAAA,GAAW;EAC/B,MAAM,WAAW,OAAA,GAAM,QAAA,QAAA,CAAQ;GAC7B,MAAM;GACN,MAAM;GACN,SAAS;GACT,SAAS;EACX,CAAC;EAED,IAAI,SAAS,eAAe,KAAA,GAAW;GACrC,cAAA,OAAO,MAAM,sBAAsB;GACnC,QAAQ,KAAK,CAAC;EAChB;EACA,gBAAgB,SAAS;CAC3B;CAEA,MAAM,cAAc,KAAA,QAAK,QAAQ,QAAQ,IAAI,GAAG,WAAY;CAC5D,MAAM,iBAAiB,qBAAqB;CAE5C,IAAI,MAD2B,kBAAkB,WAAW,GAStD;MAAA,EAAC,OAAA,GAP2B,QAAA,QAAA,CAAQ;GACtC,MAAM;GACN,MAAM;GACN,SAAS,cAAc,YAAY;GACnC,SAAS;EACX,CAAC,EAAA,CAEsB,WAAW;GAChC,cAAA,OAAO,MAAM,sBAAsB;GACnC,QAAQ,KAAK,CAAC;EAChB;;CAGF,cAAA,OAAO,KAAK,2BAA2B,aAAa;CAEpD,MAAMA,YAAAA,QAAG,MAAM,aAAa,EAAE,WAAW,KAAK,CAAC;CAE/C,MAAM,aAAa,UAAW,aAAa,aAAc;CAEzD,MAAM,kBAAkB,aAAa,aAAc,cAAc;CAEjE,cAAA,OAAO,QAAQ,cAAc,aAAa;CAE1C,IAAI,CAAC,QAAQ,aAAa;EACxB,cAAA,OAAO,KAAK,gCAAgC,eAAe,KAAK,IAAI;EACpE,MAAM,oBAAoB,aAAa,cAAc;EACrD,cAAA,OAAO,QAAQ,wBAAwB;CACzC;CAEA,cAAA,OAAO,KAAK,EAAE;CACd,cAAA,OAAO,KAAK,YAAY;CACxB,cAAA,OAAO,KAAK,QAAQ,aAAa;CACjC,IAAI,QAAQ,aACV,cAAA,OAAO,KAAK,KAAK,eAAe,KAAK,SAAS;CAEhD,cAAA,OAAO,KAAK,KAAK,cAAc,eAAe,IAAI,GAAG;CACrD,cAAA,OAAO,KAAK,EAAE;CACd,cAAA,OAAO,KAAK,kFAAkF;AAChG;AAEA,eAAe,aAAa,UAAkB,aAAqB,eAAwB;CAIzF,MAAM,QAHe,KAAA,QAAK,KAAK,WAAW,MAAM,aAAa,QAGpC,GAAG,WAAW;CAGvC,IAAI,eAAe;EACjB,MAAM,iBAAiB,KAAA,QAAK,KAAK,WAAW,MAAM,aAAa,aAAa;EAC5E,IAAI,MAAM,UAAU,cAAc,GAChC,MAAM,QAAQ,gBAAgB,WAAW;CAE7C;AACF;AAEA,eAAe,QAAQ,KAAa,MAAc;CAChD,MAAMA,YAAAA,QAAG,MAAM,MAAM,EAAE,WAAW,KAAK,CAAC;CAExC,MAAM,UAAU,MAAMA,YAAAA,QAAG,QAAQ,KAAK,EAAE,eAAe,KAAK,CAAC;CAE7D,KAAK,MAAM,SAAS,SAAS;EAC3B,MAAM,UAAU,KAAA,QAAK,KAAK,KAAK,MAAM,IAAI;EAGzC,MAAM,kBAAkB,MAAM,SAAS,cAAc,eAAe,MAAM;EAC1E,MAAM,WAAW,KAAA,QAAK,KAAK,MAAM,eAAe;EAEhD,IAAI,MAAM,YAAY,GACpB,MAAM,QAAQ,SAAS,QAAQ;OAE/B,MAAMA,YAAAA,QAAG,SAAS,SAAS,QAAQ;CAEvC;AACF;AAEA,eAAe,UAAU,QAAgC;CACvD,IAAI;EAEF,QAAO,MADYA,YAAAA,QAAG,KAAKC,MAAI,EAAA,CACnB,YAAY;CAC1B,QAAQ;EACN,OAAO;CACT;AACF;AAEA,eAAe,kBAAkB,SAAmC;CAClE,IAAI,CAAE,MAAM,UAAU,OAAO,GAC3B,OAAO;CAGT,QAAO,MADaD,YAAAA,QAAG,QAAQ,OAAO,EAAA,CACzB,SAAS;AACxB;AAEA,SAAS,oBAAoB,OAA8B;CACzD,MAAM,UAAU,MAAM,KAAK;CAC3B,IAAI,CAAC,SACH,OAAO;CAIT,IAAI,CAAC,kBAAkB,KAAK,OAAO,GACjC,OAAO;CAGT,IAAI,QAAQ,WAAW,GAAG,KAAK,QAAQ,WAAW,GAAG,GACnD,OAAO;CAGT,OAAO;AACT;AAEA,SAAS,uBAAuB,OAA8B;CAC5D,MAAM,UAAU,MAAM,KAAK;CAC3B,IAAI,CAAC,SACH,OAAO;CAGT,MAAM,aAAa,QAAQ,QAAQ,WAAW,EAAE;CAChD,MAAM,WAAW,KAAA,QAAK,SAAS,UAAU;CACzC,IAAI,CAAC,YAAY,aAAa,OAAO,aAAa,MAChD,OAAO;CAGT,OAAO,oBAAoB,QAAQ;AACrC;AAEA,SAAS,qBAAqB,MAAsB;CAClD,OAAO,KACJ,MAAM,GAAG,CAAC,CACV,KAAK,SAAS,KAAK,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,CAC3D,KAAK,GAAG;AACb;AAEA,eAAe,wBAA2C;CACxD,MAAM,gBAAgB,KAAA,QAAK,KAAK,WAAW,MAAM,WAAW;CAE5D,QAAO,MADeA,YAAAA,QAAG,QAAQ,eAAe,EAAE,eAAe,KAAK,CAAC,EAAA,CAEpE,QAAQ,UAAU,MAAM,YAAY,KAAK,CAAC,MAAM,KAAK,WAAW,GAAG,CAAC,CAAC,CACrE,KAAK,UAAU,MAAM,IAAI,CAAC,CAC1B,KAAK;AACV;AAEA,eAAe,kBACb,aACA,aACA,gBACA;CACA,MAAM,kBAAkB,KAAA,QAAK,KAAK,aAAa,cAAc;CAE7D,IAAI;EACF,MAAM,UAAU,MAAMA,YAAAA,QAAG,SAAS,iBAAiB,OAAO;EAC1D,MAAM,cAAc,KAAK,MAAM,OAAO;EAEtC,YAAY,OAAO;EACnB,IAAI,eAAe,SACjB,YAAY,iBAAiB,GAAG,eAAe,KAAK,GAAG,eAAe;EAGxE,MAAMA,YAAAA,QAAG,UAAU,iBAAiB,GAAG,KAAK,UAAU,aAAa,MAAM,CAAC,EAAE,GAAG;CACjF,QAAQ;EACN,cAAA,OAAO,KAAK,+BAA+B;CAC7C;AACF;AAEA,SAAgB,qBACd,YAAY,QAAQ,IAAI,uBACR;CAChB,MAAM,QAAQ,WAAW,MAAM,gCAAgC;CAC/D,IAAI,CAAC,OACH,OAAO,EAAE,MAAM,OAAO;CAGxB,MAAM,GAAG,MAAM,WAAW;CAC1B,OAAO;EACC;EACN,SAAS,YAAY,MAAM,KAAA,IAAY;CACzC;AACF;AAEA,SAAgB,oBACd,aACA,gBACe;CACf,OAAO,IAAI,SAAS,SAAS,WAAW;EACtC,MAAM,UACJ,QAAQ,aAAa,UAAU,GAAG,eAAe,KAAK,QAAQ,eAAe;EAC/E,MAAM,SAAA,GAAQE,mBAAAA,MAAAA,CAAM,SAAS,CAAC,SAAS,GAAG;GACxC,KAAK;GACL,KAAK,QAAQ;GACb,OAAO;EACT,CAAC;EAED,MAAM,GAAG,SAAS,MAAM;EACxB,MAAM,GAAG,UAAU,MAAM,WAAW;GAClC,IAAI,SAAS,GAAG;IACd,QAAQ;IACR;GACF;GAEA,MAAM,SAAS,SAAS,UAAU,WAAW,aAAa,QAAQ;GAClE,uBAAO,IAAI,MAAM,GAAG,eAAe,KAAK,uBAAuB,OAAO,EAAE,CAAC;EAC3E,CAAC;CACH,CAAC;AACH;AAEA,SAAS,cAAc,gBAAoC;CACzD,IAAI,mBAAmB,SAAS,mBAAmB,OACjD,OAAO,GAAG,eAAe;CAE3B,OAAO,GAAG,eAAe;AAC3B"}
|
package/dist/index.mjs
CHANGED
|
@@ -2,6 +2,7 @@ import { logger, showBanner } from "./utils.mjs";
|
|
|
2
2
|
import prompts from "prompts";
|
|
3
3
|
import path from "path";
|
|
4
4
|
import fs from "fs/promises";
|
|
5
|
+
import { spawn } from "node:child_process";
|
|
5
6
|
//#region src/index.ts
|
|
6
7
|
async function createApp(projectName, options = {}) {
|
|
7
8
|
showBanner();
|
|
@@ -67,6 +68,7 @@ async function createApp(projectName, options = {}) {
|
|
|
67
68
|
useTypeScript = response.typescript;
|
|
68
69
|
}
|
|
69
70
|
const projectPath = path.resolve(process.cwd(), projectName);
|
|
71
|
+
const packageManager = detectPackageManager();
|
|
70
72
|
if (await directoryHasFiles(projectPath)) {
|
|
71
73
|
if (!(await prompts({
|
|
72
74
|
type: "confirm",
|
|
@@ -81,13 +83,18 @@ async function createApp(projectName, options = {}) {
|
|
|
81
83
|
logger.info(`Creating Farm.js app in ${projectPath}`);
|
|
82
84
|
await fs.mkdir(projectPath, { recursive: true });
|
|
83
85
|
await copyTemplate(template, projectPath, useTypeScript);
|
|
84
|
-
await updatePackageJson(projectPath, projectName);
|
|
86
|
+
await updatePackageJson(projectPath, projectName, packageManager);
|
|
85
87
|
logger.success(`🚜 Created ${projectName}`);
|
|
88
|
+
if (!options.skipInstall) {
|
|
89
|
+
logger.info(`Installing dependencies with ${packageManager.name}...`);
|
|
90
|
+
await installDependencies(projectPath, packageManager);
|
|
91
|
+
logger.success("Dependencies installed");
|
|
92
|
+
}
|
|
86
93
|
logger.info("");
|
|
87
94
|
logger.info("Next steps");
|
|
88
95
|
logger.info(` cd ${projectName}`);
|
|
89
|
-
logger.info(
|
|
90
|
-
logger.info(
|
|
96
|
+
if (options.skipInstall) logger.info(` ${packageManager.name} install`);
|
|
97
|
+
logger.info(` ${getDevCommand(packageManager.name)}`);
|
|
91
98
|
logger.info("");
|
|
92
99
|
logger.info("Tailwind is enabled by default. You only need postcss config for custom plugins.");
|
|
93
100
|
}
|
|
@@ -103,7 +110,8 @@ async function copyDir(src, dest) {
|
|
|
103
110
|
const entries = await fs.readdir(src, { withFileTypes: true });
|
|
104
111
|
for (const entry of entries) {
|
|
105
112
|
const srcPath = path.join(src, entry.name);
|
|
106
|
-
const
|
|
113
|
+
const destinationName = entry.name === "gitignore" ? ".gitignore" : entry.name;
|
|
114
|
+
const destPath = path.join(dest, destinationName);
|
|
107
115
|
if (entry.isDirectory()) await copyDir(srcPath, destPath);
|
|
108
116
|
else await fs.copyFile(srcPath, destPath);
|
|
109
117
|
}
|
|
@@ -141,21 +149,51 @@ async function getAvailableTemplates() {
|
|
|
141
149
|
const templatesRoot = path.join(__dirname, "..", "templates");
|
|
142
150
|
return (await fs.readdir(templatesRoot, { withFileTypes: true })).filter((entry) => entry.isDirectory() && !entry.name.startsWith("_")).map((entry) => entry.name).sort();
|
|
143
151
|
}
|
|
144
|
-
async function updatePackageJson(projectPath, projectName) {
|
|
152
|
+
async function updatePackageJson(projectPath, projectName, packageManager) {
|
|
145
153
|
const packageJsonPath = path.join(projectPath, "package.json");
|
|
146
|
-
const createAppPackageJsonPath = path.join(__dirname, "..", "package.json");
|
|
147
154
|
try {
|
|
148
|
-
const
|
|
155
|
+
const content = await fs.readFile(packageJsonPath, "utf-8");
|
|
149
156
|
const packageJson = JSON.parse(content);
|
|
150
|
-
const createAppPackageJson = JSON.parse(createAppContent);
|
|
151
157
|
packageJson.name = projectName;
|
|
152
|
-
packageJson.
|
|
153
|
-
await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
154
|
-
} catch
|
|
158
|
+
if (packageManager.version) packageJson.packageManager = `${packageManager.name}@${packageManager.version}`;
|
|
159
|
+
await fs.writeFile(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`);
|
|
160
|
+
} catch {
|
|
155
161
|
logger.warn("Could not update package.json");
|
|
156
162
|
}
|
|
157
163
|
}
|
|
164
|
+
function detectPackageManager(userAgent = process.env.npm_config_user_agent) {
|
|
165
|
+
const match = userAgent?.match(/^(npm|pnpm|yarn|bun)\/([^\s]+)/);
|
|
166
|
+
if (!match) return { name: "pnpm" };
|
|
167
|
+
const [, name, version] = match;
|
|
168
|
+
return {
|
|
169
|
+
name,
|
|
170
|
+
version: version === "?" ? void 0 : version
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
function installDependencies(projectPath, packageManager) {
|
|
174
|
+
return new Promise((resolve, reject) => {
|
|
175
|
+
const command = process.platform === "win32" ? `${packageManager.name}.cmd` : packageManager.name;
|
|
176
|
+
const child = spawn(command, ["install"], {
|
|
177
|
+
cwd: projectPath,
|
|
178
|
+
env: process.env,
|
|
179
|
+
stdio: "inherit"
|
|
180
|
+
});
|
|
181
|
+
child.on("error", reject);
|
|
182
|
+
child.on("close", (code, signal) => {
|
|
183
|
+
if (code === 0) {
|
|
184
|
+
resolve();
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
const reason = signal ? `signal ${signal}` : `exit code ${code ?? "unknown"}`;
|
|
188
|
+
reject(/* @__PURE__ */ new Error(`${packageManager.name} install failed with ${reason}.`));
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
function getDevCommand(packageManager) {
|
|
193
|
+
if (packageManager === "npm" || packageManager === "bun") return `${packageManager} run dev`;
|
|
194
|
+
return `${packageManager} dev`;
|
|
195
|
+
}
|
|
158
196
|
//#endregion
|
|
159
|
-
export { createApp };
|
|
197
|
+
export { createApp, detectPackageManager, installDependencies };
|
|
160
198
|
|
|
161
199
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["import prompts from \"prompts\";\nimport path from \"path\";\nimport fs from \"fs/promises\";\nimport { logger, showBanner } from \"./utils\";\n\ninterface CreateAppOptions {\n template?: string;\n typescript?: boolean;\n}\n\nexport async function createApp(projectName?: string, options: CreateAppOptions = {}) {\n showBanner();\n\n const templates = await getAvailableTemplates();\n if (templates.length === 0) {\n logger.error(\"No templates are available in this package.\");\n process.exit(1);\n }\n\n // Get project name if not provided\n if (!projectName) {\n const response = await prompts({\n type: \"text\",\n name: \"projectName\",\n message: \"What is your project named?\",\n initial: \"my-farm-app\",\n validate: validateProjectName,\n });\n\n if (!response.projectName) {\n logger.error(\"Operation cancelled.\");\n process.exit(1);\n }\n\n projectName = response.projectName;\n } else {\n const validation = validateProjectPathArg(projectName);\n if (validation !== true) {\n logger.error(validation);\n process.exit(1);\n }\n }\n\n // Get template if not provided\n let template = options.template;\n if (!template) {\n const response = await prompts({\n type: \"select\",\n name: \"template\",\n message: \"Which template would you like to use?\",\n choices: templates.map((name) => ({\n title: prettifyTemplateName(name),\n value: name,\n description:\n name === \"basic\" ? \"A simple Farm.js app with built-in Tailwind support\" : undefined,\n })),\n initial: 0,\n });\n\n if (!response.template) {\n logger.error(\"Operation cancelled.\");\n process.exit(1);\n }\n template = response.template;\n } else if (!templates.includes(template)) {\n logger.error(\n `Unknown template \"${template}\". Available: ${templates.map((t) => `\"${t}\"`).join(\", \")}`,\n );\n process.exit(1);\n }\n\n // Check TypeScript preference\n let useTypeScript = options.typescript;\n if (useTypeScript === undefined) {\n const response = await prompts({\n type: \"confirm\",\n name: \"typescript\",\n message: \"Would you like to use TypeScript?\",\n initial: true,\n });\n\n if (response.typescript === undefined) {\n logger.error(\"Operation cancelled.\");\n process.exit(1);\n }\n useTypeScript = response.typescript;\n }\n\n const projectPath = path.resolve(process.cwd(), projectName!);\n const hasExistingFiles = await directoryHasFiles(projectPath);\n if (hasExistingFiles) {\n const overwriteResponse = await prompts({\n type: \"confirm\",\n name: \"overwrite\",\n message: `Directory \"${projectName}\" is not empty. Continue and overwrite conflicting files?`,\n initial: false,\n });\n\n if (!overwriteResponse.overwrite) {\n logger.error(\"Operation cancelled.\");\n process.exit(1);\n }\n }\n\n logger.info(`Creating Farm.js app in ${projectPath}`);\n\n await fs.mkdir(projectPath, { recursive: true });\n\n await copyTemplate(template!, projectPath, useTypeScript!);\n\n await updatePackageJson(projectPath, projectName!);\n\n logger.success(`🚜 Created ${projectName}`);\n logger.info(\"\");\n logger.info(\"Next steps\");\n logger.info(` cd ${projectName}`);\n logger.info(\" pnpm install\");\n logger.info(\" pnpm dev\");\n logger.info(\"\");\n logger.info(\"Tailwind is enabled by default. You only need postcss config for custom plugins.\");\n}\n\nasync function copyTemplate(template: string, projectPath: string, useTypeScript: boolean) {\n const templatePath = path.join(__dirname, \"..\", \"templates\", template);\n\n // Copy base template files\n await copyDir(templatePath, projectPath);\n\n // If TypeScript is requested, copy TS-specific files\n if (useTypeScript) {\n const tsTemplatePath = path.join(__dirname, \"..\", \"templates\", \"_typescript\");\n if (await dirExists(tsTemplatePath)) {\n await copyDir(tsTemplatePath, projectPath);\n }\n }\n}\n\nasync function copyDir(src: string, dest: string) {\n await fs.mkdir(dest, { recursive: true });\n\n const entries = await fs.readdir(src, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcPath = path.join(src, entry.name);\n const destPath = path.join(dest, entry.name);\n\n if (entry.isDirectory()) {\n await copyDir(srcPath, destPath);\n } else {\n await fs.copyFile(srcPath, destPath);\n }\n }\n}\n\nasync function dirExists(path: string): Promise<boolean> {\n try {\n const stat = await fs.stat(path);\n return stat.isDirectory();\n } catch {\n return false;\n }\n}\n\nasync function directoryHasFiles(dirPath: string): Promise<boolean> {\n if (!(await dirExists(dirPath))) {\n return false;\n }\n const files = await fs.readdir(dirPath);\n return files.length > 0;\n}\n\nfunction validateProjectName(value: string): true | string {\n const trimmed = value.trim();\n if (!trimmed) {\n return \"Project name is required\";\n }\n\n // npm package-safe pattern\n if (!/^[a-z0-9._-]+$/i.test(trimmed)) {\n return \"Use letters, numbers, hyphens, underscores, or dots\";\n }\n\n if (trimmed.startsWith(\".\") || trimmed.startsWith(\"_\")) {\n return \"Project name cannot start with '.' or '_'\";\n }\n\n return true;\n}\n\nfunction validateProjectPathArg(value: string): true | string {\n const trimmed = value.trim();\n if (!trimmed) {\n return \"Project name is required\";\n }\n\n const normalized = trimmed.replace(/[\\\\/]+$/, \"\");\n const baseName = path.basename(normalized);\n if (!baseName || baseName === \".\" || baseName === \"..\") {\n return \"Please provide a valid project directory name\";\n }\n\n return validateProjectName(baseName);\n}\n\nfunction prettifyTemplateName(name: string): string {\n return name\n .split(\"-\")\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join(\" \");\n}\n\nasync function getAvailableTemplates(): Promise<string[]> {\n const templatesRoot = path.join(__dirname, \"..\", \"templates\");\n const entries = await fs.readdir(templatesRoot, { withFileTypes: true });\n return entries\n .filter((entry) => entry.isDirectory() && !entry.name.startsWith(\"_\"))\n .map((entry) => entry.name)\n .sort();\n}\n\nasync function updatePackageJson(projectPath: string, projectName: string) {\n const packageJsonPath = path.join(projectPath, \"package.json\");\n const createAppPackageJsonPath = path.join(__dirname, \"..\", \"package.json\");\n\n try {\n const [content, createAppContent] = await Promise.all([\n fs.readFile(packageJsonPath, \"utf-8\"),\n fs.readFile(createAppPackageJsonPath, \"utf-8\"),\n ]);\n const packageJson = JSON.parse(content);\n const createAppPackageJson = JSON.parse(createAppContent);\n\n packageJson.name = projectName;\n packageJson.dependencies[\"@farm.js/core\"] = createAppPackageJson.version;\n\n await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));\n } catch (error) {\n logger.warn(\"Could not update package.json\");\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/index.ts"],"sourcesContent":["import prompts from \"prompts\";\nimport path from \"path\";\nimport fs from \"fs/promises\";\nimport { spawn } from \"node:child_process\";\nimport { logger, showBanner } from \"./utils\";\n\ninterface CreateAppOptions {\n template?: string;\n typescript?: boolean;\n skipInstall?: boolean;\n}\n\nexport type PackageManagerName = \"npm\" | \"pnpm\" | \"yarn\" | \"bun\";\n\nexport interface PackageManager {\n name: PackageManagerName;\n version?: string;\n}\n\nexport async function createApp(projectName?: string, options: CreateAppOptions = {}) {\n showBanner();\n\n const templates = await getAvailableTemplates();\n if (templates.length === 0) {\n logger.error(\"No templates are available in this package.\");\n process.exit(1);\n }\n\n // Get project name if not provided\n if (!projectName) {\n const response = await prompts({\n type: \"text\",\n name: \"projectName\",\n message: \"What is your project named?\",\n initial: \"my-farm-app\",\n validate: validateProjectName,\n });\n\n if (!response.projectName) {\n logger.error(\"Operation cancelled.\");\n process.exit(1);\n }\n\n projectName = response.projectName;\n } else {\n const validation = validateProjectPathArg(projectName);\n if (validation !== true) {\n logger.error(validation);\n process.exit(1);\n }\n }\n\n // Get template if not provided\n let template = options.template;\n if (!template) {\n const response = await prompts({\n type: \"select\",\n name: \"template\",\n message: \"Which template would you like to use?\",\n choices: templates.map((name) => ({\n title: prettifyTemplateName(name),\n value: name,\n description:\n name === \"basic\" ? \"A simple Farm.js app with built-in Tailwind support\" : undefined,\n })),\n initial: 0,\n });\n\n if (!response.template) {\n logger.error(\"Operation cancelled.\");\n process.exit(1);\n }\n template = response.template;\n } else if (!templates.includes(template)) {\n logger.error(\n `Unknown template \"${template}\". Available: ${templates.map((t) => `\"${t}\"`).join(\", \")}`,\n );\n process.exit(1);\n }\n\n // Check TypeScript preference\n let useTypeScript = options.typescript;\n if (useTypeScript === undefined) {\n const response = await prompts({\n type: \"confirm\",\n name: \"typescript\",\n message: \"Would you like to use TypeScript?\",\n initial: true,\n });\n\n if (response.typescript === undefined) {\n logger.error(\"Operation cancelled.\");\n process.exit(1);\n }\n useTypeScript = response.typescript;\n }\n\n const projectPath = path.resolve(process.cwd(), projectName!);\n const packageManager = detectPackageManager();\n const hasExistingFiles = await directoryHasFiles(projectPath);\n if (hasExistingFiles) {\n const overwriteResponse = await prompts({\n type: \"confirm\",\n name: \"overwrite\",\n message: `Directory \"${projectName}\" is not empty. Continue and overwrite conflicting files?`,\n initial: false,\n });\n\n if (!overwriteResponse.overwrite) {\n logger.error(\"Operation cancelled.\");\n process.exit(1);\n }\n }\n\n logger.info(`Creating Farm.js app in ${projectPath}`);\n\n await fs.mkdir(projectPath, { recursive: true });\n\n await copyTemplate(template!, projectPath, useTypeScript!);\n\n await updatePackageJson(projectPath, projectName!, packageManager);\n\n logger.success(`🚜 Created ${projectName}`);\n\n if (!options.skipInstall) {\n logger.info(`Installing dependencies with ${packageManager.name}...`);\n await installDependencies(projectPath, packageManager);\n logger.success(\"Dependencies installed\");\n }\n\n logger.info(\"\");\n logger.info(\"Next steps\");\n logger.info(` cd ${projectName}`);\n if (options.skipInstall) {\n logger.info(` ${packageManager.name} install`);\n }\n logger.info(` ${getDevCommand(packageManager.name)}`);\n logger.info(\"\");\n logger.info(\"Tailwind is enabled by default. You only need postcss config for custom plugins.\");\n}\n\nasync function copyTemplate(template: string, projectPath: string, useTypeScript: boolean) {\n const templatePath = path.join(__dirname, \"..\", \"templates\", template);\n\n // Copy base template files\n await copyDir(templatePath, projectPath);\n\n // If TypeScript is requested, copy TS-specific files\n if (useTypeScript) {\n const tsTemplatePath = path.join(__dirname, \"..\", \"templates\", \"_typescript\");\n if (await dirExists(tsTemplatePath)) {\n await copyDir(tsTemplatePath, projectPath);\n }\n }\n}\n\nasync function copyDir(src: string, dest: string) {\n await fs.mkdir(dest, { recursive: true });\n\n const entries = await fs.readdir(src, { withFileTypes: true });\n\n for (const entry of entries) {\n const srcPath = path.join(src, entry.name);\n // npm excludes .gitignore files from published tarballs. Keep the template\n // file publishable and restore its dot when generating the application.\n const destinationName = entry.name === \"gitignore\" ? \".gitignore\" : entry.name;\n const destPath = path.join(dest, destinationName);\n\n if (entry.isDirectory()) {\n await copyDir(srcPath, destPath);\n } else {\n await fs.copyFile(srcPath, destPath);\n }\n }\n}\n\nasync function dirExists(path: string): Promise<boolean> {\n try {\n const stat = await fs.stat(path);\n return stat.isDirectory();\n } catch {\n return false;\n }\n}\n\nasync function directoryHasFiles(dirPath: string): Promise<boolean> {\n if (!(await dirExists(dirPath))) {\n return false;\n }\n const files = await fs.readdir(dirPath);\n return files.length > 0;\n}\n\nfunction validateProjectName(value: string): true | string {\n const trimmed = value.trim();\n if (!trimmed) {\n return \"Project name is required\";\n }\n\n // npm package-safe pattern\n if (!/^[a-z0-9._-]+$/i.test(trimmed)) {\n return \"Use letters, numbers, hyphens, underscores, or dots\";\n }\n\n if (trimmed.startsWith(\".\") || trimmed.startsWith(\"_\")) {\n return \"Project name cannot start with '.' or '_'\";\n }\n\n return true;\n}\n\nfunction validateProjectPathArg(value: string): true | string {\n const trimmed = value.trim();\n if (!trimmed) {\n return \"Project name is required\";\n }\n\n const normalized = trimmed.replace(/[\\\\/]+$/, \"\");\n const baseName = path.basename(normalized);\n if (!baseName || baseName === \".\" || baseName === \"..\") {\n return \"Please provide a valid project directory name\";\n }\n\n return validateProjectName(baseName);\n}\n\nfunction prettifyTemplateName(name: string): string {\n return name\n .split(\"-\")\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join(\" \");\n}\n\nasync function getAvailableTemplates(): Promise<string[]> {\n const templatesRoot = path.join(__dirname, \"..\", \"templates\");\n const entries = await fs.readdir(templatesRoot, { withFileTypes: true });\n return entries\n .filter((entry) => entry.isDirectory() && !entry.name.startsWith(\"_\"))\n .map((entry) => entry.name)\n .sort();\n}\n\nasync function updatePackageJson(\n projectPath: string,\n projectName: string,\n packageManager: PackageManager,\n) {\n const packageJsonPath = path.join(projectPath, \"package.json\");\n\n try {\n const content = await fs.readFile(packageJsonPath, \"utf-8\");\n const packageJson = JSON.parse(content);\n\n packageJson.name = projectName;\n if (packageManager.version) {\n packageJson.packageManager = `${packageManager.name}@${packageManager.version}`;\n }\n\n await fs.writeFile(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\\n`);\n } catch {\n logger.warn(\"Could not update package.json\");\n }\n}\n\nexport function detectPackageManager(\n userAgent = process.env.npm_config_user_agent,\n): PackageManager {\n const match = userAgent?.match(/^(npm|pnpm|yarn|bun)\\/([^\\s]+)/);\n if (!match) {\n return { name: \"pnpm\" };\n }\n\n const [, name, version] = match;\n return {\n name: name as PackageManagerName,\n version: version === \"?\" ? undefined : version,\n };\n}\n\nexport function installDependencies(\n projectPath: string,\n packageManager: PackageManager,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const command =\n process.platform === \"win32\" ? `${packageManager.name}.cmd` : packageManager.name;\n const child = spawn(command, [\"install\"], {\n cwd: projectPath,\n env: process.env,\n stdio: \"inherit\",\n });\n\n child.on(\"error\", reject);\n child.on(\"close\", (code, signal) => {\n if (code === 0) {\n resolve();\n return;\n }\n\n const reason = signal ? `signal ${signal}` : `exit code ${code ?? \"unknown\"}`;\n reject(new Error(`${packageManager.name} install failed with ${reason}.`));\n });\n });\n}\n\nfunction getDevCommand(packageManager: PackageManagerName) {\n if (packageManager === \"npm\" || packageManager === \"bun\") {\n return `${packageManager} run dev`;\n }\n return `${packageManager} dev`;\n}\n"],"mappings":"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"}
|
|
@@ -15,7 +15,7 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
15
|
}
|
|
16
16
|
return to;
|
|
17
17
|
};
|
|
18
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
|
|
19
19
|
value: mod,
|
|
20
20
|
enumerable: true
|
|
21
21
|
}) : target, mod));
|
package/dist/utils.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const require_rolldown_runtime = require("./rolldown-runtime-
|
|
2
|
+
const require_rolldown_runtime = require("./rolldown-runtime-VH7oDXx4.js");
|
|
3
3
|
let picocolors = require("picocolors");
|
|
4
4
|
picocolors = require_rolldown_runtime.__toESM(picocolors);
|
|
5
5
|
//#region src/utils.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@farm.js/create-app",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.10",
|
|
4
4
|
"description": "Create a new Farm.js application",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"@farm.js/create-app",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"lint:fix": "biome lint --write .",
|
|
46
46
|
"format": "biome format --write .",
|
|
47
47
|
"type-check": "tsc --noEmit",
|
|
48
|
-
"test": "
|
|
48
|
+
"test": "tsdown && node --test test/*.test.mjs",
|
|
49
49
|
"clean": "rm -rf dist"
|
|
50
50
|
}
|
|
51
51
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Dependencies
|
|
2
|
+
node_modules/
|
|
3
|
+
|
|
4
|
+
# Farm and deployment output
|
|
5
|
+
.farm/
|
|
6
|
+
.output/
|
|
7
|
+
.vercel/
|
|
8
|
+
dist/
|
|
9
|
+
|
|
10
|
+
# Local environment files
|
|
11
|
+
.env
|
|
12
|
+
.env.local
|
|
13
|
+
.env.*.local
|
|
14
|
+
|
|
15
|
+
# Local databases
|
|
16
|
+
*.sqlite
|
|
17
|
+
*.sqlite-*
|
|
18
|
+
*.db
|
|
19
|
+
*.db-*
|
|
20
|
+
|
|
21
|
+
# Logs and TypeScript cache
|
|
22
|
+
*.log
|
|
23
|
+
*.tsbuildinfo
|
|
@@ -10,13 +10,16 @@
|
|
|
10
10
|
"type-check": "tsc --noEmit"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@farm.js/core": "0.1.0-beta.
|
|
14
|
-
"react": "^
|
|
15
|
-
"react-dom": "^
|
|
13
|
+
"@farm.js/core": "0.1.0-beta.10",
|
|
14
|
+
"react": "^19.0.0",
|
|
15
|
+
"react-dom": "^19.0.0"
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
18
|
-
"@
|
|
19
|
-
"@types/react
|
|
18
|
+
"@farm.js/cli": "0.1.0-beta.10",
|
|
19
|
+
"@types/react": "^19.0.0",
|
|
20
|
+
"@types/react-dom": "^19.0.0",
|
|
21
|
+
"tailwindcss": "^4.0.0",
|
|
20
22
|
"typescript": "^5.3.3"
|
|
21
|
-
}
|
|
23
|
+
},
|
|
24
|
+
"packageManager": "pnpm@8.12.1"
|
|
22
25
|
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512" fill="none" role="img" aria-labelledby="title desc">
|
|
2
|
+
<title id="title">Farming Labs</title>
|
|
3
|
+
<desc id="desc">The three-tone Farming Labs mark on a dark square.</desc>
|
|
4
|
+
<rect width="512" height="512" fill="#0A0A0A"/>
|
|
5
|
+
<svg x="135.25" y="142" width="241.5" height="228" viewBox="125 68 161 152">
|
|
6
|
+
<path d="M157 68H133C128.582 68 125 71.5817 125 76V100C125 104.418 128.582 108 133 108H157C161.418 108 165 104.418 165 100V76C165 71.5817 161.418 68 157 68Z" fill="#F5F5F4"/>
|
|
7
|
+
<path fill-rule="evenodd" clip-rule="evenodd" d="M182.383 68H280.617C282.045 68 283.414 68.8429 284.423 70.3431C285.433 71.8434 286 73.8783 286 76V100C286 102.122 285.433 104.157 284.423 105.657C283.414 107.157 282.045 108 280.617 108H182.383C180.955 108 179.586 107.157 178.577 105.657C177.567 104.157 177 102.122 177 100V76C177 73.8783 177.567 71.8434 178.577 70.3431C179.586 68.8429 180.955 68 182.383 68ZM271.852 81C270.747 81 269.852 81.8954 269.852 83V93C269.852 94.1046 270.747 95 271.852 95H277.272C278.376 95 279.272 94.1046 279.272 93V83C279.272 81.8954 278.376 81 277.272 81H271.852Z" fill="#F5F5F4"/>
|
|
8
|
+
<path d="M157 124H133C128.582 124 125 127.582 125 132V156C125 160.418 128.582 164 133 164H157C161.418 164 165 160.418 165 156V132C165 127.582 161.418 124 157 124Z" fill="#A3A3A3"/>
|
|
9
|
+
<path d="M280.334 124H182.666C179.537 124 177 127.582 177 132V156C177 160.418 179.537 164 182.666 164H280.334C283.463 164 286 160.418 286 156V132C286 127.582 283.463 124 280.334 124Z" fill="#A3A3A3"/>
|
|
10
|
+
<path d="M157 180H133C128.582 180 125 183.582 125 188V212C125 216.418 128.582 220 133 220H157C161.418 220 165 216.418 165 212V188C165 183.582 161.418 180 157 180Z" fill="#595959"/>
|
|
11
|
+
<path d="M230.189 180H182.811C179.602 180 177 183.582 177 188V212C177 216.418 179.602 220 182.811 220H230.189C233.398 220 236 216.418 236 212V188C236 183.582 233.398 180 230.189 180Z" fill="#595959"/>
|
|
12
|
+
</svg>
|
|
13
|
+
</svg>
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import type { PageProps } from "@farm.js/core";
|
|
3
|
-
import { Link } from "farm/client";
|
|
1
|
+
import { Link } from "@farm.js/core/client";
|
|
4
2
|
|
|
5
|
-
export default function AboutPage(
|
|
3
|
+
export default function AboutPage() {
|
|
6
4
|
return (
|
|
7
5
|
<div className="min-h-screen p-8">
|
|
8
6
|
<div className="max-w-4xl mx-auto space-y-8">
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import React from "react";
|
|
2
1
|
import type { LayoutProps, Metadata } from "@farm.js/core";
|
|
3
2
|
import "./globals.css";
|
|
4
3
|
|
|
5
4
|
export const metadata: Metadata = {
|
|
6
5
|
title: "Farm.js App",
|
|
7
6
|
description: "A modern React meta-framework built on Vite",
|
|
7
|
+
icons: {
|
|
8
|
+
icon: [{ url: "/favicon.svg", type: "image/svg+xml", sizes: "any" }],
|
|
9
|
+
},
|
|
8
10
|
};
|
|
9
11
|
|
|
10
12
|
export default function RootLayout({ children }: LayoutProps) {
|
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import { Link } from "farm/client";
|
|
1
|
+
import { Link } from "@farm.js/core/client";
|
|
2
|
+
import { FARM_VERSION } from "@farm.js/core/version";
|
|
4
3
|
|
|
5
|
-
export default function HomePage(
|
|
4
|
+
export default function HomePage() {
|
|
6
5
|
return (
|
|
7
6
|
<div className="min-h-screen flex items-center justify-center p-8">
|
|
8
7
|
<div className="max-w-4xl mx-auto text-center space-y-8">
|
|
9
8
|
<div>
|
|
10
9
|
<h1 className="text-6xl font-bold mb-4">
|
|
11
10
|
<span className="bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent">
|
|
12
|
-
🚜 Welcome to Farm.js
|
|
11
|
+
🚜 Welcome to Farm.js v{FARM_VERSION}
|
|
13
12
|
</span>
|
|
14
13
|
</h1>
|
|
15
14
|
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
// Generated by Farm.js. Do not edit.
|
|
2
|
-
declare module "*.avif" {
|
|
3
|
-
const image: import("@farm.js/core/image").StaticImageData;
|
|
4
|
-
export const src: string;
|
|
5
|
-
export const width: number;
|
|
6
|
-
export const height: number;
|
|
7
|
-
export const blurDataURL: string | undefined;
|
|
8
|
-
export default image;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
declare module "*.gif" {
|
|
12
|
-
const image: import("@farm.js/core/image").StaticImageData;
|
|
13
|
-
export const src: string;
|
|
14
|
-
export const width: number;
|
|
15
|
-
export const height: number;
|
|
16
|
-
export const blurDataURL: string | undefined;
|
|
17
|
-
export default image;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
declare module "*.jpeg" {
|
|
21
|
-
const image: import("@farm.js/core/image").StaticImageData;
|
|
22
|
-
export const src: string;
|
|
23
|
-
export const width: number;
|
|
24
|
-
export const height: number;
|
|
25
|
-
export const blurDataURL: string | undefined;
|
|
26
|
-
export default image;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
declare module "*.jpg" {
|
|
30
|
-
const image: import("@farm.js/core/image").StaticImageData;
|
|
31
|
-
export const src: string;
|
|
32
|
-
export const width: number;
|
|
33
|
-
export const height: number;
|
|
34
|
-
export const blurDataURL: string | undefined;
|
|
35
|
-
export default image;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
declare module "*.png" {
|
|
39
|
-
const image: import("@farm.js/core/image").StaticImageData;
|
|
40
|
-
export const src: string;
|
|
41
|
-
export const width: number;
|
|
42
|
-
export const height: number;
|
|
43
|
-
export const blurDataURL: string | undefined;
|
|
44
|
-
export default image;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
declare module "*.webp" {
|
|
48
|
-
const image: import("@farm.js/core/image").StaticImageData;
|
|
49
|
-
export const src: string;
|
|
50
|
-
export const width: number;
|
|
51
|
-
export const height: number;
|
|
52
|
-
export const blurDataURL: string | undefined;
|
|
53
|
-
export default image;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
declare module "*?url" {
|
|
57
|
-
const src: string;
|
|
58
|
-
export default src;
|
|
59
|
-
}
|