@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.
- package/BUGS.md +35 -0
- package/CNAME +1 -0
- package/LICENSE +42 -0
- package/README.md +21 -0
- package/lib/%build.yr +3 -0
- package/lib/%deploy.yr +7 -0
- package/lib/%gh-pages.yr +60 -0
- package/lib/%nvm.yr +18 -0
- package/lib/%serve.yr +7 -0
- package/lib/.yrrc +2 -0
- package/lib/Ciyr/A1.yr +25 -0
- package/lib/Ciyr/B1.yr +11 -0
- package/lib/Ciyr/B2.yr +0 -0
- package/lib/Ciyr/C1.yr +14 -0
- package/lib/Ciyr/C2.yr +5 -0
- package/lib/Ciyr/C2_2.yr +5 -0
- package/lib/Ciyr/a1.yr +23 -0
- package/lib/Ciyr/b1.yr +21 -0
- package/lib/Ciyr/c1.yr +18 -0
- package/lib/Yrci/&app.yr +1 -0
- package/lib/Yrci/&app2.yr +1 -0
- package/lib/Yrci/@m1.yr +7 -0
- package/lib/Yrci/@m2.yr +11 -0
- package/lib/Yrci/A1.yr +8 -0
- package/lib/Yrci/A2.yr +26 -0
- package/lib/Yrci/A3.yr +51 -0
- package/lib/Yrci/B1.yr +8 -0
- package/lib/Yrci/C1.yr +58 -0
- package/lib/Yrci/C1.yrr +14 -0
- package/lib/Yrci/C2.yr +17 -0
- package/lib/Yrci/C3.yr +28 -0
- package/lib/Yrci/C4.yr +4 -0
- package/lib/Yrci/C5.yr +3 -0
- package/lib/Yrci/C6.yr +7 -0
- package/lib/Yrci/C7.yr +3 -0
- package/lib/Yrci/C8.yr +3 -0
- package/lib/Yrci/C9.yr +11 -0
- package/lib/Yrci/Index_.yr +4 -0
- package/lib/Yrci/Login.yr +3 -0
- package/lib/Yrci/M1.yr +7 -0
- package/lib/Yrci/Sp.yr +5 -0
- package/lib/Yrci/T1.yr +4 -0
- package/lib/Yrci/T2.yr +4 -0
- package/lib/Yrci/Ta1.yr +4 -0
- package/lib/Yrci/Ta2.yr +4 -0
- package/lib/Yrci/Tg.yr +5 -0
- package/lib/Yrci/Wr.yr +7 -0
- package/lib/Yrci/Wrapper.yr +14 -0
- package/lib/Yrci/Wrapper1.yr +5 -0
- package/lib/Yrci/Wrapper2.yr +24 -0
- package/lib/Yrci/Wrapper3.yr +5 -0
- package/lib/Yrci/Wrapperext.yr +4 -0
- package/lib/Yrci/Wrt.yr +3 -0
- package/lib/Yrci/Yrwm.yr +32 -0
- package/lib/Yrci/a1.yr +18 -0
- package/lib/Yrci/a2.yr +10 -0
- package/lib/Yrci/app.yr +3 -0
- package/lib/Yrci/b2.yr +10 -0
- package/lib/Yrci/j1.yr +5 -0
- package/lib/Yrci/j2.yr +5 -0
- package/lib/Yrci/j3.yr +3 -0
- package/lib/Yrci/modal.yr +5 -0
- package/lib/bodyblock.yr +13 -0
- package/lib/ci.yr +21 -0
- package/lib/crypto.yr +13 -0
- package/lib/element.yr +358 -0
- package/lib/hidden.yr +9 -0
- package/lib/utils.yr +13 -0
- package/node.js +807 -0
- package/package.json +14 -0
- package/src/common.js +7 -0
- 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');
|