@fnet/cli 0.101.0 → 0.101.1

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.
Files changed (71) hide show
  1. package/dist/fnet/index.B5XE4ChJ.js +1 -0
  2. package/dist/fnet/index.Bfg4lyu-.js +1 -0
  3. package/dist/fnet/index.Bn6hEUL-.js +1 -0
  4. package/dist/fnet/index.BoO2Mnox.js +1 -0
  5. package/dist/fnet/index.C7saWH6d.js +1 -0
  6. package/dist/fnet/index.CDct_kkF.js +1 -0
  7. package/dist/fnet/index.CMC8mlye.js +1 -0
  8. package/dist/fnet/index.CmMM-Ek9.js +1 -0
  9. package/dist/fnet/index.CzAV0S36.js +1 -0
  10. package/dist/fnet/index.D2N9YZmA.js +1 -0
  11. package/dist/fnet/index.DI3yyTtl.js +1 -0
  12. package/dist/fnet/index.DLGSTm8o.js +1 -0
  13. package/dist/fnet/index.Q-CYRcna.js +1 -0
  14. package/dist/fnet/index.UOds5XLl.js +1 -0
  15. package/dist/fnet/index.W6RYgypK.js +1 -0
  16. package/dist/fnet/index.dpz2QIRu.js +1 -0
  17. package/dist/fnet/index.js +1 -4561
  18. package/dist/fnet/index.xd8c7XMr.js +1 -0
  19. package/dist/fnode/index.B5XE4ChJ.js +1 -0
  20. package/dist/fnode/index.Bfg4lyu-.js +1 -0
  21. package/dist/fnode/index.BoO2Mnox.js +1 -0
  22. package/dist/fnode/index.C7saWH6d.js +1 -0
  23. package/dist/fnode/index.CDct_kkF.js +1 -0
  24. package/dist/fnode/index.CMC8mlye.js +1 -0
  25. package/dist/fnode/index.CmMM-Ek9.js +1 -0
  26. package/dist/fnode/index.CzAV0S36.js +1 -0
  27. package/dist/fnode/index.D2N9YZmA.js +1 -0
  28. package/dist/fnode/index.DI3yyTtl.js +1 -0
  29. package/dist/fnode/index.DLGSTm8o.js +1 -0
  30. package/dist/fnode/index.DhIcnnpM.js +1 -0
  31. package/dist/fnode/index.Q-CYRcna.js +1 -0
  32. package/dist/fnode/index.UOds5XLl.js +1 -0
  33. package/dist/fnode/index.W6RYgypK.js +1 -0
  34. package/dist/fnode/index.dpz2QIRu.js +1 -0
  35. package/dist/fnode/index.js +1 -2783
  36. package/dist/fnode/index.xd8c7XMr.js +1 -0
  37. package/package.json +1 -1
  38. package/dist/fnet/index.B5vpZn1Z.js +0 -53
  39. package/dist/fnet/index.B6WHm9H0.js +0 -106
  40. package/dist/fnet/index.B90Vm9uq.js +0 -114
  41. package/dist/fnet/index.BMsD46br.js +0 -60
  42. package/dist/fnet/index.BUhoGq-h.js +0 -70
  43. package/dist/fnet/index.BjzEMdm1.js +0 -52
  44. package/dist/fnet/index.C9zKEF61.js +0 -106
  45. package/dist/fnet/index.CQNYMi1Z.js +0 -51
  46. package/dist/fnet/index.CX8eMqfH.js +0 -191
  47. package/dist/fnet/index.Ce8sTnt_.js +0 -52
  48. package/dist/fnet/index.D2kFuxXo.js +0 -52
  49. package/dist/fnet/index.D61MduW1.js +0 -106
  50. package/dist/fnet/index.Dd0lngp8.js +0 -41
  51. package/dist/fnet/index.DqwVukIB.js +0 -52
  52. package/dist/fnet/index.MWHLt6g3.js +0 -52
  53. package/dist/fnet/index.f798DPwo.js +0 -93
  54. package/dist/fnet/index.j5JP-zGw.js +0 -52
  55. package/dist/fnode/index.B5vpZn1Z.js +0 -53
  56. package/dist/fnode/index.B6WHm9H0.js +0 -106
  57. package/dist/fnode/index.BMsD46br.js +0 -60
  58. package/dist/fnode/index.BNSTS5o6.js +0 -109
  59. package/dist/fnode/index.BUhoGq-h.js +0 -70
  60. package/dist/fnode/index.BjzEMdm1.js +0 -52
  61. package/dist/fnode/index.C9zKEF61.js +0 -106
  62. package/dist/fnode/index.CQNYMi1Z.js +0 -51
  63. package/dist/fnode/index.CX8eMqfH.js +0 -191
  64. package/dist/fnode/index.Ce8sTnt_.js +0 -52
  65. package/dist/fnode/index.D2kFuxXo.js +0 -52
  66. package/dist/fnode/index.D61MduW1.js +0 -106
  67. package/dist/fnode/index.Dd0lngp8.js +0 -41
  68. package/dist/fnode/index.DqwVukIB.js +0 -52
  69. package/dist/fnode/index.MWHLt6g3.js +0 -52
  70. package/dist/fnode/index.f798DPwo.js +0 -93
  71. package/dist/fnode/index.j5JP-zGw.js +0 -52
