@yr-lang/yr 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/BUGS.md +35 -0
  2. package/CNAME +1 -0
  3. package/LICENSE +42 -0
  4. package/README.md +21 -0
  5. package/lib/%build.yr +3 -0
  6. package/lib/%deploy.yr +7 -0
  7. package/lib/%gh-pages.yr +60 -0
  8. package/lib/%nvm.yr +18 -0
  9. package/lib/%serve.yr +7 -0
  10. package/lib/.yrrc +2 -0
  11. package/lib/Ciyr/A1.yr +25 -0
  12. package/lib/Ciyr/B1.yr +11 -0
  13. package/lib/Ciyr/B2.yr +0 -0
  14. package/lib/Ciyr/C1.yr +14 -0
  15. package/lib/Ciyr/C2.yr +5 -0
  16. package/lib/Ciyr/C2_2.yr +5 -0
  17. package/lib/Ciyr/a1.yr +23 -0
  18. package/lib/Ciyr/b1.yr +21 -0
  19. package/lib/Ciyr/c1.yr +18 -0
  20. package/lib/Yrci/&app.yr +1 -0
  21. package/lib/Yrci/&app2.yr +1 -0
  22. package/lib/Yrci/@m1.yr +7 -0
  23. package/lib/Yrci/@m2.yr +11 -0
  24. package/lib/Yrci/A1.yr +8 -0
  25. package/lib/Yrci/A2.yr +26 -0
  26. package/lib/Yrci/A3.yr +51 -0
  27. package/lib/Yrci/B1.yr +8 -0
  28. package/lib/Yrci/C1.yr +58 -0
  29. package/lib/Yrci/C1.yrr +14 -0
  30. package/lib/Yrci/C2.yr +17 -0
  31. package/lib/Yrci/C3.yr +28 -0
  32. package/lib/Yrci/C4.yr +4 -0
  33. package/lib/Yrci/C5.yr +3 -0
  34. package/lib/Yrci/C6.yr +7 -0
  35. package/lib/Yrci/C7.yr +3 -0
  36. package/lib/Yrci/C8.yr +3 -0
  37. package/lib/Yrci/C9.yr +11 -0
  38. package/lib/Yrci/Index_.yr +4 -0
  39. package/lib/Yrci/Login.yr +3 -0
  40. package/lib/Yrci/M1.yr +7 -0
  41. package/lib/Yrci/Sp.yr +5 -0
  42. package/lib/Yrci/T1.yr +4 -0
  43. package/lib/Yrci/T2.yr +4 -0
  44. package/lib/Yrci/Ta1.yr +4 -0
  45. package/lib/Yrci/Ta2.yr +4 -0
  46. package/lib/Yrci/Tg.yr +5 -0
  47. package/lib/Yrci/Wr.yr +7 -0
  48. package/lib/Yrci/Wrapper.yr +14 -0
  49. package/lib/Yrci/Wrapper1.yr +5 -0
  50. package/lib/Yrci/Wrapper2.yr +24 -0
  51. package/lib/Yrci/Wrapper3.yr +5 -0
  52. package/lib/Yrci/Wrapperext.yr +4 -0
  53. package/lib/Yrci/Wrt.yr +3 -0
  54. package/lib/Yrci/Yrwm.yr +32 -0
  55. package/lib/Yrci/a1.yr +18 -0
  56. package/lib/Yrci/a2.yr +10 -0
  57. package/lib/Yrci/app.yr +3 -0
  58. package/lib/Yrci/b2.yr +10 -0
  59. package/lib/Yrci/j1.yr +5 -0
  60. package/lib/Yrci/j2.yr +5 -0
  61. package/lib/Yrci/j3.yr +3 -0
  62. package/lib/Yrci/modal.yr +5 -0
  63. package/lib/bodyblock.yr +13 -0
  64. package/lib/ci.yr +21 -0
  65. package/lib/crypto.yr +13 -0
  66. package/lib/element.yr +358 -0
  67. package/lib/hidden.yr +9 -0
  68. package/lib/utils.yr +13 -0
  69. package/node.js +807 -0
  70. package/package.json +14 -0
  71. package/src/common.js +7 -0
  72. package/yr.js +1308 -0
