@fnet/cli 0.100.2 → 0.101.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/dist/fnet/index.B5vpZn1Z.js +53 -0
- package/dist/fnet/index.B6WHm9H0.js +106 -0
- package/dist/fnet/index.B90Vm9uq.js +114 -0
- package/dist/fnet/index.BMsD46br.js +60 -0
- package/dist/fnet/index.BUhoGq-h.js +70 -0
- package/dist/fnet/index.BjzEMdm1.js +52 -0
- package/dist/fnet/index.C9zKEF61.js +106 -0
- package/dist/fnet/index.CQNYMi1Z.js +51 -0
- package/dist/fnet/index.CX8eMqfH.js +191 -0
- package/dist/fnet/index.Ce8sTnt_.js +52 -0
- package/dist/fnet/index.D2kFuxXo.js +52 -0
- package/dist/fnet/index.D61MduW1.js +106 -0
- package/dist/fnet/index.Dd0lngp8.js +41 -0
- package/dist/fnet/index.DqwVukIB.js +52 -0
- package/dist/fnet/index.MWHLt6g3.js +52 -0
- package/dist/fnet/index.f798DPwo.js +93 -0
- package/dist/fnet/index.j5JP-zGw.js +52 -0
- package/dist/fnet/index.js +4562 -0
- package/dist/fnode/index.B5vpZn1Z.js +53 -0
- package/dist/fnode/index.B6WHm9H0.js +106 -0
- package/dist/fnode/index.BMsD46br.js +60 -0
- package/dist/fnode/index.BNSTS5o6.js +109 -0
- package/dist/fnode/index.BUhoGq-h.js +70 -0
- package/dist/fnode/index.BjzEMdm1.js +52 -0
- package/dist/fnode/index.C9zKEF61.js +106 -0
- package/dist/fnode/index.CQNYMi1Z.js +51 -0
- package/dist/fnode/index.CX8eMqfH.js +191 -0
- package/dist/fnode/index.Ce8sTnt_.js +52 -0
- package/dist/fnode/index.D2kFuxXo.js +52 -0
- package/dist/fnode/index.D61MduW1.js +106 -0
- package/dist/fnode/index.Dd0lngp8.js +41 -0
- package/dist/fnode/index.DqwVukIB.js +52 -0
- package/dist/fnode/index.MWHLt6g3.js +52 -0
- package/dist/fnode/index.f798DPwo.js +93 -0
- package/dist/fnode/index.j5JP-zGw.js +52 -0
- package/dist/fnode/index.js +2784 -0
- package/package.json +3 -3
- package/dist/fnet/index.B5XE4ChJ.mjs +0 -1
- package/dist/fnet/index.Bfg4lyu-.mjs +0 -1
- package/dist/fnet/index.BoO2Mnox.mjs +0 -1
- package/dist/fnet/index.C7saWH6d.mjs +0 -1
- package/dist/fnet/index.CDct_kkF.mjs +0 -1
- package/dist/fnet/index.CMC8mlye.mjs +0 -1
- package/dist/fnet/index.CmMM-Ek9.mjs +0 -1
- package/dist/fnet/index.CzAV0S36.mjs +0 -1
- package/dist/fnet/index.D2N9YZmA.mjs +0 -1
- package/dist/fnet/index.DI3yyTtl.mjs +0 -1
- package/dist/fnet/index.DLGSTm8o.mjs +0 -1
- package/dist/fnet/index.Q-CYRcna.mjs +0 -1
- package/dist/fnet/index.TGA5BzMy.mjs +0 -1
- package/dist/fnet/index.UOds5XLl.mjs +0 -1
- package/dist/fnet/index.W6RYgypK.mjs +0 -1
- package/dist/fnet/index.dpz2QIRu.mjs +0 -1
- package/dist/fnet/index.mjs +0 -2
- package/dist/fnet/index.xd8c7XMr.mjs +0 -1
- package/dist/fnode/index.B5XE4ChJ.mjs +0 -1
- package/dist/fnode/index.Bfg4lyu-.mjs +0 -1
- package/dist/fnode/index.BoO2Mnox.mjs +0 -1
- package/dist/fnode/index.C7saWH6d.mjs +0 -1
- package/dist/fnode/index.CDct_kkF.mjs +0 -1
- package/dist/fnode/index.CMC8mlye.mjs +0 -1
- package/dist/fnode/index.CmMM-Ek9.mjs +0 -1
- package/dist/fnode/index.CzAV0S36.mjs +0 -1
- package/dist/fnode/index.D2N9YZmA.mjs +0 -1
- package/dist/fnode/index.DI3yyTtl.mjs +0 -1
- package/dist/fnode/index.DLGSTm8o.mjs +0 -1
- package/dist/fnode/index.DLs4zDM6.mjs +0 -1
- package/dist/fnode/index.Q-CYRcna.mjs +0 -1
- package/dist/fnode/index.UOds5XLl.mjs +0 -1
- package/dist/fnode/index.W6RYgypK.mjs +0 -1
- package/dist/fnode/index.dpz2QIRu.mjs +0 -1
- package/dist/fnode/index.mjs +0 -2
- package/dist/fnode/index.xd8c7XMr.mjs +0 -1
|
@@ -0,0 +1,2784 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import path$1 from 'path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { spawn } from 'child_process';
|
|
5
|
+
import prompt from '@fnet/prompt';
|
|
6
|
+
import { Command, Option } from 'commander';
|
|
7
|
+
import fs$1 from 'fs';
|
|
8
|
+
import yaml from 'yaml';
|
|
9
|
+
import fnetShellJs from '@fnet/shelljs';
|
|
10
|
+
import os$1 from 'os';
|
|
11
|
+
import fnetYaml from '@fnet/yaml';
|
|
12
|
+
import fnetConfig from '@fnet/config';
|
|
13
|
+
import fnetObjectFromSchema from '@fnet/object-from-schema';
|
|
14
|
+
import fnetShellFlow from '@fnet/shell-flow';
|
|
15
|
+
import fnetRender from '@flownet/lib-render-templates-dir';
|
|
16
|
+
import fs, { existsSync } from 'node:fs';
|
|
17
|
+
import path, { delimiter, join } from 'node:path';
|
|
18
|
+
import os from 'node:os';
|
|
19
|
+
import nunjucks from 'nunjucks';
|
|
20
|
+
import { randomUUID } from 'node:crypto';
|
|
21
|
+
import { Api, Atom } from '@flownet/lib-atom-api-js';
|
|
22
|
+
import fnetParseNodeUrl from '@flownet/lib-parse-node-url';
|
|
23
|
+
import fnetParseImports from '@flownet/lib-parse-imports-js';
|
|
24
|
+
import fnetListFiles from '@fnet/list-files';
|
|
25
|
+
import chalk from 'chalk';
|
|
26
|
+
import redis from 'redis';
|
|
27
|
+
import fnetIsRedisOnline from '@flownet/lib-is-redis-online';
|
|
28
|
+
import merge from 'lodash.merge';
|
|
29
|
+
import fnetListNpmVersions from '@fnet/npm-list-versions';
|
|
30
|
+
import fnetPickNpmVersions from '@fnet/npm-pick-versions';
|
|
31
|
+
import hash from 'object-hash';
|
|
32
|
+
import Ajv from 'ajv/dist/2020.js';
|
|
33
|
+
import standaloneCode from 'ajv/dist/standalone/index.js';
|
|
34
|
+
import addFormats from 'ajv-formats';
|
|
35
|
+
import fnetAutoCondaEnv from '@fnet/auto-conda-env';
|
|
36
|
+
|
|
37
|
+
async function createRedisClient() {
|
|
38
|
+
const isOnline = await fnetIsRedisOnline({ host: process.env.REDIS_HOST, port: process.env.REDIS_PORT });
|
|
39
|
+
if (!isOnline) return;
|
|
40
|
+
|
|
41
|
+
const redisClient = redis.createClient({
|
|
42
|
+
socket: { host: process.env.REDIS_HOST, port: process.env.REDIS_PORT }
|
|
43
|
+
});
|
|
44
|
+
await redisClient.connect();
|
|
45
|
+
|
|
46
|
+
return redisClient;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
class Auth {
|
|
50
|
+
init({ config, accessToken }) {
|
|
51
|
+
return new Promise((resolve, reject) => {
|
|
52
|
+
|
|
53
|
+
Api.set_api_url(config.data.url);
|
|
54
|
+
|
|
55
|
+
if (accessToken) {
|
|
56
|
+
Api.set_req_token(accessToken);
|
|
57
|
+
resolve(accessToken);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
fetch(`${config.data.issuer}/protocol/openid-connect/token`, {
|
|
62
|
+
method: "POST",
|
|
63
|
+
headers: {
|
|
64
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
65
|
+
},
|
|
66
|
+
body: new URLSearchParams(config.data.grant.params)
|
|
67
|
+
})
|
|
68
|
+
.then(async (response) => {
|
|
69
|
+
if (!response.ok) throw new Error(await response.text());
|
|
70
|
+
return response.json();
|
|
71
|
+
})
|
|
72
|
+
.then(response => {
|
|
73
|
+
Api.set_req_token(response.access_token);
|
|
74
|
+
resolve(response.access_token);
|
|
75
|
+
})
|
|
76
|
+
.catch(error => {
|
|
77
|
+
Api.set_req_token();
|
|
78
|
+
reject(error);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function featureTemplate({ feature, features, packageDevDependencies }) {
|
|
85
|
+
|
|
86
|
+
const { name, packages, options, extraCheck, explicit } = feature;
|
|
87
|
+
|
|
88
|
+
const keyEnabled = `${name}_enabled`;
|
|
89
|
+
|
|
90
|
+
const rollup_output = features.rollup_output || {};
|
|
91
|
+
|
|
92
|
+
const allKeys = Object.keys(rollup_output);
|
|
93
|
+
|
|
94
|
+
let initialOptions = options || {};
|
|
95
|
+
|
|
96
|
+
const featureOptions = features[name]?.options;
|
|
97
|
+
|
|
98
|
+
if (featureOptions) initialOptions = merge(initialOptions, featureOptions);
|
|
99
|
+
|
|
100
|
+
const globallyDisabled = !features[name] || features[name]?.enabled === false;
|
|
101
|
+
|
|
102
|
+
allKeys.forEach(key => {
|
|
103
|
+
const output = features.rollup_output[key];
|
|
104
|
+
|
|
105
|
+
if (!output) return;
|
|
106
|
+
|
|
107
|
+
// Output has the feature
|
|
108
|
+
if (Reflect.has(output, name)) {
|
|
109
|
+
if (globallyDisabled || !output[name] || output[name]?.enabled === false) {
|
|
110
|
+
delete output[name];
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (output[name] === true) {
|
|
114
|
+
output[name] = {
|
|
115
|
+
enabled: true,
|
|
116
|
+
options: initialOptions
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
} else {
|
|
120
|
+
// Output hasn't the feature
|
|
121
|
+
if (!globallyDisabled && !explicit && features[keyEnabled] !== false) {
|
|
122
|
+
output[name] = {
|
|
123
|
+
enabled: true,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
else return;
|
|
127
|
+
}
|
|
128
|
+
output[name] = output[name] || {};
|
|
129
|
+
output[name].options = {
|
|
130
|
+
...initialOptions,
|
|
131
|
+
...output[name].options
|
|
132
|
+
};
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
let exists = allKeys.some(w => features.rollup_output[w][name]?.enabled === true);
|
|
136
|
+
|
|
137
|
+
if (extraCheck) exists = extraCheck() && exists;
|
|
138
|
+
|
|
139
|
+
features[keyEnabled] = exists;
|
|
140
|
+
|
|
141
|
+
if (exists) {
|
|
142
|
+
packages.forEach(p => packageDevDependencies.push({ package: p[0], version: p[1] }));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function initWorkboxFeature(apiContext) {
|
|
147
|
+
|
|
148
|
+
const { atom, packageDevDependencies } = apiContext;
|
|
149
|
+
const features = atom.doc.features;
|
|
150
|
+
|
|
151
|
+
featureTemplate({
|
|
152
|
+
feature: {
|
|
153
|
+
name: "workbox",
|
|
154
|
+
packages: [["rollup-plugin-workbox", "^8"]],
|
|
155
|
+
options: {
|
|
156
|
+
generate: {
|
|
157
|
+
swDest: 'dist/app/esm/sw.js',
|
|
158
|
+
globDirectory: 'dist/app/esm',
|
|
159
|
+
globPatterns: ['**/*.{html,js,css,png,jpg}'],
|
|
160
|
+
skipWaiting: true,
|
|
161
|
+
clientsClaim: true
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
explicit: true
|
|
165
|
+
}, features, packageDevDependencies
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function initGzipFeature(apiContext) {
|
|
170
|
+
|
|
171
|
+
const { atom, packageDevDependencies } = apiContext;
|
|
172
|
+
const features = atom.doc.features;
|
|
173
|
+
|
|
174
|
+
featureTemplate({
|
|
175
|
+
feature: {
|
|
176
|
+
name: "gzip",
|
|
177
|
+
packages: [["rollup-plugin-gzip", "^4"]],
|
|
178
|
+
explicit: true
|
|
179
|
+
}, features, packageDevDependencies
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function initNunjucksFeature(apiContext) {
|
|
184
|
+
|
|
185
|
+
const { atom, packageDevDependencies } = apiContext;
|
|
186
|
+
const features = atom.doc.features;
|
|
187
|
+
|
|
188
|
+
featureTemplate({
|
|
189
|
+
feature: {
|
|
190
|
+
name: "nunjucks",
|
|
191
|
+
packages: [["@fnet/rollup-plugin-nunjucks", "0.1.8"]],
|
|
192
|
+
}, features, packageDevDependencies
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
function initPolyfillFeature(apiContext) {
|
|
197
|
+
|
|
198
|
+
const { atom, packageDevDependencies } = apiContext;
|
|
199
|
+
const features = atom.doc.features;
|
|
200
|
+
|
|
201
|
+
featureTemplate({
|
|
202
|
+
feature: {
|
|
203
|
+
name: "polyfill",
|
|
204
|
+
packages: [["rollup-plugin-node-polyfills", "^0.2"]],
|
|
205
|
+
}, features, packageDevDependencies
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function initVisualizerFeature(apiContext) {
|
|
210
|
+
|
|
211
|
+
const { atom, packageDevDependencies } = apiContext;
|
|
212
|
+
const features = atom.doc.features;
|
|
213
|
+
|
|
214
|
+
featureTemplate({
|
|
215
|
+
feature: {
|
|
216
|
+
name: "visualizer",
|
|
217
|
+
packages: [["rollup-plugin-visualizer", "^5"]]}, features, packageDevDependencies
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
function initAnalyzerFeature(apiContext) {
|
|
222
|
+
const { atom, packageDevDependencies } = apiContext;
|
|
223
|
+
const features = atom.doc.features;
|
|
224
|
+
|
|
225
|
+
featureTemplate({
|
|
226
|
+
feature: {
|
|
227
|
+
name: "analyzer",
|
|
228
|
+
packages: [["rollup-plugin-analyzer", "^3"]],
|
|
229
|
+
options: {
|
|
230
|
+
summaryOnly: true,
|
|
231
|
+
limit: 12
|
|
232
|
+
},
|
|
233
|
+
explicit: true
|
|
234
|
+
}, features, packageDevDependencies
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function initStringFeature(apiContext) {
|
|
239
|
+
|
|
240
|
+
const { atom, packageDevDependencies } = apiContext;
|
|
241
|
+
const features = atom.doc.features;
|
|
242
|
+
|
|
243
|
+
featureTemplate({
|
|
244
|
+
feature: {
|
|
245
|
+
name: "string",
|
|
246
|
+
packages: [["rollup-plugin-string", "^3"]],
|
|
247
|
+
}, features, packageDevDependencies
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function initImageFeature(apiContext) {
|
|
252
|
+
|
|
253
|
+
const { atom, packageDevDependencies } = apiContext;
|
|
254
|
+
const features = atom.doc.features;
|
|
255
|
+
|
|
256
|
+
featureTemplate({
|
|
257
|
+
feature: {
|
|
258
|
+
name: "image",
|
|
259
|
+
packages: [["@rollup/plugin-image", "^3"]],
|
|
260
|
+
}, features, packageDevDependencies
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
function initJsonFeature(apiContext) {
|
|
265
|
+
|
|
266
|
+
const { atom, packageDevDependencies } = apiContext;
|
|
267
|
+
const features = atom.doc.features;
|
|
268
|
+
|
|
269
|
+
featureTemplate({
|
|
270
|
+
feature: {
|
|
271
|
+
name: "json",
|
|
272
|
+
packages: [["@rollup/plugin-json", "^6"]],
|
|
273
|
+
}, features, packageDevDependencies
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function initTerserFeature(apiContext) {
|
|
278
|
+
|
|
279
|
+
const { atom, packageDevDependencies } = apiContext;
|
|
280
|
+
const features = atom.doc.features;
|
|
281
|
+
|
|
282
|
+
featureTemplate({
|
|
283
|
+
feature: {
|
|
284
|
+
name: "terser",
|
|
285
|
+
packages: [["@rollup/plugin-terser", "^0.4"]],
|
|
286
|
+
}, features, packageDevDependencies
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function initWasmFeature(apiContext) {
|
|
291
|
+
|
|
292
|
+
const { atom, packageDevDependencies } = apiContext;
|
|
293
|
+
const features = atom.doc.features;
|
|
294
|
+
|
|
295
|
+
featureTemplate({
|
|
296
|
+
feature: {
|
|
297
|
+
name: "wasm",
|
|
298
|
+
packages: [["@rollup/plugin-wasm", "^6"]],
|
|
299
|
+
}, features, packageDevDependencies
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function initCopyFeature(apiContext) {
|
|
304
|
+
|
|
305
|
+
const { atom, packageDevDependencies } = apiContext;
|
|
306
|
+
const features = atom.doc.features;
|
|
307
|
+
|
|
308
|
+
const options = {};
|
|
309
|
+
|
|
310
|
+
// TODO: remove it later
|
|
311
|
+
// app specific
|
|
312
|
+
if (features.app?.enabled === true) {
|
|
313
|
+
options.targets = options.targets || [];
|
|
314
|
+
options.targets.push({ src: "./src/app/index.html", dest: features.app.dir });
|
|
315
|
+
if (!Reflect.has(features.app, "copy")) {
|
|
316
|
+
if (!Reflect.has(features, "copy")) {
|
|
317
|
+
features.copy = true;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// const extraCheck = () => {
|
|
323
|
+
// return features.app_enabled;
|
|
324
|
+
// }
|
|
325
|
+
|
|
326
|
+
featureTemplate({
|
|
327
|
+
feature: {
|
|
328
|
+
name: "copy",
|
|
329
|
+
packages: [["rollup-plugin-copy", "^3"], ["chokidar", "^3"]],
|
|
330
|
+
options
|
|
331
|
+
// extraCheck
|
|
332
|
+
}, features, packageDevDependencies
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
function initCssFeature(apiContext) {
|
|
337
|
+
|
|
338
|
+
const { atom, packageDevDependencies } = apiContext;
|
|
339
|
+
const features = atom.doc.features;
|
|
340
|
+
|
|
341
|
+
const cssEnabled = features.css && features.css.enabled !== false;
|
|
342
|
+
|
|
343
|
+
let packages = [];
|
|
344
|
+
|
|
345
|
+
if (cssEnabled) {
|
|
346
|
+
packages.push(["rollup-plugin-postcss", "^4"]);
|
|
347
|
+
packages.push(["sass", "^1.66"]);
|
|
348
|
+
const plugins = features.css?.options?.plugins || [];
|
|
349
|
+
plugins.forEach(plugin => {
|
|
350
|
+
switch (plugin.name) {
|
|
351
|
+
case 'postcss-import':
|
|
352
|
+
packages.push(["postcss-import", "^15"]);
|
|
353
|
+
break;
|
|
354
|
+
case 'postcss-url':
|
|
355
|
+
packages.push(["postcss-url", "^10"]);
|
|
356
|
+
break;
|
|
357
|
+
case 'postcss-preset-env':
|
|
358
|
+
packages.push(["postcss-preset-env", "^9"]);
|
|
359
|
+
break;
|
|
360
|
+
case 'autoprefixer':
|
|
361
|
+
packages.push(["autoprefixer", "^10"]);
|
|
362
|
+
break;
|
|
363
|
+
case 'cssnano':
|
|
364
|
+
packages.push(["cssnano", "^6"]);
|
|
365
|
+
break;
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
featureTemplate({
|
|
371
|
+
feature: {
|
|
372
|
+
name: "css",
|
|
373
|
+
packages: packages,
|
|
374
|
+
}, features, packageDevDependencies
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
function findEntryFile({ dir, name = 'index' }) {
|
|
379
|
+
let entryFile = path.resolve(dir, `./${name}.tsx`);
|
|
380
|
+
|
|
381
|
+
if (!fs.existsSync(entryFile)) entryFile = path.resolve(dir, `./${name}.ts`);
|
|
382
|
+
if (!fs.existsSync(entryFile)) entryFile = path.resolve(dir, `./${name}.jsx`);
|
|
383
|
+
if (!fs.existsSync(entryFile)) entryFile = path.resolve(dir, `./${name}.js`);
|
|
384
|
+
if (!fs.existsSync(entryFile)) return {};
|
|
385
|
+
|
|
386
|
+
const file = entryFile;
|
|
387
|
+
const ext = path.extname(entryFile);
|
|
388
|
+
const ts = ext === '.ts' || ext === '.tsx';
|
|
389
|
+
|
|
390
|
+
return { file, ext, ts, name };
|
|
391
|
+
}
|
|
392
|
+
async function initFeatures(apiContext) {
|
|
393
|
+
|
|
394
|
+
const { atom, context, setProgress } = apiContext;
|
|
395
|
+
|
|
396
|
+
setProgress('Initializing features...');
|
|
397
|
+
|
|
398
|
+
atom.doc.features = atom.doc.features || {};
|
|
399
|
+
const features = atom.doc.features;
|
|
400
|
+
|
|
401
|
+
// project format
|
|
402
|
+
features.project = features.project || {};
|
|
403
|
+
features.project.format = features.project.format || features.project_format || "esm";
|
|
404
|
+
features.project_format = features.project.format;
|
|
405
|
+
|
|
406
|
+
features.dts_enabled = features.dts === true || (typeof features.dts !== 'undefined' && features.dts !== false);
|
|
407
|
+
|
|
408
|
+
const projectDir = path.resolve(context.project.projectDir);
|
|
409
|
+
|
|
410
|
+
const appEntry = findEntryFile({ dir: path.resolve(projectDir, './app') });
|
|
411
|
+
if (appEntry.file) {
|
|
412
|
+
setProgress('Parsing app entry imports...');
|
|
413
|
+
|
|
414
|
+
let parsed = await fnetParseImports({ file: appEntry.file, recursive: true });
|
|
415
|
+
let usesJSX = parsed.all.some(w => w.usesJSX === true && w.type === 'local');
|
|
416
|
+
features.app_uses_jsx = usesJSX;
|
|
417
|
+
features.app_has_entry = true;
|
|
418
|
+
parsed = await fnetParseImports({ file: appEntry.file });
|
|
419
|
+
usesJSX = parsed.all.some(w => w.usesJSX === true && w.type === 'local');
|
|
420
|
+
features.app_entry_uses_jsx = usesJSX;
|
|
421
|
+
features.app_entry_is_ts = appEntry.ts;
|
|
422
|
+
features.app_entry_ext = appEntry.ext;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
const cliEntry = findEntryFile({ dir: path.resolve(projectDir, './cli') });
|
|
426
|
+
if (cliEntry.file) {
|
|
427
|
+
setProgress('Parsing cli entry imports...');
|
|
428
|
+
|
|
429
|
+
let parsed = await fnetParseImports({ file: cliEntry.file, recursive: true });
|
|
430
|
+
let usesJSX = parsed.all.some(w => w.usesJSX === true && w.type === 'local');
|
|
431
|
+
features.cli_uses_jsx = usesJSX;
|
|
432
|
+
features.cli_has_entry = true;
|
|
433
|
+
parsed = await fnetParseImports({ file: cliEntry.file });
|
|
434
|
+
usesJSX = parsed.all.some(w => w.usesJSX === true && w.type === 'local');
|
|
435
|
+
features.cli_entry_uses_jsx = usesJSX;
|
|
436
|
+
features.cli_entry_is_ts = cliEntry.ts;
|
|
437
|
+
features.cli_entry_ext = cliEntry.ext;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
if (atom.type === 'workflow.lib') {
|
|
441
|
+
const srcEntry = findEntryFile({ dir: path.resolve(projectDir, './src') });
|
|
442
|
+
|
|
443
|
+
if (srcEntry.file) {
|
|
444
|
+
setProgress('Parsing src entry imports...');
|
|
445
|
+
|
|
446
|
+
let parsed = await fnetParseImports({ file: srcEntry.file, recursive: true });
|
|
447
|
+
let usesJSX = parsed.all.some(w => w.usesJSX === true && w.type === 'local');
|
|
448
|
+
features.src_uses_jsx = usesJSX;
|
|
449
|
+
features.src_has_entry = true;
|
|
450
|
+
parsed = await fnetParseImports({ file: srcEntry.file });
|
|
451
|
+
usesJSX = parsed.all.some(w => w.usesJSX === true && w.type === 'local');
|
|
452
|
+
features.src_entry_uses_jsx = usesJSX;
|
|
453
|
+
features.src_entry_is_ts = srcEntry.ts;
|
|
454
|
+
features.src_entry_ext = srcEntry.ext;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
const isAppReact = Reflect.has(features, 'app_entry_uses_jsx') ? features.app_entry_uses_jsx === true : features.src_entry_uses_jsx === true;
|
|
459
|
+
const isCliReact = Reflect.has(features, 'cli_entry_uses_jsx') ? features.cli_entry_uses_jsx === true : features.src_entry_uses_jsx === true;
|
|
460
|
+
|
|
461
|
+
features.form_enabled = (isAppReact || isCliReact) || features.form === true || features.form?.enabled === true;
|
|
462
|
+
features.multiple_enabled = features.multiple_enabled || features.multiple === true || features.multiple?.enabled === true;
|
|
463
|
+
|
|
464
|
+
// APP PROPS
|
|
465
|
+
if (features.app === false) {
|
|
466
|
+
features.app = {
|
|
467
|
+
enabled: false,
|
|
468
|
+
};
|
|
469
|
+
} else if (features.app === true) {
|
|
470
|
+
features.app = {
|
|
471
|
+
enabled: true,
|
|
472
|
+
extend: features.app_has_entry === true,
|
|
473
|
+
export: true,
|
|
474
|
+
react: isAppReact
|
|
475
|
+
};
|
|
476
|
+
} else features.app = { enabled: true, extend: features.app_has_entry === true, export: true, react: isAppReact, ...(features.app || {}) };
|
|
477
|
+
|
|
478
|
+
|
|
479
|
+
features.app.enabled = features.app.enabled === true && (atom.doc.features.form_enabled === true || features.app.extend === true || features.app.enabled === true);
|
|
480
|
+
features.app.format = features.app.format || "esm";
|
|
481
|
+
features.app.folder = features.app.folder || features.app.format || "default";
|
|
482
|
+
|
|
483
|
+
// CLI PROPS
|
|
484
|
+
if (features.cli === false) {
|
|
485
|
+
features.cli = {
|
|
486
|
+
enabled: false
|
|
487
|
+
};
|
|
488
|
+
} else if (features.cli === true) {
|
|
489
|
+
features.cli = {
|
|
490
|
+
enabled: true,
|
|
491
|
+
extend: features.cli_has_entry === true,
|
|
492
|
+
export: true,
|
|
493
|
+
react: isCliReact
|
|
494
|
+
};
|
|
495
|
+
} else features.cli = {
|
|
496
|
+
enabled: true,
|
|
497
|
+
extend: features.cli_has_entry === true,
|
|
498
|
+
export: true,
|
|
499
|
+
react: isCliReact, ...(features.cli || {})
|
|
500
|
+
};
|
|
501
|
+
|
|
502
|
+
features.cli.enabled = features.cli.enabled === true && (atom.doc.features.form_enabled === false || features.cli.extend === true || features.cli.enabled === true);
|
|
503
|
+
features.cli.format = features.cli.format || "esm";
|
|
504
|
+
features.cli.folder = features.cli.folder || features.cli.folder || "esm";
|
|
505
|
+
features.cli.node_options = features.cli.node?.options || features.cli.node_options || '';
|
|
506
|
+
features.json = features.cli.enabled || features.json;
|
|
507
|
+
|
|
508
|
+
// rollup output default
|
|
509
|
+
const rollup_output_default = {
|
|
510
|
+
cjs: {
|
|
511
|
+
format: "cjs",
|
|
512
|
+
context: features.form_enabled ? "window" : "global",
|
|
513
|
+
babel: (features.src_uses_jsx === true) || false,
|
|
514
|
+
browser: false,
|
|
515
|
+
replace: true,
|
|
516
|
+
terser: true,
|
|
517
|
+
enabled: features.cjs !== false,
|
|
518
|
+
copy: false,
|
|
519
|
+
},
|
|
520
|
+
esm: {
|
|
521
|
+
format: "esm",
|
|
522
|
+
context: features.form_enabled ? "window" : "global",
|
|
523
|
+
babel: (features.src_uses_jsx === true) || false,
|
|
524
|
+
browser: false,
|
|
525
|
+
replace: true,
|
|
526
|
+
terser: false,
|
|
527
|
+
enabled: features.esm !== false,
|
|
528
|
+
copy: true,
|
|
529
|
+
},
|
|
530
|
+
iife: {
|
|
531
|
+
format: "iife",
|
|
532
|
+
context: features.form_enabled ? "window" : "global",
|
|
533
|
+
babel: true,
|
|
534
|
+
browser: true,
|
|
535
|
+
replace: true,
|
|
536
|
+
enabled: features.iife === true,
|
|
537
|
+
terser: true,
|
|
538
|
+
copy: false,
|
|
539
|
+
}
|
|
540
|
+
};
|
|
541
|
+
|
|
542
|
+
// babel targets default
|
|
543
|
+
const babel_default = {
|
|
544
|
+
targets: {
|
|
545
|
+
browsers: "last 9 versions, not dead",
|
|
546
|
+
node: "18"
|
|
547
|
+
}
|
|
548
|
+
};
|
|
549
|
+
|
|
550
|
+
// replace default
|
|
551
|
+
const replace_default = {};
|
|
552
|
+
|
|
553
|
+
// webos default
|
|
554
|
+
if (features.webos === true) {
|
|
555
|
+
rollup_output_default.webos = {
|
|
556
|
+
format: "iife",
|
|
557
|
+
browser: true,
|
|
558
|
+
babel: true,
|
|
559
|
+
context: "window",
|
|
560
|
+
replace: true,
|
|
561
|
+
terser: true,
|
|
562
|
+
input: "./src/app/index.js",
|
|
563
|
+
output_dir: `./dist/app/webos`,
|
|
564
|
+
copy: false,
|
|
565
|
+
babel_options: {
|
|
566
|
+
targets: {
|
|
567
|
+
chrome: "79"
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
// electron default
|
|
574
|
+
if (features.electron === true) {
|
|
575
|
+
rollup_output_default.electron = {
|
|
576
|
+
format: "iife",
|
|
577
|
+
browser: true,
|
|
578
|
+
babel: true,
|
|
579
|
+
context: "window",
|
|
580
|
+
replace: true,
|
|
581
|
+
terser: true,
|
|
582
|
+
copy: false,
|
|
583
|
+
input: "./src/app/index.js",
|
|
584
|
+
output_dir: `./dist/app/electron`,
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
// nextsj default
|
|
589
|
+
if (features.nextjs === true) {
|
|
590
|
+
rollup_output_default.nextjs = {
|
|
591
|
+
format: "esm",
|
|
592
|
+
browser: true,
|
|
593
|
+
babel: true,
|
|
594
|
+
context: "window",
|
|
595
|
+
replace: true,
|
|
596
|
+
terser: true,
|
|
597
|
+
copy: false,
|
|
598
|
+
input: "./src/app/index.js",
|
|
599
|
+
output_dir: `./dist/app/nextjs`,
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
// ios default
|
|
604
|
+
if (features.ios === true) {
|
|
605
|
+
rollup_output_default.ios = {
|
|
606
|
+
format: "iife",
|
|
607
|
+
browser: true,
|
|
608
|
+
babel: true,
|
|
609
|
+
context: "window",
|
|
610
|
+
replace: true,
|
|
611
|
+
terser: true,
|
|
612
|
+
copy: false,
|
|
613
|
+
input: "./src/app/index.js",
|
|
614
|
+
output_dir: `./dist/app/ios`,
|
|
615
|
+
};
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
// macos default
|
|
619
|
+
if (features.macos === true) {
|
|
620
|
+
rollup_output_default.macos = {
|
|
621
|
+
format: "iife",
|
|
622
|
+
browser: true,
|
|
623
|
+
babel: true,
|
|
624
|
+
context: "window",
|
|
625
|
+
replace: true,
|
|
626
|
+
terser: true,
|
|
627
|
+
copy: false,
|
|
628
|
+
input: "./src/app/index.js",
|
|
629
|
+
output_dir: `./dist/app/macos`,
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
// app default
|
|
634
|
+
if (features.app.enabled === true) {
|
|
635
|
+
features.app.dir = `./dist/app/${features.app.folder}`;
|
|
636
|
+
|
|
637
|
+
rollup_output_default.app = {
|
|
638
|
+
format: features.app.format,
|
|
639
|
+
browser: true,
|
|
640
|
+
babel: true,
|
|
641
|
+
context: "window",
|
|
642
|
+
replace: true,
|
|
643
|
+
input: "./src/app/index.js",
|
|
644
|
+
output_dir: features.app.dir,
|
|
645
|
+
terser: true,
|
|
646
|
+
output_exports: features.app.export === false ? "none" : "auto",
|
|
647
|
+
browsersync: true,
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
// cli default
|
|
652
|
+
if (features.cli.enabled === true) {
|
|
653
|
+
features.cli.dir = `./dist/cli/${features.cli.folder}`;
|
|
654
|
+
|
|
655
|
+
rollup_output_default.cli = {
|
|
656
|
+
format: features.cli.format,
|
|
657
|
+
context: "global",
|
|
658
|
+
babel: (features.src_uses_jsx === true || features.cli_uses_jsx === true) || false,
|
|
659
|
+
browser: false,
|
|
660
|
+
replace: true,
|
|
661
|
+
enabled: true,
|
|
662
|
+
input: "./src/cli/index.js",
|
|
663
|
+
output_dir: features.cli.dir,
|
|
664
|
+
banner: "#!/usr/bin/env node",
|
|
665
|
+
terser: true,
|
|
666
|
+
output_exports: features.cli.export === false ? "none" : "auto",
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
// browsersync default
|
|
671
|
+
const browsersync_default = {
|
|
672
|
+
server: '.',
|
|
673
|
+
startPath: `${path.normalize(features.app.dir || '.')}`,
|
|
674
|
+
files: [path.normalize("./dist/**/*")],
|
|
675
|
+
cors: true,
|
|
676
|
+
open: false,
|
|
677
|
+
};
|
|
678
|
+
|
|
679
|
+
features.babel_options = merge(babel_default, features.babel_options || features.babel?.options);
|
|
680
|
+
features.browsersync_options = merge(browsersync_default, features.browsersync_options || features.browsersync?.options || {});
|
|
681
|
+
features.replace_options = merge(replace_default, features.replace_options || features.replace?.options || {});
|
|
682
|
+
|
|
683
|
+
if (Reflect.has(features.browsersync_options, 'proxy')) {
|
|
684
|
+
delete features.browsersync_options.server;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
features.rollup = features.rollup || {};
|
|
688
|
+
features.rollup_output = merge(rollup_output_default, features.rollup_output || features.rollup?.output || {});
|
|
689
|
+
|
|
690
|
+
features.preact_enabled = features.preact === true || (features.preact && features.preact?.enabled !== false);
|
|
691
|
+
|
|
692
|
+
// rollup outputs
|
|
693
|
+
let rollup_output_keys = Object.keys(rollup_output_default);
|
|
694
|
+
for (const key of rollup_output_keys) {
|
|
695
|
+
const output = rollup_output_default[key];
|
|
696
|
+
|
|
697
|
+
if (!output) continue;
|
|
698
|
+
|
|
699
|
+
if (features.rollup[key] === false) {
|
|
700
|
+
delete features.rollup_output[key];
|
|
701
|
+
continue;
|
|
702
|
+
}
|
|
703
|
+
output.babel_options = output.babel_options || features.babel_options;
|
|
704
|
+
output.browsersync_options = merge(features.browsersync_options, output.browsersync_options);
|
|
705
|
+
output.replace_options = merge(features.replace_options, output.replace_options);
|
|
706
|
+
|
|
707
|
+
if (features.preact_enabled) {
|
|
708
|
+
output.alias_enabled = true;
|
|
709
|
+
output.alias = output.alias || {};
|
|
710
|
+
output.alias.entries = output.alias.entries || {};
|
|
711
|
+
output.alias.entries['react'] = 'preact/compat';
|
|
712
|
+
output.alias.entries['react-dom'] = 'preact/compat';
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
if (features.form_enabled || features.babel) output.babel = true;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
rollup_output_keys = Object.keys(features.rollup_output);
|
|
719
|
+
|
|
720
|
+
features.babel_enabled = rollup_output_keys.some(w => features.rollup_output[w].babel === true);
|
|
721
|
+
features.browser_enabled = rollup_output_keys.some(w => features.rollup_output[w].babel === true);
|
|
722
|
+
features.browsersync_enabled = features.browsersync !== false && rollup_output_keys.some(w => features.rollup_output[w].browsersync === true);
|
|
723
|
+
features.browsersync_enabled = features.browsersync_enabled && features.app.enabled;
|
|
724
|
+
features.dependency_auto_enabled = features.dependency_auto !== false && features.dependency_auto?.enabled !== false;
|
|
725
|
+
features.npm_install_flags = features.npm_install_flags || '';
|
|
726
|
+
features.react_version = features.react_version || features.react?.version || 18;
|
|
727
|
+
|
|
728
|
+
initCssFeature(apiContext);
|
|
729
|
+
initCopyFeature(apiContext);
|
|
730
|
+
initWasmFeature(apiContext);
|
|
731
|
+
initTerserFeature(apiContext);
|
|
732
|
+
initJsonFeature(apiContext);
|
|
733
|
+
initStringFeature(apiContext);
|
|
734
|
+
initImageFeature(apiContext);
|
|
735
|
+
initAnalyzerFeature(apiContext);
|
|
736
|
+
initVisualizerFeature(apiContext);
|
|
737
|
+
initPolyfillFeature(apiContext);
|
|
738
|
+
initNunjucksFeature(apiContext);
|
|
739
|
+
initWorkboxFeature(apiContext);
|
|
740
|
+
initGzipFeature(apiContext);
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
async function initPythonFeature(apiContext) {
|
|
744
|
+
const { atom, context, setProgress } = apiContext;
|
|
745
|
+
setProgress('Initializing features...');
|
|
746
|
+
|
|
747
|
+
atom.doc.features = atom.doc.features || {};
|
|
748
|
+
const features = atom.doc.features;
|
|
749
|
+
|
|
750
|
+
// CLI PROPS
|
|
751
|
+
if (features.cli === false) {
|
|
752
|
+
features.cli = {
|
|
753
|
+
enabled: false
|
|
754
|
+
};
|
|
755
|
+
} else if (features.cli === true) {
|
|
756
|
+
features.cli = {
|
|
757
|
+
enabled: true,
|
|
758
|
+
};
|
|
759
|
+
} else features.cli = {
|
|
760
|
+
enabled: true
|
|
761
|
+
};
|
|
762
|
+
|
|
763
|
+
features.cli.enabled = features.cli.enabled === true && (atom.doc.features.form_enabled === false || features.cli.extend === true || features.cli.enabled === true);
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
async function initDependencies({ atom, packageDependencies, packageDevDependencies, setProgress }) {
|
|
767
|
+
|
|
768
|
+
setProgress('Initializing dependencies');
|
|
769
|
+
|
|
770
|
+
const userDependencies = atom.doc.dependencies || [];
|
|
771
|
+
userDependencies.filter(w => !w.dev).forEach(dep => packageDependencies.push(dep));
|
|
772
|
+
userDependencies.filter(w => w.dev).forEach(dep => packageDevDependencies.push(dep));
|
|
773
|
+
|
|
774
|
+
if (atom.type === 'workflow') {
|
|
775
|
+
packageDependencies.push({ package: "get-value", version: "^3" });
|
|
776
|
+
packageDependencies.push({ package: "set-value", version: "^4" });
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
if (atom.doc.features.form_enabled) {
|
|
780
|
+
if (atom.doc.features.dependency_auto_enabled) {
|
|
781
|
+
let reactVersion = '^18.2';
|
|
782
|
+
setProgress('Fetching React versions');
|
|
783
|
+
const versions = await fnetListNpmVersions({ name: "react", groupBy: { major: true } });
|
|
784
|
+
const found = versions.find(w => w[0] === atom.doc.features.react_version.toString());
|
|
785
|
+
reactVersion = `^${found[0]}`;
|
|
786
|
+
packageDependencies.push({ package: "react", version: reactVersion });
|
|
787
|
+
packageDependencies.push({ package: "react-dom", version: reactVersion });
|
|
788
|
+
|
|
789
|
+
if (atom.type === 'workflow') {
|
|
790
|
+
packageDependencies.push({ package: "@fnet/react-app", version: "^0.1" });
|
|
791
|
+
packageDependencies.push({ package: "@fnet/react-app-state", version: "^0.1" });
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
if (atom.doc.features.preact_enabled) {
|
|
797
|
+
packageDependencies.push({ package: "preact", version: "^10" });
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
if (atom.doc.features.cli.enabled === true) {
|
|
801
|
+
packageDependencies.push({ package: "@fnet/args", version: "^0.1" });
|
|
802
|
+
packageDevDependencies.push({ package: "ajv", version: "^8" });
|
|
803
|
+
|
|
804
|
+
if (atom.doc.features.cli.fargs && atom.doc.features.cli.fargs?.enabled !== false) {
|
|
805
|
+
packageDependencies.push({ package: "@fnet/config", version: "0.2.21" });
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
if (atom.doc.features.render && atom.doc.features.render.enabled !== false) {
|
|
810
|
+
packageDevDependencies.push({ package: "@flownet/lib-render-templates-dir", version: "0.1.19" });
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
// DEV DEPENDENCIES
|
|
814
|
+
packageDevDependencies.push({ package: "@babel/core", version: "^7" });
|
|
815
|
+
packageDevDependencies.push({ package: "@rollup/plugin-commonjs", version: "^28" });
|
|
816
|
+
packageDevDependencies.push({ package: "@rollup/plugin-node-resolve", version: "^16" });
|
|
817
|
+
packageDevDependencies.push({ package: "@rollup/plugin-replace", version: "^6" });
|
|
818
|
+
packageDevDependencies.push({ package: "rollup", version: "^4" });
|
|
819
|
+
if (atom.doc.features.dts_enabled) {
|
|
820
|
+
packageDevDependencies.push({ package: "rollup-plugin-dts", version: "^6" });
|
|
821
|
+
}
|
|
822
|
+
packageDevDependencies.push({ package: "rollup-plugin-peer-deps-external", version: "^2" });
|
|
823
|
+
packageDevDependencies.push({ package: "@rollup/plugin-alias", version: "^5" });
|
|
824
|
+
packageDevDependencies.push({ package: "fs-extra", version: "^11" });
|
|
825
|
+
|
|
826
|
+
if (atom.doc.features.babel_enabled) {
|
|
827
|
+
packageDevDependencies.push({ package: "@rollup/plugin-babel", version: "^6" });
|
|
828
|
+
packageDevDependencies.push({ package: "@babel/preset-env", version: "^7" });
|
|
829
|
+
packageDevDependencies.push({ package: "@babel/preset-react", version: "^7" });
|
|
830
|
+
|
|
831
|
+
atom.doc.features.babel?.options?.plugins?.forEach(plugin => {
|
|
832
|
+
const pluginName = plugin[0];
|
|
833
|
+
switch (pluginName) {
|
|
834
|
+
case '@babel/plugin-proposal-decorators':
|
|
835
|
+
packageDevDependencies.push({ package: "@babel/plugin-proposal-decorators", version: "^7" });
|
|
836
|
+
break;
|
|
837
|
+
case '@babel/plugin-proposal-class-properties':
|
|
838
|
+
packageDevDependencies.push({ package: "@babel/plugin-proposal-class-properties", version: "^7" });
|
|
839
|
+
break;
|
|
840
|
+
case '@babel/plugin-proposal-private-methods':
|
|
841
|
+
packageDevDependencies.push({ package: "@babel/plugin-proposal-private-methods", version: "^7" });
|
|
842
|
+
break;
|
|
843
|
+
case '@babel/plugin-proposal-private-property-in-object':
|
|
844
|
+
packageDevDependencies.push({ package: "@babel/plugin-proposal-private-property-in-object", version: "^7" });
|
|
845
|
+
break;
|
|
846
|
+
case '@babel/plugin-proposal-optional-chaining':
|
|
847
|
+
packageDevDependencies.push({ package: "@babel/plugin-proposal-optional-chaining", version: "^7" });
|
|
848
|
+
break;
|
|
849
|
+
}
|
|
850
|
+
});
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
packageDevDependencies.push({ package: "@fnet/rollup-plugin-delete", version: "0.1.10" });
|
|
854
|
+
|
|
855
|
+
if (atom.doc.features.browsersync_enabled) {
|
|
856
|
+
packageDevDependencies.push({ package: "@fnet/rollup-plugin-browsersync", version: "0.1.11" });
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
async function initPythonDependencies({ atom, packageDependencies, packageDevDependencies, setProgress }) {
|
|
861
|
+
setProgress('Initializing dependencies');
|
|
862
|
+
}
|
|
863
|
+
|
|
864
|
+
async function createApp({ atom, setProgress, context, packageDependencies }) {
|
|
865
|
+
|
|
866
|
+
if (atom.doc.features.app.enabled !== true) return;
|
|
867
|
+
|
|
868
|
+
await setProgress({ message: "Creating app folder" });
|
|
869
|
+
|
|
870
|
+
const templateContext = {
|
|
871
|
+
atom: atom,
|
|
872
|
+
packageDependencies: packageDependencies,
|
|
873
|
+
ts: Date.now()
|
|
874
|
+
};
|
|
875
|
+
const templateDir = context.templateDir;
|
|
876
|
+
|
|
877
|
+
const outDir = path.resolve(context.projectDir, `src/app`);
|
|
878
|
+
if (!fs.existsSync(outDir)) fs.mkdirSync(outDir, { recursive: true });
|
|
879
|
+
|
|
880
|
+
let pattern = ["index.js.njk"];
|
|
881
|
+
if (atom.doc.features.app.html !== false) pattern.push("index.html.njk");
|
|
882
|
+
await fnetRender({
|
|
883
|
+
pattern: pattern,
|
|
884
|
+
dir: path.resolve(templateDir, `src/app`),
|
|
885
|
+
outDir,
|
|
886
|
+
context: templateContext,
|
|
887
|
+
});
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
async function pickNpmVersions({ projectDir, name, setProgress, count = 1 }) {
|
|
891
|
+
|
|
892
|
+
let npmVersions;
|
|
893
|
+
|
|
894
|
+
const key = ['npm-pick-versions', name, count];
|
|
895
|
+
const cacheKey = hash(key);
|
|
896
|
+
const cacheDir = path.join(projectDir, '.cache');
|
|
897
|
+
const cacheFile = path.join(cacheDir, cacheKey + '.json');
|
|
898
|
+
|
|
899
|
+
if (fs.existsSync(cacheFile)) {
|
|
900
|
+
if (setProgress) setProgress(`Picking npm version of ${name} from cache ...`);
|
|
901
|
+
npmVersions = JSON.parse(fs.readFileSync(cacheFile, 'utf8'));
|
|
902
|
+
}
|
|
903
|
+
else {
|
|
904
|
+
if (setProgress) setProgress(`Picking npm version of ${name} ...`);
|
|
905
|
+
npmVersions = await fnetPickNpmVersions({ name: name, count });
|
|
906
|
+
fs.mkdirSync(cacheDir, { recursive: true });
|
|
907
|
+
fs.writeFileSync(cacheFile, JSON.stringify(npmVersions), 'utf8');
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
return npmVersions;
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
async function createPackageJson({ atom, context, packageDependencies, packageDevDependencies, setProgress }) {
|
|
914
|
+
|
|
915
|
+
await setProgress({ message: "Creating package.json." });
|
|
916
|
+
|
|
917
|
+
// move dev dependencies in packageDependencies to packageDevDependencies
|
|
918
|
+
const devPackages = packageDependencies.filter(w => w.dev === true);
|
|
919
|
+
devPackages.forEach(w => {
|
|
920
|
+
if (!packageDevDependencies.find(x => x.package === w.package)) {
|
|
921
|
+
packageDevDependencies.push(w);
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
const index = packageDependencies.findIndex(x => x.package === w.package);
|
|
925
|
+
packageDependencies.splice(index, 1);
|
|
926
|
+
});
|
|
927
|
+
|
|
928
|
+
// TODO: PEER DEPENDENCIES
|
|
929
|
+
// REACT CHECK
|
|
930
|
+
const reactDep = packageDependencies.find(w => w.package === "react");
|
|
931
|
+
const reactDomDep = packageDependencies.find(w => w.package === "react-dom");
|
|
932
|
+
|
|
933
|
+
if (reactDep && !reactDomDep)
|
|
934
|
+
packageDependencies.push({ package: "react-dom", version: reactDep.version });
|
|
935
|
+
else if (reactDep && reactDomDep)
|
|
936
|
+
reactDomDep.version = reactDep.version;
|
|
937
|
+
|
|
938
|
+
// EMOTION CHECK
|
|
939
|
+
if (reactDep && atom.doc.features.react_version >= 17) {
|
|
940
|
+
if (!packageDependencies.find(w => w.package === '@emotion/react'))
|
|
941
|
+
packageDependencies.push({ package: "@emotion/react", version: "^11" });
|
|
942
|
+
if (!packageDependencies.find(w => w.package === '@emotion/styled'))
|
|
943
|
+
packageDependencies.push({ package: "@emotion/styled", version: "^11" });
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
const checkFiles = [];
|
|
947
|
+
|
|
948
|
+
if (atom.doc.features.app.enabled === true) {
|
|
949
|
+
checkFiles.push({
|
|
950
|
+
file: path.resolve(context.projectDir, `src/app/index.js`),
|
|
951
|
+
dev: atom.doc.features.app.dev !== false
|
|
952
|
+
});
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
if (atom.doc.features.cli.enabled === true) {
|
|
956
|
+
checkFiles.push({
|
|
957
|
+
file: path.resolve(context.projectDir, `src/cli/index.js`),
|
|
958
|
+
dev: atom.doc.features.cli.dev !== false
|
|
959
|
+
});
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
for await (const checkFile of checkFiles) {
|
|
963
|
+
const srcFilePath = checkFile.file;
|
|
964
|
+
if (!fs.existsSync(srcFilePath)) throw new Error(`App file not found: ${srcFilePath}`);
|
|
965
|
+
|
|
966
|
+
const parsedImports = await fnetParseImports({ file: srcFilePath, recursive: true });
|
|
967
|
+
const targetImports = parsedImports.all;
|
|
968
|
+
|
|
969
|
+
for await (const parsedImport of targetImports) {
|
|
970
|
+
if (parsedImport.type !== 'npm') continue;
|
|
971
|
+
|
|
972
|
+
if (packageDependencies.find(w => w.package === parsedImport.package)) continue;
|
|
973
|
+
if (packageDevDependencies.find(w => w.package === parsedImport.package)) continue;
|
|
974
|
+
|
|
975
|
+
const npmVersions = await pickNpmVersions({
|
|
976
|
+
name: parsedImport.package,
|
|
977
|
+
projectDir: context.projectDir,
|
|
978
|
+
setProgress
|
|
979
|
+
});
|
|
980
|
+
|
|
981
|
+
const targetDependencies = checkFile.dev === true ? packageDevDependencies : packageDependencies;
|
|
982
|
+
targetDependencies.push({
|
|
983
|
+
package: parsedImport.package,
|
|
984
|
+
subpath: parsedImport.subpath,
|
|
985
|
+
version: npmVersions.minorRange,
|
|
986
|
+
type: "npm"
|
|
987
|
+
});
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
|
|
991
|
+
const templateContext = {
|
|
992
|
+
atom: atom,
|
|
993
|
+
packageDependencies: packageDependencies,
|
|
994
|
+
packageDevDependencies: packageDevDependencies
|
|
995
|
+
};
|
|
996
|
+
|
|
997
|
+
const templateDir = context.templateCommonDir;
|
|
998
|
+
const template = nunjucks.compile(
|
|
999
|
+
fs.readFileSync(path.resolve(templateDir, `package.json.njk`), "utf8"),
|
|
1000
|
+
nunjucks.configure(templateDir)
|
|
1001
|
+
);
|
|
1002
|
+
|
|
1003
|
+
const templateRender = template.render(templateContext);
|
|
1004
|
+
|
|
1005
|
+
const projectDir = context.projectDir;
|
|
1006
|
+
const filePath = path.resolve(projectDir, `package.json`);
|
|
1007
|
+
fs.writeFileSync(filePath, templateRender, 'utf8');
|
|
1008
|
+
|
|
1009
|
+
// copy fnet files to projectDir
|
|
1010
|
+
const fnetSrcDir = path.resolve(context.project.projectDir, 'fnet');
|
|
1011
|
+
if (fs.existsSync(fnetSrcDir)) {
|
|
1012
|
+
const fnetDestDir = path.resolve(context.projectDir, 'fnet');
|
|
1013
|
+
if (!fs.existsSync(fnetDestDir)) {
|
|
1014
|
+
fs.mkdirSync(fnetDestDir);
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
const fnetFiles = fs.readdirSync(fnetSrcDir);
|
|
1018
|
+
for (const fnetFile of fnetFiles) {
|
|
1019
|
+
const fnetFilePath = path.resolve(fnetSrcDir, fnetFile);
|
|
1020
|
+
if (!fs.lstatSync(fnetFilePath).isFile()) continue;
|
|
1021
|
+
const targetFilePath = path.resolve(fnetDestDir, fnetFile);
|
|
1022
|
+
fs.copyFileSync(fnetFilePath, targetFilePath);
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
async function createCli({ atom, setProgress, context, packageDependencies }) {
|
|
1028
|
+
|
|
1029
|
+
if (atom.doc.features.cli.enabled !== true) return;
|
|
1030
|
+
|
|
1031
|
+
await setProgress({ message: "Creating cli." });
|
|
1032
|
+
|
|
1033
|
+
const templateContext = {
|
|
1034
|
+
atom: atom,
|
|
1035
|
+
packageDependencies: packageDependencies
|
|
1036
|
+
};
|
|
1037
|
+
|
|
1038
|
+
const templateDir = context.templateDir;
|
|
1039
|
+
|
|
1040
|
+
const outDir = path.resolve(context.projectDir, `src/cli`);
|
|
1041
|
+
if (!fs.existsSync(outDir)) fs.mkdirSync(outDir, { recursive: true });
|
|
1042
|
+
|
|
1043
|
+
await fnetRender({
|
|
1044
|
+
pattern: ["index.js.njk"],
|
|
1045
|
+
dir: path.resolve(templateDir, `src/cli`),
|
|
1046
|
+
outDir,
|
|
1047
|
+
context: templateContext,
|
|
1048
|
+
});
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1051
|
+
async function createCliPython({ atom, setProgress, context, packageDependencies }) {
|
|
1052
|
+
|
|
1053
|
+
if (atom.doc.features.cli.enabled !== true) return;
|
|
1054
|
+
|
|
1055
|
+
await setProgress({ message: "Creating cli." });
|
|
1056
|
+
|
|
1057
|
+
const templateContext = {
|
|
1058
|
+
atom: atom,
|
|
1059
|
+
packageDependencies: packageDependencies
|
|
1060
|
+
};
|
|
1061
|
+
|
|
1062
|
+
const templateDir = context.templateDir;
|
|
1063
|
+
|
|
1064
|
+
const outDir = path.join(context.projectDir, 'src', 'cli');
|
|
1065
|
+
if (!fs.existsSync(outDir)) fs.mkdirSync(outDir, { recursive: true });
|
|
1066
|
+
|
|
1067
|
+
await fnetRender({
|
|
1068
|
+
pattern: ["index.py.njk", "__init__.py.njk"],
|
|
1069
|
+
dir: path.join(templateDir, 'src', 'cli'),
|
|
1070
|
+
outDir,
|
|
1071
|
+
context: templateContext,
|
|
1072
|
+
});
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
async function createRollup({ atom, setProgress, context, packageDependencies }) {
|
|
1076
|
+
|
|
1077
|
+
await setProgress({ message: "Creating rollup file." });
|
|
1078
|
+
|
|
1079
|
+
const templateContext = {
|
|
1080
|
+
atom,
|
|
1081
|
+
packageDependencies
|
|
1082
|
+
};
|
|
1083
|
+
|
|
1084
|
+
// SCAN ENTRY FILE
|
|
1085
|
+
const entryFile = path.resolve(context.projectDir, "src", "default/index.js");
|
|
1086
|
+
if (!fs.existsSync(entryFile)) throw new Error(`Entry file not found: ${entryFile}`);
|
|
1087
|
+
|
|
1088
|
+
const packages = await fnetParseImports({ file: entryFile, recursive: true });
|
|
1089
|
+
|
|
1090
|
+
// ADD NODE BUILTINS
|
|
1091
|
+
const nodeBuiltins = packages.all.filter(p => p.type === "node").map(p => p.path);
|
|
1092
|
+
const rollup_output = atom.doc.features.rollup_output;
|
|
1093
|
+
const keys = Object.keys(rollup_output);
|
|
1094
|
+
for (let i = 0; i < keys.length; i++) {
|
|
1095
|
+
const key = keys[i];
|
|
1096
|
+
const value = rollup_output[key];
|
|
1097
|
+
if (value.browser === true) {
|
|
1098
|
+
if (nodeBuiltins.length > 0) {
|
|
1099
|
+
|
|
1100
|
+
// GLOBALS
|
|
1101
|
+
value.globals_enabled = true;
|
|
1102
|
+
value.globals = value.globals || [];
|
|
1103
|
+
value.globals = value.globals.concat(nodeBuiltins.map(nodeBuiltin => { return { key: nodeBuiltin, value: nodeBuiltin } }));
|
|
1104
|
+
|
|
1105
|
+
// ALIAS
|
|
1106
|
+
value.alias_enabled = true;
|
|
1107
|
+
value.alias = value.alias || {};
|
|
1108
|
+
value.alias.entries = value.alias.entries || {};
|
|
1109
|
+
for (let j = 0; j < nodeBuiltins.length; j++) {
|
|
1110
|
+
const nodeBuiltin = nodeBuiltins[j];
|
|
1111
|
+
value.alias.entries[nodeBuiltin] = `node:${nodeBuiltin}`;
|
|
1112
|
+
value.alias.entries[`node:${nodeBuiltin}`] = nodeBuiltin;
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
// EXTERNAL
|
|
1116
|
+
value.external_enabled = true;
|
|
1117
|
+
value.external = value.external || [];
|
|
1118
|
+
value.external = value.external.concat(nodeBuiltins);
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
// RENDER TEMPLATE rollup.config.js.njk
|
|
1124
|
+
const templateDir = context.templateCommonDir;
|
|
1125
|
+
let template = nunjucks.compile(
|
|
1126
|
+
fs.readFileSync(path.resolve(templateDir, `rollup.config.mjs.njk`), "utf8"),
|
|
1127
|
+
nunjucks.configure(templateDir)
|
|
1128
|
+
);
|
|
1129
|
+
|
|
1130
|
+
let templateRender = template.render(templateContext);
|
|
1131
|
+
|
|
1132
|
+
const projectDir = context.projectDir;
|
|
1133
|
+
let filePath = path.resolve(projectDir, `rollup.config.mjs`);
|
|
1134
|
+
fs.writeFileSync(filePath, templateRender, 'utf8');
|
|
1135
|
+
|
|
1136
|
+
|
|
1137
|
+
// // RENDER TEMPLATE rollup.config.mjs.njk
|
|
1138
|
+
// // check file if exists
|
|
1139
|
+
// if (fs.existsSync(path.resolve(templateDir, `rollup.config.mjs.njk`))) {
|
|
1140
|
+
// template = nunjucks.compile(
|
|
1141
|
+
// fs.readFileSync(path.resolve(templateDir, `rollup.config.mjs.njk`), "utf8"),
|
|
1142
|
+
// nunjucks.configure(templateDir)
|
|
1143
|
+
// );
|
|
1144
|
+
|
|
1145
|
+
// templateRender = template.render(templateContext);
|
|
1146
|
+
|
|
1147
|
+
// filePath = path.resolve(projectDir, `rollup.config.mjs`);
|
|
1148
|
+
// fs.writeFileSync(filePath, templateRender, 'utf8');
|
|
1149
|
+
// };
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
async function createToYargs({ atom, setProgress, context, njEnv }) {
|
|
1153
|
+
|
|
1154
|
+
if (atom.doc.features.cli.enabled !== true) return;
|
|
1155
|
+
|
|
1156
|
+
await setProgress({ message: "Creating yargs." });
|
|
1157
|
+
|
|
1158
|
+
let schema = {};
|
|
1159
|
+
const imports = [];
|
|
1160
|
+
|
|
1161
|
+
const input = atom.doc.input;
|
|
1162
|
+
if (input) {
|
|
1163
|
+
schema = atom.doc.input;
|
|
1164
|
+
}
|
|
1165
|
+
else {
|
|
1166
|
+
schema = {
|
|
1167
|
+
type: "object",
|
|
1168
|
+
properties: {},
|
|
1169
|
+
required: []
|
|
1170
|
+
};
|
|
1171
|
+
}
|
|
1172
|
+
if (atom.doc.features.cli.fargs && atom.doc.features.cli.fargs?.enabled !== false) {
|
|
1173
|
+
|
|
1174
|
+
const fargsOptions = atom.doc.features.cli.fargs;
|
|
1175
|
+
|
|
1176
|
+
const fargs = { type: "string", description: "Config name to load args", hidden: false };
|
|
1177
|
+
const ftag = { type: "array", description: "Tags to filter the config", hidden: false };
|
|
1178
|
+
|
|
1179
|
+
if (Reflect.has(fargsOptions, 'default')) fargs.default = fargsOptions.default;
|
|
1180
|
+
// if (Reflect.has(fargsOptions, 'describe') || Reflect.has(fargsOptions, 'description')) fargs.describe = fargsOptions.describe || fargsOptions.description;
|
|
1181
|
+
// if (Reflect.has(fargsOptions, 'choices')) fargs.choices = fargsOptions.choices;
|
|
1182
|
+
|
|
1183
|
+
if (schema.properties) {
|
|
1184
|
+
schema.properties["fargs"] = fargs;
|
|
1185
|
+
schema.properties["ftag"] = ftag;
|
|
1186
|
+
}
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
const templateContext = { options: schema, imports, atom: atom };
|
|
1190
|
+
|
|
1191
|
+
const templateDir = context.templateDir;
|
|
1192
|
+
const template = nunjucks.compile(
|
|
1193
|
+
fs.readFileSync(path.resolve(templateDir, `src/default/to.args.js.njk`), "utf8"),
|
|
1194
|
+
njEnv
|
|
1195
|
+
);
|
|
1196
|
+
|
|
1197
|
+
const templateRender = template.render(templateContext);
|
|
1198
|
+
|
|
1199
|
+
const projectDir = context.projectDir;
|
|
1200
|
+
const filePath = path.resolve(projectDir, `src/default/to.args.js`);
|
|
1201
|
+
fs.writeFileSync(filePath, templateRender, 'utf8');
|
|
1202
|
+
|
|
1203
|
+
const ajv = new Ajv({
|
|
1204
|
+
allErrors: true,
|
|
1205
|
+
useDefaults: true,
|
|
1206
|
+
formats: { },
|
|
1207
|
+
strict: false,
|
|
1208
|
+
code: {
|
|
1209
|
+
esm: true,
|
|
1210
|
+
lines: true,
|
|
1211
|
+
optimize: false,
|
|
1212
|
+
source: true
|
|
1213
|
+
},
|
|
1214
|
+
});
|
|
1215
|
+
|
|
1216
|
+
addFormats(ajv);
|
|
1217
|
+
const validate = ajv.compile(schema);
|
|
1218
|
+
const validateCode = standaloneCode(ajv, validate);
|
|
1219
|
+
|
|
1220
|
+
fs.writeFileSync(path.resolve(projectDir, `src/default/validate_input.js`), validateCode, 'utf8');
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
async function createGitIgnore({ atom, setProgress, context, packageDependencies }) {
|
|
1224
|
+
await setProgress({ message: "Creating .gitignore" });
|
|
1225
|
+
|
|
1226
|
+
const templateContext = {
|
|
1227
|
+
atom: atom,
|
|
1228
|
+
packageDependencies:
|
|
1229
|
+
packageDependencies
|
|
1230
|
+
};
|
|
1231
|
+
|
|
1232
|
+
const templateDir = context.templateCommonDir;
|
|
1233
|
+
const template = nunjucks.compile(
|
|
1234
|
+
fs.readFileSync(path.resolve(templateDir, `.gitignore.njk`), "utf8"),
|
|
1235
|
+
nunjucks.configure(templateDir)
|
|
1236
|
+
);
|
|
1237
|
+
|
|
1238
|
+
const templateRender = template.render(templateContext);
|
|
1239
|
+
|
|
1240
|
+
const projectDir = context.projectDir;
|
|
1241
|
+
const filePath = path.resolve(projectDir, `.gitignore`);
|
|
1242
|
+
fs.writeFileSync(filePath, templateRender, 'utf8');
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
async function createTsConfig({ atom, setProgress, context, packageDependencies }) {
|
|
1246
|
+
await setProgress({ message: "Creating tsconfig.json." });
|
|
1247
|
+
|
|
1248
|
+
const templateContext = {
|
|
1249
|
+
atom: atom,
|
|
1250
|
+
packageDependencies:
|
|
1251
|
+
packageDependencies
|
|
1252
|
+
};
|
|
1253
|
+
|
|
1254
|
+
const templateDir = context.templateCommonDir;
|
|
1255
|
+
const template = nunjucks.compile(
|
|
1256
|
+
fs.readFileSync(path.resolve(templateDir, `tsconfig.json.njk`), "utf8"),
|
|
1257
|
+
nunjucks.configure(templateDir)
|
|
1258
|
+
);
|
|
1259
|
+
|
|
1260
|
+
const templateRender = template.render(templateContext);
|
|
1261
|
+
|
|
1262
|
+
const projectDir = context.projectDir;
|
|
1263
|
+
const filePath = path.resolve(projectDir, `tsconfig.json`);
|
|
1264
|
+
fs.writeFileSync(filePath, templateRender, 'utf8');
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
async function createProjectReadme({ atom, context, setProgress, Atom }) {
|
|
1268
|
+
|
|
1269
|
+
const fileBase = `readme.md`;
|
|
1270
|
+
const message = `Creating ${fileBase}`;
|
|
1271
|
+
|
|
1272
|
+
await setProgress({ message: message });
|
|
1273
|
+
|
|
1274
|
+
if (context.project?.readme) {
|
|
1275
|
+
|
|
1276
|
+
const projectDir = context.projectDir;
|
|
1277
|
+
|
|
1278
|
+
const templateContext = {
|
|
1279
|
+
content: context.project.readme.doc.content
|
|
1280
|
+
};
|
|
1281
|
+
|
|
1282
|
+
const howtoPath = path.resolve(context.project.projectDir, `fnet/how-to.md`);
|
|
1283
|
+
if (fs.existsSync(howtoPath)) {
|
|
1284
|
+
const howtoContent = fs.readFileSync(howtoPath, 'utf8');
|
|
1285
|
+
templateContext.howto = howtoContent;
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
const inputSchemaPath = path.resolve(context.project.projectDir, `fnet/input.yaml`);
|
|
1289
|
+
if (fs.existsSync(inputSchemaPath)) {
|
|
1290
|
+
const yaml = await fnetYaml({ file: inputSchemaPath, tags: context.tags });
|
|
1291
|
+
templateContext.input = yaml.content;
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
const templateDir = context.templateCommonDir;
|
|
1295
|
+
const template = nunjucks.compile(
|
|
1296
|
+
fs.readFileSync(path.resolve(templateDir, `${fileBase}.njk`), "utf8"),
|
|
1297
|
+
nunjucks.configure(templateDir)
|
|
1298
|
+
);
|
|
1299
|
+
|
|
1300
|
+
const templateRender = template.render(templateContext);
|
|
1301
|
+
|
|
1302
|
+
const filePath = path.resolve(projectDir, `${fileBase}`);
|
|
1303
|
+
fs.writeFileSync(filePath, templateRender, 'utf8');
|
|
1304
|
+
}
|
|
1305
|
+
else if (atom.id) {
|
|
1306
|
+
const wiki = await Atom.first({ type: "wiki", parent_id: atom.id });
|
|
1307
|
+
|
|
1308
|
+
if (!wiki || wiki.doc?.["content-type"] !== 'markdown') return;
|
|
1309
|
+
|
|
1310
|
+
const { content: main, ...content } = wiki.doc;
|
|
1311
|
+
|
|
1312
|
+
const templateContext = { content: main };
|
|
1313
|
+
|
|
1314
|
+
const templateDir = context.templateCommonDir;
|
|
1315
|
+
const template = nunjucks.compile(
|
|
1316
|
+
fs.readFileSync(path.resolve(templateDir, `${fileBase}.njk`), "utf8"),
|
|
1317
|
+
nunjucks.configure(templateDir)
|
|
1318
|
+
);
|
|
1319
|
+
|
|
1320
|
+
const templateRender = template.render(templateContext);
|
|
1321
|
+
|
|
1322
|
+
const projectDir = context.projectDir;
|
|
1323
|
+
const filePath = path.resolve(projectDir, `${fileBase}`);
|
|
1324
|
+
fs.writeFileSync(filePath, templateRender, 'utf8');
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
|
|
1328
|
+
async function formatFiles({ setProgress, context }) {
|
|
1329
|
+
|
|
1330
|
+
const projectDir = context.projectDir;
|
|
1331
|
+
|
|
1332
|
+
await setProgress({ message: "Prettifiying source files." });
|
|
1333
|
+
|
|
1334
|
+
let srcDir = path$1.join("src","**", "*");
|
|
1335
|
+
|
|
1336
|
+
await fnetShellFlow({
|
|
1337
|
+
commands: {
|
|
1338
|
+
steps: [`prettier --write ${srcDir} *.{js,cjs,mjs,json,yaml,html} --no-error-on-unmatched-pattern`],
|
|
1339
|
+
wdir: projectDir,
|
|
1340
|
+
}
|
|
1341
|
+
});
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
async function createDts({ atom, setProgress, context }) {
|
|
1345
|
+
|
|
1346
|
+
if(!atom.doc.features.dts_enabled) return;
|
|
1347
|
+
|
|
1348
|
+
const projectDir = context.projectDir;
|
|
1349
|
+
|
|
1350
|
+
await setProgress({ message: "Creating .d.ts" });
|
|
1351
|
+
const result = await fnetShellJs(`tsc`, { cwd: projectDir });
|
|
1352
|
+
if (result.code !== 0) throw new Error('Couldnt create .d.ts files.');
|
|
1353
|
+
}
|
|
1354
|
+
|
|
1355
|
+
var which = (binName) => {
|
|
1356
|
+
const pathEnv = process.env.PATH || '';
|
|
1357
|
+
const pathExt = process.platform === 'win32'
|
|
1358
|
+
? (process.env.PATHEXT || '.EXE;.CMD;.BAT;.COM').split(';')
|
|
1359
|
+
: [''];
|
|
1360
|
+
|
|
1361
|
+
const paths = pathEnv.split(delimiter);
|
|
1362
|
+
|
|
1363
|
+
for (const dir of paths) {
|
|
1364
|
+
for (const ext of pathExt) {
|
|
1365
|
+
const fullPath = join(dir, process.platform === 'win32' ? binName + ext : binName);
|
|
1366
|
+
if (existsSync(fullPath)) {
|
|
1367
|
+
return fullPath;
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
|
|
1372
|
+
return null;
|
|
1373
|
+
};
|
|
1374
|
+
|
|
1375
|
+
async function installNpmPackages({ setProgress, atom, context }) {
|
|
1376
|
+
|
|
1377
|
+
const projectDir = context.projectDir;
|
|
1378
|
+
|
|
1379
|
+
await setProgress({ message: "Installing npm packages." });
|
|
1380
|
+
const packageManager = which('bun') ? 'bun' : 'npm';
|
|
1381
|
+
const result = await fnetShellJs(`${packageManager} install ${atom.doc.features.npm_install_flags}`, { cwd: projectDir });
|
|
1382
|
+
if (result.code !== 0) throw new Error('Couldnt install npm packages.');
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
async function installPythonPackages(args) {
|
|
1386
|
+
|
|
1387
|
+
const { setProgress, atom, context } = args;
|
|
1388
|
+
|
|
1389
|
+
setProgress({ message: 'Installing Python packages' });
|
|
1390
|
+
|
|
1391
|
+
const projectDir = context.projectDir;
|
|
1392
|
+
|
|
1393
|
+
const parserEnv = await fnetAutoCondaEnv({
|
|
1394
|
+
pythonVersion: "3.12",
|
|
1395
|
+
packages: [{ package: "fnet-import-parser", version: "0.1.9" }]
|
|
1396
|
+
});
|
|
1397
|
+
|
|
1398
|
+
const { errors, result } = await parserEnv.runBin('fnet_import_parser', [
|
|
1399
|
+
"--entry_file", path.join(projectDir, 'src', 'default', 'index.py')
|
|
1400
|
+
], { captureName: 'result' });
|
|
1401
|
+
|
|
1402
|
+
if (errors) throw new Error(errors.format());
|
|
1403
|
+
|
|
1404
|
+
const parsedImports = JSON.parse(result.items[0].stdout);
|
|
1405
|
+
const detectedDependencies = parsedImports.required['third-party']?.map(pkg => {
|
|
1406
|
+
return {
|
|
1407
|
+
package: pkg.metadata?.package || pkg.path,
|
|
1408
|
+
version: pkg.metadata?.version || undefined,
|
|
1409
|
+
channel: pkg.metadata?.channel || undefined
|
|
1410
|
+
}
|
|
1411
|
+
}) || [];
|
|
1412
|
+
|
|
1413
|
+
// console.log(detectedDependencies);
|
|
1414
|
+
|
|
1415
|
+
const userDependencies = atom.doc.dependencies || [];
|
|
1416
|
+
|
|
1417
|
+
// expand userDependencies with detectedDependencies if not already present
|
|
1418
|
+
for (const dep of detectedDependencies) {
|
|
1419
|
+
if (!userDependencies.some(userDep => userDep.package === dep.package)) {
|
|
1420
|
+
userDependencies.push(dep);
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
|
|
1424
|
+
// project workspace
|
|
1425
|
+
const condaDir = path.join(projectDir, '.conda');
|
|
1426
|
+
|
|
1427
|
+
const pythonEnv = await fnetAutoCondaEnv({
|
|
1428
|
+
// name: atom.doc.name,
|
|
1429
|
+
envDir: condaDir,
|
|
1430
|
+
pythonVersion: atom.doc.features.runtime.version || "3.12",
|
|
1431
|
+
packages: userDependencies
|
|
1432
|
+
});
|
|
1433
|
+
|
|
1434
|
+
context.pythonEnv = pythonEnv;
|
|
1435
|
+
|
|
1436
|
+
args.packageDependencies = userDependencies;
|
|
1437
|
+
|
|
1438
|
+
// TODO: move to a separate plugin
|
|
1439
|
+
const dirs = atom.doc.features.render?.dirs || [];
|
|
1440
|
+
|
|
1441
|
+
for (const dir of dirs) {
|
|
1442
|
+
dir.dir = path.resolve(projectDir, dir.dir);
|
|
1443
|
+
dir.outDir = path.resolve(projectDir, dir.outDir);
|
|
1444
|
+
await fnetRender(dir);
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
// TODO: move to a separate plugin
|
|
1448
|
+
let tmplCtx = { params: {} };
|
|
1449
|
+
tmplCtx.params.package_name = atom.doc.name;
|
|
1450
|
+
tmplCtx.params.version = "0.1.0";
|
|
1451
|
+
tmplCtx.params.bin_name = atom.doc.name;
|
|
1452
|
+
tmplCtx.params.python_requires = atom.doc.features.runtime.version || ">=3.12";
|
|
1453
|
+
tmplCtx.params.dependencies = userDependencies;
|
|
1454
|
+
tmplCtx.params.scripts = JSON.stringify({
|
|
1455
|
+
"cli": `PYTHONPATH='${path.join('src')}' '${path.relative(context.projectDir, pythonEnv.pythonBin)}' '${path.join('src', 'cli', 'index.py')}'`
|
|
1456
|
+
});
|
|
1457
|
+
|
|
1458
|
+
await fnetRender({
|
|
1459
|
+
pattern: ["setup.py.njk", "package.json.njk", "pyproject.toml.njk"],
|
|
1460
|
+
dir: context.templateDir,
|
|
1461
|
+
outDir: context.projectDir,
|
|
1462
|
+
context: tmplCtx,
|
|
1463
|
+
});
|
|
1464
|
+
|
|
1465
|
+
// await pythonEnv.runPip(["install", "-e", '.'], { wdir: context.projectDir });
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
async function runNpmBuild({ setProgress, context }) {
|
|
1469
|
+
|
|
1470
|
+
const projectDir = context.projectDir;
|
|
1471
|
+
|
|
1472
|
+
await setProgress({ message: "Building main project." });
|
|
1473
|
+
const result = await fnetShellJs(`npm run build`, { cwd: projectDir });
|
|
1474
|
+
if (result.code !== 0) throw new Error('Couldnt build project.');
|
|
1475
|
+
}
|
|
1476
|
+
|
|
1477
|
+
var deployTo = async (apiContext) => {
|
|
1478
|
+
|
|
1479
|
+
// Destructure the apiContext to get needed variables
|
|
1480
|
+
const {
|
|
1481
|
+
atom,
|
|
1482
|
+
packageDependencies,
|
|
1483
|
+
context,
|
|
1484
|
+
deploymentProjectTarget,
|
|
1485
|
+
setProgress,
|
|
1486
|
+
deploymentProject,
|
|
1487
|
+
yamlTarget
|
|
1488
|
+
} = apiContext;
|
|
1489
|
+
|
|
1490
|
+
// Early exit if the target is not enabled
|
|
1491
|
+
if (deploymentProjectTarget.enabled !== true) return;
|
|
1492
|
+
|
|
1493
|
+
const type = deploymentProjectTarget.type;
|
|
1494
|
+
|
|
1495
|
+
try {
|
|
1496
|
+
// Handle the first set of deployment types
|
|
1497
|
+
if (type === "lib") {
|
|
1498
|
+
await (await import('./index.f798DPwo.js')).default({ ...apiContext });
|
|
1499
|
+
} else if (type === "red") {
|
|
1500
|
+
await (await import('./index.CX8eMqfH.js')).default({ ...apiContext });
|
|
1501
|
+
} else if (type === "npm") {
|
|
1502
|
+
await (await import('./index.BNSTS5o6.js')).default({ ...apiContext });
|
|
1503
|
+
} else if (type === "gcs") {
|
|
1504
|
+
await (await import('./index.BMsD46br.js')).default({ ...apiContext });
|
|
1505
|
+
} else if (type === "gitlab") {
|
|
1506
|
+
await (await import('./index.Dd0lngp8.js')).default({ ...apiContext });
|
|
1507
|
+
} else if (type === "fnet-package") {
|
|
1508
|
+
await (await import('./index.C9zKEF61.js')).default({ ...apiContext });
|
|
1509
|
+
} else if (type === "fnet-form") {
|
|
1510
|
+
await (await import('./index.BUhoGq-h.js')).default({ ...apiContext });
|
|
1511
|
+
} else if (type === "fnet-node") {
|
|
1512
|
+
await (await import('./index.B6WHm9H0.js')).default({ ...apiContext });
|
|
1513
|
+
} else if (type === "fnet-flow") {
|
|
1514
|
+
await (await import('./index.D61MduW1.js')).default({ ...apiContext });
|
|
1515
|
+
}
|
|
1516
|
+
// Handle the second set of deployment types
|
|
1517
|
+
else if (type === 'nextjs') {
|
|
1518
|
+
await (await import('./index.DqwVukIB.js')).default({
|
|
1519
|
+
atom,
|
|
1520
|
+
target: deploymentProjectTarget,
|
|
1521
|
+
onProgress: setProgress,
|
|
1522
|
+
projectDir: context.projectDir,
|
|
1523
|
+
dependencies: packageDependencies,
|
|
1524
|
+
context,
|
|
1525
|
+
yamlTarget
|
|
1526
|
+
});
|
|
1527
|
+
deploymentProject.isDirty = true;
|
|
1528
|
+
} else if (type === 'webos') {
|
|
1529
|
+
await (await import('./index.MWHLt6g3.js')).default({
|
|
1530
|
+
atom,
|
|
1531
|
+
target: deploymentProjectTarget,
|
|
1532
|
+
onProgress: setProgress,
|
|
1533
|
+
projectDir: context.projectDir,
|
|
1534
|
+
dependencies: packageDependencies,
|
|
1535
|
+
context,
|
|
1536
|
+
yamlTarget
|
|
1537
|
+
});
|
|
1538
|
+
deploymentProject.isDirty = true;
|
|
1539
|
+
} else if (type === 'electron') {
|
|
1540
|
+
await (await import('./index.CQNYMi1Z.js')).default({
|
|
1541
|
+
atom,
|
|
1542
|
+
target: deploymentProjectTarget,
|
|
1543
|
+
onProgress: setProgress,
|
|
1544
|
+
projectDir: context.projectDir,
|
|
1545
|
+
dependencies: packageDependencies,
|
|
1546
|
+
context,
|
|
1547
|
+
yamlTarget
|
|
1548
|
+
});
|
|
1549
|
+
deploymentProject.isDirty = true;
|
|
1550
|
+
} else if (type === 'docker') {
|
|
1551
|
+
await (await import('./index.B5vpZn1Z.js')).default({
|
|
1552
|
+
atom,
|
|
1553
|
+
target: deploymentProjectTarget,
|
|
1554
|
+
onProgress: setProgress,
|
|
1555
|
+
projectDir: context.projectDir,
|
|
1556
|
+
dependencies: packageDependencies,
|
|
1557
|
+
context,
|
|
1558
|
+
yamlTarget
|
|
1559
|
+
});
|
|
1560
|
+
deploymentProject.isDirty = true;
|
|
1561
|
+
} else if (type === 'ios') {
|
|
1562
|
+
await (await import('./index.D2kFuxXo.js')).default({
|
|
1563
|
+
atom,
|
|
1564
|
+
target: deploymentProjectTarget,
|
|
1565
|
+
onProgress: setProgress,
|
|
1566
|
+
projectDir: context.projectDir,
|
|
1567
|
+
dependencies: packageDependencies,
|
|
1568
|
+
context,
|
|
1569
|
+
yamlTarget
|
|
1570
|
+
});
|
|
1571
|
+
deploymentProject.isDirty = true;
|
|
1572
|
+
} else if (type === 'macos') {
|
|
1573
|
+
await (await import('./index.Ce8sTnt_.js')).default({
|
|
1574
|
+
atom,
|
|
1575
|
+
target: deploymentProjectTarget,
|
|
1576
|
+
onProgress: setProgress,
|
|
1577
|
+
projectDir: context.projectDir,
|
|
1578
|
+
dependencies: packageDependencies,
|
|
1579
|
+
context,
|
|
1580
|
+
yamlTarget
|
|
1581
|
+
});
|
|
1582
|
+
deploymentProject.isDirty = true;
|
|
1583
|
+
} else if (type === 'rust') {
|
|
1584
|
+
await (await import('./index.BjzEMdm1.js')).default({
|
|
1585
|
+
atom,
|
|
1586
|
+
target: deploymentProjectTarget,
|
|
1587
|
+
onProgress: setProgress,
|
|
1588
|
+
projectDir: context.projectDir,
|
|
1589
|
+
dependencies: packageDependencies,
|
|
1590
|
+
context,
|
|
1591
|
+
yamlTarget
|
|
1592
|
+
});
|
|
1593
|
+
deploymentProject.isDirty = true;
|
|
1594
|
+
} else if (type === 'pypi') {
|
|
1595
|
+
await (await import('./index.j5JP-zGw.js')).default({
|
|
1596
|
+
atom,
|
|
1597
|
+
target: deploymentProjectTarget,
|
|
1598
|
+
onProgress: setProgress,
|
|
1599
|
+
projectDir: context.projectDir,
|
|
1600
|
+
dependencies: packageDependencies,
|
|
1601
|
+
context,
|
|
1602
|
+
yamlTarget
|
|
1603
|
+
});
|
|
1604
|
+
deploymentProject.isDirty = true;
|
|
1605
|
+
} else {
|
|
1606
|
+
console.warn(`No deployer found for type: ${type}`);
|
|
1607
|
+
return;
|
|
1608
|
+
}
|
|
1609
|
+
} catch (error) {
|
|
1610
|
+
// Add error handling for require failures or execution errors
|
|
1611
|
+
console.error(`Error during deployment for type "${type}":`, error);
|
|
1612
|
+
// Re-throw the error or handle it as appropriate for your application
|
|
1613
|
+
throw error;
|
|
1614
|
+
}
|
|
1615
|
+
};
|
|
1616
|
+
|
|
1617
|
+
class Builder {
|
|
1618
|
+
|
|
1619
|
+
#auth;
|
|
1620
|
+
#context;
|
|
1621
|
+
#atom;
|
|
1622
|
+
#njEnv;
|
|
1623
|
+
#libs;
|
|
1624
|
+
#packageDependencies;
|
|
1625
|
+
#packageDevDependencies;
|
|
1626
|
+
#atomAccessToken;
|
|
1627
|
+
#buildId;
|
|
1628
|
+
#buildKey;
|
|
1629
|
+
#protocol;
|
|
1630
|
+
#atomConfig;
|
|
1631
|
+
|
|
1632
|
+
#mode;
|
|
1633
|
+
#fileMode;
|
|
1634
|
+
#buildMode;
|
|
1635
|
+
#deployMode;
|
|
1636
|
+
#apiContext;
|
|
1637
|
+
|
|
1638
|
+
constructor(context) {
|
|
1639
|
+
this.#auth = new Auth();
|
|
1640
|
+
this.#context = context;
|
|
1641
|
+
this.#packageDependencies = [];
|
|
1642
|
+
this.#packageDevDependencies = [];
|
|
1643
|
+
|
|
1644
|
+
this._expire_ttl = 3600; // 1-hour
|
|
1645
|
+
this._expire_ttl_short = 300; // 5-minutes
|
|
1646
|
+
|
|
1647
|
+
this.#apiContext = {
|
|
1648
|
+
packageDependencies: this.#packageDependencies,
|
|
1649
|
+
packageDevDependencies: this.#packageDevDependencies,
|
|
1650
|
+
setProgress: this.setProgress.bind(this),
|
|
1651
|
+
context: this.#context,
|
|
1652
|
+
Atom,
|
|
1653
|
+
registerToPackageManager: this.registerToPackageManager.bind(this)
|
|
1654
|
+
};
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
async _cache_set(key, value, expire_ttl) {
|
|
1658
|
+
if (!this._redis_client) return;
|
|
1659
|
+
|
|
1660
|
+
await this._redis_client.SETEX(
|
|
1661
|
+
key,
|
|
1662
|
+
expire_ttl || this._expire_ttl,
|
|
1663
|
+
JSON.stringify(value),
|
|
1664
|
+
).catch(console.error);
|
|
1665
|
+
}
|
|
1666
|
+
|
|
1667
|
+
|
|
1668
|
+
|
|
1669
|
+
async initAuth() {
|
|
1670
|
+
if (!this.#context.id) return;
|
|
1671
|
+
this.#atomAccessToken = await this.#auth.init({ config: this.#atomConfig });
|
|
1672
|
+
this.#apiContext.atomAccessToken = this.#atomAccessToken;
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
async initLibrary() {
|
|
1676
|
+
const libraryId = this.#context.id;
|
|
1677
|
+
this.#atom = this.#context.project?.libraryAtom || await Atom.get({ id: libraryId });
|
|
1678
|
+
let bundleName = this.#atom.doc.bundleName;
|
|
1679
|
+
bundleName = bundleName || (this.#atom.doc.name || "").toUpperCase().replace(/[^A-Z0-9]/g, "_");
|
|
1680
|
+
this.#atom.doc.bundleName = bundleName;
|
|
1681
|
+
this.#atom.type = this.#atom.type || "workflow.lib";
|
|
1682
|
+
this.#apiContext.atom = this.#atom;
|
|
1683
|
+
}
|
|
1684
|
+
|
|
1685
|
+
async initLibraryDir() {
|
|
1686
|
+
|
|
1687
|
+
this.setProgress({ message: "Initializing library directory." });
|
|
1688
|
+
|
|
1689
|
+
const projectDir = this.#context.projectDir;
|
|
1690
|
+
|
|
1691
|
+
this.setProgress({ message: "Cleaning project directory." });
|
|
1692
|
+
|
|
1693
|
+
const assets = fnetListFiles({ dir: projectDir, ignore: ['.cache', 'node_modules', '.conda'], absolute: true });
|
|
1694
|
+
for (const asset of assets) {
|
|
1695
|
+
fs.rmSync(asset, { recursive: true, force: true });
|
|
1696
|
+
}
|
|
1697
|
+
|
|
1698
|
+
this.setProgress({ message: "Creating project directory." });
|
|
1699
|
+
|
|
1700
|
+
// .
|
|
1701
|
+
let target = projectDir;
|
|
1702
|
+
if (!fs.existsSync(target)) {
|
|
1703
|
+
fs.mkdirSync(target, { recursive: true });
|
|
1704
|
+
}
|
|
1705
|
+
|
|
1706
|
+
// src
|
|
1707
|
+
target = path.join(projectDir, "src");
|
|
1708
|
+
|
|
1709
|
+
if (!fs.existsSync(target)) {
|
|
1710
|
+
fs.mkdirSync(target, { recursive: true });
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
// default
|
|
1714
|
+
target = path.join(projectDir, "src", "default");
|
|
1715
|
+
if (!fs.existsSync()) {
|
|
1716
|
+
fs.mkdirSync(target, { recursive: true });
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1720
|
+
|
|
1721
|
+
async initLibraryDirPython() {
|
|
1722
|
+
this.setProgress({ message: "Initializing library directory." });
|
|
1723
|
+
|
|
1724
|
+
const projectDir = this.#context.projectDir;
|
|
1725
|
+
|
|
1726
|
+
this.setProgress({ message: "Cleaning project directory." });
|
|
1727
|
+
|
|
1728
|
+
const assets = fnetListFiles({ dir: projectDir, ignore: ['.cache', 'node_modules', '.conda'], absolute: true });
|
|
1729
|
+
for (const asset of assets) {
|
|
1730
|
+
fs.rmSync(asset, { recursive: true, force: true });
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
this.setProgress({ message: "Creating project directory." });
|
|
1734
|
+
|
|
1735
|
+
let target = projectDir;
|
|
1736
|
+
if (!fs.existsSync(target)) {
|
|
1737
|
+
fs.mkdirSync(target, { recursive: true });
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1740
|
+
target = path.join(projectDir, 'src');
|
|
1741
|
+
if (!fs.existsSync(target)) {
|
|
1742
|
+
fs.mkdirSync(target, { recursive: true });
|
|
1743
|
+
}
|
|
1744
|
+
|
|
1745
|
+
target = path.join(projectDir, 'src', 'default');
|
|
1746
|
+
const source = this.#context.projectSrcDir;
|
|
1747
|
+
|
|
1748
|
+
if (!fs.existsSync(target)) {
|
|
1749
|
+
try {
|
|
1750
|
+
if (os.platform() === 'win32') {
|
|
1751
|
+
// Windows requires special handling
|
|
1752
|
+
fs.symlinkSync(source, target, 'junction');
|
|
1753
|
+
} else {
|
|
1754
|
+
// For Unix-like systems
|
|
1755
|
+
fs.symlinkSync(source, target, 'dir');
|
|
1756
|
+
}
|
|
1757
|
+
} catch (err) {
|
|
1758
|
+
throw new Error(`Couldn't create symlink. Error: ${err.message}`);
|
|
1759
|
+
}
|
|
1760
|
+
}
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
async initNunjucks() {
|
|
1764
|
+
this.setProgress({ message: "Initializing nunjucks." });
|
|
1765
|
+
|
|
1766
|
+
const templateDir = this.#context.templateDir;
|
|
1767
|
+
this.#njEnv = nunjucks.configure(templateDir, { watch: false, dev: true });
|
|
1768
|
+
this.#apiContext.njEnv = this.#njEnv;
|
|
1769
|
+
}
|
|
1770
|
+
|
|
1771
|
+
async initLibs() {
|
|
1772
|
+
|
|
1773
|
+
this.setProgress({ message: "Initializing external libs." });
|
|
1774
|
+
|
|
1775
|
+
const libs = [{
|
|
1776
|
+
name: this.#atom.doc.name,
|
|
1777
|
+
type: "atom",
|
|
1778
|
+
parent_id: this.#atom.parent_id
|
|
1779
|
+
}];
|
|
1780
|
+
|
|
1781
|
+
this.#libs = libs;
|
|
1782
|
+
|
|
1783
|
+
await this.initAtomLibsAndDeps({ libs, packageDependencies: this.#packageDependencies });
|
|
1784
|
+
}
|
|
1785
|
+
|
|
1786
|
+
async initLibsPython() {
|
|
1787
|
+
|
|
1788
|
+
this.setProgress({ message: "Initializing external libs." });
|
|
1789
|
+
|
|
1790
|
+
const atom = this.#atom;
|
|
1791
|
+
atom.protocol = "local:";
|
|
1792
|
+
atom.doc.dependencies = atom.doc.dependencies || [];
|
|
1793
|
+
atom.name = atom.doc.name;
|
|
1794
|
+
|
|
1795
|
+
const libs = [{
|
|
1796
|
+
name: this.#atom.doc.name,
|
|
1797
|
+
type: "atom",
|
|
1798
|
+
parent_id: this.#atom.parent_id,
|
|
1799
|
+
atom
|
|
1800
|
+
}];
|
|
1801
|
+
|
|
1802
|
+
this.#libs = libs;
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1805
|
+
async initAtomLibsAndDeps({ libs, packageDependencies }) {
|
|
1806
|
+
const atomLibRefs = libs.filter(w => w.type === 'atom');
|
|
1807
|
+
for (let i = 0; i < atomLibRefs.length; i++) {
|
|
1808
|
+
const atomLibRef = atomLibRefs[i];
|
|
1809
|
+
|
|
1810
|
+
const atomLib = await this.findAtomLibrary({ url: atomLibRef.name });
|
|
1811
|
+
atomLibRef.atom = atomLib;
|
|
1812
|
+
|
|
1813
|
+
const packageDeps = atomLib.doc.dependencies?.filter(w => typeof w.repo === 'undefined' || w.repo === 'npm');
|
|
1814
|
+
packageDeps?.forEach(npmDep => {
|
|
1815
|
+
const found = packageDependencies.find(w => w.package === npmDep.package);
|
|
1816
|
+
if (found) {
|
|
1817
|
+
if (typeof npmDep.path === 'string') {
|
|
1818
|
+
if (!(found.path || []).some(w => w === npmDep.path)) {
|
|
1819
|
+
found.path = found.path || [];
|
|
1820
|
+
found.path.push(npmDep.path);
|
|
1821
|
+
}
|
|
1822
|
+
}
|
|
1823
|
+
else if (Array.isArray(npmDep.path)) {
|
|
1824
|
+
npmDep.path.forEach(item => {
|
|
1825
|
+
if (!(found.path || []).some(w => w === item)) {
|
|
1826
|
+
found.path = found.path || [];
|
|
1827
|
+
found.path.push(item);
|
|
1828
|
+
}
|
|
1829
|
+
});
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
else packageDependencies.push(npmDep);
|
|
1833
|
+
});
|
|
1834
|
+
}
|
|
1835
|
+
packageDependencies.sort((a, b) => a.package?.localeCompare(b.package));
|
|
1836
|
+
}
|
|
1837
|
+
|
|
1838
|
+
async findAtomLibrary({ url }) {
|
|
1839
|
+
const parsedUrl = fnetParseNodeUrl({ url: url });
|
|
1840
|
+
if (!parsedUrl) throw new Error(`Invalid package name: ${url}`);
|
|
1841
|
+
|
|
1842
|
+
if (!parsedUrl.protocol) parsedUrl.protocol = this.#protocol;
|
|
1843
|
+
|
|
1844
|
+
if (parsedUrl.protocol === 'ac:') {
|
|
1845
|
+
const parts = parsedUrl.pathname.split('/');
|
|
1846
|
+
if (parts.length === 1) {
|
|
1847
|
+
return await Atom.first({ where: { name: url, parent_id: this.#atomConfig.env.ATOM_LIBRARIES_ID, type: "workflow.lib" } });
|
|
1848
|
+
}
|
|
1849
|
+
|
|
1850
|
+
if (parts.length === 2) {
|
|
1851
|
+
const folder = await Atom.first({ where: { name: parts[0], parent_id: this.#atomConfig.env.ATOM_LIBRARIES_ID, type: "folder" } });
|
|
1852
|
+
return await Atom.first({ where: { name: parts[1], parent_id: folder.id, type: "workflow.lib" } });
|
|
1853
|
+
}
|
|
1854
|
+
}
|
|
1855
|
+
else if (parsedUrl.protocol === 'local:') {
|
|
1856
|
+
|
|
1857
|
+
const atom = this.#atom;
|
|
1858
|
+
atom.protocol = "local:";
|
|
1859
|
+
atom.doc.dependencies = atom.doc.dependencies || [];
|
|
1860
|
+
atom.name = atom.doc.name;
|
|
1861
|
+
|
|
1862
|
+
const srcFilePath = path.resolve(this.#context.projectSrcDir, `${'index'}.js`);
|
|
1863
|
+
const parsedImports = await fnetParseImports({ file: srcFilePath, recursive: true });
|
|
1864
|
+
const dependencies = atom.doc.dependencies;
|
|
1865
|
+
const targetImports = parsedImports.all;
|
|
1866
|
+
|
|
1867
|
+
for await (const parsedImport of targetImports) {
|
|
1868
|
+
if (parsedImport.type !== 'npm') continue;
|
|
1869
|
+
|
|
1870
|
+
if (dependencies.find(w => w.package === parsedImport.package)) continue;
|
|
1871
|
+
|
|
1872
|
+
const npmVersions = await pickNpmVersions({
|
|
1873
|
+
name: parsedImport.package,
|
|
1874
|
+
projectDir: this.#context.projectDir,
|
|
1875
|
+
setProgress: this.#apiContext.setProgress
|
|
1876
|
+
});
|
|
1877
|
+
|
|
1878
|
+
dependencies.push({
|
|
1879
|
+
package: parsedImport.package,
|
|
1880
|
+
subpath: parsedImport.subpath,
|
|
1881
|
+
version: npmVersions.minorRange,
|
|
1882
|
+
type: "npm"
|
|
1883
|
+
});
|
|
1884
|
+
}
|
|
1885
|
+
|
|
1886
|
+
return atom;
|
|
1887
|
+
}
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
async createAtomLibFiles({ libs }) {
|
|
1891
|
+
await this.setProgress({ message: "Creating external lib files." });
|
|
1892
|
+
|
|
1893
|
+
this.#atom.typesDir = './types';
|
|
1894
|
+
|
|
1895
|
+
const atomLibRefs = libs.filter(w => w.type === 'atom');
|
|
1896
|
+
for (let i = 0; i < atomLibRefs.length; i++) {
|
|
1897
|
+
const atomLibRef = atomLibRefs[i];
|
|
1898
|
+
|
|
1899
|
+
const atomLib = atomLibRef.atom;
|
|
1900
|
+
const projectDir = this.#context.projectDir;
|
|
1901
|
+
if (atomLib.protocol === 'local:') {
|
|
1902
|
+
const srcFilePath = path.resolve(this.#context.projectSrcDir, `${atomLib.fileName || atomLib.name}.js`);
|
|
1903
|
+
const relativePath = path.relative(path.join(this.#context.projectDir, 'src', 'default'), srcFilePath);
|
|
1904
|
+
|
|
1905
|
+
if (!fs.existsSync(srcFilePath)) {
|
|
1906
|
+
fs.mkdirSync(path.dirname(srcFilePath), { recursive: true });
|
|
1907
|
+
let template = 'export default async (args)=>{\n';
|
|
1908
|
+
template += '}';
|
|
1909
|
+
fs.writeFileSync(srcFilePath, template, 'utf8');
|
|
1910
|
+
}
|
|
1911
|
+
|
|
1912
|
+
atomLib.relativePath = relativePath.split(path.sep).join('/');
|
|
1913
|
+
|
|
1914
|
+
this.#atom.typesDir = `./types/${path.basename(projectDir)}/src`;
|
|
1915
|
+
}
|
|
1916
|
+
else {
|
|
1917
|
+
const atomLibPath = path.join(projectDir, 'src', 'libs', `${atomLib.id}.js`);
|
|
1918
|
+
const content = atomLib.doc.contents?.find(w => w.format === 'esm') || atomLib.doc;
|
|
1919
|
+
fs.writeFileSync(atomLibPath, content.content, 'utf8');
|
|
1920
|
+
}
|
|
1921
|
+
}
|
|
1922
|
+
}
|
|
1923
|
+
|
|
1924
|
+
async createAtomLibFilesPython({ libs }) {
|
|
1925
|
+
await this.setProgress({ message: "Creating external lib files." });
|
|
1926
|
+
|
|
1927
|
+
const atomLibRefs = libs.filter(w => w.type === 'atom');
|
|
1928
|
+
for (let i = 0; i < atomLibRefs.length; i++) {
|
|
1929
|
+
const atomLibRef = atomLibRefs[i];
|
|
1930
|
+
|
|
1931
|
+
const atomLib = atomLibRef.atom;
|
|
1932
|
+
if (atomLib.protocol === 'local:') {
|
|
1933
|
+
const srcFilePath = path.resolve(this.#context.projectSrcDir, `${atomLib.fileName || atomLib.name}.py`);
|
|
1934
|
+
if (!fs.existsSync(srcFilePath)) {
|
|
1935
|
+
fs.mkdirSync(path.dirname(srcFilePath), { recursive: true });
|
|
1936
|
+
let template = 'def default():\n';
|
|
1937
|
+
template += ' print("Hello world!")\n';
|
|
1938
|
+
fs.writeFileSync(srcFilePath, template, 'utf8');
|
|
1939
|
+
}
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
|
|
1944
|
+
async createEngine() {
|
|
1945
|
+
|
|
1946
|
+
await this.setProgress({ message: "Creating engine file." });
|
|
1947
|
+
|
|
1948
|
+
const libs = this.#libs.filter(w => w.type === 'atom');
|
|
1949
|
+
|
|
1950
|
+
const templateContext = { libs, libraryAtom: this.#atom, atom: this.#atom };
|
|
1951
|
+
|
|
1952
|
+
const templateDir = this.#context.templateDir;
|
|
1953
|
+
const template = nunjucks.compile(
|
|
1954
|
+
fs.readFileSync(path.resolve(templateDir, path.join('src', 'default', 'engine.js.njk')), "utf8"),
|
|
1955
|
+
this.#njEnv
|
|
1956
|
+
);
|
|
1957
|
+
|
|
1958
|
+
const templateRender = template.render(templateContext);
|
|
1959
|
+
|
|
1960
|
+
const projectDir = this.#context.projectDir;
|
|
1961
|
+
const filePath = path.resolve(projectDir, path.join('src', 'default', 'index.js'));
|
|
1962
|
+
fs.writeFileSync(filePath, templateRender, 'utf8');
|
|
1963
|
+
}
|
|
1964
|
+
|
|
1965
|
+
async createProjectYaml() {
|
|
1966
|
+
|
|
1967
|
+
const fileBase = `node.yaml`;
|
|
1968
|
+
const message = `Creating ${fileBase}`;
|
|
1969
|
+
|
|
1970
|
+
await this.setProgress({ message: message });
|
|
1971
|
+
|
|
1972
|
+
const { content: main, ...content } = this.#atom.doc;
|
|
1973
|
+
|
|
1974
|
+
const templateContext = { content: yaml.stringify(content) };
|
|
1975
|
+
|
|
1976
|
+
const templateDir = this.#context.templateDir;
|
|
1977
|
+
const template = nunjucks.compile(
|
|
1978
|
+
fs.readFileSync(path.resolve(templateDir, `${fileBase}.njk`), "utf8"),
|
|
1979
|
+
this.#njEnv
|
|
1980
|
+
);
|
|
1981
|
+
|
|
1982
|
+
const templateRender = template.render(templateContext);
|
|
1983
|
+
|
|
1984
|
+
const projectDir = this.#context.projectDir;
|
|
1985
|
+
const filePath = path.resolve(projectDir, `${fileBase}`);
|
|
1986
|
+
fs.writeFileSync(filePath, templateRender, 'utf8');
|
|
1987
|
+
}
|
|
1988
|
+
|
|
1989
|
+
async deploy() {
|
|
1990
|
+
|
|
1991
|
+
await this.setProgress({ message: "Deploying." });
|
|
1992
|
+
|
|
1993
|
+
if (this.#context.project?.devops) {
|
|
1994
|
+
const devopsProjects = [this.#context.project?.devops];
|
|
1995
|
+
for (let i = 0; i < devopsProjects.length; i++) {
|
|
1996
|
+
let deploymentProject = devopsProjects[i];
|
|
1997
|
+
await this.deployProject({ deploymentProject });
|
|
1998
|
+
|
|
1999
|
+
if (deploymentProject.isDirty === true) {
|
|
2000
|
+
await deploymentProject.save();
|
|
2001
|
+
}
|
|
2002
|
+
}
|
|
2003
|
+
|
|
2004
|
+
}
|
|
2005
|
+
else if (this.#atom.id) {
|
|
2006
|
+
const devopsProjects = await Atom.list({ type: "library.deploy", parent_id: this.#atom.id });
|
|
2007
|
+
for (let i = 0; i < devopsProjects.length; i++) {
|
|
2008
|
+
let deploymentProject = devopsProjects[i];
|
|
2009
|
+
await this.deployProject({ deploymentProject });
|
|
2010
|
+
|
|
2011
|
+
if (deploymentProject.isDirty === true) {
|
|
2012
|
+
deploymentProject = await Atom.update(deploymentProject, { id: deploymentProject.id });
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
|
|
2018
|
+
async deployProject(context) {
|
|
2019
|
+
const { deploymentProject } = context;
|
|
2020
|
+
const { yamlDocument } = deploymentProject;
|
|
2021
|
+
|
|
2022
|
+
if (deploymentProject.doc.targets && Array.isArray(deploymentProject.doc.targets))
|
|
2023
|
+
throw new Error("Deployment project targets are deprecated. Please update targets in the yaml file.");
|
|
2024
|
+
|
|
2025
|
+
const targetKeys = Object.keys(deploymentProject.doc || {});
|
|
2026
|
+
const yamlTargets = yamlDocument || {};
|
|
2027
|
+
for (let i = 0; i < targetKeys.length; i++) {
|
|
2028
|
+
const deploymentProjectTarget = deploymentProject.doc[targetKeys[i]];
|
|
2029
|
+
deploymentProjectTarget.name = targetKeys[i];
|
|
2030
|
+
const yamlTarget = yamlTargets.get(targetKeys[i]);
|
|
2031
|
+
await deployTo({ ...this.#apiContext, deploymentProject, deploymentProjectTarget, yamlTarget });
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
|
|
2035
|
+
async registerToPackageManager(context) {
|
|
2036
|
+
const { target, packageJSON } = context;
|
|
2037
|
+
|
|
2038
|
+
if (!this.#context.id) return;
|
|
2039
|
+
|
|
2040
|
+
// update
|
|
2041
|
+
let packageAtom = await Atom.first({ name: target.params.name, parent_id: this.#atomConfig.env.ATOM_PACKAGES_ID });
|
|
2042
|
+
|
|
2043
|
+
if (!packageAtom) {
|
|
2044
|
+
// create new
|
|
2045
|
+
packageAtom = await Atom.create({
|
|
2046
|
+
parent_id: this.#atomConfig.env.ATOM_PACKAGES_ID,
|
|
2047
|
+
doc: {
|
|
2048
|
+
name: target.params.name,
|
|
2049
|
+
type: "pm",
|
|
2050
|
+
versions: [{ v: packageJSON.version }]
|
|
2051
|
+
}
|
|
2052
|
+
});
|
|
2053
|
+
}
|
|
2054
|
+
else {
|
|
2055
|
+
// update existing
|
|
2056
|
+
packageAtom.doc.versions.splice(0, 0, { v: packageJSON.version });
|
|
2057
|
+
|
|
2058
|
+
await Atom.update(packageAtom, { id: packageAtom.id });
|
|
2059
|
+
}
|
|
2060
|
+
}
|
|
2061
|
+
|
|
2062
|
+
async setProgress(args) {
|
|
2063
|
+
|
|
2064
|
+
const message = typeof args === 'string' ? args : args?.message;
|
|
2065
|
+
|
|
2066
|
+
console.log(chalk.blue(message));
|
|
2067
|
+
|
|
2068
|
+
await this._cache_set(this.#buildKey, { status: "IN_PROGRESS", message });
|
|
2069
|
+
}
|
|
2070
|
+
|
|
2071
|
+
async initNode() {
|
|
2072
|
+
await initFeatures(this.#apiContext);
|
|
2073
|
+
await initDependencies(this.#apiContext);
|
|
2074
|
+
await this.initLibraryDir();
|
|
2075
|
+
await this.initNunjucks();
|
|
2076
|
+
await this.initLibs();
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
async initPython() {
|
|
2080
|
+
await initPythonFeature(this.#apiContext);
|
|
2081
|
+
await initPythonDependencies(this.#apiContext);
|
|
2082
|
+
await this.initLibraryDirPython();
|
|
2083
|
+
await this.initNunjucks();
|
|
2084
|
+
await this.initLibsPython();
|
|
2085
|
+
}
|
|
2086
|
+
|
|
2087
|
+
async nodeBuild() {
|
|
2088
|
+
if (this.#fileMode) {
|
|
2089
|
+
await this.createAtomLibFiles({ libs: this.#libs });
|
|
2090
|
+
await this.createEngine();
|
|
2091
|
+
await this.createProjectYaml();
|
|
2092
|
+
|
|
2093
|
+
await createProjectReadme(this.#apiContext);
|
|
2094
|
+
await createTsConfig(this.#apiContext);
|
|
2095
|
+
await createGitIgnore(this.#apiContext);
|
|
2096
|
+
await createToYargs(this.#apiContext);
|
|
2097
|
+
await createCli(this.#apiContext);
|
|
2098
|
+
await createApp(this.#apiContext);
|
|
2099
|
+
await createRollup(this.#apiContext);
|
|
2100
|
+
await createPackageJson(this.#apiContext);
|
|
2101
|
+
|
|
2102
|
+
await formatFiles(this.#apiContext);
|
|
2103
|
+
|
|
2104
|
+
await createDts(this.#apiContext);
|
|
2105
|
+
|
|
2106
|
+
if (this.#buildMode) {
|
|
2107
|
+
|
|
2108
|
+
await installNpmPackages(this.#apiContext);
|
|
2109
|
+
await runNpmBuild(this.#apiContext);
|
|
2110
|
+
|
|
2111
|
+
if (this.#deployMode)
|
|
2112
|
+
await this.deploy();
|
|
2113
|
+
}
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
|
|
2117
|
+
async pythonBuild() {
|
|
2118
|
+
if (this.#fileMode) {
|
|
2119
|
+
await this.createAtomLibFilesPython({ libs: this.#libs });
|
|
2120
|
+
// await this.createEngine();
|
|
2121
|
+
await this.createProjectYaml();
|
|
2122
|
+
|
|
2123
|
+
await createProjectReadme(this.#apiContext);
|
|
2124
|
+
// await createTsConfig(this.#apiContext);
|
|
2125
|
+
await createGitIgnore(this.#apiContext);
|
|
2126
|
+
// await createToYargs(this.#apiContext);
|
|
2127
|
+
await createCliPython(this.#apiContext);
|
|
2128
|
+
// await createApp(this.#apiContext);
|
|
2129
|
+
// await createRollup(this.#apiContext);
|
|
2130
|
+
// await createPackageJson(this.#apiContext);
|
|
2131
|
+
|
|
2132
|
+
// await formatFiles(this.#apiContext);
|
|
2133
|
+
|
|
2134
|
+
// await createDts(this.#apiContext);
|
|
2135
|
+
|
|
2136
|
+
if (this.#buildMode) {
|
|
2137
|
+
await installPythonPackages(this.#apiContext);
|
|
2138
|
+
// await runNpmBuild(this.#apiContext);
|
|
2139
|
+
|
|
2140
|
+
if (this.#deployMode)
|
|
2141
|
+
await this.deploy();
|
|
2142
|
+
}
|
|
2143
|
+
}
|
|
2144
|
+
}
|
|
2145
|
+
|
|
2146
|
+
async init() {
|
|
2147
|
+
|
|
2148
|
+
this._redis_client = await createRedisClient();
|
|
2149
|
+
|
|
2150
|
+
this.#buildId = this.#context.buildId || randomUUID();
|
|
2151
|
+
this.#apiContext.buildId = this.#buildId;
|
|
2152
|
+
|
|
2153
|
+
this.#mode = this.#context.mode;
|
|
2154
|
+
this.#fileMode = ['all', 'deploy', 'build', 'file'].includes(this.#mode);
|
|
2155
|
+
this.#buildMode = ['all', 'deploy', 'build'].includes(this.#mode);
|
|
2156
|
+
this.#deployMode = ['all', 'deploy'].includes(this.#mode);
|
|
2157
|
+
|
|
2158
|
+
this.#protocol = this.#context.protocol;
|
|
2159
|
+
this.#buildKey = "BUILD:" + this.#buildId;
|
|
2160
|
+
|
|
2161
|
+
this.#atomConfig = (await fnetConfig({ optional: true, name: this.#context.atomConfig || "atom", dir: this.#context.projectDir, tags: this.#context.tags }))?.data;
|
|
2162
|
+
|
|
2163
|
+
try {
|
|
2164
|
+
await this.setProgress({ message: "Initialization started." });
|
|
2165
|
+
|
|
2166
|
+
await this.initAuth();
|
|
2167
|
+
await this.initLibrary();
|
|
2168
|
+
if (this.#atom.doc.features.runtime.type === 'node')
|
|
2169
|
+
await this.initNode();
|
|
2170
|
+
else if (this.#atom.doc.features.runtime.type === 'python')
|
|
2171
|
+
await this.initPython();
|
|
2172
|
+
}
|
|
2173
|
+
catch (error) {
|
|
2174
|
+
await this._cache_set(this.#buildKey, { status: "FAILED", message: error?.message || error });
|
|
2175
|
+
throw error;
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
|
|
2179
|
+
async build() {
|
|
2180
|
+
try {
|
|
2181
|
+
if (this.#atom.doc.features.runtime.type === 'node')
|
|
2182
|
+
await this.nodeBuild();
|
|
2183
|
+
else if (this.#atom.doc.features.runtime.type === 'python')
|
|
2184
|
+
await this.pythonBuild();
|
|
2185
|
+
|
|
2186
|
+
await this._cache_set(this.#buildKey, { status: "COMPLETED" });
|
|
2187
|
+
}
|
|
2188
|
+
catch (error) {
|
|
2189
|
+
await this._cache_set(this.#buildKey, { status: "FAILED", message: error.message || error });
|
|
2190
|
+
console.log(error);
|
|
2191
|
+
throw error;
|
|
2192
|
+
}
|
|
2193
|
+
}
|
|
2194
|
+
}
|
|
2195
|
+
|
|
2196
|
+
const __dirname$1 = path.dirname(fileURLToPath(import.meta.url));
|
|
2197
|
+
|
|
2198
|
+
function findNodeModules({ baseDir }) {
|
|
2199
|
+
|
|
2200
|
+
baseDir = baseDir || __dirname$1;
|
|
2201
|
+
|
|
2202
|
+
let currentDir = baseDir;
|
|
2203
|
+
|
|
2204
|
+
while (currentDir !== path.parse(currentDir).root) {
|
|
2205
|
+
const potentialPath = path.join(currentDir, 'node_modules');
|
|
2206
|
+
|
|
2207
|
+
if (fs.existsSync(potentialPath)) {
|
|
2208
|
+
return potentialPath;
|
|
2209
|
+
}
|
|
2210
|
+
|
|
2211
|
+
currentDir = path.dirname(currentDir);
|
|
2212
|
+
}
|
|
2213
|
+
|
|
2214
|
+
return null;
|
|
2215
|
+
}
|
|
2216
|
+
|
|
2217
|
+
var version = "0.101.0";
|
|
2218
|
+
var pkg = {
|
|
2219
|
+
version: version};
|
|
2220
|
+
|
|
2221
|
+
const __dirname = path$1.dirname(fileURLToPath(import.meta.url));
|
|
2222
|
+
const cwd = process.cwd();
|
|
2223
|
+
|
|
2224
|
+
// fnet env (Assuming this sets up environment variables based on redis config)
|
|
2225
|
+
fnetConfig({
|
|
2226
|
+
name: ["redis"],
|
|
2227
|
+
dir: cwd,
|
|
2228
|
+
optional: true
|
|
2229
|
+
});
|
|
2230
|
+
|
|
2231
|
+
const nodeModulesDir = findNodeModules({ baseDir: __dirname });
|
|
2232
|
+
const pathSeparator = process.platform === 'win32' ? ';' : ':';
|
|
2233
|
+
|
|
2234
|
+
if (nodeModulesDir)
|
|
2235
|
+
process.env.PATH = `${path$1.join(nodeModulesDir, '/.bin')}${pathSeparator}${process.env.PATH}`;
|
|
2236
|
+
|
|
2237
|
+
// --- Commander Setup ---
|
|
2238
|
+
const program = new Command();
|
|
2239
|
+
|
|
2240
|
+
program
|
|
2241
|
+
.name('fnode') // Optional: Set the name for help messages
|
|
2242
|
+
.version(pkg.version) // Set the version from package.json
|
|
2243
|
+
.description('CLI tool for FlowNet node projects');
|
|
2244
|
+
|
|
2245
|
+
// --- Create Command ---
|
|
2246
|
+
program
|
|
2247
|
+
.command('create')
|
|
2248
|
+
.description('Create flow node project')
|
|
2249
|
+
.requiredOption('-n, --name <string>', 'Project name') // Required option
|
|
2250
|
+
.addOption(new Option('-r, --runtime <type>', 'Runtime environment').choices(['node', 'python']).default('node')) // Option with choices and default
|
|
2251
|
+
.option('--vscode', 'Open project in VSCode after creation', true) // Boolean option, default true
|
|
2252
|
+
.option('--no-vscode', 'Do not open project in VSCode') // Commander automatically creates the negation
|
|
2253
|
+
.action(async (options) => { // Handler receives options object
|
|
2254
|
+
try {
|
|
2255
|
+
const templateDir = path$1.resolve(nodeModulesDir, '@fnet/cli-project-node/dist/template/project');
|
|
2256
|
+
const outDir = path$1.resolve(cwd, options.name); // Access options via options object
|
|
2257
|
+
if (!fs$1.existsSync(outDir)) fs$1.mkdirSync(outDir);
|
|
2258
|
+
|
|
2259
|
+
await fnetRender({
|
|
2260
|
+
dir: templateDir,
|
|
2261
|
+
outDir,
|
|
2262
|
+
context: {
|
|
2263
|
+
name: options.name,
|
|
2264
|
+
runtime: options.runtime,
|
|
2265
|
+
platform: os$1.platform(),
|
|
2266
|
+
},
|
|
2267
|
+
copyUnmatchedAlso: true
|
|
2268
|
+
});
|
|
2269
|
+
|
|
2270
|
+
let shellResult = await fnetShellJs(`fnode build`, { cwd: outDir });
|
|
2271
|
+
if (shellResult.code !== 0) throw new Error('Failed to build project.');
|
|
2272
|
+
|
|
2273
|
+
if (which('git')) {
|
|
2274
|
+
shellResult = await fnetShellJs(`git init --initial-branch=main`, { cwd: outDir });
|
|
2275
|
+
if (shellResult.code !== 0) throw new Error('Failed to initialize git.');
|
|
2276
|
+
}
|
|
2277
|
+
|
|
2278
|
+
// Check the boolean flag correctly
|
|
2279
|
+
if (options.vscode && which('code')) {
|
|
2280
|
+
shellResult = await fnetShellJs(`cd ${outDir} && code .`);
|
|
2281
|
+
if (shellResult.code !== 0) throw new Error('Failed to open vscode.');
|
|
2282
|
+
}
|
|
2283
|
+
|
|
2284
|
+
console.log('Creating project succeeded!');
|
|
2285
|
+
process.exit(0);
|
|
2286
|
+
} catch (error) {
|
|
2287
|
+
console.error('Initialization failed!', error.message);
|
|
2288
|
+
process.exit(1);
|
|
2289
|
+
}
|
|
2290
|
+
});
|
|
2291
|
+
|
|
2292
|
+
// --- Project Command ---
|
|
2293
|
+
program
|
|
2294
|
+
.command('project')
|
|
2295
|
+
.description('Flow node project operations')
|
|
2296
|
+
.option('-u, --update', 'Update project files from template', false) // Boolean option, default false
|
|
2297
|
+
.action(async (options) => {
|
|
2298
|
+
try {
|
|
2299
|
+
const templateDir = path$1.resolve(nodeModulesDir, '@fnet/cli-project-node/dist/template/project');
|
|
2300
|
+
const outDir = process.cwd();
|
|
2301
|
+
|
|
2302
|
+
// Pass options to createContext
|
|
2303
|
+
const context = await createContext(options);
|
|
2304
|
+
|
|
2305
|
+
if (options.update) {
|
|
2306
|
+
await fnetRender({
|
|
2307
|
+
dir: templateDir,
|
|
2308
|
+
outDir,
|
|
2309
|
+
context: {
|
|
2310
|
+
name: context.project.projectFileParsed.name,
|
|
2311
|
+
runtime: context.project.runtime.type,
|
|
2312
|
+
platform: os$1.platform(),
|
|
2313
|
+
},
|
|
2314
|
+
copyUnmatchedAlso: true
|
|
2315
|
+
});
|
|
2316
|
+
|
|
2317
|
+
let shellResult = await fnetShellJs(`fnode build`, { cwd: outDir });
|
|
2318
|
+
if (shellResult.code !== 0) throw new Error('Failed to build project.');
|
|
2319
|
+
|
|
2320
|
+
console.log('Updating project succeeded!');
|
|
2321
|
+
} else {
|
|
2322
|
+
console.log("Use 'fnode project --update' to update project files."); // Inform user if no action taken
|
|
2323
|
+
}
|
|
2324
|
+
|
|
2325
|
+
|
|
2326
|
+
process.exit(0);
|
|
2327
|
+
} catch (error) {
|
|
2328
|
+
console.error('Project command failed.', error.message);
|
|
2329
|
+
process.exit(1);
|
|
2330
|
+
}
|
|
2331
|
+
});
|
|
2332
|
+
|
|
2333
|
+
// --- Build Command ---
|
|
2334
|
+
program
|
|
2335
|
+
.command('build')
|
|
2336
|
+
.description('Build flow node project')
|
|
2337
|
+
.option('--id <string>', 'Build identifier')
|
|
2338
|
+
.option('--buildId <string>', 'Specific build ID (alias: bid)') // Alias needs manual handling if desired, or just use long form
|
|
2339
|
+
.addOption(new Option('--mode <mode>', 'Build mode').choices(['all', 'file', 'build', 'deploy', 'bpmn']).default('build'))
|
|
2340
|
+
.option('--ftag <tags...>', 'Filter tags (specify multiple times or space-separated)') // Array option
|
|
2341
|
+
.action(async (options) => {
|
|
2342
|
+
try {
|
|
2343
|
+
// Pass options to createContext
|
|
2344
|
+
const context = await createContext(options);
|
|
2345
|
+
const builder = new Builder(context);
|
|
2346
|
+
await builder.init();
|
|
2347
|
+
await builder.build();
|
|
2348
|
+
|
|
2349
|
+
console.log('Building library succeeded!');
|
|
2350
|
+
process.exit(0);
|
|
2351
|
+
} catch (error) {
|
|
2352
|
+
console.error('Building library failed!', error.message);
|
|
2353
|
+
process.exit(1);
|
|
2354
|
+
}
|
|
2355
|
+
});
|
|
2356
|
+
|
|
2357
|
+
|
|
2358
|
+
// --- Deploy Command ---
|
|
2359
|
+
program
|
|
2360
|
+
.command('deploy')
|
|
2361
|
+
.description('Build and deploy flow node project')
|
|
2362
|
+
.option('--id <string>', 'Build identifier')
|
|
2363
|
+
.option('--buildId <string>', 'Specific build ID')
|
|
2364
|
+
.option('--ftag <tags...>', 'Filter tags')
|
|
2365
|
+
.action(async (options) => {
|
|
2366
|
+
try {
|
|
2367
|
+
// Pass options to createContext, overriding mode
|
|
2368
|
+
const context = await createContext({ ...options, mode: "all" });
|
|
2369
|
+
const builder = new Builder(context);
|
|
2370
|
+
await builder.init();
|
|
2371
|
+
await builder.build();
|
|
2372
|
+
|
|
2373
|
+
console.log('Building and deploying library succeeded!'); // Message updated
|
|
2374
|
+
process.exit(0);
|
|
2375
|
+
} catch (error) {
|
|
2376
|
+
console.error('Building/deploying library failed!', error.message);
|
|
2377
|
+
process.exit(1);
|
|
2378
|
+
}
|
|
2379
|
+
});
|
|
2380
|
+
|
|
2381
|
+
|
|
2382
|
+
// --- File Command ---
|
|
2383
|
+
program
|
|
2384
|
+
.command('file')
|
|
2385
|
+
.description('Just create files (part of build process)')
|
|
2386
|
+
.option('--id <string>', 'Build identifier')
|
|
2387
|
+
.option('--buildId <string>', 'Specific build ID')
|
|
2388
|
+
.option('--ftag <tags...>', 'Filter tags')
|
|
2389
|
+
.action(async (options) => {
|
|
2390
|
+
try {
|
|
2391
|
+
// Pass options to createContext, overriding mode
|
|
2392
|
+
const context = await createContext({ ...options, mode: "file" });
|
|
2393
|
+
const builder = new Builder(context);
|
|
2394
|
+
await builder.init();
|
|
2395
|
+
await builder.build();
|
|
2396
|
+
|
|
2397
|
+
console.log('Creating files succeeded!'); // Message updated
|
|
2398
|
+
process.exit(0);
|
|
2399
|
+
} catch (error) {
|
|
2400
|
+
console.error('Creating files failed!', error.message);
|
|
2401
|
+
process.exit(1);
|
|
2402
|
+
}
|
|
2403
|
+
});
|
|
2404
|
+
|
|
2405
|
+
|
|
2406
|
+
// --- Input Command ---
|
|
2407
|
+
program
|
|
2408
|
+
.command('input')
|
|
2409
|
+
.description('Create or modify an input config file')
|
|
2410
|
+
.argument('[name]', 'Optional input configuration name (e.g., dev, prod)') // Positional argument
|
|
2411
|
+
.action(async (name, options) => { // Handler receives positional args first, then options
|
|
2412
|
+
try {
|
|
2413
|
+
// Pass options and name to createContext
|
|
2414
|
+
const context = await createContext({ ...options, name }); // Include name if needed by createContext
|
|
2415
|
+
const { project } = context;
|
|
2416
|
+
const { projectDir, projectFileParsed } = project;
|
|
2417
|
+
const schema = projectFileParsed.input;
|
|
2418
|
+
if (!schema) throw new Error('Config schema not found in project file.');
|
|
2419
|
+
|
|
2420
|
+
let configName = name; // Use the positional argument
|
|
2421
|
+
if (!configName) {
|
|
2422
|
+
const answers = await prompt({ type: 'input', name: 'inputName', message: 'Input name:', initial: 'dev' });
|
|
2423
|
+
configName = answers.inputName;
|
|
2424
|
+
}
|
|
2425
|
+
|
|
2426
|
+
const dotFnetDir = path$1.resolve(projectDir, '.fnet');
|
|
2427
|
+
if (!fs$1.existsSync(dotFnetDir)) fs$1.mkdirSync(dotFnetDir);
|
|
2428
|
+
|
|
2429
|
+
const configFilePath = path$1.resolve(dotFnetDir, `${configName}.fnet`);
|
|
2430
|
+
const exists = fs$1.existsSync(configFilePath);
|
|
2431
|
+
|
|
2432
|
+
const result = await fnetObjectFromSchema({ schema, format: "yaml", ref: exists ? configFilePath : undefined });
|
|
2433
|
+
fs$1.writeFileSync(configFilePath, result);
|
|
2434
|
+
console.log(`Input config '${configName}.fnet' ${exists ? 'updated' : 'created'}.`);
|
|
2435
|
+
} catch (error) {
|
|
2436
|
+
console.error(error.message);
|
|
2437
|
+
process.exit(1);
|
|
2438
|
+
}
|
|
2439
|
+
});
|
|
2440
|
+
|
|
2441
|
+
// --- Helper function for simple pass-through commands ---
|
|
2442
|
+
function bindSimpleContextCommand(prog, { name, bin, preArgs = [] }) {
|
|
2443
|
+
const cmdName = name || bin;
|
|
2444
|
+
prog
|
|
2445
|
+
.command(cmdName, { isDefault: false, hidden: false }) // Explicitly define command
|
|
2446
|
+
.description(`Run ${bin} ${preArgs.join(' ')} in project context. Pass arguments after '--'.`)
|
|
2447
|
+
.argument('[command_args...]', `Arguments for ${bin}`) // Capture arguments
|
|
2448
|
+
.allowUnknownOption() // Allow options meant for the sub-process
|
|
2449
|
+
.action(async (command_args, options) => {
|
|
2450
|
+
try {
|
|
2451
|
+
// Pass command's own options (if any were defined) to createContext
|
|
2452
|
+
const context = await createContext(options);
|
|
2453
|
+
const { projectDir } = context;
|
|
2454
|
+
|
|
2455
|
+
// Use the captured arguments
|
|
2456
|
+
const rawArgs = command_args;
|
|
2457
|
+
console.log(rawArgs);
|
|
2458
|
+
|
|
2459
|
+
// Ensure bin exists? (Optional, spawn will fail anyway)
|
|
2460
|
+
// const binPath = which(bin);
|
|
2461
|
+
// if (!binPath) throw new Error(`Command not found: ${bin}`);
|
|
2462
|
+
|
|
2463
|
+
const subprocess = spawn(bin, [...preArgs, ...rawArgs], {
|
|
2464
|
+
cwd: projectDir,
|
|
2465
|
+
stdio: 'inherit',
|
|
2466
|
+
shell: true // Keep shell true for convenience, though direct execution is safer
|
|
2467
|
+
});
|
|
2468
|
+
|
|
2469
|
+
subprocess.on('close', (code) => {
|
|
2470
|
+
process.exit(code);
|
|
2471
|
+
});
|
|
2472
|
+
subprocess.on('error', (err) => {
|
|
2473
|
+
console.error(`Failed to start ${bin}:`, err);
|
|
2474
|
+
process.exit(1);
|
|
2475
|
+
});
|
|
2476
|
+
|
|
2477
|
+
} catch (error) {
|
|
2478
|
+
console.error(error.message);
|
|
2479
|
+
process.exit(1);
|
|
2480
|
+
}
|
|
2481
|
+
});
|
|
2482
|
+
}
|
|
2483
|
+
|
|
2484
|
+
|
|
2485
|
+
// --- Helper function for conda pass-through commands ---
|
|
2486
|
+
function bindCondaContextCommand(prog, { name, bin, preArgs = [] }) {
|
|
2487
|
+
const cmdName = name || bin;
|
|
2488
|
+
prog
|
|
2489
|
+
.command(cmdName, { isDefault: false, hidden: false })
|
|
2490
|
+
.description(`Run ${bin} ${preArgs.join(' ')} using project's conda env. Pass arguments after '--'.`)
|
|
2491
|
+
.argument('[command_args...]', `Arguments for ${bin}`)
|
|
2492
|
+
.allowUnknownOption()
|
|
2493
|
+
.action(async (command_args, options) => {
|
|
2494
|
+
try {
|
|
2495
|
+
const context = await createContext(options);
|
|
2496
|
+
const { projectDir } = context;
|
|
2497
|
+
|
|
2498
|
+
const binPath = path$1.join(projectDir, '.conda', 'bin', bin || name);
|
|
2499
|
+
// Basic check if conda env seems present
|
|
2500
|
+
if (!fs$1.existsSync(path$1.dirname(binPath))) {
|
|
2501
|
+
throw new Error(`Conda environment not found in ${path$1.join(projectDir, '.conda')}. Did you initialize it?`);
|
|
2502
|
+
}
|
|
2503
|
+
if (!fs$1.existsSync(binPath)) {
|
|
2504
|
+
throw new Error(`Command '${bin || name}' not found in conda environment: ${binPath}`);
|
|
2505
|
+
}
|
|
2506
|
+
|
|
2507
|
+
|
|
2508
|
+
const rawArgs = command_args; // Use captured args
|
|
2509
|
+
|
|
2510
|
+
const subprocess = spawn(binPath, [...preArgs, ...rawArgs], {
|
|
2511
|
+
cwd: projectDir,
|
|
2512
|
+
stdio: 'inherit',
|
|
2513
|
+
shell: false, // Safer to run specific binary directly
|
|
2514
|
+
env: {
|
|
2515
|
+
...process.env, // Inherit current env
|
|
2516
|
+
"PYTHONPATH": projectDir // Add projectDir to PYTHONPATH
|
|
2517
|
+
}
|
|
2518
|
+
});
|
|
2519
|
+
|
|
2520
|
+
subprocess.on('close', (code) => {
|
|
2521
|
+
process.exit(code);
|
|
2522
|
+
});
|
|
2523
|
+
subprocess.on('error', (err) => {
|
|
2524
|
+
console.error(`Failed to start ${binPath}:`, err);
|
|
2525
|
+
process.exit(1);
|
|
2526
|
+
});
|
|
2527
|
+
|
|
2528
|
+
} catch (error) {
|
|
2529
|
+
console.error(error.message);
|
|
2530
|
+
process.exit(1);
|
|
2531
|
+
}
|
|
2532
|
+
});
|
|
2533
|
+
}
|
|
2534
|
+
|
|
2535
|
+
|
|
2536
|
+
// --- Helper function for "with" command ---
|
|
2537
|
+
function bindWithContextCommand(prog, { name, preArgs = [] }) { // Added prog parameter
|
|
2538
|
+
prog
|
|
2539
|
+
.command(name)
|
|
2540
|
+
.description('Run a command with environment variables from a .fnet config file.')
|
|
2541
|
+
.argument('<config>', 'Name of the .fnet config file (without extension)')
|
|
2542
|
+
.argument('<command>', 'The command to execute')
|
|
2543
|
+
.argument('[command_args...]', 'Arguments for the command')
|
|
2544
|
+
.option('--ftag <tags...>', 'Filter tags for loading config') // Added ftag option for context creation
|
|
2545
|
+
.allowUnknownOption() // Allow options intended for the sub-process
|
|
2546
|
+
.action(async (configName, commandName, command_args, options) => { // Arguments come first
|
|
2547
|
+
try {
|
|
2548
|
+
// Pass the 'with' command's own options to createContext
|
|
2549
|
+
const context = await createContext(options);
|
|
2550
|
+
const { projectDir } = context;
|
|
2551
|
+
|
|
2552
|
+
// Load the specified .fnet config
|
|
2553
|
+
const config = await fnetConfig({
|
|
2554
|
+
name: configName,
|
|
2555
|
+
dir: projectDir,
|
|
2556
|
+
transferEnv: false, // Keep false as per original
|
|
2557
|
+
optional: true, // Keep true as per original
|
|
2558
|
+
tags: context.tags // Pass tags from context
|
|
2559
|
+
});
|
|
2560
|
+
const env = config?.data?.env || {}; // Default to empty object if not found
|
|
2561
|
+
|
|
2562
|
+
const rawArgs = command_args; // Use captured args
|
|
2563
|
+
|
|
2564
|
+
const subprocess = spawn(commandName, [...preArgs, ...rawArgs], {
|
|
2565
|
+
cwd: fs$1.existsSync(projectDir) ? projectDir : cwd, // Original logic for cwd
|
|
2566
|
+
stdio: 'inherit',
|
|
2567
|
+
shell: true, // Keep shell: true
|
|
2568
|
+
env: {
|
|
2569
|
+
...process.env, // Inherit current env
|
|
2570
|
+
...env // Override with config env
|
|
2571
|
+
}
|
|
2572
|
+
});
|
|
2573
|
+
|
|
2574
|
+
subprocess.on('close', (code) => {
|
|
2575
|
+
process.exit(code);
|
|
2576
|
+
});
|
|
2577
|
+
subprocess.on('error', (err) => {
|
|
2578
|
+
// Provide more context on error
|
|
2579
|
+
if (err.code === 'ENOENT') {
|
|
2580
|
+
console.error(`Error: Command not found: '${commandName}'. Is it installed or in your PATH?`);
|
|
2581
|
+
} else {
|
|
2582
|
+
console.error(`Failed to start command '${commandName}':`, err);
|
|
2583
|
+
}
|
|
2584
|
+
process.exit(1);
|
|
2585
|
+
});
|
|
2586
|
+
} catch (error) {
|
|
2587
|
+
console.error(error.message);
|
|
2588
|
+
process.exit(1);
|
|
2589
|
+
}
|
|
2590
|
+
});
|
|
2591
|
+
}
|
|
2592
|
+
|
|
2593
|
+
// --- Helper function for "run" command ---
|
|
2594
|
+
// Disable --version on parent command
|
|
2595
|
+
function bindRunContextCommand(prog, { name, preArgs = [] }) { // Added prog parameter
|
|
2596
|
+
prog
|
|
2597
|
+
.command(name)
|
|
2598
|
+
.description('Run a command group defined in node.yaml.')
|
|
2599
|
+
.argument('<group>', 'Name of the command group in node.yaml commands section')
|
|
2600
|
+
// .argument('[command_options...]', 'Options passed to the commands (not implemented in original)')
|
|
2601
|
+
.option('--ftag <tags...>', 'Filter tags for loading project config')
|
|
2602
|
+
.version(false) // Disable version for this command
|
|
2603
|
+
// .allowUnknownOption() // Not needed unless passing through options
|
|
2604
|
+
.action(async (groupName, options) => { // Capture positional arg 'group' as groupName
|
|
2605
|
+
try {
|
|
2606
|
+
// Pass the 'run' command's own options to createContext
|
|
2607
|
+
const context = await createContext(options);
|
|
2608
|
+
const { project } = context;
|
|
2609
|
+
const { projectFileParsed } = project;
|
|
2610
|
+
const commands = projectFileParsed.commands;
|
|
2611
|
+
if (!commands) throw new Error('`commands` section not found in project file (node.yaml).');
|
|
2612
|
+
|
|
2613
|
+
const group = commands[groupName]; // Use the captured groupName
|
|
2614
|
+
if (!group) throw new Error(`Command group '${groupName}' not found in project file.`);
|
|
2615
|
+
|
|
2616
|
+
// Execute the command flow
|
|
2617
|
+
await fnetShellFlow({ commands: group });
|
|
2618
|
+
// Success is implicit if fnetShellFlow doesn't throw
|
|
2619
|
+
process.exit(0);
|
|
2620
|
+
|
|
2621
|
+
} catch (error) {
|
|
2622
|
+
// fnetShellFlow might throw errors, catch them here
|
|
2623
|
+
console.error(`Error running command group '${groupName}':`, error.message);
|
|
2624
|
+
process.exit(1);
|
|
2625
|
+
}
|
|
2626
|
+
});
|
|
2627
|
+
}
|
|
2628
|
+
|
|
2629
|
+
// --- Bind dynamic/pass-through commands ---
|
|
2630
|
+
bindSimpleContextCommand(program, { bin: 'npm' });
|
|
2631
|
+
bindSimpleContextCommand(program, { bin: 'node' });
|
|
2632
|
+
bindSimpleContextCommand(program, { bin: 'bun' });
|
|
2633
|
+
bindSimpleContextCommand(program, { name: "serve", bin: 'npm', preArgs: ['run', 'serve'] }); // simplified preArgs for commander handling
|
|
2634
|
+
bindSimpleContextCommand(program, { name: "watch", bin: 'npm', preArgs: ['run', 'watch'] });
|
|
2635
|
+
bindSimpleContextCommand(program, { name: "app", bin: 'npm', preArgs: ['run', 'app'] });
|
|
2636
|
+
bindSimpleContextCommand(program, { name: "cli", bin: 'npm', preArgs: ['run', 'cli'] });
|
|
2637
|
+
bindSimpleContextCommand(program, { bin: 'npx' });
|
|
2638
|
+
bindSimpleContextCommand(program, { bin: 'cdk' });
|
|
2639
|
+
bindSimpleContextCommand(program, { bin: 'aws' });
|
|
2640
|
+
bindWithContextCommand(program, { name: 'with' }); // Pass program instance
|
|
2641
|
+
bindRunContextCommand(program, { name: 'run' }); // Pass program instance
|
|
2642
|
+
bindCondaContextCommand(program, { name: 'python' });
|
|
2643
|
+
bindCondaContextCommand(program, { name: 'python3' });
|
|
2644
|
+
bindCondaContextCommand(program, { name: 'pip' });
|
|
2645
|
+
bindCondaContextCommand(program, { name: 'pip3' });
|
|
2646
|
+
|
|
2647
|
+
|
|
2648
|
+
// --- createContext Function (modified to accept commander options) ---
|
|
2649
|
+
async function createContext(options) { // Accepts commander's options object
|
|
2650
|
+
// Check for options specific to build/deploy/file commands
|
|
2651
|
+
if (options.id) {
|
|
2652
|
+
return {
|
|
2653
|
+
id: options.id,
|
|
2654
|
+
buildId: options.buildId, // Use options.buildId
|
|
2655
|
+
mode: options.mode,
|
|
2656
|
+
protocol: options.protocol || "ac:", // options.protocol might not be defined, handle default
|
|
2657
|
+
templateDir: path$1.resolve(nodeModulesDir, './@fnet/cli-project-node/dist/template/default'),
|
|
2658
|
+
templateCommonDir: path$1.resolve(nodeModulesDir, './@fnet/cli-project-common/dist/template/default'),
|
|
2659
|
+
projectDir: path$1.resolve(cwd, `./.output/${options.id}`),
|
|
2660
|
+
tags: options.ftag || [], // Default to empty array if undefined
|
|
2661
|
+
};
|
|
2662
|
+
} else {
|
|
2663
|
+
// Load project based on CWD, pass tags from options
|
|
2664
|
+
const project = await loadLocalProject({ tags: options.ftag || [] });
|
|
2665
|
+
return {
|
|
2666
|
+
buildId: options.buildId,
|
|
2667
|
+
mode: options.mode,
|
|
2668
|
+
protocol: options.protocol || "local:",
|
|
2669
|
+
templateDir: path$1.resolve(nodeModulesDir, `./@fnet/cli-project-node/dist/template/${project.runtime.template}`),
|
|
2670
|
+
templateCommonDir: path$1.resolve(nodeModulesDir, `./@fnet/cli-project-common/dist/template/${project.runtime.template}`),
|
|
2671
|
+
projectDir: path$1.resolve(project.projectDir, `./.workspace`),
|
|
2672
|
+
projectSrcDir: path$1.resolve(project.projectDir, `./src`),
|
|
2673
|
+
project,
|
|
2674
|
+
tags: options.ftag || [], // Ensure tags is always an array
|
|
2675
|
+
};
|
|
2676
|
+
}
|
|
2677
|
+
}
|
|
2678
|
+
|
|
2679
|
+
// --- loadLocalProject Function (Unchanged, but ensure tags are handled) ---
|
|
2680
|
+
async function loadLocalProject({ tags = [] }) { // Default tags to empty array
|
|
2681
|
+
const projectFilePath = path$1.resolve(cwd, 'node.yaml');
|
|
2682
|
+
if (!fs$1.existsSync(projectFilePath)) throw new Error('node.yaml file not found in current directory.');
|
|
2683
|
+
|
|
2684
|
+
// Ensure tags is an array before passing to fnetYaml
|
|
2685
|
+
const effectiveTags = Array.isArray(tags) ? tags : (tags ? [tags] : []);
|
|
2686
|
+
|
|
2687
|
+
const { raw, parsed: projectFileParsed } = await fnetYaml({ file: projectFilePath, tags: effectiveTags });
|
|
2688
|
+
const projectDir = path$1.dirname(projectFilePath);
|
|
2689
|
+
|
|
2690
|
+
projectFileParsed.features = projectFileParsed.features || {};
|
|
2691
|
+
|
|
2692
|
+
const features = projectFileParsed.features;
|
|
2693
|
+
features.runtime = features.runtime || {};
|
|
2694
|
+
features.runtime.type = features.runtime.type || "node";
|
|
2695
|
+
|
|
2696
|
+
if (features.runtime.type === "python") features.runtime.template = features.runtime.template || "python";
|
|
2697
|
+
else features.runtime.template = features.runtime.template || "default";
|
|
2698
|
+
|
|
2699
|
+
const libraryAtom = {
|
|
2700
|
+
doc: {
|
|
2701
|
+
...projectFileParsed,
|
|
2702
|
+
},
|
|
2703
|
+
fileName: "index"
|
|
2704
|
+
};
|
|
2705
|
+
|
|
2706
|
+
const result = {
|
|
2707
|
+
libraryAtom,
|
|
2708
|
+
projectDir,
|
|
2709
|
+
projectFilePath,
|
|
2710
|
+
projectFileContent: raw,
|
|
2711
|
+
projectFileParsed,
|
|
2712
|
+
runtime: features.runtime
|
|
2713
|
+
};
|
|
2714
|
+
|
|
2715
|
+
// Load devops file (logic remains the same)
|
|
2716
|
+
let devopsFilePath = path$1.resolve(projectDir, 'fnet/targets.yaml');
|
|
2717
|
+
if (!fs$1.existsSync(devopsFilePath)) {
|
|
2718
|
+
// migrate legacy devops file
|
|
2719
|
+
devopsFilePath = path$1.resolve(projectDir, 'node.devops.yaml');
|
|
2720
|
+
if (fs$1.existsSync(devopsFilePath)) {
|
|
2721
|
+
const fnetDir = path$1.resolve(projectDir, 'fnet');
|
|
2722
|
+
if (!fs$1.existsSync(fnetDir)) fs$1.mkdirSync(fnetDir);
|
|
2723
|
+
const targetPath = path$1.resolve(projectDir, 'fnet/targets.yaml');
|
|
2724
|
+
fs$1.copyFileSync(devopsFilePath, targetPath);
|
|
2725
|
+
// delete legacy devops file
|
|
2726
|
+
try {
|
|
2727
|
+
fs$1.unlinkSync(devopsFilePath);
|
|
2728
|
+
console.log(`Migrated legacy devops file: ${devopsFilePath} to ${targetPath}`);
|
|
2729
|
+
} catch (err) {
|
|
2730
|
+
console.warn(`Could not delete legacy devops file ${devopsFilePath}: ${err.message}`);
|
|
2731
|
+
}
|
|
2732
|
+
|
|
2733
|
+
}
|
|
2734
|
+
}
|
|
2735
|
+
|
|
2736
|
+
if (fs$1.existsSync(devopsFilePath)) {
|
|
2737
|
+
const { raw: devopsFileContent, parsed: devopsFileParsed } = await fnetYaml({ file: devopsFilePath, tags: effectiveTags }); // Pass tags here too
|
|
2738
|
+
const yamlDocument = yaml.parseDocument(devopsFileContent);
|
|
2739
|
+
|
|
2740
|
+
result.devops = {
|
|
2741
|
+
filePath: devopsFilePath,
|
|
2742
|
+
fileContent: devopsFileContent,
|
|
2743
|
+
yamlDocument,
|
|
2744
|
+
doc: {
|
|
2745
|
+
...devopsFileParsed,
|
|
2746
|
+
},
|
|
2747
|
+
type: "library.deploy",
|
|
2748
|
+
save: async () => {
|
|
2749
|
+
// Ensure doc is up-to-date before saving
|
|
2750
|
+
// This assumes mutations happen on yamlDocument, which is good practice
|
|
2751
|
+
fs$1.writeFileSync(result.devops.filePath, yamlDocument.toString());
|
|
2752
|
+
// fs.writeFileSync(result.devops.filePath, YAML.stringify(result.devops.doc)); // Stringifying doc might lose comments/formatting
|
|
2753
|
+
}
|
|
2754
|
+
};
|
|
2755
|
+
}
|
|
2756
|
+
|
|
2757
|
+
const readmeFilePath = path$1.resolve(projectDir, 'readme.md');
|
|
2758
|
+
if (fs$1.existsSync(readmeFilePath)) {
|
|
2759
|
+
const readmeFileContent = fs$1.readFileSync(readmeFilePath, 'utf8');
|
|
2760
|
+
result.readme = {
|
|
2761
|
+
filePath: readmeFilePath,
|
|
2762
|
+
fileContent: readmeFileContent,
|
|
2763
|
+
doc: {
|
|
2764
|
+
content: readmeFileContent,
|
|
2765
|
+
"content-type": "markdown",
|
|
2766
|
+
},
|
|
2767
|
+
type: "wiki"
|
|
2768
|
+
};
|
|
2769
|
+
}
|
|
2770
|
+
|
|
2771
|
+
return result;
|
|
2772
|
+
}
|
|
2773
|
+
|
|
2774
|
+
|
|
2775
|
+
// --- Parse Arguments ---
|
|
2776
|
+
// This replaces the final .argv call in yargs
|
|
2777
|
+
program.parse(process.argv);
|
|
2778
|
+
|
|
2779
|
+
// Add a fallback for when no command is provided
|
|
2780
|
+
if (!process.argv.slice(2).length) {
|
|
2781
|
+
program.outputHelp();
|
|
2782
|
+
}
|
|
2783
|
+
|
|
2784
|
+
export { which as w };
|