@farm.js/create-app 0.1.0-beta.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 ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Farm.js Team
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
package/README.md ADDED
@@ -0,0 +1,11 @@
1
+ # @farm.js/create-app
2
+
3
+ Create a new Farm.js application
4
+
5
+ Farm.js is currently in beta.
6
+
7
+ ```bash
8
+ npm create @farm.js/app@beta
9
+ ```
10
+
11
+ See the [Farm.js repository](https://github.com/farming-labs/farm.js) for documentation, examples, and support.
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { program } = require("commander");
4
+ const { createApp } = require("../dist/index.js");
5
+ const { version } = require("../package.json");
6
+
7
+ program
8
+ .name("create-farm-app")
9
+ .description("Create a new Farm.js application")
10
+ .version(version)
11
+ .argument("[project-name]", "Name of the project")
12
+ .option("-t, --template <template>", "Template to use")
13
+ .option("--typescript", "Use TypeScript template")
14
+ .action(async (projectName, options) => {
15
+ try {
16
+ await createApp(projectName, options);
17
+ } catch (error) {
18
+ console.error("Failed to create app:", error);
19
+ process.exit(1);
20
+ }
21
+ });
22
+
23
+ program.parse();
package/dist/index.js ADDED
@@ -0,0 +1,166 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_rolldown_runtime = require("./rolldown-runtime-D6vf50IK.js");
3
+ const require_utils = require("./utils.js");
4
+ let prompts = require("prompts");
5
+ prompts = require_rolldown_runtime.__toESM(prompts);
6
+ let path = require("path");
7
+ path = require_rolldown_runtime.__toESM(path);
8
+ let fs_promises = require("fs/promises");
9
+ fs_promises = require_rolldown_runtime.__toESM(fs_promises);
10
+ //#region src/index.ts
11
+ async function createApp(projectName, options = {}) {
12
+ require_utils.showBanner();
13
+ const templates = await getAvailableTemplates();
14
+ if (templates.length === 0) {
15
+ require_utils.logger.error("No templates are available in this package.");
16
+ process.exit(1);
17
+ }
18
+ if (!projectName) {
19
+ const response = await (0, prompts.default)({
20
+ type: "text",
21
+ name: "projectName",
22
+ message: "What is your project named?",
23
+ initial: "my-farm-app",
24
+ validate: validateProjectName
25
+ });
26
+ if (!response.projectName) {
27
+ require_utils.logger.error("Operation cancelled.");
28
+ process.exit(1);
29
+ }
30
+ projectName = response.projectName;
31
+ } else {
32
+ const validation = validateProjectPathArg(projectName);
33
+ if (validation !== true) {
34
+ require_utils.logger.error(validation);
35
+ process.exit(1);
36
+ }
37
+ }
38
+ let template = options.template;
39
+ if (!template) {
40
+ const response = await (0, prompts.default)({
41
+ type: "select",
42
+ name: "template",
43
+ message: "Which template would you like to use?",
44
+ choices: templates.map((name) => ({
45
+ title: prettifyTemplateName(name),
46
+ value: name,
47
+ description: name === "basic" ? "A simple Farm.js app with built-in Tailwind support" : void 0
48
+ })),
49
+ initial: 0
50
+ });
51
+ if (!response.template) {
52
+ require_utils.logger.error("Operation cancelled.");
53
+ process.exit(1);
54
+ }
55
+ template = response.template;
56
+ } else if (!templates.includes(template)) {
57
+ require_utils.logger.error(`Unknown template "${template}". Available: ${templates.map((t) => `"${t}"`).join(", ")}`);
58
+ process.exit(1);
59
+ }
60
+ let useTypeScript = options.typescript;
61
+ if (useTypeScript === void 0) {
62
+ const response = await (0, prompts.default)({
63
+ type: "confirm",
64
+ name: "typescript",
65
+ message: "Would you like to use TypeScript?",
66
+ initial: true
67
+ });
68
+ if (response.typescript === void 0) {
69
+ require_utils.logger.error("Operation cancelled.");
70
+ process.exit(1);
71
+ }
72
+ useTypeScript = response.typescript;
73
+ }
74
+ const projectPath = path.default.resolve(process.cwd(), projectName);
75
+ if (await directoryHasFiles(projectPath)) {
76
+ if (!(await (0, prompts.default)({
77
+ type: "confirm",
78
+ name: "overwrite",
79
+ message: `Directory "${projectName}" is not empty. Continue and overwrite conflicting files?`,
80
+ initial: false
81
+ })).overwrite) {
82
+ require_utils.logger.error("Operation cancelled.");
83
+ process.exit(1);
84
+ }
85
+ }
86
+ require_utils.logger.info(`Creating Farm.js app in ${projectPath}`);
87
+ await fs_promises.default.mkdir(projectPath, { recursive: true });
88
+ await copyTemplate(template, projectPath, useTypeScript);
89
+ await updatePackageJson(projectPath, projectName);
90
+ require_utils.logger.success(`๐Ÿšœ Created ${projectName}`);
91
+ require_utils.logger.info("");
92
+ require_utils.logger.info("Next steps");
93
+ require_utils.logger.info(` cd ${projectName}`);
94
+ require_utils.logger.info(" pnpm install");
95
+ require_utils.logger.info(" pnpm dev");
96
+ require_utils.logger.info("");
97
+ require_utils.logger.info("Tailwind is enabled by default. You only need postcss config for custom plugins.");
98
+ }
99
+ async function copyTemplate(template, projectPath, useTypeScript) {
100
+ await copyDir(path.default.join(__dirname, "..", "templates", template), projectPath);
101
+ if (useTypeScript) {
102
+ const tsTemplatePath = path.default.join(__dirname, "..", "templates", "_typescript");
103
+ if (await dirExists(tsTemplatePath)) await copyDir(tsTemplatePath, projectPath);
104
+ }
105
+ }
106
+ async function copyDir(src, dest) {
107
+ await fs_promises.default.mkdir(dest, { recursive: true });
108
+ const entries = await fs_promises.default.readdir(src, { withFileTypes: true });
109
+ for (const entry of entries) {
110
+ const srcPath = path.default.join(src, entry.name);
111
+ const destPath = path.default.join(dest, entry.name);
112
+ if (entry.isDirectory()) await copyDir(srcPath, destPath);
113
+ else await fs_promises.default.copyFile(srcPath, destPath);
114
+ }
115
+ }
116
+ async function dirExists(path$2) {
117
+ try {
118
+ return (await fs_promises.default.stat(path$2)).isDirectory();
119
+ } catch {
120
+ return false;
121
+ }
122
+ }
123
+ async function directoryHasFiles(dirPath) {
124
+ if (!await dirExists(dirPath)) return false;
125
+ return (await fs_promises.default.readdir(dirPath)).length > 0;
126
+ }
127
+ function validateProjectName(value) {
128
+ const trimmed = value.trim();
129
+ if (!trimmed) return "Project name is required";
130
+ if (!/^[a-z0-9._-]+$/i.test(trimmed)) return "Use letters, numbers, hyphens, underscores, or dots";
131
+ if (trimmed.startsWith(".") || trimmed.startsWith("_")) return "Project name cannot start with '.' or '_'";
132
+ return true;
133
+ }
134
+ function validateProjectPathArg(value) {
135
+ const trimmed = value.trim();
136
+ if (!trimmed) return "Project name is required";
137
+ const normalized = trimmed.replace(/[\\/]+$/, "");
138
+ const baseName = path.default.basename(normalized);
139
+ if (!baseName || baseName === "." || baseName === "..") return "Please provide a valid project directory name";
140
+ return validateProjectName(baseName);
141
+ }
142
+ function prettifyTemplateName(name) {
143
+ return name.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
144
+ }
145
+ async function getAvailableTemplates() {
146
+ const templatesRoot = path.default.join(__dirname, "..", "templates");
147
+ return (await fs_promises.default.readdir(templatesRoot, { withFileTypes: true })).filter((entry) => entry.isDirectory() && !entry.name.startsWith("_")).map((entry) => entry.name).sort();
148
+ }
149
+ async function updatePackageJson(projectPath, projectName) {
150
+ const packageJsonPath = path.default.join(projectPath, "package.json");
151
+ const createAppPackageJsonPath = path.default.join(__dirname, "..", "package.json");
152
+ try {
153
+ const [content, createAppContent] = await Promise.all([fs_promises.default.readFile(packageJsonPath, "utf-8"), fs_promises.default.readFile(createAppPackageJsonPath, "utf-8")]);
154
+ const packageJson = JSON.parse(content);
155
+ const createAppPackageJson = JSON.parse(createAppContent);
156
+ packageJson.name = projectName;
157
+ packageJson.dependencies["@farm.js/core"] = createAppPackageJson.version;
158
+ await fs_promises.default.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
159
+ } catch (error) {
160
+ require_utils.logger.warn("Could not update package.json");
161
+ }
162
+ }
163
+ //#endregion
164
+ exports.createApp = createApp;
165
+
166
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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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"}
package/dist/index.mjs ADDED
@@ -0,0 +1,161 @@
1
+ import { logger, showBanner } from "./utils.mjs";
2
+ import prompts from "prompts";
3
+ import path from "path";
4
+ import fs from "fs/promises";
5
+ //#region src/index.ts
6
+ async function createApp(projectName, options = {}) {
7
+ showBanner();
8
+ const templates = await getAvailableTemplates();
9
+ if (templates.length === 0) {
10
+ logger.error("No templates are available in this package.");
11
+ process.exit(1);
12
+ }
13
+ if (!projectName) {
14
+ const response = await prompts({
15
+ type: "text",
16
+ name: "projectName",
17
+ message: "What is your project named?",
18
+ initial: "my-farm-app",
19
+ validate: validateProjectName
20
+ });
21
+ if (!response.projectName) {
22
+ logger.error("Operation cancelled.");
23
+ process.exit(1);
24
+ }
25
+ projectName = response.projectName;
26
+ } else {
27
+ const validation = validateProjectPathArg(projectName);
28
+ if (validation !== true) {
29
+ logger.error(validation);
30
+ process.exit(1);
31
+ }
32
+ }
33
+ let template = options.template;
34
+ if (!template) {
35
+ const response = await prompts({
36
+ type: "select",
37
+ name: "template",
38
+ message: "Which template would you like to use?",
39
+ choices: templates.map((name) => ({
40
+ title: prettifyTemplateName(name),
41
+ value: name,
42
+ description: name === "basic" ? "A simple Farm.js app with built-in Tailwind support" : void 0
43
+ })),
44
+ initial: 0
45
+ });
46
+ if (!response.template) {
47
+ logger.error("Operation cancelled.");
48
+ process.exit(1);
49
+ }
50
+ template = response.template;
51
+ } else if (!templates.includes(template)) {
52
+ logger.error(`Unknown template "${template}". Available: ${templates.map((t) => `"${t}"`).join(", ")}`);
53
+ process.exit(1);
54
+ }
55
+ let useTypeScript = options.typescript;
56
+ if (useTypeScript === void 0) {
57
+ const response = await prompts({
58
+ type: "confirm",
59
+ name: "typescript",
60
+ message: "Would you like to use TypeScript?",
61
+ initial: true
62
+ });
63
+ if (response.typescript === void 0) {
64
+ logger.error("Operation cancelled.");
65
+ process.exit(1);
66
+ }
67
+ useTypeScript = response.typescript;
68
+ }
69
+ const projectPath = path.resolve(process.cwd(), projectName);
70
+ if (await directoryHasFiles(projectPath)) {
71
+ if (!(await prompts({
72
+ type: "confirm",
73
+ name: "overwrite",
74
+ message: `Directory "${projectName}" is not empty. Continue and overwrite conflicting files?`,
75
+ initial: false
76
+ })).overwrite) {
77
+ logger.error("Operation cancelled.");
78
+ process.exit(1);
79
+ }
80
+ }
81
+ logger.info(`Creating Farm.js app in ${projectPath}`);
82
+ await fs.mkdir(projectPath, { recursive: true });
83
+ await copyTemplate(template, projectPath, useTypeScript);
84
+ await updatePackageJson(projectPath, projectName);
85
+ logger.success(`๐Ÿšœ Created ${projectName}`);
86
+ logger.info("");
87
+ logger.info("Next steps");
88
+ logger.info(` cd ${projectName}`);
89
+ logger.info(" pnpm install");
90
+ logger.info(" pnpm dev");
91
+ logger.info("");
92
+ logger.info("Tailwind is enabled by default. You only need postcss config for custom plugins.");
93
+ }
94
+ async function copyTemplate(template, projectPath, useTypeScript) {
95
+ await copyDir(path.join(__dirname, "..", "templates", template), projectPath);
96
+ if (useTypeScript) {
97
+ const tsTemplatePath = path.join(__dirname, "..", "templates", "_typescript");
98
+ if (await dirExists(tsTemplatePath)) await copyDir(tsTemplatePath, projectPath);
99
+ }
100
+ }
101
+ async function copyDir(src, dest) {
102
+ await fs.mkdir(dest, { recursive: true });
103
+ const entries = await fs.readdir(src, { withFileTypes: true });
104
+ for (const entry of entries) {
105
+ const srcPath = path.join(src, entry.name);
106
+ const destPath = path.join(dest, entry.name);
107
+ if (entry.isDirectory()) await copyDir(srcPath, destPath);
108
+ else await fs.copyFile(srcPath, destPath);
109
+ }
110
+ }
111
+ async function dirExists(path) {
112
+ try {
113
+ return (await fs.stat(path)).isDirectory();
114
+ } catch {
115
+ return false;
116
+ }
117
+ }
118
+ async function directoryHasFiles(dirPath) {
119
+ if (!await dirExists(dirPath)) return false;
120
+ return (await fs.readdir(dirPath)).length > 0;
121
+ }
122
+ function validateProjectName(value) {
123
+ const trimmed = value.trim();
124
+ if (!trimmed) return "Project name is required";
125
+ if (!/^[a-z0-9._-]+$/i.test(trimmed)) return "Use letters, numbers, hyphens, underscores, or dots";
126
+ if (trimmed.startsWith(".") || trimmed.startsWith("_")) return "Project name cannot start with '.' or '_'";
127
+ return true;
128
+ }
129
+ function validateProjectPathArg(value) {
130
+ const trimmed = value.trim();
131
+ if (!trimmed) return "Project name is required";
132
+ const normalized = trimmed.replace(/[\\/]+$/, "");
133
+ const baseName = path.basename(normalized);
134
+ if (!baseName || baseName === "." || baseName === "..") return "Please provide a valid project directory name";
135
+ return validateProjectName(baseName);
136
+ }
137
+ function prettifyTemplateName(name) {
138
+ return name.split("-").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(" ");
139
+ }
140
+ async function getAvailableTemplates() {
141
+ const templatesRoot = path.join(__dirname, "..", "templates");
142
+ return (await fs.readdir(templatesRoot, { withFileTypes: true })).filter((entry) => entry.isDirectory() && !entry.name.startsWith("_")).map((entry) => entry.name).sort();
143
+ }
144
+ async function updatePackageJson(projectPath, projectName) {
145
+ const packageJsonPath = path.join(projectPath, "package.json");
146
+ const createAppPackageJsonPath = path.join(__dirname, "..", "package.json");
147
+ try {
148
+ const [content, createAppContent] = await Promise.all([fs.readFile(packageJsonPath, "utf-8"), fs.readFile(createAppPackageJsonPath, "utf-8")]);
149
+ const packageJson = JSON.parse(content);
150
+ const createAppPackageJson = JSON.parse(createAppContent);
151
+ packageJson.name = projectName;
152
+ packageJson.dependencies["@farm.js/core"] = createAppPackageJson.version;
153
+ await fs.writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
154
+ } catch (error) {
155
+ logger.warn("Could not update package.json");
156
+ }
157
+ }
158
+ //#endregion
159
+ export { createApp };
160
+
161
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +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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"}
@@ -0,0 +1,28 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
+ key = keys[i];
11
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
+ get: ((k) => from[k]).bind(null, key),
13
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
+ });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ value: mod,
20
+ enumerable: true
21
+ }) : target, mod));
22
+ //#endregion
23
+ Object.defineProperty(exports, "__toESM", {
24
+ enumerable: true,
25
+ get: function() {
26
+ return __toESM;
27
+ }
28
+ });
package/dist/utils.js ADDED
@@ -0,0 +1,29 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_rolldown_runtime = require("./rolldown-runtime-D6vf50IK.js");
3
+ let picocolors = require("picocolors");
4
+ picocolors = require_rolldown_runtime.__toESM(picocolors);
5
+ //#region src/utils.ts
6
+ const logger = {
7
+ info: (message) => console.log(`${picocolors.default.blue("โ„น")} ${message}`),
8
+ success: (message) => console.log(`${picocolors.default.green("โœ“")} ${message}`),
9
+ warn: (message) => console.warn(`${picocolors.default.yellow("โš ")} ${message}`),
10
+ error: (message) => console.error(`${picocolors.default.red("โœ—")} ${message}`)
11
+ };
12
+ function showBanner() {
13
+ const art = [
14
+ " _______ ",
15
+ "| ___ |__ _ _ __ _ __ ___ ",
16
+ "| |_ /| / _` | '__| '_ ` _ \\ ",
17
+ "| _ \\| | (_| | | | | | | | | ",
18
+ "|_| \\_\\_|\\__,_|_| |_| |_| |_|"
19
+ ];
20
+ console.log("");
21
+ for (const line of art) console.log(picocolors.default.cyan(line));
22
+ console.log(picocolors.default.bold(picocolors.default.green("Create Farm.js App")) + picocolors.default.dim(" modern React meta-framework"));
23
+ console.log("");
24
+ }
25
+ //#endregion
26
+ exports.logger = logger;
27
+ exports.showBanner = showBanner;
28
+
29
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","names":["pc"],"sources":["../src/utils.ts"],"sourcesContent":["import pc from \"picocolors\";\n\nexport const logger = {\n info: (message: string) => console.log(`${pc.blue(\"โ„น\")} ${message}`),\n success: (message: string) => console.log(`${pc.green(\"โœ“\")} ${message}`),\n warn: (message: string) => console.warn(`${pc.yellow(\"โš \")} ${message}`),\n error: (message: string) => console.error(`${pc.red(\"โœ—\")} ${message}`),\n};\n\nexport function showBanner() {\n const art = [\n \" _______ \",\n \"| ___ |__ _ _ __ _ __ ___ \",\n \"| |_ /| / _` | '__| '_ ` _ \\\\ \",\n \"| _ \\\\| | (_| | | | | | | | | \",\n \"|_| \\\\_\\\\_|\\\\__,_|_| |_| |_| |_|\",\n ];\n\n console.log(\"\");\n for (const line of art) {\n console.log(pc.cyan(line));\n }\n console.log(pc.bold(pc.green(\"Create Farm.js App\")) + pc.dim(\" modern React meta-framework\"));\n console.log(\"\");\n}\n"],"mappings":";;;;;AAEA,MAAa,SAAS;CACpB,OAAO,YAAoB,QAAQ,IAAI,GAAGA,WAAAA,QAAG,KAAK,GAAG,EAAE,GAAG,SAAS;CACnE,UAAU,YAAoB,QAAQ,IAAI,GAAGA,WAAAA,QAAG,MAAM,GAAG,EAAE,GAAG,SAAS;CACvE,OAAO,YAAoB,QAAQ,KAAK,GAAGA,WAAAA,QAAG,OAAO,GAAG,EAAE,GAAG,SAAS;CACtE,QAAQ,YAAoB,QAAQ,MAAM,GAAGA,WAAAA,QAAG,IAAI,GAAG,EAAE,GAAG,SAAS;AACvE;AAEA,SAAgB,aAAa;CAC3B,MAAM,MAAM;EACV;EACA;EACA;EACA;EACA;CACF;CAEA,QAAQ,IAAI,EAAE;CACd,KAAK,MAAM,QAAQ,KACjB,QAAQ,IAAIA,WAAAA,QAAG,KAAK,IAAI,CAAC;CAE3B,QAAQ,IAAIA,WAAAA,QAAG,KAAKA,WAAAA,QAAG,MAAM,oBAAoB,CAAC,IAAIA,WAAAA,QAAG,IAAI,+BAA+B,CAAC;CAC7F,QAAQ,IAAI,EAAE;AAChB"}
package/dist/utils.mjs ADDED
@@ -0,0 +1,25 @@
1
+ import pc from "picocolors";
2
+ //#region src/utils.ts
3
+ const logger = {
4
+ info: (message) => console.log(`${pc.blue("โ„น")} ${message}`),
5
+ success: (message) => console.log(`${pc.green("โœ“")} ${message}`),
6
+ warn: (message) => console.warn(`${pc.yellow("โš ")} ${message}`),
7
+ error: (message) => console.error(`${pc.red("โœ—")} ${message}`)
8
+ };
9
+ function showBanner() {
10
+ const art = [
11
+ " _______ ",
12
+ "| ___ |__ _ _ __ _ __ ___ ",
13
+ "| |_ /| / _` | '__| '_ ` _ \\ ",
14
+ "| _ \\| | (_| | | | | | | | | ",
15
+ "|_| \\_\\_|\\__,_|_| |_| |_| |_|"
16
+ ];
17
+ console.log("");
18
+ for (const line of art) console.log(pc.cyan(line));
19
+ console.log(pc.bold(pc.green("Create Farm.js App")) + pc.dim(" modern React meta-framework"));
20
+ console.log("");
21
+ }
22
+ //#endregion
23
+ export { logger, showBanner };
24
+
25
+ //# sourceMappingURL=utils.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.mjs","names":[],"sources":["../src/utils.ts"],"sourcesContent":["import pc from \"picocolors\";\n\nexport const logger = {\n info: (message: string) => console.log(`${pc.blue(\"โ„น\")} ${message}`),\n success: (message: string) => console.log(`${pc.green(\"โœ“\")} ${message}`),\n warn: (message: string) => console.warn(`${pc.yellow(\"โš \")} ${message}`),\n error: (message: string) => console.error(`${pc.red(\"โœ—\")} ${message}`),\n};\n\nexport function showBanner() {\n const art = [\n \" _______ \",\n \"| ___ |__ _ _ __ _ __ ___ \",\n \"| |_ /| / _` | '__| '_ ` _ \\\\ \",\n \"| _ \\\\| | (_| | | | | | | | | \",\n \"|_| \\\\_\\\\_|\\\\__,_|_| |_| |_| |_|\",\n ];\n\n console.log(\"\");\n for (const line of art) {\n console.log(pc.cyan(line));\n }\n console.log(pc.bold(pc.green(\"Create Farm.js App\")) + pc.dim(\" modern React meta-framework\"));\n console.log(\"\");\n}\n"],"mappings":";;AAEA,MAAa,SAAS;CACpB,OAAO,YAAoB,QAAQ,IAAI,GAAG,GAAG,KAAK,GAAG,EAAE,GAAG,SAAS;CACnE,UAAU,YAAoB,QAAQ,IAAI,GAAG,GAAG,MAAM,GAAG,EAAE,GAAG,SAAS;CACvE,OAAO,YAAoB,QAAQ,KAAK,GAAG,GAAG,OAAO,GAAG,EAAE,GAAG,SAAS;CACtE,QAAQ,YAAoB,QAAQ,MAAM,GAAG,GAAG,IAAI,GAAG,EAAE,GAAG,SAAS;AACvE;AAEA,SAAgB,aAAa;CAC3B,MAAM,MAAM;EACV;EACA;EACA;EACA;EACA;CACF;CAEA,QAAQ,IAAI,EAAE;CACd,KAAK,MAAM,QAAQ,KACjB,QAAQ,IAAI,GAAG,KAAK,IAAI,CAAC;CAE3B,QAAQ,IAAI,GAAG,KAAK,GAAG,MAAM,oBAAoB,CAAC,IAAI,GAAG,IAAI,+BAA+B,CAAC;CAC7F,QAAQ,IAAI,EAAE;AAChB"}
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "@farm.js/create-app",
3
+ "version": "0.1.0-beta.0",
4
+ "description": "Create a new Farm.js application",
5
+ "keywords": [
6
+ "@farm.js/create-app",
7
+ "create-app",
8
+ "react",
9
+ "template",
10
+ "vite"
11
+ ],
12
+ "license": "MIT",
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "https://github.com/farming-labs/farm.js",
16
+ "directory": "packages/create-farm-app"
17
+ },
18
+ "bin": {
19
+ "create-farm-app": "./bin/create-farm-app.js"
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "bin",
24
+ "templates"
25
+ ],
26
+ "main": "./dist/index.js",
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "dependencies": {
31
+ "commander": "^11.1.0",
32
+ "picocolors": "^1.0.0",
33
+ "prompts": "^2.4.2"
34
+ },
35
+ "devDependencies": {
36
+ "@types/node": "^20.10.5",
37
+ "@types/prompts": "^2.4.9",
38
+ "tsdown": "^0.15.7",
39
+ "typescript": "^5.3.3"
40
+ },
41
+ "scripts": {
42
+ "build": "tsdown",
43
+ "dev": "tsdown --watch",
44
+ "lint": "biome lint .",
45
+ "lint:fix": "biome lint --write .",
46
+ "format": "biome format --write .",
47
+ "type-check": "tsc --noEmit",
48
+ "test": "echo 'No tests in this package'",
49
+ "clean": "rm -rf dist"
50
+ }
51
+ }
@@ -0,0 +1,8 @@
1
+ import { defineConfig } from "@farm.js/core";
2
+
3
+ export default defineConfig({
4
+ srcDir: "src",
5
+ deploy: {
6
+ target: "vercel",
7
+ },
8
+ });
@@ -0,0 +1,22 @@
1
+ {
2
+ "name": "farm-app",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "dev": "farm dev",
7
+ "build": "farm build",
8
+ "deploy": "farm deploy",
9
+ "start": "farm start",
10
+ "type-check": "tsc --noEmit"
11
+ },
12
+ "dependencies": {
13
+ "@farm.js/core": "0.1.0-beta.0",
14
+ "react": "^18.2.0",
15
+ "react-dom": "^18.2.0"
16
+ },
17
+ "devDependencies": {
18
+ "@types/react": "^18.2.45",
19
+ "@types/react-dom": "^18.2.18",
20
+ "typescript": "^5.3.3"
21
+ }
22
+ }
@@ -0,0 +1,34 @@
1
+ import React from "react";
2
+ import type { PageProps } from "@farm.js/core";
3
+ import { Link } from "farm/client";
4
+
5
+ export default function AboutPage({ params, searchParams }: PageProps) {
6
+ return (
7
+ <div className="min-h-screen p-8">
8
+ <div className="max-w-4xl mx-auto space-y-8">
9
+ <h1 className="text-5xl font-bold text-gray-900 mb-4">About Farm.js</h1>
10
+
11
+ <p className="text-xl text-gray-600 leading-relaxed">
12
+ Farm.js is a modern React meta-framework that combines the best of Vite's lightning-fast
13
+ development experience with Next.js-like semantics and React Server Components support.
14
+ </p>
15
+
16
+ <div className="bg-blue-50 border border-blue-200 rounded-lg p-6">
17
+ <h2 className="text-2xl font-semibold mb-3 text-blue-900">Why Farm.js?</h2>
18
+ <p className="text-gray-700 leading-relaxed">
19
+ We built Farm.js to provide developers with a framework that's both powerful and simple.
20
+ No complex configuration, no waiting for builds, just pure development joy with modern
21
+ React features.
22
+ </p>
23
+ </div>
24
+
25
+ <Link
26
+ href="/"
27
+ className="inline-flex items-center px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors font-medium shadow-md hover:shadow-lg"
28
+ >
29
+ โ† Back to Home
30
+ </Link>
31
+ </div>
32
+ </div>
33
+ );
34
+ }
@@ -0,0 +1 @@
1
+ @import "tailwindcss";
@@ -0,0 +1,22 @@
1
+ import React from "react";
2
+ import type { LayoutProps, Metadata } from "@farm.js/core";
3
+ import "./globals.css";
4
+
5
+ export const metadata: Metadata = {
6
+ title: "Farm.js App",
7
+ description: "A modern React meta-framework built on Vite",
8
+ };
9
+
10
+ export default function RootLayout({ children }: LayoutProps) {
11
+ return (
12
+ <html lang="en">
13
+ <head>
14
+ <meta charSet="utf-8" />
15
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
16
+ </head>
17
+ <body className="bg-gray-50 antialiased">
18
+ <main className="min-h-screen">{children}</main>
19
+ </body>
20
+ </html>
21
+ );
22
+ }
@@ -0,0 +1,71 @@
1
+ import React from "react";
2
+ import type { PageProps } from "@farm.js/core";
3
+ import { Link } from "farm/client";
4
+
5
+ export default function HomePage({ params, searchParams }: PageProps) {
6
+ return (
7
+ <div className="min-h-screen flex items-center justify-center p-8">
8
+ <div className="max-w-4xl mx-auto text-center space-y-8">
9
+ <div>
10
+ <h1 className="text-6xl font-bold mb-4">
11
+ <span className="bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent">
12
+ ๐Ÿšœ Welcome to Farm.js
13
+ </span>
14
+ </h1>
15
+
16
+ <p className="text-xl text-gray-600 max-w-2xl mx-auto">
17
+ A modern React meta-framework built on Vite with Next.js-like semantics
18
+ </p>
19
+ </div>
20
+
21
+ <div className="flex gap-4 justify-center flex-wrap">
22
+ <Link
23
+ href="/about"
24
+ className="px-6 py-3 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors font-medium shadow-md hover:shadow-lg"
25
+ >
26
+ About Page
27
+ </Link>
28
+
29
+ <a
30
+ href="https://farm.js.dev"
31
+ target="_blank"
32
+ rel="noopener noreferrer"
33
+ className="px-6 py-3 border-2 border-blue-600 text-blue-600 rounded-lg hover:bg-blue-50 transition-colors font-medium"
34
+ >
35
+ Documentation
36
+ </a>
37
+ </div>
38
+
39
+ <div className="bg-white rounded-lg shadow-xl p-8 text-left">
40
+ <h2 className="text-2xl font-bold mb-6 text-gray-900">Features</h2>
41
+ <ul className="space-y-3">
42
+ <li className="flex items-start gap-3">
43
+ <span className="text-2xl">๐Ÿš€</span>
44
+ <span className="text-gray-700">Blazing fast development with Vite</span>
45
+ </li>
46
+ <li className="flex items-start gap-3">
47
+ <span className="text-2xl">โš›๏ธ</span>
48
+ <span className="text-gray-700">React Server Components support</span>
49
+ </li>
50
+ <li className="flex items-start gap-3">
51
+ <span className="text-2xl">๐ŸŽฏ</span>
52
+ <span className="text-gray-700">Next.js-like file-based routing</span>
53
+ </li>
54
+ <li className="flex items-start gap-3">
55
+ <span className="text-2xl">๐ŸŽจ</span>
56
+ <span className="text-gray-700">Tailwind CSS built-in</span>
57
+ </li>
58
+ <li className="flex items-start gap-3">
59
+ <span className="text-2xl">๐Ÿ“ฆ</span>
60
+ <span className="text-gray-700">Zero configuration setup</span>
61
+ </li>
62
+ <li className="flex items-start gap-3">
63
+ <span className="text-2xl">๐Ÿงช</span>
64
+ <span className="text-gray-700">AI-friendly code structure</span>
65
+ </li>
66
+ </ul>
67
+ </div>
68
+ </div>
69
+ </div>
70
+ );
71
+ }
@@ -0,0 +1,59 @@
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
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "useDefineForClassFields": true,
5
+ "lib": ["ES2020", "DOM", "DOM.Iterable"],
6
+ "module": "ESNext",
7
+ "skipLibCheck": true,
8
+ "moduleResolution": "bundler",
9
+ "allowImportingTsExtensions": true,
10
+ "resolveJsonModule": true,
11
+ "isolatedModules": true,
12
+ "noEmit": true,
13
+ "jsx": "react-jsx",
14
+ "strict": true,
15
+ "noUnusedLocals": true,
16
+ "noUnusedParameters": true,
17
+ "noFallthroughCasesInSwitch": true
18
+ },
19
+ "include": ["src", "farm.config.ts"]
20
+ }