package/node.js ADDED
@@ -0,0 +1,807 @@
1
+ const fs = require('fs');
2
+ const vm = require('vm');
3
+ const spawn = require('child_process').spawn;
4
+ const common = require('./src/common');
5
+ const core = require('./yr');
6
+ const yrlib = __dirname + '/lib';
7
+
8
+ const env = {
9
+ HOME: process.env.HOME,
10
+ LIBS: [yrlib, process.env.HOME + '/.yrlibs'],
11
+ BUILDS: process.env.HOME + '/.yrb'
12
+ };
13
+
14
+ fs.mkdirSync(process.env.HOME + '/.yrlibs', { recursive: true });
15
+ fs.mkdirSync(process.env.HOME + '/.yrb', { recursive: true });
16
+
17
+ function getWrapperName(item) {
18
+ return (item.category && item.category !== 'yr')
19
+ ? `${item.category}/${item.option}` : item.option;
20
+ }
21
+
22
+ function parsePaths(newPaths, useWildcard=false) {
23
+ let newStrPath = [];
24
+
25
+ for (let item of newPaths.split(',')) {
26
+ if (!useWildcard) {
27
+ if (item.startsWith(process.env.HOME)) item = item.replace(process.env.HOME, '~/');
28
+ if (item.startsWith(__dirname)) item = item.replace(__dirname, './');
29
+ } else {
30
+ if (item.startsWith('~/')) item = item.replace(/~/, process.env.HOME);
31
+ if (item.startsWith('./')) item = item.replace(/\./, __dirname);
32
+ }
33
+
34
+ newStrPath.push(item.replace(/\/\//g, '/'));
35
+ }
36
+
37
+ return newStrPath.join(',');;
38
+ };
39
+
40
+ module.exports = {
41
+ env,
42
+ mergeYrSections(sections, extensions=false) {
43
+ function _updateBlockAttributes(code, referenceId, attributes) {
44
+ function buildAttributes(obj) {
45
+ const list = [];
46
+ for (const key in obj) {
47
+ if (obj[key] != null) {
48
+ let k = key.toString();
49
+ let v = obj[key].toString();
50
+ const quotesK = k.includes('"') ? "'" : '"';
51
+ const quotesV = v.includes('"') ? "'" : '"';
52
+ k = k.includes(",") || k.includes(" ") ? `${quotesK}${k}${quotesK}` : k;
53
+ v = v.includes(",") || v.includes(" ") ? `${quotesV}${v}${quotesV}` : v;
54
+ list.push(`${k}: ${v}`);
55
+ }
56
+ }
57
+ return list.length ? `att={{ ${list.join(", ")} }}` : null;
58
+ }
59
+
60
+ const newAtt = buildAttributes(attributes);
61
+ if (!newAtt) return code;
62
+
63
+ const lines = code.split("\n");
64
+
65
+ for (let i = 0; i < lines.length; i++) {
66
+ let line = lines[i];
67
+
68
+ // Find first token (first non-whitespace)
69
+ let firstIdx = 0;
70
+ while (firstIdx < line.length && /\s/.test(line[firstIdx])) firstIdx++;
71
+ if (firstIdx >= line.length) continue;
72
+
73
+ let tokenEnd = firstIdx;
74
+ while (tokenEnd < line.length && !/\s/.test(line[tokenEnd])) tokenEnd++;
75
+ const firstToken = line.slice(firstIdx, tokenEnd);
76
+
77
+ // Validate first token
78
+ const core = firstToken.startsWith("_!") ? firstToken.slice(2) : firstToken.slice(1);
79
+ const slashIdx = core.indexOf("/");
80
+ if (slashIdx <= 0 || slashIdx >= core.length - 1) continue;
81
+
82
+ // Find the last dot-segment sequence that contains the referenceId
83
+ const dotRegex = new RegExp(`\\.${referenceId}(?:\\.[\\w]+)*`, "g");
84
+ let match;
85
+ let lastDotStart = -1;
86
+ let lastDotEnd = -1;
87
+ while ((match = dotRegex.exec(line)) !== null) {
88
+ lastDotStart = match.index;
89
+ lastDotEnd = match.index + match[0].length;
90
+ }
91
+ if (lastDotStart === -1) continue;
92
+
93
+ // Check for existing att={{ … }} after the lastDotEnd
94
+ let attStart = line.indexOf("att={{", lastDotEnd);
95
+ if (attStart >= 0) {
96
+ // Find the matching closing }} while respecting quotes
97
+ let iChar = attStart + 6;
98
+ let inSingle = false, inDouble = false;
99
+ let attEnd = -1;
100
+ while (iChar < line.length - 1) {
101
+ const ch = line[iChar];
102
+ if (ch === "'" && !inDouble) inSingle = !inSingle;
103
+ else if (ch === '"' && !inSingle) inDouble = !inDouble;
104
+ else if (ch === "}" && line[iChar + 1] === "}" && !inSingle && !inDouble) {
105
+ attEnd = iChar + 2;
106
+ break;
107
+ }
108
+ iChar++;
109
+ }
110
+ if (attEnd > attStart) {
111
+ line = line.slice(0, attStart) + newAtt + line.slice(attEnd);
112
+ lines[i] = line;
113
+ continue;
114
+ }
115
+ }
116
+
117
+ // Insert att={{ … }} after last dot-segment, preserving trailing spaces
118
+ let insertPos = lastDotEnd;
119
+ while (insertPos < line.length && /\s/.test(line[insertPos])) insertPos++;
120
+ line = line.slice(0, lastDotEnd) + " " + newAtt + line.slice(lastDotEnd);
121
+ lines[i] = line;
122
+ }
123
+
124
+ return lines.join("\n");
125
+ }
126
+
127
+ let result = '';
128
+ if (extensions) result += extensions + '\n';
129
+
130
+ for (let item of ['nosection', 'extensions']) {
131
+ if (sections[item]) {
132
+ result += sections[item] + '\n';
133
+ delete sections[item];
134
+ }
135
+ }
136
+
137
+ for (let item of sections.wrapperjs.split('\n')) {
138
+ if (!item) continue;
139
+ let _config;
140
+ try {
141
+ _config = JSON.parse('{' + (item.split('({')[1].split('})')[0]) + '}');
142
+ } catch(error) { continue; }
143
+ if (!_config.attributes) continue;
144
+ const attributes = {};
145
+ for (let value of _config.attributes) attributes[value] = _config[value];
146
+ sections.body = _updateBlockAttributes(sections.body, _config.id, attributes);
147
+ }
148
+
149
+ delete sections.wrapperjs;
150
+
151
+ for (let item in sections)
152
+ result += `${core.parsers.names[item]}\n\n${sections[item]}\n`;
153
+
154
+ return result;
155
+ },
156
+ tree(dirPath, config={}, result=[]) {
157
+ const dirs = fs.readdirSync(dirPath, 'utf8').map(item => {
158
+ const path = `${dirPath}/${item}`;
159
+ const isDir = fs.lstatSync(path).isDirectory();
160
+
161
+ if ((isDir && (item === '.git' || item.includes('node_modules') || item.includes('__pycache__')))
162
+ || (!isDir && item.endsWith('.swp'))) return false;
163
+
164
+ if (config.dirName && item !== config.dirName
165
+ && (isDir || (!isDir && !path.endsWith(`${config.dirName}/${item}`))))
166
+ return false;
167
+
168
+ if (config.filename && item !== config.filename && !isDir) return false;
169
+
170
+ if (config.yr) {
171
+ if (!isDir && !item.endsWith('.yr') && !config.yrCategory) return false;
172
+
173
+ if (!isDir) {
174
+ const result = {
175
+ isDir, category: (config.yrCategory) ? config.yrCategory : false,
176
+ option: item.replace(/\.yr/g, '')
177
+ };
178
+
179
+ if (config.yr === 'code') {
180
+ result.yr = fs.readFileSync(path, 'utf8');
181
+ result.vars = module.exports.parse(result.yr, { onlyVars: true });
182
+ }
183
+
184
+ if (config.yr === 'wrapper') {
185
+ if (!/^[A-Z]/.test(item) || !item.endsWith('.yr')) return false;
186
+
187
+ result.vars = module.exports
188
+ .parse(fs.readFileSync(path, 'utf8'), { onlyVars: true });
189
+ }
190
+
191
+ return result;
192
+ }
193
+
194
+ return { isDir, path, name: item, yr: config.yr, tree: config.tree };
195
+ }
196
+
197
+ const result = { isDir, path, name: item, tree: config.tree };
198
+ if (config.file && !isDir) result.file = fs.readFileSync(path, 'utf8');
199
+ return result;
200
+ }).sort((a, b) => {
201
+ const multiple = (config.filesFirst) ? 0 : -1;
202
+ return (a.isDir - b.isDir) * multiple || (b.name - a.name) * multiple;
203
+ });
204
+
205
+ for (let item of dirs) {
206
+ if (!item) continue;
207
+
208
+ if (item.isDir) {
209
+ if (!config.onlyLibs && !config.yr) result.push(item);
210
+ if (item.yr) config.yrCategory = item.name;
211
+ if (fs.existsSync(`${item.path}/.yrrc`)) item.yrlib = true;
212
+ result = this.tree(item.path, config, result);
213
+ } else {
214
+ if (config.onlyLibs) {
215
+ if (item.name !== '.yrrc') continue;
216
+ result.push(dirPath);
217
+ break;
218
+ } else {
219
+ result.push(item);
220
+ }
221
+ }
222
+ }
223
+
224
+ return result;
225
+ },
226
+ set(newEnv) {
227
+ for (let item of ['TREE', 'BUILDS', 'VIEWS', 'CONFIG']) {
228
+ if (item === 'TREE') {
229
+ env.LIBS = [yrlib];
230
+
231
+ if (newEnv.TREE) {
232
+ for (let value of newEnv.TREE) env.LIBS = [ ...env.LIBS,
233
+ ...this.tree(parsePaths(value, true), {
234
+ onlyLibs: true, filesFirst: true
235
+ })
236
+ ];
237
+ }
238
+ }
239
+
240
+ env[item] = newEnv[item];
241
+ }
242
+ },
243
+ spawn(path, args=[], callbackClose=false, log=true, exit=false, callbackData=false, callbackError=false) {
244
+ if (args === '-k') {
245
+ try {
246
+ console.log('killing spawn');
247
+ console.log(path, args);
248
+ //path.stdin.pause();
249
+ path.kill();
250
+ console.log('spawn killed');
251
+ } catch(error) { console.log(error); }
252
+
253
+ return;
254
+ }
255
+
256
+ if (log) console.log('starting spawn...');
257
+
258
+ const child = spawn(path, args, { shell: true });
259
+
260
+ //child.stdin.on('data', function(data){
261
+ // console.log(data.toString());
262
+ //});
263
+
264
+ child.stdout.on('data', (data) => {
265
+ data = data.toString();
266
+ if (log) console.log(data);
267
+ if (callbackData) callbackData(data);
268
+ });
269
+
270
+ child.stderr.on('data', (data) => {
271
+ data = data.toString();
272
+ if (log) console.log('\x1b[31m' + data + '\x1b[0m');
273
+ if (callbackError) callbackError(data);
274
+ });
275
+
276
+ child.on('exit', (code, signal) => {
277
+ if (log) console.log('finish spawn\n');
278
+ //if (state.building === 1) {
279
+ // state.building = true;
280
+ // return this.devops(appName, deploy, log, exit);
281
+ //}
282
+ //state.building = false;
283
+ if (callbackClose) callbackClose(code, signal);
284
+ if (exit) process.exit();
285
+ });
286
+
287
+ return child;
288
+ },
289
+ build(projectName=false, config={}, viewsPaths=env.VIEWS, assetsPath=false) {
290
+ if (!config) config = {};
291
+
292
+ if (config.save && !projectName)
293
+ throw "Can't save build, no project name";
294
+
295
+ const result = {
296
+ html: [], app: '', devops: {}, modules: [], macros: {},
297
+ config: (config.projectConfig)
298
+ ? config.projectConfig : require(`${env.CONFIG}/yrconfig.json`)
299
+ };
300
+
301
+ const projectPath = (projectName) ? `${
302
+ (config.buildPath) ? config.buildPath : env.BUILDS
303
+ }/${projectName}` : false;
304
+
305
+ fs.mkdirSync(projectPath, { recursive: true });
306
+
307
+ const views = [];
308
+ const app = { jsapp: [], appheader: [], app: [], appfooter: [] };
309
+ let devops = [];
310
+
311
+ const buildWithPages = [];
312
+ if (result.config.config.buildWith) {
313
+ for (let value of result.config.config.buildWith) {
314
+ const appName = (value.includes(':')) ? value.split(':')[0] : value;
315
+ const viewName = (value.includes(':')) ? value.split(':')[1] : value;
316
+
317
+ let hasView;
318
+ for (let key of views) {
319
+ if (key.wrapper.option === utils.capitalize(viewName) + '_') {
320
+ hasView = true;
321
+ break;
322
+ }
323
+ }
324
+
325
+ if (hasView) continue;
326
+
327
+ buildWithPages.push({ wrapper: {
328
+ category: false, option: utils.capitalize(viewName) + '_',
329
+ yr: `!! &authapp\n><\n_${appName.toLowerCase()}/app`
330
+ } });
331
+ }
332
+ }
333
+ if (buildWithPages.length > 0) viewsPaths.push({ pages: buildWithPages });
334
+
335
+ for (let value of viewsPaths) {
336
+ let pages = [], ignoreViews;
337
+
338
+ if (value.pages) {
339
+ pages = value.pages;
340
+ ignoreViews = true;
341
+ }
342
+
343
+ if (!ignoreViews) {
344
+ if (value.includes('/')) {
345
+ pages = [value.split('/')[1] + '_.yr'];
346
+ value = value.split('/')[0];
347
+ } else { pages = this.getViews(value); }
348
+ }
349
+
350
+ for (let key of pages) {
351
+ let wrapper = {}, ignoreLib;
352
+
353
+ if (key.wrapper) {
354
+ wrapper = key.wrapper;
355
+ ignoreLib = true;
356
+ }
357
+
358
+ if (!ignoreLib)
359
+ wrapper = this.lib(value, key.replace(/\.yr/g, ''));
360
+
361
+ const viewName = wrapper.option.toLowerCase().replace(/_\.yr/g, '')
362
+ .replace(/_$/, '');
363
+
364
+ const itemName =
365
+ `${(wrapper.category) ? wrapper.category + '/': ''}${viewName}`;
366
+
367
+ wrapper = this.parse(wrapper.yr, {
368
+ name: viewName, window: config.window,
369
+ localStorage: config.localStorage
370
+ });
371
+
372
+ const item = { name: itemName, output: { ...wrapper } };
373
+
374
+ for (let value of ['jsapp', 'appheader', 'app', 'appfooter']) {
375
+ if (item.output[value])
376
+ app[value] = [...new Set([...app[value], ...item.output[value]])];
377
+ }
378
+
379
+ devops = [...item.output.devops, ...devops];
380
+ result.macros = { ...item.output.macros, ...result.macros };
381
+
382
+ result.modules = [...new Set([
383
+ ...item.output.modules, ...result.modules
384
+ ])];
385
+
386
+ views.push(item);
387
+ }
388
+ }
389
+
390
+ for (let value of ['jsapp', 'appheader', 'app', 'appfooter'])
391
+ result.app += app[value].join('');
392
+
393
+ for (let value of devops) {
394
+ for (let key in value) {
395
+ if (!result.devops[key]) result.devops[key] = '';
396
+ if (result.devops[key].includes(value[key])) continue;
397
+ result.devops[key] += value[key];
398
+ }
399
+ }
400
+
401
+ if (!fs.existsSync(`${projectPath}/.env.json`)) {
402
+ const newEnv = JSON.parse(JSON.stringify(env));
403
+
404
+ for (let item of ['HOME', 'LIBS', 'BUILDS', 'TREE', 'CONFIG']) {
405
+ if (typeof newEnv[item] === 'object') {
406
+ newEnv[item] = parsePaths(newEnv[item].join(',')).split(',');
407
+ } else {
408
+ newEnv[item] = parsePaths(newEnv[item]);
409
+ }
410
+ }
411
+
412
+ if (projectName !== 'yrdev') newEnv.VIEWS = [];
413
+
414
+ fs.writeFileSync(`${projectPath}/.env.json`,
415
+ JSON.stringify(newEnv, null, 2));
416
+ }
417
+
418
+ result.app = `#!/usr/bin/env node
419
+ const window = {
420
+ localStorage: {
421
+ getItem: () => null,
422
+ setItem: () => {},
423
+ },
424
+ __api: '',
425
+ };
426
+ const fs = require('fs');
427
+ let _PROJECT_PATH = '${parsePaths(projectPath)}';
428
+ const _globals = [];
429
+ function parsePaths(newPaths) {
430
+ let newStrPath = [];
431
+ for (let item of newPaths.split(',')) {
432
+ if (item.startsWith('~/')) item = item.replace(/~/, process.env.HOME);
433
+ if (item.startsWith('./')) item = item.replace(/\\./, __dirname);
434
+ newStrPath.push(item.replace(/\\/\\//g, '/'));
435
+ }
436
+
437
+ return newStrPath.join(',');
438
+ }
439
+ function setGlobal(name, item) {
440
+ if (!_globals.includes(name)) {
441
+ global[name] = item;
442
+ _globals.push(name);
443
+ }
444
+ }
445
+ _PROJECT_PATH = parsePaths(_PROJECT_PATH);
446
+ const _config = require(\`\${_PROJECT_PATH}/yrconfig.json\`);
447
+ const env = require(\`\${_PROJECT_PATH}/.env.json\`);
448
+ for (let item of ['HOME', 'LIBS', 'BUILDS', 'TREE', 'CONFIG']) {
449
+ if (typeof env[item] === 'object') {
450
+ env[item] = parsePaths(env[item].join(',')).split(',');
451
+ } else {
452
+ env[item] = parsePaths(env[item]);
453
+ }
454
+ }\n` + result.app;
455
+
456
+ result.app = core.macros(result, 'app');
457
+
458
+ result.modules = result.modules.join(' ');
459
+ result.devops = this.devops({
460
+ devops, modules: result.modules
461
+ }, projectPath)[0];
462
+
463
+ for (let item of views) {
464
+ const parsedHtml = item.output.ui;
465
+ result.html.push(parsedHtml);
466
+ }
467
+
468
+ if (config.save) {
469
+ let outputPaths =
470
+ [projectPath + '/yrconfig.json', projectPath + '/actions'];
471
+
472
+ for (let value of ['www', 'app']) {
473
+ try {
474
+ for (let item of fs.readdirSync(projectPath + `/${value}`))
475
+ outputPaths.push(`${projectPath}/${value}/${item}`);
476
+ } catch(error) {/* pass */}
477
+ }
478
+
479
+ for (let item of outputPaths) {
480
+ if (item.endsWith('assets')) continue;
481
+
482
+ try {
483
+ fs.rmSync(item, { recursive: true });
484
+ } catch(error) {/* pass */}
485
+ }
486
+
487
+ for (let item of [
488
+ env.BUILDS, projectPath,
489
+ `${projectPath}/www`, `${projectPath}/www/assets`,
490
+ `${projectPath}/app`, `${projectPath}/app/assets`,
491
+ `${projectPath}/actions`
492
+ ]) { if (!fs.existsSync(item)) fs.mkdirSync(item, { recursive: true }); }
493
+
494
+ fs.writeFileSync(projectPath + '/.gitignore', `*/node_modules/
495
+ */__pycache__/
496
+ *.swp
497
+ *\:Zone.Identifier
498
+ node_modules/
499
+ __pycache__/
500
+ dist/`);
501
+
502
+ fs.writeFileSync(projectPath + '/yrconfig.json', JSON.stringify(result.config, null, 2));
503
+ fs.writeFileSync(projectPath + '/app/app.js', result.app);
504
+ spawn('chmod', ['+x', projectPath + '/app/app.js']);
505
+
506
+ let modules = '', requirements = '';
507
+ for (let item of result.modules.split(' ')) {
508
+ if (!item) continue;
509
+ if (item.startsWith('pip==')) requirements += item.replace(/pip==/g, '') + '\n';
510
+ else modules += item + ' ';
511
+ }
512
+ fs.writeFileSync(`${projectPath}/node_modules.txt`, modules);
513
+ fs.writeFileSync(`${projectPath}/requirements.txt`, requirements);
514
+
515
+ for (let item in result.devops) {
516
+ fs.writeFileSync(`${projectPath}/actions/${item}`, result.devops[item])
517
+ spawn('chmod', ['+x', `${projectPath}/actions/${item}`]);
518
+ }
519
+
520
+ for (let item of result.html) {
521
+ for (let value of item) {
522
+ if (value.name.endsWith('.yr')) continue;
523
+ fs.writeFileSync(projectPath + `/www/${value.name}`, value.content);
524
+ }
525
+ }
526
+
527
+ if (projectName && assetsPath) {
528
+ for (let item of fs.readdirSync(assetsPath)) {
529
+ fs.writeFileSync(`${projectPath}/www/${item}`,
530
+ fs.readFileSync(`${assetsPath}/${item}`));
531
+ }
532
+ }
533
+
534
+ if (result.devops.build) {
535
+ this.spawn(`${projectPath}/actions/build`, [], () => {
536
+ if (config.exec) this.spawn(`${projectPath}/app/app.js`);
537
+ });
538
+ } else if (config.exec) {
539
+ this.spawn(`${projectPath}/app/app.js`);
540
+ }
541
+ }
542
+
543
+ return result;
544
+ },
545
+ actions(action, projectName, callbackClose=false, log=true, exit=false, callbackData=false, callbackError=false) {
546
+ const projectPath = (projectName) ? `${env.BUILDS}/${projectName}` : false;
547
+ return this.spawn(`${projectPath}/actions/${action}`, [], callbackClose, log, exit, callbackData, callbackError);
548
+ },
549
+ indent(code, indentation) {
550
+ let parsedCode = '';
551
+ for (let item of code.split('\n')) {
552
+ if (item === '') {
553
+ parsedCode += '\n';
554
+ continue;
555
+ }
556
+
557
+ parsedCode += common.getWhiteSpace(indentation) + item + '\n';
558
+ }
559
+
560
+ return parsedCode;
561
+ },
562
+ devops(sections, projectPath=false, obfuscate=true) {
563
+ // prevent devops from accessing files from outside env.LIB
564
+ const parsed = {};
565
+
566
+ const scrConfig = (lang) => {
567
+ if (lang === 'bash') {
568
+ return `_BUILDS="${parsePaths(env.BUILDS).replace(/~/, '$HOME')}"
569
+ _PROJECT_PATH="${parsePaths(projectPath).replace(/~/, '$HOME')}"
570
+ _CONFIG=$(cat "$_PROJECT_PATH/yrconfig.json")`;
571
+ } else if (lang.startsWith('python')) {
572
+ return `from pathlib import Path
573
+ import json
574
+
575
+ _BUILDS = Path("${parsePaths(env.BUILDS)}").expanduser()
576
+ _PROJECT_PATH = Path("${parsePaths(projectPath)}").expanduser()
577
+
578
+ with open(_PROJECT_PATH / "yrconfig.json", "r") as f:
579
+ _CONFIG = json.load(f)`;
580
+ } else if (lang.startsWith('node')) {
581
+ return `function parsePaths(newPaths) {
582
+ let newStrPath = [];
583
+ for (let item of newPaths.split(',')) {
584
+ if (item.startsWith('~/')) item = item.replace(/~/, process.env.HOME);
585
+ if (item.startsWith('./')) item = item.replace(/\\./, __dirname);
586
+ newStrPath.push(item.replace(/\\/\\//g, '/'));
587
+ }
588
+
589
+ return newStrPath.join(',');
590
+ }
591
+ const _BUILDS = parsePaths('${parsePaths(env.BUILDS)}');
592
+ const _PROJECT_PATH = parsePaths('${parsePaths(projectPath)}');
593
+ const _CONFIG = require(\`\${_PROJECT_PATH}/yrconfig.json\`);`;
594
+ }
595
+ return '';
596
+ };
597
+
598
+ const newDevops = (projectPath, shebang='', addDist=false) => {
599
+ const lang = shebang.startsWith('#!') ? shebang.replace(/#!/, '') : 'bash';
600
+ shebang = '#!' + ((lang === 'bash') ? '/bin/' : '/usr/bin/env ') + lang;
601
+
602
+ return `${shebang}\n${scrConfig(lang)}${(addDist && lang === 'bash') ? `
603
+ rm -r "$_PROJECT_PATH/dist/"
604
+ cp -r "$_PROJECT_PATH/www/" "$_PROJECT_PATH/dist/"
605
+ cp -r "$_PROJECT_PATH/static/." "$_PROJECT_PATH/dist/"` : ''}\n`;
606
+ };
607
+
608
+ const getDefaultDevops = (name) => this.parse(fs.readFileSync(`${
609
+ env.HOME
610
+ }/_yrs/yrlib/%${name}.yr`, 'utf8'), { onlySections: true, ignoreYr: true }).devops[name];
611
+
612
+ for (let item of sections.devops) {
613
+ for (let value of Object.keys(item)) {
614
+ if (item[value] === '\n\n') {
615
+ delete item[value];
616
+ continue;
617
+ }
618
+
619
+ const shebang = item[value].trim().split('\n')[0];
620
+ if (shebang.startsWith('#!')) item[value] = item[value].trim().replace(shebang + '\n', '');
621
+
622
+ if (!parsed[value]) parsed[value] =
623
+ newDevops(projectPath, shebang, (value === 'build'));
624
+
625
+ if (!parsed[value].includes(item[value]))
626
+ parsed[value] += item[value] + '\n';
627
+ }
628
+ }
629
+
630
+ for (let item of ['build', 'serve', 'deploy']) {
631
+ try {
632
+ let index = (item !== 'serve') ? 0 : 1;
633
+
634
+ let wrapper = fs.readFileSync(`${yrlib}/\%${item}.yr`, 'utf8')
635
+ const shebang = wrapper.trim().split('\n')[0];
636
+ if (shebang.startsWith('#!')) wrapper = wrapper.trim().replace(shebang + '\n', '');
637
+
638
+ if (!parsed[item]) {
639
+ let value;
640
+ for (let key of this.parse(wrapper, { onlySections: true }).devops) {
641
+ for (let obj in key) {
642
+ if (!key[obj]) continue;
643
+ if (!parsed[obj]) parsed[obj] = newDevops(projectPath, shebang, (item === 'build'));
644
+ if (!parsed[obj].includes(key[obj])) parsed[obj] += '\n' + key[obj];
645
+ }
646
+ }
647
+ }
648
+ } catch(error) {/* pass */}
649
+ }
650
+
651
+ return [parsed];
652
+ },
653
+ extend(wrapper, wrapperName, sections, state, config={}) {
654
+ core.extend(wrapper, wrapperName, sections, state, config);
655
+ },
656
+ parse(code, config={}) {
657
+ core.set((category=false, option=false, parseConfig=false) =>
658
+ this.lib(category, option, parseConfig))
659
+
660
+ return core.parse(code, config);
661
+ },
662
+ getViews(category) {
663
+ let views = [];
664
+
665
+ for (let item of env.LIBS) {
666
+ try {
667
+ views = [...views, ...fs.readdirSync(`${item}/${category}`)
668
+ .filter(filename => filename.endsWith('_.yr'))];
669
+ } catch(error) {/* pass */}
670
+ }
671
+
672
+ return views.filter((item, pos) => views.indexOf(item) == pos);
673
+ },
674
+ require(wrapper) {
675
+ const wrapperName = (!wrapper.includes('/')) ? wrapper.toLowerCase()
676
+ : wrapper.split('/')[0].toLowerCase() + utils.capitalize(wrapper.split('/')[1]);
677
+
678
+ const script = this.parse(`!! ${wrapper}`).jsapp.join('');
679
+
680
+ if (!script) return {};
681
+
682
+ const context = new vm.createContext({
683
+ console, setTimeout, setInterval
684
+ });
685
+
686
+ (new vm.Script(script)).runInContext(context);
687
+ return (context[wrapperName]) ? context[wrapperName] : context;
688
+ },
689
+ wrappers(category=false, option=false, libs=false, onlyLibs=false, code=false, parse=false, preview=false) {
690
+ const wrappers = {}, categories = [];
691
+
692
+ const treeConfig = {
693
+ onlyLibs, filesFirst: true, yr: (!onlyLibs) ? 'wrapper' : false,
694
+ filename: option, dirName: (category === '__') ? false : category
695
+ };
696
+
697
+ if ((code || parse) && !onlyLibs) treeConfig.yr = 'code';
698
+
699
+ for (let item of (libs ? libs : env.LIBS)) {
700
+ const result = this.tree(item, treeConfig);
701
+
702
+ for (let value of result) {
703
+ if (!onlyLibs) {
704
+ const wrapperName = getWrapperName(value);
705
+ if (wrappers[wrapperName]) continue;
706
+ delete value.isDir;
707
+
708
+ if (parse) {
709
+ if (preview) value.yr = '!! preview\n' + value.yr;
710
+
711
+ try {
712
+ value.output = this.parse(value.yr, { preview }).parsedhtml;
713
+ } catch(error) {
714
+ value.output =
715
+ `<pre>${(error.message) ? error.message : error}</pre>`;
716
+ }
717
+
718
+ delete value.yr;
719
+ }
720
+
721
+ wrappers[wrapperName] = value;
722
+ } else {
723
+ const split = value.split('/');
724
+ let name = split[split.length - 1];
725
+ if (name === 'yr') name = split[split.length - 2];
726
+ categories.push(name);
727
+ }
728
+ }
729
+ }
730
+
731
+ return (!onlyLibs) ? wrappers : categories;
732
+ },
733
+ lib(category=false, option=false, parseConfig=false) {
734
+ if (option) option += '.yr';
735
+ const lib = {};
736
+
737
+ for (let item of env.LIBS) {
738
+ const result = this.tree(item, {
739
+ filesFirst: true, yr: 'code', filename: option,
740
+ dirName: (category === '__') ? false : category
741
+ });
742
+
743
+ for (let value of result) {
744
+ const wrapperName = getWrapperName(value);
745
+ if (lib[wrapperName]) continue;
746
+ delete value.isDir;
747
+
748
+ if (parseConfig) value.output = this.parse(value.yr, parseConfig);
749
+ lib[wrapperName] = value;
750
+ }
751
+ }
752
+
753
+ return (category && option) ? lib[`${
754
+ (category === '__') ? '' : category + '/'
755
+ }${option}`.replace(/\.yr/g, '')] : lib;
756
+ },
757
+ ci(category='Yrci', option=false) {
758
+ console.log('yrCI started...\n');
759
+ let wrappers = this.lib(category, option);
760
+ if (category && option) wrappers = [wrappers];
761
+
762
+ for (let item in wrappers) {
763
+ console.log(`####### Testing [${getWrapperName(wrappers[item])}]\n`);
764
+ const wrapper = this.parse(wrappers[item].yr, { debug: true, preview: true });
765
+ //console.log('===================== Wrapper');
766
+ console.log(wrapper);
767
+ //console.log(wrappers[item].yr);
768
+ //console.log('===================== Parsed');
769
+ //console.log(wrapper.parsedyr.body);
770
+ //console.log('=================== BODY assert');
771
+ //console.log(wrapper.body);
772
+ //console.log('=================== YR assert');
773
+ //console.log(wrappers[item].yr);
774
+ //console.log('===================');
775
+ //console.log('Reality: ');
776
+ //console.log(wrapper.yr.body);
777
+ //console.log('===================');
778
+ //console.log('Expect: ');
779
+ //console.log(wrapper.assert);
780
+ //console.log('===================');
781
+ //console.log(`Asserted: ${wrapper.yr.body === wrapper.assert}`);
782
+ //console.log('=================== JS assert');
783
+ //console.log(wrapper.parsedjs);
784
+
785
+ //console.log('===================== Yr');
786
+ //console.log(wrapper.yr);
787
+ //console.log('===================== Merged sections');
788
+ //const merged = this.mergeYrSections(wrapper.yr)
789
+ //console.log(merged);
790
+ //console.log('');
791
+ //console.log('===================== Parsed merged');
792
+
793
+ //console.log(this.parse(merged, {
794
+ // debug: true, preview: true
795
+ //}).parsedhtml);
796
+
797
+ //console.log(wrapper.parsedbody);
798
+ //console.log(wrapper.yr);
799
+ //console.log(wrapper.parsedyr);
800
+ }
801
+
802
+ console.log('yrCI finished');
803
+ }
804
+ };
805
+
806
+ const utils = module.exports.require('utils');
807
+ const crypto = module.exports.require('crypto');