render-create 0.1.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/README.md +207 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.js +45 -0
- package/dist/commands/check.d.ts +8 -0
- package/dist/commands/check.js +96 -0
- package/dist/commands/init.d.ts +12 -0
- package/dist/commands/init.js +1201 -0
- package/dist/commands/sync.d.ts +8 -0
- package/dist/commands/sync.js +126 -0
- package/dist/types.d.ts +246 -0
- package/dist/types.js +4 -0
- package/dist/utils.d.ts +53 -0
- package/dist/utils.js +142 -0
- package/package.json +65 -0
- package/templates/LINTING_SETUP.md +205 -0
- package/templates/README_TEMPLATE.md +68 -0
- package/templates/STYLE_GUIDE.md +241 -0
- package/templates/assets/favicon.png +0 -0
- package/templates/assets/favicon.svg +17 -0
- package/templates/biome.json +43 -0
- package/templates/cursor/rules/drizzle.mdc +165 -0
- package/templates/cursor/rules/fastify.mdc +132 -0
- package/templates/cursor/rules/general.mdc +112 -0
- package/templates/cursor/rules/nextjs.mdc +89 -0
- package/templates/cursor/rules/python.mdc +89 -0
- package/templates/cursor/rules/react.mdc +200 -0
- package/templates/cursor/rules/sqlalchemy.mdc +205 -0
- package/templates/cursor/rules/tailwind.mdc +139 -0
- package/templates/cursor/rules/typescript.mdc +112 -0
- package/templates/cursor/rules/vite.mdc +169 -0
- package/templates/cursor/rules/workflows.mdc +349 -0
- package/templates/docker-compose.example.yml +55 -0
- package/templates/drizzle/db-index.ts +15 -0
- package/templates/drizzle/drizzle.config.ts +10 -0
- package/templates/drizzle/schema.ts +12 -0
- package/templates/env.example +15 -0
- package/templates/fastapi/app/__init__.py +1 -0
- package/templates/fastapi/app/config.py +12 -0
- package/templates/fastapi/app/database.py +16 -0
- package/templates/fastapi/app/models.py +13 -0
- package/templates/fastapi/main.py +22 -0
- package/templates/fastify/index.ts +40 -0
- package/templates/github/CODEOWNERS +10 -0
- package/templates/github/ISSUE_TEMPLATE/bug_report.md +39 -0
- package/templates/github/ISSUE_TEMPLATE/feature_request.md +23 -0
- package/templates/github/PULL_REQUEST_TEMPLATE.md +25 -0
- package/templates/gitignore/node.gitignore +41 -0
- package/templates/gitignore/python.gitignore +49 -0
- package/templates/multi-api/README.md +60 -0
- package/templates/multi-api/gitignore +28 -0
- package/templates/multi-api/node-api/drizzle.config.ts +10 -0
- package/templates/multi-api/node-api/package-simple.json +13 -0
- package/templates/multi-api/node-api/package.json +16 -0
- package/templates/multi-api/node-api/src/db/index.ts +13 -0
- package/templates/multi-api/node-api/src/db/schema.ts +9 -0
- package/templates/multi-api/node-api/src/index-simple.ts +36 -0
- package/templates/multi-api/node-api/src/index.ts +50 -0
- package/templates/multi-api/node-api/tsconfig.json +20 -0
- package/templates/multi-api/python-api/app/__init__.py +1 -0
- package/templates/multi-api/python-api/app/config.py +12 -0
- package/templates/multi-api/python-api/app/database.py +16 -0
- package/templates/multi-api/python-api/app/models.py +13 -0
- package/templates/multi-api/python-api/main-simple.py +25 -0
- package/templates/multi-api/python-api/main.py +44 -0
- package/templates/multi-api/python-api/requirements-simple.txt +3 -0
- package/templates/multi-api/python-api/requirements.txt +8 -0
- package/templates/next/globals.css +126 -0
- package/templates/next/layout.tsx +34 -0
- package/templates/next/next.config.static.ts +10 -0
- package/templates/next/page-fullstack.tsx +120 -0
- package/templates/next/page.tsx +72 -0
- package/templates/presets.json +581 -0
- package/templates/ruff.toml +30 -0
- package/templates/tsconfig.base.json +17 -0
- package/templates/vite/index.css +127 -0
- package/templates/vite/vite.config.ts +7 -0
- package/templates/worker/py/cron.py +53 -0
- package/templates/worker/py/worker.py +95 -0
- package/templates/worker/py/workflow.py +73 -0
- package/templates/worker/ts/cron.ts +49 -0
- package/templates/worker/ts/worker.ts +84 -0
- package/templates/worker/ts/workflow.ts +67 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sync command - Update local rules with the latest package templates
|
|
3
|
+
*/
|
|
4
|
+
import { existsSync, readdirSync } from "node:fs";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import chalk from "chalk";
|
|
7
|
+
import inquirer from "inquirer";
|
|
8
|
+
import { compareFiles, copyTemplate, displayDiff, getTargetDir, TEMPLATES_DIR } from "../utils.js";
|
|
9
|
+
/**
|
|
10
|
+
* Get list of synced files in the target project
|
|
11
|
+
*/
|
|
12
|
+
function getSyncedFiles(targetDir) {
|
|
13
|
+
const rules = [];
|
|
14
|
+
const configs = [];
|
|
15
|
+
// Check for cursor rules
|
|
16
|
+
const rulesDir = join(targetDir, ".cursor", "rules");
|
|
17
|
+
if (existsSync(rulesDir)) {
|
|
18
|
+
const files = readdirSync(rulesDir);
|
|
19
|
+
for (const file of files) {
|
|
20
|
+
if (file.endsWith(".mdc")) {
|
|
21
|
+
rules.push(file.replace(".mdc", ""));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// Check for config files
|
|
26
|
+
if (existsSync(join(targetDir, "biome.json"))) {
|
|
27
|
+
configs.push("biome");
|
|
28
|
+
}
|
|
29
|
+
if (existsSync(join(targetDir, "ruff.toml"))) {
|
|
30
|
+
configs.push("ruff");
|
|
31
|
+
}
|
|
32
|
+
if (existsSync(join(targetDir, "tsconfig.base.json"))) {
|
|
33
|
+
configs.push("tsconfig");
|
|
34
|
+
}
|
|
35
|
+
return { rules, configs };
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Main sync command handler
|
|
39
|
+
*/
|
|
40
|
+
export async function sync(options) {
|
|
41
|
+
const targetDir = getTargetDir();
|
|
42
|
+
const { rules, configs } = getSyncedFiles(targetDir);
|
|
43
|
+
if (rules.length === 0 && configs.length === 0) {
|
|
44
|
+
console.log(chalk.yellow("No cursor-rules files found in this project."));
|
|
45
|
+
console.log(chalk.gray("Run 'npx @render-examples/cursor-rules init' to set up."));
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
console.log(chalk.blue("Checking for updates...\n"));
|
|
49
|
+
const outOfSync = [];
|
|
50
|
+
// Check rule files
|
|
51
|
+
for (const rule of rules) {
|
|
52
|
+
const templatePath = `cursor/rules/${rule}.mdc`;
|
|
53
|
+
const targetPath = join(targetDir, ".cursor", "rules", `${rule}.mdc`);
|
|
54
|
+
// Check if template exists
|
|
55
|
+
if (!existsSync(join(TEMPLATES_DIR, templatePath))) {
|
|
56
|
+
console.log(chalk.yellow(` ${rule}.mdc - custom rule (no template)`));
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
const result = compareFiles(templatePath, targetPath);
|
|
60
|
+
if (result.status === "in-sync") {
|
|
61
|
+
console.log(chalk.green(` ${rule}.mdc - up to date`));
|
|
62
|
+
}
|
|
63
|
+
else if (result.status === "out-of-sync" && result.diff) {
|
|
64
|
+
console.log(chalk.yellow(` ${rule}.mdc - out of sync`));
|
|
65
|
+
outOfSync.push({ templatePath, targetPath, diff: result.diff });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Check config files
|
|
69
|
+
const configMappings = {
|
|
70
|
+
biome: { template: "biome.json", target: "biome.json" },
|
|
71
|
+
ruff: { template: "ruff.toml", target: "ruff.toml" },
|
|
72
|
+
tsconfig: { template: "tsconfig.base.json", target: "tsconfig.base.json" },
|
|
73
|
+
};
|
|
74
|
+
for (const config of configs) {
|
|
75
|
+
const mapping = configMappings[config];
|
|
76
|
+
if (!mapping) {
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
const targetPath = join(targetDir, mapping.target);
|
|
80
|
+
const result = compareFiles(mapping.template, targetPath);
|
|
81
|
+
if (result.status === "in-sync") {
|
|
82
|
+
console.log(chalk.green(` ${mapping.target} - up to date`));
|
|
83
|
+
}
|
|
84
|
+
else if (result.status === "out-of-sync" && result.diff) {
|
|
85
|
+
console.log(chalk.yellow(` ${mapping.target} - out of sync`));
|
|
86
|
+
outOfSync.push({ templatePath: mapping.template, targetPath, diff: result.diff });
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (outOfSync.length === 0) {
|
|
90
|
+
console.log(chalk.green("\nAll files are up to date!"));
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
console.log(chalk.yellow(`\n${outOfSync.length} file(s) out of sync.`));
|
|
94
|
+
// Show diffs if not in dry-run mode
|
|
95
|
+
if (options.dryRun) {
|
|
96
|
+
console.log(chalk.gray("\n--dry-run: Showing diffs without applying changes:\n"));
|
|
97
|
+
for (const file of outOfSync) {
|
|
98
|
+
displayDiff(file.diff, file.targetPath);
|
|
99
|
+
}
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
// Confirm before updating
|
|
103
|
+
if (!options.force) {
|
|
104
|
+
for (const file of outOfSync) {
|
|
105
|
+
displayDiff(file.diff, file.targetPath);
|
|
106
|
+
}
|
|
107
|
+
const { confirm } = await inquirer.prompt([
|
|
108
|
+
{
|
|
109
|
+
type: "confirm",
|
|
110
|
+
name: "confirm",
|
|
111
|
+
message: "Apply these changes?",
|
|
112
|
+
default: false,
|
|
113
|
+
},
|
|
114
|
+
]);
|
|
115
|
+
if (!confirm) {
|
|
116
|
+
console.log(chalk.gray("Sync cancelled."));
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// Apply updates
|
|
121
|
+
console.log(chalk.blue("\nApplying updates...\n"));
|
|
122
|
+
for (const file of outOfSync) {
|
|
123
|
+
copyTemplate(file.templatePath, file.targetPath);
|
|
124
|
+
}
|
|
125
|
+
console.log(chalk.green("\nSync complete!"));
|
|
126
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for cursor-rules CLI
|
|
3
|
+
*/
|
|
4
|
+
/** Environment variable from key/value */
|
|
5
|
+
export interface EnvVarKeyValue {
|
|
6
|
+
key: string;
|
|
7
|
+
value?: string;
|
|
8
|
+
generateValue?: boolean;
|
|
9
|
+
sync?: boolean;
|
|
10
|
+
}
|
|
11
|
+
/** Environment variable from database reference */
|
|
12
|
+
export interface EnvVarFromDatabase {
|
|
13
|
+
key: string;
|
|
14
|
+
fromDatabase: {
|
|
15
|
+
name: string;
|
|
16
|
+
property: string;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/** Environment variable from service reference */
|
|
20
|
+
export interface EnvVarFromService {
|
|
21
|
+
key: string;
|
|
22
|
+
fromService: {
|
|
23
|
+
type: string;
|
|
24
|
+
name: string;
|
|
25
|
+
property?: string;
|
|
26
|
+
envVarKey?: string;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export type BlueprintEnvVar = EnvVarKeyValue | EnvVarFromDatabase | EnvVarFromService;
|
|
30
|
+
/** Route configuration for static sites */
|
|
31
|
+
export interface BlueprintRoute {
|
|
32
|
+
type: "redirect" | "rewrite";
|
|
33
|
+
source: string;
|
|
34
|
+
destination: string;
|
|
35
|
+
}
|
|
36
|
+
/** Service definition in blueprint */
|
|
37
|
+
export interface BlueprintService {
|
|
38
|
+
type: "web" | "worker" | "pserv" | "cron";
|
|
39
|
+
name?: string;
|
|
40
|
+
runtime: "node" | "python" | "docker" | "static" | "go" | "rust" | "ruby" | "elixir";
|
|
41
|
+
plan?: string;
|
|
42
|
+
rootDir?: string;
|
|
43
|
+
buildCommand?: string;
|
|
44
|
+
startCommand?: string;
|
|
45
|
+
healthCheckPath?: string;
|
|
46
|
+
staticPublishPath?: string;
|
|
47
|
+
envVars?: BlueprintEnvVar[];
|
|
48
|
+
routes?: BlueprintRoute[];
|
|
49
|
+
}
|
|
50
|
+
/** Database definition in blueprint */
|
|
51
|
+
export interface BlueprintDatabase {
|
|
52
|
+
name: string;
|
|
53
|
+
plan?: string;
|
|
54
|
+
postgresMajorVersion?: string;
|
|
55
|
+
}
|
|
56
|
+
/** Key Value (Redis) definition in blueprint */
|
|
57
|
+
export interface BlueprintKeyValue {
|
|
58
|
+
type: "keyvalue";
|
|
59
|
+
name: string;
|
|
60
|
+
plan?: string;
|
|
61
|
+
maxmemoryPolicy?: string;
|
|
62
|
+
ipAllowList?: Array<{
|
|
63
|
+
source: string;
|
|
64
|
+
description?: string;
|
|
65
|
+
}>;
|
|
66
|
+
}
|
|
67
|
+
/** Blueprint configuration for render.yaml */
|
|
68
|
+
export interface BlueprintConfig {
|
|
69
|
+
services?: BlueprintService[];
|
|
70
|
+
databases?: BlueprintDatabase[];
|
|
71
|
+
keyValues?: BlueprintKeyValue[];
|
|
72
|
+
}
|
|
73
|
+
export interface Preset {
|
|
74
|
+
name: string;
|
|
75
|
+
description: string;
|
|
76
|
+
rules: string[];
|
|
77
|
+
configs: string[];
|
|
78
|
+
/** Package manager to use (npm, pnpm, yarn, pip) */
|
|
79
|
+
packageManager?: "npm" | "pnpm" | "yarn" | "pip";
|
|
80
|
+
/** Command to scaffold the project (e.g., npx create-next-app) */
|
|
81
|
+
createCommand?: string;
|
|
82
|
+
/** Dependencies to add after create command */
|
|
83
|
+
postCreateDependencies?: string[];
|
|
84
|
+
/** Dev dependencies to add after create command */
|
|
85
|
+
postCreateDevDependencies?: string[];
|
|
86
|
+
/** Scripts to add to package.json after create */
|
|
87
|
+
postCreateScripts?: Record<string, string>;
|
|
88
|
+
/** Files to copy after create command (target -> template source) */
|
|
89
|
+
postCreateFiles?: Record<string, string>;
|
|
90
|
+
/** Files to delete after create command */
|
|
91
|
+
postCreateDelete?: string[];
|
|
92
|
+
/** For presets without createCommand: npm dependencies */
|
|
93
|
+
dependencies?: string[];
|
|
94
|
+
/** For presets without createCommand: npm dev dependencies */
|
|
95
|
+
devDependencies?: string[];
|
|
96
|
+
/** For presets without createCommand: scripts for package.json */
|
|
97
|
+
scripts?: Record<string, string>;
|
|
98
|
+
/** For presets without createCommand: files to scaffold (target -> template) */
|
|
99
|
+
scaffoldFiles?: Record<string, string>;
|
|
100
|
+
/** Python dependencies for requirements.txt */
|
|
101
|
+
pythonDependencies?: string[];
|
|
102
|
+
/** Render Blueprint configuration */
|
|
103
|
+
blueprint?: BlueprintConfig;
|
|
104
|
+
}
|
|
105
|
+
export interface PresetsConfig {
|
|
106
|
+
presets: Record<string, Preset>;
|
|
107
|
+
components?: ComponentsConfig;
|
|
108
|
+
}
|
|
109
|
+
/** Base component definition */
|
|
110
|
+
export interface BaseComponent {
|
|
111
|
+
name: string;
|
|
112
|
+
description?: string;
|
|
113
|
+
subdir: string;
|
|
114
|
+
rules?: string[];
|
|
115
|
+
configs?: string[];
|
|
116
|
+
}
|
|
117
|
+
/** Blueprint config for frontend deploy types */
|
|
118
|
+
export interface FrontendBlueprintConfig {
|
|
119
|
+
type: "web";
|
|
120
|
+
runtime: "node" | "static";
|
|
121
|
+
buildCommand: string;
|
|
122
|
+
startCommand?: string;
|
|
123
|
+
staticPublishPath?: string;
|
|
124
|
+
healthCheckPath?: string;
|
|
125
|
+
envVars?: BlueprintEnvVar[];
|
|
126
|
+
routes?: BlueprintRoute[];
|
|
127
|
+
}
|
|
128
|
+
/** Frontend component (Next.js, Vite) */
|
|
129
|
+
export interface FrontendComponent extends BaseComponent {
|
|
130
|
+
createCommand: string;
|
|
131
|
+
postCreateDependencies?: string[];
|
|
132
|
+
postCreateDevDependencies?: string[];
|
|
133
|
+
postCreateScripts?: Record<string, string>;
|
|
134
|
+
/** Files to copy for static deploy */
|
|
135
|
+
postCreateFilesStatic?: Record<string, string>;
|
|
136
|
+
/** Files to copy for webservice deploy */
|
|
137
|
+
postCreateFilesWebservice?: Record<string, string>;
|
|
138
|
+
/** Files to copy for both deploy types */
|
|
139
|
+
postCreateFiles?: Record<string, string>;
|
|
140
|
+
postCreateDelete?: string[];
|
|
141
|
+
/** Whether this frontend supports webservice deploy (default: true for Next.js, false for Vite) */
|
|
142
|
+
supportsWebservice?: boolean;
|
|
143
|
+
/** Blueprint config for static deploy */
|
|
144
|
+
blueprintStatic: FrontendBlueprintConfig;
|
|
145
|
+
/** Blueprint config for webservice deploy */
|
|
146
|
+
blueprintWebservice?: FrontendBlueprintConfig;
|
|
147
|
+
}
|
|
148
|
+
/** API component (Fastify, FastAPI) */
|
|
149
|
+
export interface ApiComponent extends BaseComponent {
|
|
150
|
+
runtime: "node" | "python";
|
|
151
|
+
/** For Node.js APIs */
|
|
152
|
+
dependencies?: string[];
|
|
153
|
+
devDependencies?: string[];
|
|
154
|
+
scripts?: Record<string, string>;
|
|
155
|
+
/** For Python APIs */
|
|
156
|
+
pythonDependencies?: string[];
|
|
157
|
+
scaffoldFiles: Record<string, string>;
|
|
158
|
+
blueprint: {
|
|
159
|
+
type: "web";
|
|
160
|
+
runtime: "node" | "python";
|
|
161
|
+
buildCommand: string;
|
|
162
|
+
startCommand: string;
|
|
163
|
+
healthCheckPath: string;
|
|
164
|
+
envVars?: BlueprintEnvVar[];
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
/** Worker type for async components */
|
|
168
|
+
export type WorkerType = "worker" | "cron" | "workflow";
|
|
169
|
+
/** Worker/Cron/Workflow component */
|
|
170
|
+
export interface WorkerComponent extends BaseComponent {
|
|
171
|
+
workerType: WorkerType;
|
|
172
|
+
runtime: "node" | "python";
|
|
173
|
+
/** SDK to install (e.g., @renderinc/sdk for workflows) */
|
|
174
|
+
sdk?: string;
|
|
175
|
+
/** For Node.js workers */
|
|
176
|
+
dependencies?: string[];
|
|
177
|
+
devDependencies?: string[];
|
|
178
|
+
scripts?: Record<string, string>;
|
|
179
|
+
/** For Python workers */
|
|
180
|
+
pythonDependencies?: string[];
|
|
181
|
+
scaffoldFiles: Record<string, string>;
|
|
182
|
+
/** Blueprint config - not available for workflows yet */
|
|
183
|
+
blueprint?: {
|
|
184
|
+
type: "worker" | "cron";
|
|
185
|
+
runtime: "node" | "python";
|
|
186
|
+
buildCommand: string;
|
|
187
|
+
startCommand: string;
|
|
188
|
+
schedule?: string;
|
|
189
|
+
envVars?: BlueprintEnvVar[];
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
/** Database component (PostgreSQL) */
|
|
193
|
+
export interface DatabaseComponent {
|
|
194
|
+
name: string;
|
|
195
|
+
description?: string;
|
|
196
|
+
blueprint: BlueprintDatabase;
|
|
197
|
+
}
|
|
198
|
+
/** Cache component (Redis/KeyVal) */
|
|
199
|
+
export interface CacheComponent {
|
|
200
|
+
name: string;
|
|
201
|
+
description?: string;
|
|
202
|
+
blueprint: BlueprintKeyValue;
|
|
203
|
+
}
|
|
204
|
+
/** All components configuration */
|
|
205
|
+
export interface ComponentsConfig {
|
|
206
|
+
frontends: Record<string, FrontendComponent>;
|
|
207
|
+
apis: Record<string, ApiComponent>;
|
|
208
|
+
workers: Record<string, WorkerComponent>;
|
|
209
|
+
databases: Record<string, DatabaseComponent>;
|
|
210
|
+
caches: Record<string, CacheComponent>;
|
|
211
|
+
}
|
|
212
|
+
/** User's composable selection */
|
|
213
|
+
/** Deploy type for frontend services */
|
|
214
|
+
export type DeployType = "static" | "webservice";
|
|
215
|
+
export interface ComposableSelection {
|
|
216
|
+
projectName: string;
|
|
217
|
+
frontend: string | null;
|
|
218
|
+
frontendDeployType: DeployType | null;
|
|
219
|
+
apis: string[];
|
|
220
|
+
workers: string[];
|
|
221
|
+
database: string | null;
|
|
222
|
+
cache: string | null;
|
|
223
|
+
extras: string[];
|
|
224
|
+
}
|
|
225
|
+
export interface InitOptions {
|
|
226
|
+
preset?: string;
|
|
227
|
+
yes?: boolean;
|
|
228
|
+
name?: string;
|
|
229
|
+
skipInstall?: boolean;
|
|
230
|
+
}
|
|
231
|
+
export interface SyncOptions {
|
|
232
|
+
force?: boolean;
|
|
233
|
+
dryRun?: boolean;
|
|
234
|
+
}
|
|
235
|
+
export interface CheckOptions {
|
|
236
|
+
ci?: boolean;
|
|
237
|
+
}
|
|
238
|
+
export type FileStatus = "in-sync" | "out-of-sync" | "local-missing" | "template-missing";
|
|
239
|
+
export interface CompareResult {
|
|
240
|
+
status: FileStatus;
|
|
241
|
+
diff: import("diff").Change[] | null;
|
|
242
|
+
}
|
|
243
|
+
export interface FileMapping {
|
|
244
|
+
template: string;
|
|
245
|
+
target: string;
|
|
246
|
+
}
|
package/dist/types.js
ADDED
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for file operations, prompts, and diff display
|
|
3
|
+
*/
|
|
4
|
+
import { type Change } from "diff";
|
|
5
|
+
import type { CompareResult, PresetsConfig } from "./types.js";
|
|
6
|
+
/** Path to templates directory */
|
|
7
|
+
export declare const TEMPLATES_DIR: string;
|
|
8
|
+
/** Path to presets.json */
|
|
9
|
+
export declare const PRESETS_PATH: string;
|
|
10
|
+
/**
|
|
11
|
+
* Load presets configuration
|
|
12
|
+
*/
|
|
13
|
+
export declare function loadPresets(): PresetsConfig;
|
|
14
|
+
/**
|
|
15
|
+
* Ensure a directory exists, creating it if necessary
|
|
16
|
+
*/
|
|
17
|
+
export declare function ensureDir(dirPath: string): void;
|
|
18
|
+
/**
|
|
19
|
+
* Copy a template file to the target project
|
|
20
|
+
*/
|
|
21
|
+
export declare function copyTemplate(templatePath: string, targetPath: string): boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Copy a template file with variable substitution
|
|
24
|
+
*/
|
|
25
|
+
export declare function copyTemplateWithVars(templatePath: string, targetPath: string, vars?: Record<string, string>): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Read a file, returning null if it doesn't exist
|
|
28
|
+
*/
|
|
29
|
+
export declare function readFileSafe(filePath: string): string | null;
|
|
30
|
+
/**
|
|
31
|
+
* Compare two files and return diff
|
|
32
|
+
*/
|
|
33
|
+
export declare function compareFiles(templatePath: string, localPath: string): CompareResult;
|
|
34
|
+
/**
|
|
35
|
+
* Display a diff in the terminal
|
|
36
|
+
*/
|
|
37
|
+
export declare function displayDiff(diff: Change[], filePath: string): void;
|
|
38
|
+
/**
|
|
39
|
+
* Get the current working directory (target project)
|
|
40
|
+
*/
|
|
41
|
+
export declare function getTargetDir(): string;
|
|
42
|
+
/**
|
|
43
|
+
* Check if we're in a valid project directory
|
|
44
|
+
*/
|
|
45
|
+
export declare function isValidProjectDir(): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Get list of rules for a preset
|
|
48
|
+
*/
|
|
49
|
+
export declare function getRulesForPreset(presetId: string): string[];
|
|
50
|
+
/**
|
|
51
|
+
* Get list of configs for a preset
|
|
52
|
+
*/
|
|
53
|
+
export declare function getConfigsForPreset(presetId: string): string[];
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility functions for file operations, prompts, and diff display
|
|
3
|
+
*/
|
|
4
|
+
import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { dirname, join, resolve } from "node:path";
|
|
6
|
+
import { fileURLToPath } from "node:url";
|
|
7
|
+
import chalk from "chalk";
|
|
8
|
+
import { diffLines } from "diff";
|
|
9
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
10
|
+
const __dirname = dirname(__filename);
|
|
11
|
+
/** Path to templates directory */
|
|
12
|
+
export const TEMPLATES_DIR = resolve(__dirname, "../templates");
|
|
13
|
+
/** Path to presets.json */
|
|
14
|
+
export const PRESETS_PATH = join(TEMPLATES_DIR, "presets.json");
|
|
15
|
+
/**
|
|
16
|
+
* Load presets configuration
|
|
17
|
+
*/
|
|
18
|
+
export function loadPresets() {
|
|
19
|
+
const content = readFileSync(PRESETS_PATH, "utf-8");
|
|
20
|
+
return JSON.parse(content);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Ensure a directory exists, creating it if necessary
|
|
24
|
+
*/
|
|
25
|
+
export function ensureDir(dirPath) {
|
|
26
|
+
if (!existsSync(dirPath)) {
|
|
27
|
+
mkdirSync(dirPath, { recursive: true });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Copy a template file to the target project
|
|
32
|
+
*/
|
|
33
|
+
export function copyTemplate(templatePath, targetPath) {
|
|
34
|
+
const sourcePath = join(TEMPLATES_DIR, templatePath);
|
|
35
|
+
if (!existsSync(sourcePath)) {
|
|
36
|
+
console.log(chalk.yellow(` Warning: Template not found: ${templatePath}`));
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
ensureDir(dirname(targetPath));
|
|
40
|
+
copyFileSync(sourcePath, targetPath);
|
|
41
|
+
console.log(chalk.green(` Created ${targetPath}`));
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Copy a template file with variable substitution
|
|
46
|
+
*/
|
|
47
|
+
export function copyTemplateWithVars(templatePath, targetPath, vars = {}) {
|
|
48
|
+
const sourcePath = join(TEMPLATES_DIR, templatePath);
|
|
49
|
+
if (!existsSync(sourcePath)) {
|
|
50
|
+
console.log(chalk.yellow(` Warning: Template not found: ${templatePath}`));
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
let content = readFileSync(sourcePath, "utf-8");
|
|
54
|
+
// Replace {{VAR_NAME}} patterns
|
|
55
|
+
for (const [key, value] of Object.entries(vars)) {
|
|
56
|
+
content = content.replace(new RegExp(`\\{\\{${key}\\}\\}`, "g"), value);
|
|
57
|
+
}
|
|
58
|
+
ensureDir(dirname(targetPath));
|
|
59
|
+
writeFileSync(targetPath, content);
|
|
60
|
+
console.log(chalk.green(` Created ${targetPath}`));
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Read a file, returning null if it doesn't exist
|
|
65
|
+
*/
|
|
66
|
+
export function readFileSafe(filePath) {
|
|
67
|
+
try {
|
|
68
|
+
return readFileSync(filePath, "utf-8");
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Compare two files and return diff
|
|
76
|
+
*/
|
|
77
|
+
export function compareFiles(templatePath, localPath) {
|
|
78
|
+
const templateContent = readFileSafe(join(TEMPLATES_DIR, templatePath));
|
|
79
|
+
const localContent = readFileSafe(localPath);
|
|
80
|
+
if (!templateContent) {
|
|
81
|
+
return { status: "template-missing", diff: null };
|
|
82
|
+
}
|
|
83
|
+
if (!localContent) {
|
|
84
|
+
return { status: "local-missing", diff: null };
|
|
85
|
+
}
|
|
86
|
+
if (templateContent === localContent) {
|
|
87
|
+
return { status: "in-sync", diff: null };
|
|
88
|
+
}
|
|
89
|
+
const diff = diffLines(localContent, templateContent);
|
|
90
|
+
return { status: "out-of-sync", diff };
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Display a diff in the terminal
|
|
94
|
+
*/
|
|
95
|
+
export function displayDiff(diff, filePath) {
|
|
96
|
+
console.log(chalk.cyan(`\n--- ${filePath}`));
|
|
97
|
+
for (const part of diff) {
|
|
98
|
+
if (part.added) {
|
|
99
|
+
process.stdout.write(chalk.green(part.value));
|
|
100
|
+
}
|
|
101
|
+
else if (part.removed) {
|
|
102
|
+
process.stdout.write(chalk.red(part.value));
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
process.stdout.write(chalk.gray(part.value));
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
console.log();
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Get the current working directory (target project)
|
|
112
|
+
*/
|
|
113
|
+
export function getTargetDir() {
|
|
114
|
+
return process.cwd();
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Check if we're in a valid project directory
|
|
118
|
+
*/
|
|
119
|
+
export function isValidProjectDir() {
|
|
120
|
+
const cwd = getTargetDir();
|
|
121
|
+
// Check for common project indicators
|
|
122
|
+
return (existsSync(join(cwd, "package.json")) ||
|
|
123
|
+
existsSync(join(cwd, "requirements.txt")) ||
|
|
124
|
+
existsSync(join(cwd, "pyproject.toml")) ||
|
|
125
|
+
existsSync(join(cwd, ".git")));
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Get list of rules for a preset
|
|
129
|
+
*/
|
|
130
|
+
export function getRulesForPreset(presetId) {
|
|
131
|
+
const presets = loadPresets();
|
|
132
|
+
const preset = presets.presets[presetId];
|
|
133
|
+
return preset?.rules ?? [];
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Get list of configs for a preset
|
|
137
|
+
*/
|
|
138
|
+
export function getConfigsForPreset(presetId) {
|
|
139
|
+
const presets = loadPresets();
|
|
140
|
+
const preset = presets.presets[presetId];
|
|
141
|
+
return preset?.configs ?? [];
|
|
142
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "render-create",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CLI to scaffold and deploy applications on Render with best practices, Cursor rules, and Infrastructure as Code",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"render-create": "dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/R4ph-t/render-create-demo.git"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://github.com/R4ph-t/render-create-demo#readme",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/R4ph-t/render-create-demo/issues"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"templates"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsc",
|
|
23
|
+
"dev": "tsc --watch",
|
|
24
|
+
"lint": "biome check .",
|
|
25
|
+
"format": "biome check --write .",
|
|
26
|
+
"test": "vitest run",
|
|
27
|
+
"test:watch": "vitest",
|
|
28
|
+
"prepublishOnly": "npm run build",
|
|
29
|
+
"preversion": "npm run lint && npm run build && npm test",
|
|
30
|
+
"postversion": "git push && git push --tags",
|
|
31
|
+
"release:patch": "npm version patch",
|
|
32
|
+
"release:minor": "npm version minor",
|
|
33
|
+
"release:major": "npm version major"
|
|
34
|
+
},
|
|
35
|
+
"keywords": [
|
|
36
|
+
"render",
|
|
37
|
+
"create",
|
|
38
|
+
"scaffold",
|
|
39
|
+
"deploy",
|
|
40
|
+
"template",
|
|
41
|
+
"cursor",
|
|
42
|
+
"cli",
|
|
43
|
+
"infrastructure-as-code",
|
|
44
|
+
"blueprint"
|
|
45
|
+
],
|
|
46
|
+
"author": "Render",
|
|
47
|
+
"license": "MIT",
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"chalk": "^5.3.0",
|
|
50
|
+
"commander": "^12.1.0",
|
|
51
|
+
"diff": "^7.0.0",
|
|
52
|
+
"inquirer": "^12.3.0"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@biomejs/biome": "^2.0.0",
|
|
56
|
+
"@types/diff": "^7.0.0",
|
|
57
|
+
"@types/inquirer": "^9.0.7",
|
|
58
|
+
"@types/node": "^22.0.0",
|
|
59
|
+
"typescript": "^5.7.0",
|
|
60
|
+
"vitest": "^4.0.18"
|
|
61
|
+
},
|
|
62
|
+
"engines": {
|
|
63
|
+
"node": ">=18.0.0"
|
|
64
|
+
}
|
|
65
|
+
}
|