forked from clerk/javascript
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapplicationConfig.ts
More file actions
125 lines (115 loc) · 4.58 KB
/
Copy pathapplicationConfig.ts
File metadata and controls
125 lines (115 loc) · 4.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import * as path from 'node:path';
import { constants } from '../constants';
import { createLogger, fs } from '../scripts';
import { application } from './application.js';
import type { EnvironmentConfig } from './environment';
import type { Helpers } from './helpers.js';
import { hash, helpers } from './helpers.js';
export type ApplicationConfig = ReturnType<typeof applicationConfig>;
type Scripts = { dev: string; build: string; setup: string; serve: string };
export const applicationConfig = () => {
let name = '';
const templates: string[] = [];
const files = new Map<string, string>();
const scripts: Scripts = { dev: 'npm run dev', serve: 'npm run serve', build: 'npm run build', setup: 'npm i' };
const envFormatters = { public: (key: string) => key, private: (key: string) => key };
const logger = createLogger({ prefix: 'appConfig', color: 'yellow' });
const dependencies = new Map<string, string>();
const self = {
clone: () => {
const clone = applicationConfig();
clone.setName(name);
clone.setEnvFormatter('public', envFormatters.public);
clone.setEnvFormatter('private', envFormatters.private);
templates.forEach(t => clone.useTemplate(t));
dependencies.forEach((v, k) => clone.addDependency(k, v));
Object.entries(scripts).forEach(([k, v]) => clone.addScript(k as keyof typeof scripts, v));
files.forEach((v, k) => clone.addFile(k, () => v));
return clone;
},
setName: (_name: string) => {
name = _name;
return self;
},
addFile: (filePath: string, cbOrPath: (helpers: Helpers) => string) => {
files.set(filePath, cbOrPath(helpers));
return self;
},
useTemplate: (path: string) => {
templates.push(path);
return self;
},
setEnvFormatter: (type: keyof typeof envFormatters, formatter: typeof envFormatters.public) => {
envFormatters[type] = formatter;
return self;
},
addScript: (name: keyof typeof scripts, cmd: string) => {
if (!Object.keys(scripts).includes(name)) {
throw new Error(`Invalid script name: ${name}, must be one of ${Object.keys(scripts).join(', ')}`);
}
scripts[name] = cmd;
return self;
},
addDependency: (name: string, version: string | undefined) => {
if (version) {
dependencies.set(name, version);
}
return self;
},
commit: async (opts?: { stableHash?: string }) => {
const { stableHash } = opts || {};
logger.info(`Creating project "${name}"`);
const appDirName = stableHash || `${name}__${Date.now()}__${hash()}`;
const appDirPath = path.resolve(constants.TMP_DIR, appDirName);
// Copy template files
for (const template of templates) {
logger.info(`Copying template "${path.basename(template)}" -> ${appDirPath}`);
await fs.ensureDir(appDirPath);
await fs.copy(template, appDirPath, { overwrite: true, filter: (p: string) => !p.includes('node_modules') });
}
// Create individual files
await Promise.all(
[...files].map(async ([pathname, contents]) => {
const dest = path.resolve(appDirPath, pathname);
logger.info(`Copying file "${pathname}" -> ${dest}`);
await fs.ensureFile(dest);
await fs.writeFile(dest, contents);
}),
);
// Adjust package.json dependencies
if (dependencies.size > 0) {
const packageJsonPath = path.resolve(appDirPath, 'package.json');
logger.info(`Modifying dependencies in "${packageJsonPath}"`);
const contents = await fs.readJSON(packageJsonPath);
contents.dependencies = { ...contents.dependencies, ...Object.fromEntries(dependencies) };
await fs.writeJSON(packageJsonPath, contents, { spaces: 2 });
}
return application(self, appDirPath, appDirName);
},
setEnvWriter: () => {
throw new Error('not implemented');
},
get name() {
return name;
},
get scripts() {
return scripts;
},
get envWriter() {
const defaultWriter = async (appDir: string, env: EnvironmentConfig) => {
// Create env files
const envDest = path.join(appDir, '.env');
await fs.ensureFile(envDest);
logger.info(`Creating env file ".env" -> ${envDest}`);
await fs.writeFile(
path.join(appDir, '.env'),
[...env.publicVariables].map(([k, v]) => `${envFormatters.public(k)}=${v}`).join('\n') +
'\n' +
[...env.privateVariables].map(([k, v]) => `${envFormatters.private(k)}=${v}`).join('\n'),
);
};
return defaultWriter;
},
};
return self;
};