@@ -1,2784 +1,2 @@
1
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 };
2
+ import e from"path";import{fileURLToPath as t}from"node:url";import{spawn as o}from"child_process";import i from"@fnet/prompt";import{Command as a,Option as s}from"commander";import n from"fs";import r from"yaml";import c from"@fnet/shelljs";import p from"os";import l from"@fnet/yaml";import d from"@fnet/config";import m from"@fnet/object-from-schema";import u from"@fnet/shell-flow";import f from"@flownet/lib-render-templates-dir";import g,{existsSync as y}from"node:fs";import h,{delimiter as w,join as b}from"node:path";import j from"node:os";import v from"nunjucks";import{randomUUID as x}from"node:crypto";import{Api as k,Atom as D}from"@flownet/lib-atom-api-js";import _ from"@flownet/lib-parse-node-url";import S from"@flownet/lib-parse-imports-js";import P from"@fnet/list-files";import C from"chalk";import $ from"redis";import E from"@flownet/lib-is-redis-online";import A from"lodash.merge";import F from"@fnet/npm-list-versions";import I from"@fnet/npm-pick-versions";import T from"object-hash";import O from"ajv/dist/2020.js";import N from"ajv/dist/standalone/index.js";import R from"ajv-formats";import L from"@fnet/auto-conda-env";class M{init({config:e,accessToken:t}){return new Promise(((o,i)=>{if(k.set_api_url(e.data.url),t)return k.set_req_token(t),void o(t);fetch(`${e.data.issuer}/protocol/openid-connect/token`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams(e.data.grant.params)}).then((async e=>{if(!e.ok)throw new Error(await e.text());return e.json()})).then((e=>{k.set_req_token(e.access_token),o(e.access_token)})).catch((e=>{k.set_req_token(),i(e)}))}))}}function z({feature:e,features:t,packageDevDependencies:o}){const{name:i,packages:a,options:s,extraCheck:n,explicit:r}=e,c=`${i}_enabled`,p=t.rollup_output||{},l=Object.keys(p);let d=s||{};const m=t[i]?.options;m&&(d=A(d,m));const u=!t[i]||!1===t[i]?.enabled;l.forEach((e=>{const o=t.rollup_output[e];if(o){if(Reflect.has(o,i)){if(u||!o[i]||!1===o[i]?.enabled)return void delete o[i];!0===o[i]&&(o[i]={enabled:!0,options:d})}else{if(u||r||!1===t[c])return;o[i]={enabled:!0}}o[i]=o[i]||{},o[i].options={...d,...o[i].options}}}));let f=l.some((e=>!0===t.rollup_output[e][i]?.enabled));n&&(f=n()&&f),t[c]=f,f&&a.forEach((e=>o.push({package:e[0],version:e[1]})))}function B({dir:e,name:t="index"}){let o=h.resolve(e,`./${t}.tsx`);if(g.existsSync(o)||(o=h.resolve(e,`./${t}.ts`)),g.existsSync(o)||(o=h.resolve(e,`./${t}.jsx`)),g.existsSync(o)||(o=h.resolve(e,`./${t}.js`)),!g.existsSync(o))return{};const i=o,a=h.extname(o);return{file:i,ext:a,ts:".ts"===a||".tsx"===a,name:t}}async function H(e){const{atom:t,context:o,setProgress:i}=e;i("Initializing features..."),t.doc.features=t.doc.features||{};const a=t.doc.features;a.project=a.project||{},a.project.format=a.project.format||a.project_format||"esm",a.project_format=a.project.format,a.dts_enabled=!0===a.dts||void 0!==a.dts&&!1!==a.dts;const s=h.resolve(o.project.projectDir),n=B({dir:h.resolve(s,"./app")});if(n.file){i("Parsing app entry imports...");let e=await S({file:n.file,recursive:!0}),t=e.all.some((e=>!0===e.usesJSX&&"local"===e.type));a.app_uses_jsx=t,a.app_has_entry=!0,e=await S({file:n.file}),t=e.all.some((e=>!0===e.usesJSX&&"local"===e.type)),a.app_entry_uses_jsx=t,a.app_entry_is_ts=n.ts,a.app_entry_ext=n.ext}const r=B({dir:h.resolve(s,"./cli")});if(r.file){i("Parsing cli entry imports...");let e=await S({file:r.file,recursive:!0}),t=e.all.some((e=>!0===e.usesJSX&&"local"===e.type));a.cli_uses_jsx=t,a.cli_has_entry=!0,e=await S({file:r.file}),t=e.all.some((e=>!0===e.usesJSX&&"local"===e.type)),a.cli_entry_uses_jsx=t,a.cli_entry_is_ts=r.ts,a.cli_entry_ext=r.ext}if("workflow.lib"===t.type){const e=B({dir:h.resolve(s,"./src")});if(e.file){i("Parsing src entry imports...");let t=await S({file:e.file,recursive:!0}),o=t.all.some((e=>!0===e.usesJSX&&"local"===e.type));a.src_uses_jsx=o,a.src_has_entry=!0,t=await S({file:e.file}),o=t.all.some((e=>!0===e.usesJSX&&"local"===e.type)),a.src_entry_uses_jsx=o,a.src_entry_is_ts=e.ts,a.src_entry_ext=e.ext}}const c=Reflect.has(a,"app_entry_uses_jsx")?!0===a.app_entry_uses_jsx:!0===a.src_entry_uses_jsx,p=Reflect.has(a,"cli_entry_uses_jsx")?!0===a.cli_entry_uses_jsx:!0===a.src_entry_uses_jsx;a.form_enabled=c||p||!0===a.form||!0===a.form?.enabled,a.multiple_enabled=a.multiple_enabled||!0===a.multiple||!0===a.multiple?.enabled,!1===a.app?a.app={enabled:!1}:!0===a.app?a.app={enabled:!0,extend:!0===a.app_has_entry,export:!0,react:c}:a.app={enabled:!0,extend:!0===a.app_has_entry,export:!0,react:c,...a.app||{}},a.app.enabled=!0===a.app.enabled&&(!0===t.doc.features.form_enabled||!0===a.app.extend||!0===a.app.enabled),a.app.format=a.app.format||"esm",a.app.folder=a.app.folder||a.app.format||"default",!1===a.cli?a.cli={enabled:!1}:!0===a.cli?a.cli={enabled:!0,extend:!0===a.cli_has_entry,export:!0,react:p}:a.cli={enabled:!0,extend:!0===a.cli_has_entry,export:!0,react:p,...a.cli||{}},a.cli.enabled=!0===a.cli.enabled&&(!1===t.doc.features.form_enabled||!0===a.cli.extend||!0===a.cli.enabled),a.cli.format=a.cli.format||"esm",a.cli.folder=a.cli.folder||a.cli.folder||"esm",a.cli.node_options=a.cli.node?.options||a.cli.node_options||"",a.json=a.cli.enabled||a.json;const l={cjs:{format:"cjs",context:a.form_enabled?"window":"global",babel:!0===a.src_uses_jsx||!1,browser:!1,replace:!0,terser:!0,enabled:!1!==a.cjs,copy:!1},esm:{format:"esm",context:a.form_enabled?"window":"global",babel:!0===a.src_uses_jsx||!1,browser:!1,replace:!0,terser:!1,enabled:!1!==a.esm,copy:!0},iife:{format:"iife",context:a.form_enabled?"window":"global",babel:!0,browser:!0,replace:!0,enabled:!0===a.iife,terser:!0,copy:!1}};!0===a.webos&&(l.webos={format:"iife",browser:!0,babel:!0,context:"window",replace:!0,terser:!0,input:"./src/app/index.js",output_dir:"./dist/app/webos",copy:!1,babel_options:{targets:{chrome:"79"}}}),!0===a.electron&&(l.electron={format:"iife",browser:!0,babel:!0,context:"window",replace:!0,terser:!0,copy:!1,input:"./src/app/index.js",output_dir:"./dist/app/electron"}),!0===a.nextjs&&(l.nextjs={format:"esm",browser:!0,babel:!0,context:"window",replace:!0,terser:!0,copy:!1,input:"./src/app/index.js",output_dir:"./dist/app/nextjs"}),!0===a.ios&&(l.ios={format:"iife",browser:!0,babel:!0,context:"window",replace:!0,terser:!0,copy:!1,input:"./src/app/index.js",output_dir:"./dist/app/ios"}),!0===a.macos&&(l.macos={format:"iife",browser:!0,babel:!0,context:"window",replace:!0,terser:!0,copy:!1,input:"./src/app/index.js",output_dir:"./dist/app/macos"}),!0===a.app.enabled&&(a.app.dir=`./dist/app/${a.app.folder}`,l.app={format:a.app.format,browser:!0,babel:!0,context:"window",replace:!0,input:"./src/app/index.js",output_dir:a.app.dir,terser:!0,output_exports:!1===a.app.export?"none":"auto",browsersync:!0}),!0===a.cli.enabled&&(a.cli.dir=`./dist/cli/${a.cli.folder}`,l.cli={format:a.cli.format,context:"global",babel:!0===a.src_uses_jsx||!0===a.cli_uses_jsx||!1,browser:!1,replace:!0,enabled:!0,input:"./src/cli/index.js",output_dir:a.cli.dir,banner:"#!/usr/bin/env node",terser:!0,output_exports:!1===a.cli.export?"none":"auto"});const d={server:".",startPath:`${h.normalize(a.app.dir||".")}`,files:[h.normalize("./dist/**/*")],cors:!0,open:!1};a.babel_options=A({targets:{browsers:"last 9 versions, not dead",node:"18"}},a.babel_options||a.babel?.options),a.browsersync_options=A(d,a.browsersync_options||a.browsersync?.options||{}),a.replace_options=A({},a.replace_options||a.replace?.options||{}),Reflect.has(a.browsersync_options,"proxy")&&delete a.browsersync_options.server,a.rollup=a.rollup||{},a.rollup_output=A(l,a.rollup_output||a.rollup?.output||{}),a.preact_enabled=!0===a.preact||a.preact&&!1!==a.preact?.enabled;let m=Object.keys(l);for(const e of m){const t=l[e];t&&(!1!==a.rollup[e]?(t.babel_options=t.babel_options||a.babel_options,t.browsersync_options=A(a.browsersync_options,t.browsersync_options),t.replace_options=A(a.replace_options,t.replace_options),a.preact_enabled&&(t.alias_enabled=!0,t.alias=t.alias||{},t.alias.entries=t.alias.entries||{},t.alias.entries.react="preact/compat",t.alias.entries["react-dom"]="preact/compat"),(a.form_enabled||a.babel)&&(t.babel=!0)):delete a.rollup_output[e])}m=Object.keys(a.rollup_output),a.babel_enabled=m.some((e=>!0===a.rollup_output[e].babel)),a.browser_enabled=m.some((e=>!0===a.rollup_output[e].babel)),a.browsersync_enabled=!1!==a.browsersync&&m.some((e=>!0===a.rollup_output[e].browsersync)),a.browsersync_enabled=a.browsersync_enabled&&a.app.enabled,a.dependency_auto_enabled=!1!==a.dependency_auto&&!1!==a.dependency_auto?.enabled,a.npm_install_flags=a.npm_install_flags||"",a.react_version=a.react_version||a.react?.version||18,function(e){const{atom:t,packageDevDependencies:o}=e,i=t.doc.features,a=i.css&&!1!==i.css.enabled;let s=[];a&&(s.push(["rollup-plugin-postcss","^4"]),s.push(["sass","^1.66"]),(i.css?.options?.plugins||[]).forEach((e=>{switch(e.name){case"postcss-import":s.push(["postcss-import","^15"]);break;case"postcss-url":s.push(["postcss-url","^10"]);break;case"postcss-preset-env":s.push(["postcss-preset-env","^9"]);break;case"autoprefixer":s.push(["autoprefixer","^10"]);break;case"cssnano":s.push(["cssnano","^6"])}})));z({feature:{name:"css",packages:s},features:i,packageDevDependencies:o})}(e),function(e){const{atom:t,packageDevDependencies:o}=e,i=t.doc.features,a={};!0===i.app?.enabled&&(a.targets=a.targets||[],a.targets.push({src:"./src/app/index.html",dest:i.app.dir}),Reflect.has(i.app,"copy")||Reflect.has(i,"copy")||(i.copy=!0)),z({feature:{name:"copy",packages:[["rollup-plugin-copy","^3"],["chokidar","^3"]],options:a},features:i,packageDevDependencies:o})}(e),function(e){const{atom:t,packageDevDependencies:o}=e;z({feature:{name:"wasm",packages:[["@rollup/plugin-wasm","^6"]]},features:t.doc.features,packageDevDependencies:o})}(e),function(e){const{atom:t,packageDevDependencies:o}=e;z({feature:{name:"terser",packages:[["@rollup/plugin-terser","^0.4"]]},features:t.doc.features,packageDevDependencies:o})}(e),function(e){const{atom:t,packageDevDependencies:o}=e;z({feature:{name:"json",packages:[["@rollup/plugin-json","^6"]]},features:t.doc.features,packageDevDependencies:o})}(e),function(e){const{atom:t,packageDevDependencies:o}=e;z({feature:{name:"string",packages:[["rollup-plugin-string","^3"]]},features:t.doc.features,packageDevDependencies:o})}(e),function(e){const{atom:t,packageDevDependencies:o}=e;z({feature:{name:"image",packages:[["@rollup/plugin-image","^3"]]},features:t.doc.features,packageDevDependencies:o})}(e),function(e){const{atom:t,packageDevDependencies:o}=e;z({feature:{name:"analyzer",packages:[["rollup-plugin-analyzer","^3"]],options:{summaryOnly:!0,limit:12},explicit:!0},features:t.doc.features,packageDevDependencies:o})}(e),function(e){const{atom:t,packageDevDependencies:o}=e;z({feature:{name:"visualizer",packages:[["rollup-plugin-visualizer","^5"]]},features:t.doc.features,packageDevDependencies:o})}(e),function(e){const{atom:t,packageDevDependencies:o}=e;z({feature:{name:"polyfill",packages:[["rollup-plugin-node-polyfills","^0.2"]]},features:t.doc.features,packageDevDependencies:o})}(e),function(e){const{atom:t,packageDevDependencies:o}=e;z({feature:{name:"nunjucks",packages:[["@fnet/rollup-plugin-nunjucks","0.1.8"]]},features:t.doc.features,packageDevDependencies:o})}(e),function(e){const{atom:t,packageDevDependencies:o}=e;z({feature:{name:"workbox",packages:[["rollup-plugin-workbox","^8"]],options:{generate:{swDest:"dist/app/esm/sw.js",globDirectory:"dist/app/esm",globPatterns:["**/*.{html,js,css,png,jpg}"],skipWaiting:!0,clientsClaim:!0}},explicit:!0},features:t.doc.features,packageDevDependencies:o})}(e),function(e){const{atom:t,packageDevDependencies:o}=e;z({feature:{name:"gzip",packages:[["rollup-plugin-gzip","^4"]],explicit:!0},features:t.doc.features,packageDevDependencies:o})}(e)}async function J({projectDir:e,name:t,setProgress:o,count:i=1}){let a;const s=T(["npm-pick-versions",t,i]),n=h.join(e,".cache"),r=h.join(n,s+".json");return g.existsSync(r)?(o&&o(`Picking npm version of ${t} from cache ...`),a=JSON.parse(g.readFileSync(r,"utf8"))):(o&&o(`Picking npm version of ${t} ...`),a=await I({name:t,count:i}),g.mkdirSync(n,{recursive:!0}),g.writeFileSync(r,JSON.stringify(a),"utf8")),a}async function U({atom:e,setProgress:t,context:o,packageDependencies:i}){await t({message:"Creating .gitignore"});const a={atom:e,packageDependencies:i},s=o.templateCommonDir,n=v.compile(g.readFileSync(h.resolve(s,".gitignore.njk"),"utf8"),v.configure(s)).render(a),r=o.projectDir,c=h.resolve(r,".gitignore");g.writeFileSync(c,n,"utf8")}async function X({atom:e,context:t,setProgress:o,Atom:i}){const a="readme.md",s=`Creating ${a}`;if(await o({message:s}),t.project?.readme){const e=t.projectDir,o={content:t.project.readme.doc.content},i=h.resolve(t.project.projectDir,"fnet/how-to.md");if(g.existsSync(i)){const e=g.readFileSync(i,"utf8");o.howto=e}const s=h.resolve(t.project.projectDir,"fnet/input.yaml");if(g.existsSync(s)){const e=await l({file:s,tags:t.tags});o.input=e.content}const n=t.templateCommonDir,r=v.compile(g.readFileSync(h.resolve(n,`${a}.njk`),"utf8"),v.configure(n)).render(o),c=h.resolve(e,`${a}`);g.writeFileSync(c,r,"utf8")}else if(e.id){const o=await i.first({type:"wiki",parent_id:e.id});if(!o||"markdown"!==o.doc?.["content-type"])return;const{content:s,...n}=o.doc,r={content:s},c=t.templateCommonDir,p=v.compile(g.readFileSync(h.resolve(c,`${a}.njk`),"utf8"),v.configure(c)).render(r),l=t.projectDir,d=h.resolve(l,`${a}`);g.writeFileSync(d,p,"utf8")}}var K=e=>{const t=process.env.PATH||"",o="win32"===process.platform?(process.env.PATHEXT||".EXE;.CMD;.BAT;.COM").split(";"):[""],i=t.split(w);for(const t of i)for(const i of o){const o=b(t,"win32"===process.platform?e+i:e);if(y(o))return o}return null};var q=async e=>{const{atom:t,packageDependencies:o,context:i,deploymentProjectTarget:a,setProgress:s,deploymentProject:n,yamlTarget:r}=e;if(!0!==a.enabled)return;const c=a.type;try{if("lib"===c)await(await import("./index.DLGSTm8o.js")).default({...e});else if("red"===c)await(await import("./index.CmMM-Ek9.js")).default({...e});else if("npm"===c)await(await import("./index.DhIcnnpM.js")).default({...e});else if("gcs"===c)await(await import("./index.UOds5XLl.js")).default({...e});else if("gitlab"===c)await(await import("./index.DI3yyTtl.js")).default({...e});else if("fnet-package"===c)await(await import("./index.Bfg4lyu-.js")).default({...e});else if("fnet-form"===c)await(await import("./index.Q-CYRcna.js")).default({...e});else if("fnet-node"===c)await(await import("./index.BoO2Mnox.js")).default({...e});else if("fnet-flow"===c)await(await import("./index.dpz2QIRu.js")).default({...e});else if("nextjs"===c)await(await import("./index.CDct_kkF.js")).default({atom:t,target:a,onProgress:s,projectDir:i.projectDir,dependencies:o,context:i,yamlTarget:r}),n.isDirty=!0;else if("webos"===c)await(await import("./index.CMC8mlye.js")).default({atom:t,target:a,onProgress:s,projectDir:i.projectDir,dependencies:o,context:i,yamlTarget:r}),n.isDirty=!0;else if("electron"===c)await(await import("./index.xd8c7XMr.js")).default({atom:t,target:a,onProgress:s,projectDir:i.projectDir,dependencies:o,context:i,yamlTarget:r}),n.isDirty=!0;else if("docker"===c)await(await import("./index.D2N9YZmA.js")).default({atom:t,target:a,onProgress:s,projectDir:i.projectDir,dependencies:o,context:i,yamlTarget:r}),n.isDirty=!0;else if("ios"===c)await(await import("./index.B5XE4ChJ.js")).default({atom:t,target:a,onProgress:s,projectDir:i.projectDir,dependencies:o,context:i,yamlTarget:r}),n.isDirty=!0;else if("macos"===c)await(await import("./index.W6RYgypK.js")).default({atom:t,target:a,onProgress:s,projectDir:i.projectDir,dependencies:o,context:i,yamlTarget:r}),n.isDirty=!0;else if("rust"===c)await(await import("./index.CzAV0S36.js")).default({atom:t,target:a,onProgress:s,projectDir:i.projectDir,dependencies:o,context:i,yamlTarget:r}),n.isDirty=!0;else{if("pypi"!==c)return void console.warn(`No deployer found for type: ${c}`);await(await import("./index.C7saWH6d.js")).default({atom:t,target:a,onProgress:s,projectDir:i.projectDir,dependencies:o,context:i,yamlTarget:r}),n.isDirty=!0}}catch(e){throw console.error(`Error during deployment for type "${c}":`,e),e}};class Y{#e;#t;#o;#i;#a;#s;#n;#r;#c;#p;#l;#d;#m;#u;#f;#g;#y;constructor(e){this.#e=new M,this.#t=e,this.#s=[],this.#n=[],this._expire_ttl=3600,this._expire_ttl_short=300,this.#y={packageDependencies:this.#s,packageDevDependencies:this.#n,setProgress:this.setProgress.bind(this),context:this.#t,Atom:D,registerToPackageManager:this.registerToPackageManager.bind(this)}}async _cache_set(e,t,o){this._redis_client&&await this._redis_client.SETEX(e,o||this._expire_ttl,JSON.stringify(t)).catch(console.error)}async initAuth(){this.#t.id&&(this.#r=await this.#e.init({config:this.#d}),this.#y.atomAccessToken=this.#r)}async initLibrary(){const e=this.#t.id;this.#o=this.#t.project?.libraryAtom||await D.get({id:e});let t=this.#o.doc.bundleName;t=t||(this.#o.doc.name||"").toUpperCase().replace(/[^A-Z0-9]/g,"_"),this.#o.doc.bundleName=t,this.#o.type=this.#o.type||"workflow.lib",this.#y.atom=this.#o}async initLibraryDir(){this.setProgress({message:"Initializing library directory."});const e=this.#t.projectDir;this.setProgress({message:"Cleaning project directory."});const t=P({dir:e,ignore:[".cache","node_modules",".conda"],absolute:!0});for(const e of t)g.rmSync(e,{recursive:!0,force:!0});this.setProgress({message:"Creating project directory."});let o=e;g.existsSync(o)||g.mkdirSync(o,{recursive:!0}),o=h.join(e,"src"),g.existsSync(o)||g.mkdirSync(o,{recursive:!0}),o=h.join(e,"src","default"),g.existsSync()||g.mkdirSync(o,{recursive:!0})}async initLibraryDirPython(){this.setProgress({message:"Initializing library directory."});const e=this.#t.projectDir;this.setProgress({message:"Cleaning project directory."});const t=P({dir:e,ignore:[".cache","node_modules",".conda"],absolute:!0});for(const e of t)g.rmSync(e,{recursive:!0,force:!0});this.setProgress({message:"Creating project directory."});let o=e;g.existsSync(o)||g.mkdirSync(o,{recursive:!0}),o=h.join(e,"src"),g.existsSync(o)||g.mkdirSync(o,{recursive:!0}),o=h.join(e,"src","default");const i=this.#t.projectSrcDir;if(!g.existsSync(o))try{"win32"===j.platform()?g.symlinkSync(i,o,"junction"):g.symlinkSync(i,o,"dir")}catch(e){throw new Error(`Couldn't create symlink. Error: ${e.message}`)}}async initNunjucks(){this.setProgress({message:"Initializing nunjucks."});const e=this.#t.templateDir;this.#i=v.configure(e,{watch:!1,dev:!0}),this.#y.njEnv=this.#i}async initLibs(){this.setProgress({message:"Initializing external libs."});const e=[{name:this.#o.doc.name,type:"atom",parent_id:this.#o.parent_id}];this.#a=e,await this.initAtomLibsAndDeps({libs:e,packageDependencies:this.#s})}async initLibsPython(){this.setProgress({message:"Initializing external libs."});const e=this.#o;e.protocol="local:",e.doc.dependencies=e.doc.dependencies||[],e.name=e.doc.name;const t=[{name:this.#o.doc.name,type:"atom",parent_id:this.#o.parent_id,atom:e}];this.#a=t}async initAtomLibsAndDeps({libs:e,packageDependencies:t}){const o=e.filter((e=>"atom"===e.type));for(let e=0;e<o.length;e++){const i=o[e],a=await this.findAtomLibrary({url:i.name});i.atom=a;const s=a.doc.dependencies?.filter((e=>void 0===e.repo||"npm"===e.repo));s?.forEach((e=>{const o=t.find((t=>t.package===e.package));o?"string"==typeof e.path?(o.path||[]).some((t=>t===e.path))||(o.path=o.path||[],o.path.push(e.path)):Array.isArray(e.path)&&e.path.forEach((e=>{(o.path||[]).some((t=>t===e))||(o.path=o.path||[],o.path.push(e))})):t.push(e)}))}t.sort(((e,t)=>e.package?.localeCompare(t.package)))}async findAtomLibrary({url:e}){const t=_({url:e});if(!t)throw new Error(`Invalid package name: ${e}`);if(t.protocol||(t.protocol=this.#l),"ac:"===t.protocol){const o=t.pathname.split("/");if(1===o.length)return await D.first({where:{name:e,parent_id:this.#d.env.ATOM_LIBRARIES_ID,type:"workflow.lib"}});if(2===o.length){const e=await D.first({where:{name:o[0],parent_id:this.#d.env.ATOM_LIBRARIES_ID,type:"folder"}});return await D.first({where:{name:o[1],parent_id:e.id,type:"workflow.lib"}})}}else if("local:"===t.protocol){const e=this.#o;e.protocol="local:",e.doc.dependencies=e.doc.dependencies||[],e.name=e.doc.name;const t=h.resolve(this.#t.projectSrcDir,"index.js"),o=await S({file:t,recursive:!0}),i=e.doc.dependencies,a=o.all;for await(const e of a){if("npm"!==e.type)continue;if(i.find((t=>t.package===e.package)))continue;const t=await J({name:e.package,projectDir:this.#t.projectDir,setProgress:this.#y.setProgress});i.push({package:e.package,subpath:e.subpath,version:t.minorRange,type:"npm"})}return e}}async createAtomLibFiles({libs:e}){await this.setProgress({message:"Creating external lib files."}),this.#o.typesDir="./types";const t=e.filter((e=>"atom"===e.type));for(let e=0;e<t.length;e++){const o=t[e].atom,i=this.#t.projectDir;if("local:"===o.protocol){const e=h.resolve(this.#t.projectSrcDir,`${o.fileName||o.name}.js`),t=h.relative(h.join(this.#t.projectDir,"src","default"),e);if(!g.existsSync(e)){g.mkdirSync(h.dirname(e),{recursive:!0});let t="export default async (args)=>{\n";t+="}",g.writeFileSync(e,t,"utf8")}o.relativePath=t.split(h.sep).join("/"),this.#o.typesDir=`./types/${h.basename(i)}/src`}else{const e=h.join(i,"src","libs",`${o.id}.js`),t=o.doc.contents?.find((e=>"esm"===e.format))||o.doc;g.writeFileSync(e,t.content,"utf8")}}}async createAtomLibFilesPython({libs:e}){await this.setProgress({message:"Creating external lib files."});const t=e.filter((e=>"atom"===e.type));for(let e=0;e<t.length;e++){const o=t[e].atom;if("local:"===o.protocol){const e=h.resolve(this.#t.projectSrcDir,`${o.fileName||o.name}.py`);if(!g.existsSync(e)){g.mkdirSync(h.dirname(e),{recursive:!0});let t="def default():\n";t+=' print("Hello world!")\n',g.writeFileSync(e,t,"utf8")}}}}async createEngine(){await this.setProgress({message:"Creating engine file."});const e={libs:this.#a.filter((e=>"atom"===e.type)),libraryAtom:this.#o,atom:this.#o},t=this.#t.templateDir,o=v.compile(g.readFileSync(h.resolve(t,h.join("src","default","engine.js.njk")),"utf8"),this.#i).render(e),i=this.#t.projectDir,a=h.resolve(i,h.join("src","default","index.js"));g.writeFileSync(a,o,"utf8")}async createProjectYaml(){const e="node.yaml",t=`Creating ${e}`;await this.setProgress({message:t});const{content:o,...i}=this.#o.doc,a={content:r.stringify(i)},s=this.#t.templateDir,n=v.compile(g.readFileSync(h.resolve(s,`${e}.njk`),"utf8"),this.#i).render(a),c=this.#t.projectDir,p=h.resolve(c,`${e}`);g.writeFileSync(p,n,"utf8")}async deploy(){if(await this.setProgress({message:"Deploying."}),this.#t.project?.devops){const e=[this.#t.project?.devops];for(let t=0;t<e.length;t++){let o=e[t];await this.deployProject({deploymentProject:o}),!0===o.isDirty&&await o.save()}}else if(this.#o.id){const e=await D.list({type:"library.deploy",parent_id:this.#o.id});for(let t=0;t<e.length;t++){let o=e[t];await this.deployProject({deploymentProject:o}),!0===o.isDirty&&(o=await D.update(o,{id:o.id}))}}}async deployProject(e){const{deploymentProject:t}=e,{yamlDocument:o}=t;if(t.doc.targets&&Array.isArray(t.doc.targets))throw new Error("Deployment project targets are deprecated. Please update targets in the yaml file.");const i=Object.keys(t.doc||{}),a=o||{};for(let e=0;e<i.length;e++){const o=t.doc[i[e]];o.name=i[e];const s=a.get(i[e]);await q({...this.#y,deploymentProject:t,deploymentProjectTarget:o,yamlTarget:s})}}async registerToPackageManager(e){const{target:t,packageJSON:o}=e;if(!this.#t.id)return;let i=await D.first({name:t.params.name,parent_id:this.#d.env.ATOM_PACKAGES_ID});i?(i.doc.versions.splice(0,0,{v:o.version}),await D.update(i,{id:i.id})):i=await D.create({parent_id:this.#d.env.ATOM_PACKAGES_ID,doc:{name:t.params.name,type:"pm",versions:[{v:o.version}]}})}async setProgress(e){const t="string"==typeof e?e:e?.message;console.log(C.blue(t)),await this._cache_set(this.#p,{status:"IN_PROGRESS",message:t})}async initNode(){await H(this.#y),await async function({atom:e,packageDependencies:t,packageDevDependencies:o,setProgress:i}){i("Initializing dependencies");const a=e.doc.dependencies||[];if(a.filter((e=>!e.dev)).forEach((e=>t.push(e))),a.filter((e=>e.dev)).forEach((e=>o.push(e))),"workflow"===e.type&&(t.push({package:"get-value",version:"^3"}),t.push({package:"set-value",version:"^4"})),e.doc.features.form_enabled&&e.doc.features.dependency_auto_enabled){let o="^18.2";i("Fetching React versions"),o=`^${(await F({name:"react",groupBy:{major:!0}})).find((t=>t[0]===e.doc.features.react_version.toString()))[0]}`,t.push({package:"react",version:o}),t.push({package:"react-dom",version:o}),"workflow"===e.type&&(t.push({package:"@fnet/react-app",version:"^0.1"}),t.push({package:"@fnet/react-app-state",version:"^0.1"}))}e.doc.features.preact_enabled&&t.push({package:"preact",version:"^10"}),!0===e.doc.features.cli.enabled&&(t.push({package:"@fnet/args",version:"^0.1"}),o.push({package:"ajv",version:"^8"}),e.doc.features.cli.fargs&&!1!==e.doc.features.cli.fargs?.enabled&&t.push({package:"@fnet/config",version:"0.2.21"})),e.doc.features.render&&!1!==e.doc.features.render.enabled&&o.push({package:"@flownet/lib-render-templates-dir",version:"0.1.19"}),o.push({package:"@babel/core",version:"^7"}),o.push({package:"@rollup/plugin-commonjs",version:"^28"}),o.push({package:"@rollup/plugin-node-resolve",version:"^16"}),o.push({package:"@rollup/plugin-replace",version:"^6"}),o.push({package:"rollup",version:"^4"}),e.doc.features.dts_enabled&&o.push({package:"rollup-plugin-dts",version:"^6"}),o.push({package:"rollup-plugin-peer-deps-external",version:"^2"}),o.push({package:"@rollup/plugin-alias",version:"^5"}),o.push({package:"fs-extra",version:"^11"}),e.doc.features.babel_enabled&&(o.push({package:"@rollup/plugin-babel",version:"^6"}),o.push({package:"@babel/preset-env",version:"^7"}),o.push({package:"@babel/preset-react",version:"^7"}),e.doc.features.babel?.options?.plugins?.forEach((e=>{switch(e[0]){case"@babel/plugin-proposal-decorators":o.push({package:"@babel/plugin-proposal-decorators",version:"^7"});break;case"@babel/plugin-proposal-class-properties":o.push({package:"@babel/plugin-proposal-class-properties",version:"^7"});break;case"@babel/plugin-proposal-private-methods":o.push({package:"@babel/plugin-proposal-private-methods",version:"^7"});break;case"@babel/plugin-proposal-private-property-in-object":o.push({package:"@babel/plugin-proposal-private-property-in-object",version:"^7"});break;case"@babel/plugin-proposal-optional-chaining":o.push({package:"@babel/plugin-proposal-optional-chaining",version:"^7"})}}))),o.push({package:"@fnet/rollup-plugin-delete",version:"0.1.10"}),e.doc.features.browsersync_enabled&&o.push({package:"@fnet/rollup-plugin-browsersync",version:"0.1.11"})}(this.#y),await this.initLibraryDir(),await this.initNunjucks(),await this.initLibs()}async initPython(){await async function(e){const{atom:t,context:o,setProgress:i}=e;i("Initializing features..."),t.doc.features=t.doc.features||{};const a=t.doc.features;!1===a.cli?a.cli={enabled:!1}:(a.cli,a.cli={enabled:!0}),a.cli.enabled=!0===a.cli.enabled&&(!1===t.doc.features.form_enabled||!0===a.cli.extend||!0===a.cli.enabled)}(this.#y),await async function({atom:e,packageDependencies:t,packageDevDependencies:o,setProgress:i}){i("Initializing dependencies")}(this.#y),await this.initLibraryDirPython(),await this.initNunjucks(),await this.initLibsPython()}async nodeBuild(){this.#u&&(await this.createAtomLibFiles({libs:this.#a}),await this.createEngine(),await this.createProjectYaml(),await X(this.#y),await async function({atom:e,setProgress:t,context:o,packageDependencies:i}){await t({message:"Creating tsconfig.json."});const a={atom:e,packageDependencies:i},s=o.templateCommonDir,n=v.compile(g.readFileSync(h.resolve(s,"tsconfig.json.njk"),"utf8"),v.configure(s)).render(a),r=o.projectDir,c=h.resolve(r,"tsconfig.json");g.writeFileSync(c,n,"utf8")}(this.#y),await U(this.#y),await async function({atom:e,setProgress:t,context:o,njEnv:i}){if(!0!==e.doc.features.cli.enabled)return;await t({message:"Creating yargs."});let a={};if(a=e.doc.input?e.doc.input:{type:"object",properties:{},required:[]},e.doc.features.cli.fargs&&!1!==e.doc.features.cli.fargs?.enabled){const t=e.doc.features.cli.fargs,o={type:"string",description:"Config name to load args",hidden:!1},i={type:"array",description:"Tags to filter the config",hidden:!1};Reflect.has(t,"default")&&(o.default=t.default),a.properties&&(a.properties.fargs=o,a.properties.ftag=i)}const s={options:a,imports:[],atom:e},n=o.templateDir,r=v.compile(g.readFileSync(h.resolve(n,"src/default/to.args.js.njk"),"utf8"),i).render(s),c=o.projectDir,p=h.resolve(c,"src/default/to.args.js");g.writeFileSync(p,r,"utf8");const l=new O({allErrors:!0,useDefaults:!0,formats:{},strict:!1,code:{esm:!0,lines:!0,optimize:!1,source:!0}});R(l);const d=l.compile(a),m=N(l,d);g.writeFileSync(h.resolve(c,"src/default/validate_input.js"),m,"utf8")}(this.#y),await async function({atom:e,setProgress:t,context:o,packageDependencies:i}){if(!0!==e.doc.features.cli.enabled)return;await t({message:"Creating cli."});const a={atom:e,packageDependencies:i},s=o.templateDir,n=h.resolve(o.projectDir,"src/cli");g.existsSync(n)||g.mkdirSync(n,{recursive:!0}),await f({pattern:["index.js.njk"],dir:h.resolve(s,"src/cli"),outDir:n,context:a})}(this.#y),await async function({atom:e,setProgress:t,context:o,packageDependencies:i}){if(!0!==e.doc.features.app.enabled)return;await t({message:"Creating app folder"});const a={atom:e,packageDependencies:i,ts:Date.now()},s=o.templateDir,n=h.resolve(o.projectDir,"src/app");g.existsSync(n)||g.mkdirSync(n,{recursive:!0});let r=["index.js.njk"];!1!==e.doc.features.app.html&&r.push("index.html.njk"),await f({pattern:r,dir:h.resolve(s,"src/app"),outDir:n,context:a})}(this.#y),await async function({atom:e,setProgress:t,context:o,packageDependencies:i}){await t({message:"Creating rollup file."});const a={atom:e,packageDependencies:i},s=h.resolve(o.projectDir,"src","default/index.js");if(!g.existsSync(s))throw new Error(`Entry file not found: ${s}`);const n=(await S({file:s,recursive:!0})).all.filter((e=>"node"===e.type)).map((e=>e.path)),r=e.doc.features.rollup_output,c=Object.keys(r);for(let e=0;e<c.length;e++){const t=r[c[e]];if(!0===t.browser&&n.length>0){t.globals_enabled=!0,t.globals=t.globals||[],t.globals=t.globals.concat(n.map((e=>({key:e,value:e})))),t.alias_enabled=!0,t.alias=t.alias||{},t.alias.entries=t.alias.entries||{};for(let e=0;e<n.length;e++){const o=n[e];t.alias.entries[o]=`node:${o}`,t.alias.entries[`node:${o}`]=o}t.external_enabled=!0,t.external=t.external||[],t.external=t.external.concat(n)}}const p=o.templateCommonDir;let l=v.compile(g.readFileSync(h.resolve(p,"rollup.config.mjs.njk"),"utf8"),v.configure(p)).render(a);const d=o.projectDir;let m=h.resolve(d,"rollup.config.mjs");g.writeFileSync(m,l,"utf8")}(this.#y),await async function({atom:e,context:t,packageDependencies:o,packageDevDependencies:i,setProgress:a}){await a({message:"Creating package.json."}),o.filter((e=>!0===e.dev)).forEach((e=>{i.find((t=>t.package===e.package))||i.push(e);const t=o.findIndex((t=>t.package===e.package));o.splice(t,1)}));const s=o.find((e=>"react"===e.package)),n=o.find((e=>"react-dom"===e.package));s&&!n?o.push({package:"react-dom",version:s.version}):s&&n&&(n.version=s.version),s&&e.doc.features.react_version>=17&&(o.find((e=>"@emotion/react"===e.package))||o.push({package:"@emotion/react",version:"^11"}),o.find((e=>"@emotion/styled"===e.package))||o.push({package:"@emotion/styled",version:"^11"}));const r=[];!0===e.doc.features.app.enabled&&r.push({file:h.resolve(t.projectDir,"src/app/index.js"),dev:!1!==e.doc.features.app.dev}),!0===e.doc.features.cli.enabled&&r.push({file:h.resolve(t.projectDir,"src/cli/index.js"),dev:!1!==e.doc.features.cli.dev});for await(const e of r){const s=e.file;if(!g.existsSync(s))throw new Error(`App file not found: ${s}`);const n=(await S({file:s,recursive:!0})).all;for await(const s of n){if("npm"!==s.type)continue;if(o.find((e=>e.package===s.package)))continue;if(i.find((e=>e.package===s.package)))continue;const n=await J({name:s.package,projectDir:t.projectDir,setProgress:a});(!0===e.dev?i:o).push({package:s.package,subpath:s.subpath,version:n.minorRange,type:"npm"})}}const c={atom:e,packageDependencies:o,packageDevDependencies:i},p=t.templateCommonDir,l=v.compile(g.readFileSync(h.resolve(p,"package.json.njk"),"utf8"),v.configure(p)).render(c),d=t.projectDir,m=h.resolve(d,"package.json");g.writeFileSync(m,l,"utf8");const u=h.resolve(t.project.projectDir,"fnet");if(g.existsSync(u)){const e=h.resolve(t.projectDir,"fnet");g.existsSync(e)||g.mkdirSync(e);const o=g.readdirSync(u);for(const t of o){const o=h.resolve(u,t);if(!g.lstatSync(o).isFile())continue;const i=h.resolve(e,t);g.copyFileSync(o,i)}}}(this.#y),await async function({setProgress:t,context:o}){const i=o.projectDir;await t({message:"Prettifiying source files."});let a=e.join("src","**","*");await u({commands:{steps:[`prettier --write ${a} *.{js,cjs,mjs,json,yaml,html} --no-error-on-unmatched-pattern`],wdir:i}})}(this.#y),await async function({atom:e,setProgress:t,context:o}){if(!e.doc.features.dts_enabled)return;const i=o.projectDir;if(await t({message:"Creating .d.ts"}),0!==(await c("tsc",{cwd:i})).code)throw new Error("Couldnt create .d.ts files.")}(this.#y),this.#f&&(await async function({setProgress:e,atom:t,context:o}){const i=o.projectDir;await e({message:"Installing npm packages."});const a=K("bun")?"bun":"npm";if(0!==(await c(`${a} install ${t.doc.features.npm_install_flags}`,{cwd:i})).code)throw new Error("Couldnt install npm packages.")}(this.#y),await async function({setProgress:e,context:t}){const o=t.projectDir;if(await e({message:"Building main project."}),0!==(await c("npm run build",{cwd:o})).code)throw new Error("Couldnt build project.")}(this.#y),this.#g&&await this.deploy()))}async pythonBuild(){this.#u&&(await this.createAtomLibFilesPython({libs:this.#a}),await this.createProjectYaml(),await X(this.#y),await U(this.#y),await async function({atom:e,setProgress:t,context:o,packageDependencies:i}){if(!0!==e.doc.features.cli.enabled)return;await t({message:"Creating cli."});const a={atom:e,packageDependencies:i},s=o.templateDir,n=h.join(o.projectDir,"src","cli");g.existsSync(n)||g.mkdirSync(n,{recursive:!0}),await f({pattern:["index.py.njk","__init__.py.njk"],dir:h.join(s,"src","cli"),outDir:n,context:a})}(this.#y),this.#f&&(await async function(e){const{setProgress:t,atom:o,context:i}=e;t({message:"Installing Python packages"});const a=i.projectDir,s=await L({pythonVersion:"3.12",packages:[{package:"fnet-import-parser",version:"0.1.9"}]}),{errors:n,result:r}=await s.runBin("fnet_import_parser",["--entry_file",h.join(a,"src","default","index.py")],{captureName:"result"});if(n)throw new Error(n.format());const c=JSON.parse(r.items[0].stdout),p=c.required["third-party"]?.map((e=>({package:e.metadata?.package||e.path,version:e.metadata?.version||void 0,channel:e.metadata?.channel||void 0})))||[],l=o.doc.dependencies||[];for(const e of p)l.some((t=>t.package===e.package))||l.push(e);const d=h.join(a,".conda"),m=await L({envDir:d,pythonVersion:o.doc.features.runtime.version||"3.12",packages:l});i.pythonEnv=m,e.packageDependencies=l;const u=o.doc.features.render?.dirs||[];for(const e of u)e.dir=h.resolve(a,e.dir),e.outDir=h.resolve(a,e.outDir),await f(e);let g={params:{}};g.params.package_name=o.doc.name,g.params.version="0.1.0",g.params.bin_name=o.doc.name,g.params.python_requires=o.doc.features.runtime.version||">=3.12",g.params.dependencies=l,g.params.scripts=JSON.stringify({cli:`PYTHONPATH='${h.join("src")}' '${h.relative(i.projectDir,m.pythonBin)}' '${h.join("src","cli","index.py")}'`}),await f({pattern:["setup.py.njk","package.json.njk","pyproject.toml.njk"],dir:i.templateDir,outDir:i.projectDir,context:g})}(this.#y),this.#g&&await this.deploy()))}async init(){this._redis_client=await async function(){if(!await E({host:process.env.REDIS_HOST,port:process.env.REDIS_PORT}))return;const e=$.createClient({socket:{host:process.env.REDIS_HOST,port:process.env.REDIS_PORT}});return await e.connect(),e}(),this.#c=this.#t.buildId||x(),this.#y.buildId=this.#c,this.#m=this.#t.mode,this.#u=["all","deploy","build","file"].includes(this.#m),this.#f=["all","deploy","build"].includes(this.#m),this.#g=["all","deploy"].includes(this.#m),this.#l=this.#t.protocol,this.#p="BUILD:"+this.#c,this.#d=(await d({optional:!0,name:this.#t.atomConfig||"atom",dir:this.#t.projectDir,tags:this.#t.tags}))?.data;try{await this.setProgress({message:"Initialization started."}),await this.initAuth(),await this.initLibrary(),"node"===this.#o.doc.features.runtime.type?await this.initNode():"python"===this.#o.doc.features.runtime.type&&await this.initPython()}catch(e){throw await this._cache_set(this.#p,{status:"FAILED",message:e?.message||e}),e}}async build(){try{"node"===this.#o.doc.features.runtime.type?await this.nodeBuild():"python"===this.#o.doc.features.runtime.type&&await this.pythonBuild(),await this._cache_set(this.#p,{status:"COMPLETED"})}catch(e){throw await this._cache_set(this.#p,{status:"FAILED",message:e.message||e}),console.log(e),e}}}const V=h.dirname(t(import.meta.url));var G="0.101.0";const W=e.dirname(t(import.meta.url)),Z=process.cwd();d({name:["redis"],dir:Z,optional:!0});const Q=function({baseDir:e}){let t=e=e||V;for(;t!==h.parse(t).root;){const e=h.join(t,"node_modules");if(g.existsSync(e))return e;t=h.dirname(t)}return null}({baseDir:W}),ee="win32"===process.platform?";":":";Q&&(process.env.PATH=`${e.join(Q,"/.bin")}${ee}${process.env.PATH}`);const te=new a;function oe(e,{name:t,bin:i,preArgs:a=[]}){const s=t||i;e.command(s,{isDefault:!1,hidden:!1}).description(`Run ${i} ${a.join(" ")} in project context. Pass arguments after '--'.`).argument("[command_args...]",`Arguments for ${i}`).allowUnknownOption().action((async(e,t)=>{try{const s=await ae(t),{projectDir:n}=s,r=e;console.log(r);const c=o(i,[...a,...r],{cwd:n,stdio:"inherit",shell:!0});c.on("close",(e=>{process.exit(e)})),c.on("error",(e=>{console.error(`Failed to start ${i}:`,e),process.exit(1)}))}catch(e){console.error(e.message),process.exit(1)}}))}function ie(t,{name:i,bin:a,preArgs:s=[]}){const r=i||a;t.command(r,{isDefault:!1,hidden:!1}).description(`Run ${a} ${s.join(" ")} using project's conda env. Pass arguments after '--'.`).argument("[command_args...]",`Arguments for ${a}`).allowUnknownOption().action((async(t,r)=>{try{const c=await ae(r),{projectDir:p}=c,l=e.join(p,".conda","bin",a||i);if(!n.existsSync(e.dirname(l)))throw new Error(`Conda environment not found in ${e.join(p,".conda")}. Did you initialize it?`);if(!n.existsSync(l))throw new Error(`Command '${a||i}' not found in conda environment: ${l}`);const d=t,m=o(l,[...s,...d],{cwd:p,stdio:"inherit",shell:!1,env:{...process.env,PYTHONPATH:p}});m.on("close",(e=>{process.exit(e)})),m.on("error",(e=>{console.error(`Failed to start ${l}:`,e),process.exit(1)}))}catch(e){console.error(e.message),process.exit(1)}}))}async function ae(t){if(t.id)return{id:t.id,buildId:t.buildId,mode:t.mode,protocol:t.protocol||"ac:",templateDir:e.resolve(Q,"./@fnet/cli-project-node/dist/template/default"),templateCommonDir:e.resolve(Q,"./@fnet/cli-project-common/dist/template/default"),projectDir:e.resolve(Z,`./.output/${t.id}`),tags:t.ftag||[]};{const o=await async function({tags:t=[]}){const o=e.resolve(Z,"node.yaml");if(!n.existsSync(o))throw new Error("node.yaml file not found in current directory.");const i=Array.isArray(t)?t:t?[t]:[],{raw:a,parsed:s}=await l({file:o,tags:i}),c=e.dirname(o);s.features=s.features||{};const p=s.features;p.runtime=p.runtime||{},p.runtime.type=p.runtime.type||"node","python"===p.runtime.type?p.runtime.template=p.runtime.template||"python":p.runtime.template=p.runtime.template||"default";const d={libraryAtom:{doc:{...s},fileName:"index"},projectDir:c,projectFilePath:o,projectFileContent:a,projectFileParsed:s,runtime:p.runtime};let m=e.resolve(c,"fnet/targets.yaml");if(!n.existsSync(m)&&(m=e.resolve(c,"node.devops.yaml"),n.existsSync(m))){const t=e.resolve(c,"fnet");n.existsSync(t)||n.mkdirSync(t);const o=e.resolve(c,"fnet/targets.yaml");n.copyFileSync(m,o);try{n.unlinkSync(m),console.log(`Migrated legacy devops file: ${m} to ${o}`)}catch(e){console.warn(`Could not delete legacy devops file ${m}: ${e.message}`)}}if(n.existsSync(m)){const{raw:e,parsed:t}=await l({file:m,tags:i}),o=r.parseDocument(e);d.devops={filePath:m,fileContent:e,yamlDocument:o,doc:{...t},type:"library.deploy",save:async()=>{n.writeFileSync(d.devops.filePath,o.toString())}}}const u=e.resolve(c,"readme.md");if(n.existsSync(u)){const e=n.readFileSync(u,"utf8");d.readme={filePath:u,fileContent:e,doc:{content:e,"content-type":"markdown"},type:"wiki"}}return d}({tags:t.ftag||[]});return{buildId:t.buildId,mode:t.mode,protocol:t.protocol||"local:",templateDir:e.resolve(Q,`./@fnet/cli-project-node/dist/template/${o.runtime.template}`),templateCommonDir:e.resolve(Q,`./@fnet/cli-project-common/dist/template/${o.runtime.template}`),projectDir:e.resolve(o.projectDir,"./.workspace"),projectSrcDir:e.resolve(o.projectDir,"./src"),project:o,tags:t.ftag||[]}}}te.name("fnode").version(G).description("CLI tool for FlowNet node projects"),te.command("create").description("Create flow node project").requiredOption("-n, --name <string>","Project name").addOption(new s("-r, --runtime <type>","Runtime environment").choices(["node","python"]).default("node")).option("--vscode","Open project in VSCode after creation",!0).option("--no-vscode","Do not open project in VSCode").action((async t=>{try{const o=e.resolve(Q,"@fnet/cli-project-node/dist/template/project"),i=e.resolve(Z,t.name);n.existsSync(i)||n.mkdirSync(i),await f({dir:o,outDir:i,context:{name:t.name,runtime:t.runtime,platform:p.platform()},copyUnmatchedAlso:!0});let a=await c("fnode build",{cwd:i});if(0!==a.code)throw new Error("Failed to build project.");if(K("git")&&(a=await c("git init --initial-branch=main",{cwd:i}),0!==a.code))throw new Error("Failed to initialize git.");if(t.vscode&&K("code")&&(a=await c(`cd ${i} && code .`),0!==a.code))throw new Error("Failed to open vscode.");console.log("Creating project succeeded!"),process.exit(0)}catch(e){console.error("Initialization failed!",e.message),process.exit(1)}})),te.command("project").description("Flow node project operations").option("-u, --update","Update project files from template",!1).action((async t=>{try{const o=e.resolve(Q,"@fnet/cli-project-node/dist/template/project"),i=process.cwd(),a=await ae(t);if(t.update){if(await f({dir:o,outDir:i,context:{name:a.project.projectFileParsed.name,runtime:a.project.runtime.type,platform:p.platform()},copyUnmatchedAlso:!0}),0!==(await c("fnode build",{cwd:i})).code)throw new Error("Failed to build project.");console.log("Updating project succeeded!")}else console.log("Use 'fnode project --update' to update project files.");process.exit(0)}catch(e){console.error("Project command failed.",e.message),process.exit(1)}})),te.command("build").description("Build flow node project").option("--id <string>","Build identifier").option("--buildId <string>","Specific build ID (alias: bid)").addOption(new s("--mode <mode>","Build mode").choices(["all","file","build","deploy","bpmn"]).default("build")).option("--ftag <tags...>","Filter tags (specify multiple times or space-separated)").action((async e=>{try{const t=await ae(e),o=new Y(t);await o.init(),await o.build(),console.log("Building library succeeded!"),process.exit(0)}catch(e){console.error("Building library failed!",e.message),process.exit(1)}})),te.command("deploy").description("Build and deploy flow node project").option("--id <string>","Build identifier").option("--buildId <string>","Specific build ID").option("--ftag <tags...>","Filter tags").action((async e=>{try{const t=await ae({...e,mode:"all"}),o=new Y(t);await o.init(),await o.build(),console.log("Building and deploying library succeeded!"),process.exit(0)}catch(e){console.error("Building/deploying library failed!",e.message),process.exit(1)}})),te.command("file").description("Just create files (part of build process)").option("--id <string>","Build identifier").option("--buildId <string>","Specific build ID").option("--ftag <tags...>","Filter tags").action((async e=>{try{const t=await ae({...e,mode:"file"}),o=new Y(t);await o.init(),await o.build(),console.log("Creating files succeeded!"),process.exit(0)}catch(e){console.error("Creating files failed!",e.message),process.exit(1)}})),te.command("input").description("Create or modify an input config file").argument("[name]","Optional input configuration name (e.g., dev, prod)").action((async(t,o)=>{try{const a=await ae({...o,name:t}),{project:s}=a,{projectDir:r,projectFileParsed:c}=s,p=c.input;if(!p)throw new Error("Config schema not found in project file.");let l=t;if(!l){l=(await i({type:"input",name:"inputName",message:"Input name:",initial:"dev"})).inputName}const d=e.resolve(r,".fnet");n.existsSync(d)||n.mkdirSync(d);const u=e.resolve(d,`${l}.fnet`),f=n.existsSync(u),g=await m({schema:p,format:"yaml",ref:f?u:void 0});n.writeFileSync(u,g),console.log(`Input config '${l}.fnet' ${f?"updated":"created"}.`)}catch(e){console.error(e.message),process.exit(1)}})),oe(te,{bin:"npm"}),oe(te,{bin:"node"}),oe(te,{bin:"bun"}),oe(te,{name:"serve",bin:"npm",preArgs:["run","serve"]}),oe(te,{name:"watch",bin:"npm",preArgs:["run","watch"]}),oe(te,{name:"app",bin:"npm",preArgs:["run","app"]}),oe(te,{name:"cli",bin:"npm",preArgs:["run","cli"]}),oe(te,{bin:"npx"}),oe(te,{bin:"cdk"}),oe(te,{bin:"aws"}),function(e,{name:t,preArgs:i=[]}){e.command(t).description("Run a command with environment variables from a .fnet config file.").argument("<config>","Name of the .fnet config file (without extension)").argument("<command>","The command to execute").argument("[command_args...]","Arguments for the command").option("--ftag <tags...>","Filter tags for loading config").allowUnknownOption().action((async(e,t,a,s)=>{try{const r=await ae(s),{projectDir:c}=r,p=await d({name:e,dir:c,transferEnv:!1,optional:!0,tags:r.tags}),l=p?.data?.env||{},m=o(t,[...i,...a],{cwd:n.existsSync(c)?c:Z,stdio:"inherit",shell:!0,env:{...process.env,...l}});m.on("close",(e=>{process.exit(e)})),m.on("error",(e=>{"ENOENT"===e.code?console.error(`Error: Command not found: '${t}'. Is it installed or in your PATH?`):console.error(`Failed to start command '${t}':`,e),process.exit(1)}))}catch(e){console.error(e.message),process.exit(1)}}))}(te,{name:"with"}),function(e,{name:t,preArgs:o=[]}){e.command(t).description("Run a command group defined in node.yaml.").argument("<group>","Name of the command group in node.yaml commands section").option("--ftag <tags...>","Filter tags for loading project config").version(!1).action((async(e,t)=>{try{const o=await ae(t),{project:i}=o,{projectFileParsed:a}=i,s=a.commands;if(!s)throw new Error("`commands` section not found in project file (node.yaml).");const n=s[e];if(!n)throw new Error(`Command group '${e}' not found in project file.`);await u({commands:n}),process.exit(0)}catch(t){console.error(`Error running command group '${e}':`,t.message),process.exit(1)}}))}(te,{name:"run"}),ie(te,{name:"python"}),ie(te,{name:"python3"}),ie(te,{name:"pip"}),ie(te,{name:"pip3"}),te.parse(process.argv),process.argv.slice(2).length||te.outputHelp();export{K as w};