@yr-lang/yr 0.2.0 → 0.2.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.
- package/CHANGELOG.md +6 -0
- package/lib/%build.yr +1 -1
- package/lib/%deploy.yr +2 -0
- package/lib/%gh-pages.yr +3 -1
- package/lib/%serve.yr +6 -0
- package/lib/@try.yr +9 -0
- package/lib/contenteditable.yr +68 -0
- package/lib/element.yr +2 -0
- package/lib/windowListener.yr +9 -0
- package/node.js +39 -33
- package/package.json +1 -1
- package/yr.js +405 -31
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.3.0] - 2026-04-27
|
|
4
|
+
|
|
5
|
+
Remove `wrapperheader`, `header`, `scripts` and `footer` from parsedYr
|
|
6
|
+
Created `wrapperheader` sections
|
|
7
|
+
Added `VOID_TAGS` in order to not add elementId to all elements `if (preview === true)`
|
|
8
|
+
|
|
3
9
|
## [0.2.0] - 2026-03-01
|
|
4
10
|
|
|
5
11
|
### Fixed
|
package/lib/%build.yr
CHANGED
package/lib/%deploy.yr
CHANGED
package/lib/%gh-pages.yr
CHANGED
|
@@ -14,6 +14,8 @@ gh-pages() {
|
|
|
14
14
|
rm -rf $git_name
|
|
15
15
|
fi
|
|
16
16
|
|
|
17
|
+
if [[ ! -d .git ]]; then exit 1; fi
|
|
18
|
+
|
|
17
19
|
git add .
|
|
18
20
|
git commit -m "# DEPLOY"
|
|
19
21
|
git push -f origin main
|
|
@@ -57,4 +59,4 @@ gh-pages_fix() {
|
|
|
57
59
|
-X PUT \
|
|
58
60
|
-F source.branch=gh-pages \
|
|
59
61
|
2>/dev/null || true
|
|
60
|
-
}
|
|
62
|
+
}
|
package/lib/%serve.yr
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
___serve
|
|
4
4
|
|
|
5
|
+
APP_NAME=$(echo $_CONFIG | jq -r .name)
|
|
5
6
|
cd $_PROJECT_PATH
|
|
6
7
|
if [[ ! -d node_modules ]]; then npm i $(cat node_modules.txt); fi
|
|
8
|
+
|
|
9
|
+
pkill -9 -f "^node app/app.js$"
|
|
7
10
|
node app/app.js
|
|
11
|
+
|
|
12
|
+
#pkill -9 -f "$APP_NAME" 2>/dev/null
|
|
13
|
+
#exec -a "$APP_NAME" node app/app.js
|
package/lib/@try.yr
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
@@
|
|
2
|
+
|
|
3
|
+
const htmlEntities = {
|
|
4
|
+
'&': '&',
|
|
5
|
+
'<': '<',
|
|
6
|
+
'>': '>',
|
|
7
|
+
'"': '"',
|
|
8
|
+
''': "'",
|
|
9
|
+
'–': '-',
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
function unblurcontenteditable(element) {
|
|
13
|
+
element.setAttribute('contenteditable', false);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function blurcontenteditable(element, callback=false, selectEnd=false, blurOnEnter=true, removeEmpty=false) {
|
|
17
|
+
element.setAttribute('contenteditable', true);
|
|
18
|
+
if (element.getAttribute('_blurcontenteditable') === 'true') return;
|
|
19
|
+
element.setAttribute('_blurcontenteditable', true);
|
|
20
|
+
let content = element.textContent.trim();
|
|
21
|
+
|
|
22
|
+
if (blurOnEnter) element.addEventListener('keydown', (e) => {
|
|
23
|
+
if (e.key === 'Enter' || e.keyCode === 13) {
|
|
24
|
+
e.target.innerHTML = e.target.innerHTML.replace('<br>', '');
|
|
25
|
+
element.blur();
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
if (selectEnd) {
|
|
30
|
+
for (let item of ['click', 'focus']) element.addEventListener(item, (e) => {
|
|
31
|
+
const range = document.createRange();
|
|
32
|
+
range.selectNodeContents(element);
|
|
33
|
+
range.collapse(false);
|
|
34
|
+
window.getSelection().removeAllRanges();
|
|
35
|
+
window.getSelection().addRange(range);
|
|
36
|
+
element.focus();
|
|
37
|
+
range.detach();
|
|
38
|
+
element.scrollTop = e.target.scrollHeight;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
element.addEventListener('blur', (e) => {
|
|
43
|
+
if (element._ignoreBlurCallback) return;
|
|
44
|
+
|
|
45
|
+
if (removeEmpty && e.target.innerHTML === '') {
|
|
46
|
+
((removeEmpty === true) ? element : removeEmpty).remove();
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (blurOnEnter)
|
|
51
|
+
e.target.innerHTML = e.target.innerHTML.replace('<br>', '');
|
|
52
|
+
|
|
53
|
+
if (e.target.innerHTML === content) return;
|
|
54
|
+
|
|
55
|
+
element.innerHTML = e.target.innerHTML.replace(/<\/div><div>/gi, '\n')
|
|
56
|
+
.replace(/(<.*?div>)/gi, '\n').trim();
|
|
57
|
+
|
|
58
|
+
let newContent = element.textContent;
|
|
59
|
+
for (let item in htmlEntities)
|
|
60
|
+
newContent = newContent.split(item).join(htmlEntities[item]);
|
|
61
|
+
|
|
62
|
+
try {
|
|
63
|
+
callback(content, newContent, e);
|
|
64
|
+
} catch(error) {/* pass */}
|
|
65
|
+
|
|
66
|
+
content = element.textContent;
|
|
67
|
+
});
|
|
68
|
+
}
|
package/lib/element.yr
CHANGED
package/node.js
CHANGED
|
@@ -147,6 +147,8 @@ module.exports = {
|
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
delete sections.wrapperjs;
|
|
150
|
+
delete sections.header;
|
|
151
|
+
delete sections.footer;
|
|
150
152
|
|
|
151
153
|
for (let item in sections)
|
|
152
154
|
result += `${core.parsers.names[item]}\n\n${sections[item]}\n`;
|
|
@@ -241,51 +243,55 @@ module.exports = {
|
|
|
241
243
|
}
|
|
242
244
|
},
|
|
243
245
|
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
246
|
if (log) console.log('starting spawn...');
|
|
257
247
|
|
|
258
|
-
|
|
248
|
+
// garante execução via bash (sem shell intermediário problemático)
|
|
249
|
+
const child = spawn(path, args, {
|
|
250
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
251
|
+
detached: true
|
|
252
|
+
});
|
|
259
253
|
|
|
260
|
-
|
|
261
|
-
// console.log(data.toString());
|
|
262
|
-
//});
|
|
254
|
+
if (log) console.log('spawn pid:', child.pid);
|
|
263
255
|
|
|
264
|
-
child.stdout
|
|
265
|
-
data
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
256
|
+
if (child.stdout) {
|
|
257
|
+
child.stdout.on('data', (data) => {
|
|
258
|
+
data = data.toString();
|
|
259
|
+
if (log) process.stdout.write(data);
|
|
260
|
+
if (callbackData) callbackData(data);
|
|
261
|
+
});
|
|
262
|
+
}
|
|
269
263
|
|
|
270
|
-
child.stderr
|
|
271
|
-
data
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
264
|
+
if (child.stderr) {
|
|
265
|
+
child.stderr.on('data', (data) => {
|
|
266
|
+
data = data.toString();
|
|
267
|
+
if (log) process.stderr.write(data);
|
|
268
|
+
if (callbackError) callbackError(data);
|
|
269
|
+
});
|
|
270
|
+
}
|
|
275
271
|
|
|
276
272
|
child.on('exit', (code, signal) => {
|
|
277
|
-
if (log) console.log('
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
//state.building = false;
|
|
273
|
+
if (log) console.log('exit:', { code, signal });
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
child.on('close', (code, signal) => {
|
|
277
|
+
if (log) console.log('close:', { code, signal });
|
|
283
278
|
if (callbackClose) callbackClose(code, signal);
|
|
284
279
|
if (exit) process.exit();
|
|
285
280
|
});
|
|
286
281
|
|
|
287
282
|
return child;
|
|
288
283
|
},
|
|
284
|
+
kill(child) {
|
|
285
|
+
if (!child || !child.pid) return;
|
|
286
|
+
|
|
287
|
+
try {
|
|
288
|
+
// mata o grupo inteiro (bash + node + qualquer filho)
|
|
289
|
+
process.kill(-child.pid, 'SIGTERM');
|
|
290
|
+
console.log('process group killed:', child.pid);
|
|
291
|
+
} catch (e) {
|
|
292
|
+
console.log('kill error:', e);
|
|
293
|
+
}
|
|
294
|
+
},
|
|
289
295
|
build(projectName=false, config={}, viewsPaths=env.VIEWS, assetsPath=false) {
|
|
290
296
|
if (!config) config = {};
|
|
291
297
|
|
|
@@ -532,7 +538,7 @@ dist/`);
|
|
|
532
538
|
}
|
|
533
539
|
|
|
534
540
|
if (result.devops.build) {
|
|
535
|
-
this.spawn(`${projectPath}/actions/build`, [], () => {
|
|
541
|
+
if (!config.ignoreBuild) this.spawn(`${projectPath}/actions/build`, [], () => {
|
|
536
542
|
if (config.exec) this.spawn(`${projectPath}/app/app.js`);
|
|
537
543
|
});
|
|
538
544
|
} else if (config.exec) {
|
package/package.json
CHANGED
package/yr.js
CHANGED
|
@@ -28,6 +28,7 @@ const common = {
|
|
|
28
28
|
const namespaces = {
|
|
29
29
|
'@&': { name: 'jsapp', parser: 'array', default: [], merge: true },
|
|
30
30
|
'++': { name: 'wrappers', parser: 'auxstring', default: {}, merge: true },
|
|
31
|
+
'+>': { name: 'wrapperheader', parser: 'html', default: '', merge: true },
|
|
31
32
|
'>+': { name: 'wrapperbody', parser: 'html', default: '', merge: true },
|
|
32
33
|
'><': { name: 'body', parser: 'html', default: '', merge: true },
|
|
33
34
|
'@>': { name: 'jsheader', parser: 'string', default: '', merge: true },
|
|
@@ -149,6 +150,13 @@ function getElementAttributes(line) {
|
|
|
149
150
|
}
|
|
150
151
|
|
|
151
152
|
function addIdToElement(line, config, elementId=false) {
|
|
153
|
+
let tag = line.trim().split(' ')[0];
|
|
154
|
+
|
|
155
|
+
if (tag.startsWith('_')) {
|
|
156
|
+
tag = tag.replace(/^_/, '');
|
|
157
|
+
if (VOID_TAGS.has(tag) || ['title', 'script', 'style'].includes(tag)) return line;
|
|
158
|
+
}
|
|
159
|
+
|
|
152
160
|
if (config.preview && !line.includes('.__') && !line.includes('.{{__')) {
|
|
153
161
|
if (!elementId) elementId = '__' + crypto.generateToken(8);
|
|
154
162
|
if (!line.trim().startsWith('_')) elementId = '{{' + elementId;
|
|
@@ -183,6 +191,11 @@ function addIdToElement(line, config, elementId=false) {
|
|
|
183
191
|
return line;
|
|
184
192
|
}
|
|
185
193
|
|
|
194
|
+
const VOID_TAGS = new Set([
|
|
195
|
+
'area','base','br','col','embed','hr','img','input',
|
|
196
|
+
'link','meta','param','source','track','wbr'
|
|
197
|
+
]);
|
|
198
|
+
|
|
186
199
|
const parserFns = {
|
|
187
200
|
array(line, sections, section, state, lineNumber, config={}) {
|
|
188
201
|
if (state.sectionChanged) sections[section].push('')
|
|
@@ -200,7 +213,7 @@ const parserFns = {
|
|
|
200
213
|
sections[section] += line + '\n';
|
|
201
214
|
},
|
|
202
215
|
html(line, sections, section, state, lineNumber, config={}) {
|
|
203
|
-
if (config.ignoreHtml) return;
|
|
216
|
+
if (config.ignoreHtml && !['wrapperheader', 'header', 'footer', 'scripts'].includes(section)) return;
|
|
204
217
|
if (!sections.yr[section]) sections.yr[section] = '';
|
|
205
218
|
const parsedLine = parseLine(line);
|
|
206
219
|
if (parsedLine.line.startsWith('//')) {
|
|
@@ -235,7 +248,8 @@ const parserFns = {
|
|
|
235
248
|
elementId = '__' + split[1];
|
|
236
249
|
parsedLine.line = split[0].trimEnd();
|
|
237
250
|
}
|
|
238
|
-
|
|
251
|
+
if (!['wrapperheader', 'header', 'footer', 'scripts'].includes(section))
|
|
252
|
+
yrParsedLine = addIdToElement(yrParsedLine, config, elementId);
|
|
239
253
|
let yrIndentation = 0, ignoreYr, wildCard = '', replaceYr;
|
|
240
254
|
// Bug fix: use while loop to close ALL wrappers that need closing (not just one)
|
|
241
255
|
// A single element may need to close multiple nested wrappers at once
|
|
@@ -253,7 +267,7 @@ const parserFns = {
|
|
|
253
267
|
if (!layer) continue;
|
|
254
268
|
// Only close layers that belong inside this wrapper (indentation >= wrapper.reference)
|
|
255
269
|
if (layer.indentation >= wrapper.reference) {
|
|
256
|
-
sections[layer.section] +=
|
|
270
|
+
if (!VOID_TAGS.has(layer.tag)) sections[layer.section] +=
|
|
257
271
|
layer.whiteSpace + `</${layer.tag}>\n`;
|
|
258
272
|
state.layers.pop();
|
|
259
273
|
} else {
|
|
@@ -284,13 +298,13 @@ const parserFns = {
|
|
|
284
298
|
if (parsedLine.level < state.level) {
|
|
285
299
|
for (let j = state.layers.length; j > parsedLine.level - 1; j--) {
|
|
286
300
|
if (!state.layers[j - 1]) continue;
|
|
287
|
-
sections[state.layers[j - 1].section] +=
|
|
301
|
+
if (!VOID_TAGS.has(state.layers[j - 1].tag)) sections[state.layers[j - 1].section] +=
|
|
288
302
|
state.layers[j - 1].whiteSpace + `</${state.layers[j - 1].tag}>\n`;
|
|
289
303
|
state.layers.pop();
|
|
290
304
|
}
|
|
291
305
|
} else if (parsedLine.level === state.level
|
|
292
306
|
&& state.element && state.layers.length > 0) {
|
|
293
|
-
sections[state.layers[state.layers.length - 1].section] +=
|
|
307
|
+
if (!VOID_TAGS.has(state.layers[state.layers.length - 1].tag)) sections[state.layers[state.layers.length - 1].section] +=
|
|
294
308
|
`</${state.layers[state.layers.length - 1].tag}>\n`;
|
|
295
309
|
state.layers.pop();
|
|
296
310
|
}
|
|
@@ -299,7 +313,7 @@ const parserFns = {
|
|
|
299
313
|
|| state.layers[state.layers.length - 1].indentation === parsedLine.indentation)) {
|
|
300
314
|
for (let j = state.layers.length - 1; j >= 0; j--) {
|
|
301
315
|
if (j === -1) continue;
|
|
302
|
-
sections[state.layers[j].section] +=
|
|
316
|
+
if (!VOID_TAGS.has(state.layers[j].tag)) sections[state.layers[j].section] +=
|
|
303
317
|
state.layers[j].whiteSpace + `</${state.layers[j].tag}>\n`;
|
|
304
318
|
state.layers.pop();
|
|
305
319
|
}
|
|
@@ -315,7 +329,7 @@ const parserFns = {
|
|
|
315
329
|
if (tag[0] === '_') {
|
|
316
330
|
tag = tag.replace(/__/, '');
|
|
317
331
|
if (!tag) tag = 'div';
|
|
318
|
-
wildCard += '<!--#@#-->';
|
|
332
|
+
if (!config.simple) wildCard += '<!--#@#-->';
|
|
319
333
|
}
|
|
320
334
|
let attributes = '', id = '', classes = '';
|
|
321
335
|
for (let item of lineSplit) {
|
|
@@ -336,12 +350,22 @@ const parserFns = {
|
|
|
336
350
|
attributes += ` ${item}`;
|
|
337
351
|
}
|
|
338
352
|
}
|
|
339
|
-
if (tag.includes('/')) {
|
|
353
|
+
if (tag.includes('/') && config.simple) {
|
|
354
|
+
const wrapper = '___' + tag.replace(/!/, '').replace(/\//, '__');
|
|
355
|
+
tag = 'div';
|
|
356
|
+
if (!classes) {
|
|
357
|
+
classes = ` class="${elementId} ${wrapper}"`;
|
|
358
|
+
} else if (!classes.includes(elementId)) {
|
|
359
|
+
classes = classes.split('class="').join(`class="${elementId} ${wrapper} `);
|
|
360
|
+
}
|
|
361
|
+
} else if (tag.includes('/') && !config.simple) {
|
|
340
362
|
const wrapper = tag.replace(/!/, '').split('/');
|
|
341
363
|
wrapper[0] = utils.capitalize(wrapper[0]);
|
|
342
364
|
wrapper[1] = utils.capitalize(wrapper[1]);
|
|
343
365
|
const wrapperName = wrapper.join('/');
|
|
344
|
-
core.extend(wrapper, wrapperName, sections, state, {
|
|
366
|
+
core.extend(wrapper, wrapperName, sections, state, {
|
|
367
|
+
redoWrapper: true, simple: config.simple
|
|
368
|
+
});
|
|
345
369
|
let newWrapper, wrapperIndentation;
|
|
346
370
|
if (!tag.includes('!')) {
|
|
347
371
|
newWrapper = {
|
|
@@ -408,7 +432,7 @@ const parserFns = {
|
|
|
408
432
|
classes = classes.split('class="').join(`class="${elementId} `);
|
|
409
433
|
}
|
|
410
434
|
}
|
|
411
|
-
if (config.preview) {
|
|
435
|
+
if (config.preview && !['wrapperheader', 'header', 'footer', 'scripts'].includes(section)) {
|
|
412
436
|
if (!classes) {
|
|
413
437
|
classes = ` class="${elementId}"`;
|
|
414
438
|
} else if (!classes.includes(elementId)) {
|
|
@@ -422,7 +446,7 @@ const parserFns = {
|
|
|
422
446
|
state.element = true;
|
|
423
447
|
} else {
|
|
424
448
|
if (section) {
|
|
425
|
-
if (section === 'header') {
|
|
449
|
+
if (section === 'header' || section === 'wrapperheader') {
|
|
426
450
|
sections[section] += parsedLine.whiteSpace + parsedLine.line + '\n';
|
|
427
451
|
} else {
|
|
428
452
|
let attributes = '';
|
|
@@ -437,6 +461,16 @@ const parserFns = {
|
|
|
437
461
|
}
|
|
438
462
|
}
|
|
439
463
|
|
|
464
|
+
function isYrSyntax(code) {
|
|
465
|
+
code = code.split('!! preview\n!! bodyblock\n!! iframeConsole\n!! element\n').join('');
|
|
466
|
+
code = code.trim();
|
|
467
|
+
|
|
468
|
+
for (let item of [...Object.keys(namespaces), '!!', '[[', '--'])
|
|
469
|
+
if (code.startsWith(item)) return true;
|
|
470
|
+
|
|
471
|
+
return false;
|
|
472
|
+
}
|
|
473
|
+
|
|
440
474
|
const parsers = {
|
|
441
475
|
namespaces, tokens: Object.keys(namespaces),
|
|
442
476
|
parsers: _parsers, mergers, names,
|
|
@@ -614,6 +648,8 @@ const core = {
|
|
|
614
648
|
}
|
|
615
649
|
},
|
|
616
650
|
extend(wrapper, wrapperName, sections, state, config={}) {
|
|
651
|
+
if (config.simple && !wrapperName.includes('@')) return;
|
|
652
|
+
|
|
617
653
|
if (!sections.parsedyr)
|
|
618
654
|
sections.parsedyr = { header: '', body: '', footer: '', scripts: '' };
|
|
619
655
|
|
|
@@ -649,7 +685,7 @@ const core = {
|
|
|
649
685
|
sections.yr = {};
|
|
650
686
|
|
|
651
687
|
const aux = {};
|
|
652
|
-
for (let item of ['header', 'body', 'footer', 'scripts']) {
|
|
688
|
+
for (let item of ['wrapperheader', 'header', 'body', 'footer', 'scripts']) {
|
|
653
689
|
aux[item] = sections[item];
|
|
654
690
|
sections[item] = '';
|
|
655
691
|
}
|
|
@@ -667,7 +703,7 @@ const core = {
|
|
|
667
703
|
if (!sections.wrappers[wrapperName].vars)
|
|
668
704
|
sections.wrappers[wrapperName].vars = {};
|
|
669
705
|
|
|
670
|
-
for (let item of ['header', 'body', 'footer', 'scripts']) {
|
|
706
|
+
for (let item of ['wrapperheader', 'header', 'body', 'footer', 'scripts']) {
|
|
671
707
|
sections.wrappers[wrapperName].parsed[item] = result[item];
|
|
672
708
|
sections[item] = aux[item];
|
|
673
709
|
}
|
|
@@ -683,6 +719,329 @@ const core = {
|
|
|
683
719
|
}
|
|
684
720
|
},
|
|
685
721
|
parse(code, config={}) {
|
|
722
|
+
if (!isYrSyntax(code)) {
|
|
723
|
+
const sections = { parsedhtml: code };
|
|
724
|
+
|
|
725
|
+
if (config.name) sections.ui = [{
|
|
726
|
+
name: (config.name.includes('.html'))
|
|
727
|
+
? config.name : `${config.name}.html`,
|
|
728
|
+
content: sections.parsedhtml
|
|
729
|
+
}];
|
|
730
|
+
|
|
731
|
+
return sections;
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
if (config.opposite) {
|
|
735
|
+
const file = code;
|
|
736
|
+
const isProject = config.isProject;
|
|
737
|
+
let yrResult = isProject ? '' : '!! @wrapper\n\n';
|
|
738
|
+
|
|
739
|
+
const VOID_TAGS = new Set([
|
|
740
|
+
'area','base','br','col','embed','hr','img','input',
|
|
741
|
+
'link','meta','param','source','track','wbr'
|
|
742
|
+
]);
|
|
743
|
+
|
|
744
|
+
const P_BREAKERS = new Set([
|
|
745
|
+
'address','article','aside','blockquote','div','dl',
|
|
746
|
+
'fieldset','footer','form','h1','h2','h3','h4','h5','h6',
|
|
747
|
+
'header','hr','main','nav','ol','p','pre','section','table','ul'
|
|
748
|
+
]);
|
|
749
|
+
|
|
750
|
+
function tokenize(html) {
|
|
751
|
+
const tokens = [];
|
|
752
|
+
let i = 0;
|
|
753
|
+
|
|
754
|
+
while (i < html.length) {
|
|
755
|
+
if (html[i] === '<') {
|
|
756
|
+
const close = html.indexOf('>', i);
|
|
757
|
+
if (close === -1) break;
|
|
758
|
+
|
|
759
|
+
tokens.push({
|
|
760
|
+
type: 'tag',
|
|
761
|
+
value: html.slice(i, close + 1)
|
|
762
|
+
});
|
|
763
|
+
|
|
764
|
+
i = close + 1;
|
|
765
|
+
} else {
|
|
766
|
+
const next = html.indexOf('<', i);
|
|
767
|
+
tokens.push({
|
|
768
|
+
type: 'text',
|
|
769
|
+
value: html.slice(i, next === -1 ? html.length : next)
|
|
770
|
+
});
|
|
771
|
+
i = next === -1 ? html.length : next;
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
return tokens;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
function parseTag(str) {
|
|
779
|
+
const isClosing = /^<\//.test(str);
|
|
780
|
+
const isSelfClosing = /\/>$/.test(str);
|
|
781
|
+
|
|
782
|
+
const nameMatch = str.match(/^<\/?([a-zA-Z0-9-]+)/);
|
|
783
|
+
if (!nameMatch) return null;
|
|
784
|
+
|
|
785
|
+
const tag = nameMatch[1].toLowerCase();
|
|
786
|
+
|
|
787
|
+
const attrs = {};
|
|
788
|
+
[...str.matchAll(/([\w-:]+)(?:="([^"]*)")?/g)].forEach(m => {
|
|
789
|
+
const key = m[1];
|
|
790
|
+
if (key === tag) return;
|
|
791
|
+
attrs[key] = m[2] ?? true;
|
|
792
|
+
});
|
|
793
|
+
|
|
794
|
+
return { tag, attrs, isClosing, isSelfClosing };
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
function parseHTML(html) {
|
|
798
|
+
const tokens = tokenize(html);
|
|
799
|
+
|
|
800
|
+
const root = { tag: '_root', children: [] };
|
|
801
|
+
const stack = [root];
|
|
802
|
+
|
|
803
|
+
for (let t of tokens) {
|
|
804
|
+
let current = stack[stack.length - 1];
|
|
805
|
+
|
|
806
|
+
if (t.type === 'text') {
|
|
807
|
+
const text = t.value.trim();
|
|
808
|
+
if (text) current.children.push({ text });
|
|
809
|
+
continue;
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
const parsed = parseTag(t.value);
|
|
813
|
+
if (!parsed) continue;
|
|
814
|
+
|
|
815
|
+
const { tag, attrs, isClosing, isSelfClosing } = parsed;
|
|
816
|
+
|
|
817
|
+
if (isClosing) {
|
|
818
|
+
while (stack.length > 1) {
|
|
819
|
+
const top = stack.pop();
|
|
820
|
+
if (top.tag === tag) break;
|
|
821
|
+
}
|
|
822
|
+
continue;
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
if (current.tag === 'p' && P_BREAKERS.has(tag)) {
|
|
826
|
+
stack.pop();
|
|
827
|
+
current = stack[stack.length - 1];
|
|
828
|
+
}
|
|
829
|
+
|
|
830
|
+
const node = { tag, attrs, children: [] };
|
|
831
|
+
current.children.push(node);
|
|
832
|
+
|
|
833
|
+
if (!isSelfClosing && !VOID_TAGS.has(tag)) {
|
|
834
|
+
stack.push(node);
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
return root.children;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
function toYr(nodes, indent = 0) {
|
|
842
|
+
let out = '';
|
|
843
|
+
|
|
844
|
+
for (let node of nodes) {
|
|
845
|
+
const space = ' '.repeat(indent);
|
|
846
|
+
|
|
847
|
+
if (node.text) {
|
|
848
|
+
let text = node.text;
|
|
849
|
+
|
|
850
|
+
if (text.trimStart().startsWith('//')) {
|
|
851
|
+
text = text.replace(/^(\s*)\/\//, (_, spaces) => {
|
|
852
|
+
return spaces + '//';
|
|
853
|
+
});
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
if (text.trimStart().startsWith('_')) {
|
|
857
|
+
text = text.replace(/^(\s*)_/, (_, spaces) => {
|
|
858
|
+
return spaces + '_';
|
|
859
|
+
});
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
if (text.trimStart().startsWith('.')) {
|
|
863
|
+
text = text.replace(/^(\s*)\./, (_, spaces) => {
|
|
864
|
+
return spaces + '.';
|
|
865
|
+
});
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
out += `${space}${text}\n`;
|
|
869
|
+
continue;
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
if (node.tag === 'script') continue;
|
|
873
|
+
|
|
874
|
+
let line = '_';
|
|
875
|
+
|
|
876
|
+
if (node.tag !== 'div') line += node.tag;
|
|
877
|
+
|
|
878
|
+
if (node.attrs?.id) line += ` #${node.attrs.id}`;
|
|
879
|
+
|
|
880
|
+
if (node.attrs?.class) {
|
|
881
|
+
const cls = node.attrs.class.split(' ').join('.');
|
|
882
|
+
line += ` .${cls}`;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
for (let key in node.attrs) {
|
|
886
|
+
if (key === 'class' || key === 'id') continue;
|
|
887
|
+
|
|
888
|
+
if (node.attrs[key] === true) {
|
|
889
|
+
line += ` ${key}`;
|
|
890
|
+
} else {
|
|
891
|
+
line += ` ${key}="${node.attrs[key]}"`;
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
out += `${space}${line}\n`;
|
|
896
|
+
|
|
897
|
+
if (node.children?.length) {
|
|
898
|
+
out += toYr(node.children, indent + 2);
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
return out;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
function extract(tag, str) {
|
|
906
|
+
const match = str.match(new RegExp(`<${tag}[^>]*>([\\s\\S]*?)<\\/${tag}>`));
|
|
907
|
+
return match ? match[1].trim() : '';
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
function formatCSS(css) {
|
|
911
|
+
if (!css) return '';
|
|
912
|
+
const comments = [];
|
|
913
|
+
let normalized = css.replace(/\/\*[\s\S]*?\*\//g, m => {
|
|
914
|
+
const idx = comments.length;
|
|
915
|
+
comments.push(m);
|
|
916
|
+
return `__COMMENT_${idx}__`;
|
|
917
|
+
});
|
|
918
|
+
|
|
919
|
+
normalized = normalized
|
|
920
|
+
.replace(/\s*\{\s*/g, ' {')
|
|
921
|
+
.replace(/\s*\}\s*/g, ' }')
|
|
922
|
+
.replace(/\s*;\s*/g, '; ')
|
|
923
|
+
.replace(/,\s*/g, ', ')
|
|
924
|
+
//.replace(/([\w-])\s*:\s*(?!:)/g, '$1: ')
|
|
925
|
+
.replace(/\s+/g, ' ')
|
|
926
|
+
.replace(/__COMMENT_(\d+)__/g, (_, i) => '\n' + comments[+i] + '\n')
|
|
927
|
+
.trim();
|
|
928
|
+
|
|
929
|
+
let indent = 0;
|
|
930
|
+
let out = '';
|
|
931
|
+
let i = 0;
|
|
932
|
+
|
|
933
|
+
while (i < normalized.length) {
|
|
934
|
+
const char = normalized[i];
|
|
935
|
+
|
|
936
|
+
if (char === '{') {
|
|
937
|
+
out = out.trimEnd();
|
|
938
|
+
out += ' {\n';
|
|
939
|
+
indent++;
|
|
940
|
+
out += ' '.repeat(indent);
|
|
941
|
+
} else if (char === '}') {
|
|
942
|
+
indent--;
|
|
943
|
+
out = out.trimEnd();
|
|
944
|
+
out += '\n' + ' '.repeat(indent) + '}\n';
|
|
945
|
+
if (indent >= 0) out += '\n' + ' '.repeat(indent);
|
|
946
|
+
} else if (char === ';') {
|
|
947
|
+
out = out.trimEnd();
|
|
948
|
+
out += ';\n' + ' '.repeat(indent);
|
|
949
|
+
} else if (char === ' ' && out.endsWith('\n' + ' '.repeat(indent))) {
|
|
950
|
+
} else {
|
|
951
|
+
out += char;
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
i++;
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
return out
|
|
958
|
+
.split('\n')
|
|
959
|
+
.map(l => l.trimEnd())
|
|
960
|
+
.join('\n')
|
|
961
|
+
.replace(/\n{3,}/g, '\n\n')
|
|
962
|
+
.trim();
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
function wrapScript(js) {
|
|
966
|
+
if (!js) return '';
|
|
967
|
+
let category = '';
|
|
968
|
+
let option = '';
|
|
969
|
+
|
|
970
|
+
const match = js.match(/__([A-Za-z0-9]+)_([A-Za-z0-9]+)/);
|
|
971
|
+
if (match) {
|
|
972
|
+
category = match[1];
|
|
973
|
+
option = match[2];
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
const startBlock =
|
|
977
|
+
`async function __${category}_${option}(_config) {
|
|
978
|
+
let element = (_config.id === 'body') ? document.body
|
|
979
|
+
: document.querySelector(\`.\${_config.id}\`);
|
|
980
|
+
if (!element) return;
|
|
981
|
+
try {
|
|
982
|
+
element._config = _config;
|
|
983
|
+
if (window.__preview) {
|
|
984
|
+
element._html = element.outerHTML;
|
|
985
|
+
element._refresh = () => {
|
|
986
|
+
element.outerHTML = element._html;
|
|
987
|
+
__Triggers_Disclaimermodal(_config)
|
|
988
|
+
};
|
|
989
|
+
}
|
|
990
|
+
`;
|
|
991
|
+
|
|
992
|
+
js = js.replace(startBlock, `_@wrapper(${category}, ${option}) {\n`);
|
|
993
|
+
|
|
994
|
+
const catchBlock = `
|
|
995
|
+
} catch(error) {
|
|
996
|
+
if (window.__preview || false) {
|
|
997
|
+
//element.innerHTML = '<div style="background: red; color: white">'
|
|
998
|
+
//+ \`${category} ${option} error: \${error.message}</div>\`;
|
|
999
|
+
console.error(error);
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
}`;
|
|
1003
|
+
|
|
1004
|
+
js = js.replace(catchBlock, '\n@}');
|
|
1005
|
+
return js;
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
const tree = parseHTML(file);
|
|
1009
|
+
|
|
1010
|
+
const headContent = extract('head', file);
|
|
1011
|
+
const bodyContent = extract('body', file);
|
|
1012
|
+
const styleContent = extract('style', headContent);
|
|
1013
|
+
const scriptContent = extract('script', bodyContent);
|
|
1014
|
+
|
|
1015
|
+
function removeTags(nodes, blacklist = ['style', 'script']) {
|
|
1016
|
+
return nodes
|
|
1017
|
+
.filter(n => !n.tag || !blacklist.includes(n.tag))
|
|
1018
|
+
.map(n => ({
|
|
1019
|
+
...n,
|
|
1020
|
+
children: n.children ? removeTags(n.children, blacklist) : []
|
|
1021
|
+
}));
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
const cleanTree = removeTags(tree);
|
|
1025
|
+
|
|
1026
|
+
let headNodes = [];
|
|
1027
|
+
let bodyNodes = [];
|
|
1028
|
+
|
|
1029
|
+
for (let n of cleanTree) {
|
|
1030
|
+
if (n.tag === 'html') {
|
|
1031
|
+
for (let c of n.children) {
|
|
1032
|
+
if (c.tag === 'head') headNodes = c.children;
|
|
1033
|
+
if (c.tag === 'body') bodyNodes = c.children;
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
yrResult += '>>\n\n' + toYr(headNodes) + '\n\n';
|
|
1039
|
+
yrResult += (isProject ? '<#' : '##') + '\n\n' + formatCSS(styleContent) + '\n\n';
|
|
1040
|
+
yrResult += (isProject ? '><' : '++') + '\n\n' + toYr(bodyNodes) + '\n\n';
|
|
1041
|
+
yrResult += (isProject ? '<@' : '@>') + '\n\n' + wrapScript(scriptContent) + '\n';
|
|
1042
|
+
return yrResult;
|
|
1043
|
+
}
|
|
1044
|
+
|
|
686
1045
|
const sections = (config.sections) ? config.sections : parsers.defaults();
|
|
687
1046
|
|
|
688
1047
|
const state = {
|
|
@@ -742,7 +1101,8 @@ const core = {
|
|
|
742
1101
|
for (let j = state.layers.length - 1; j >= 0; j--) {
|
|
743
1102
|
const layer = state.layers[j];
|
|
744
1103
|
if (!layer || layer.indentation < wrapper.reference) break;
|
|
745
|
-
sections[layer.section] +=
|
|
1104
|
+
if (!VOID_TAGS.has(layer.tag)) sections[layer.section] +=
|
|
1105
|
+
layer.whiteSpace + `</${layer.tag}>\n`;
|
|
746
1106
|
state.layers.pop();
|
|
747
1107
|
}
|
|
748
1108
|
|
|
@@ -775,7 +1135,9 @@ const core = {
|
|
|
775
1135
|
const wrapper = wrapperName.split('/');
|
|
776
1136
|
if (wrapper.length === 1) wrapper.unshift('__');
|
|
777
1137
|
|
|
778
|
-
this.extend(wrapper, wrapperName, sections, state
|
|
1138
|
+
this.extend(wrapper, wrapperName, sections, state, {
|
|
1139
|
+
simple: config.simple
|
|
1140
|
+
});
|
|
779
1141
|
//} else if (line.startsWith('\\\\')) {
|
|
780
1142
|
// const wrapperName = line.replace(/\\\\/g, '').trim() + '\n';
|
|
781
1143
|
|
|
@@ -839,7 +1201,7 @@ const core = {
|
|
|
839
1201
|
};
|
|
840
1202
|
|
|
841
1203
|
const aux = {};
|
|
842
|
-
for (let item of ['header', 'body', 'footer', 'scripts']) {
|
|
1204
|
+
for (let item of ['wrapperheader', 'header', 'body', 'footer', 'scripts']) {
|
|
843
1205
|
aux[item] = sections[item];
|
|
844
1206
|
sections[item] = '';
|
|
845
1207
|
}
|
|
@@ -857,7 +1219,7 @@ const core = {
|
|
|
857
1219
|
if (!sections.wrappers[config.wrapper].vars)
|
|
858
1220
|
sections.wrappers[config.wrapper].vars = {};
|
|
859
1221
|
|
|
860
|
-
for (let item of ['header', 'body', 'footer', 'scripts']) {
|
|
1222
|
+
for (let item of ['wrapperheader', 'header', 'body', 'footer', 'scripts']) {
|
|
861
1223
|
sections.wrappers[config.wrapper].parsed[item] = extension[item];
|
|
862
1224
|
sections[item] = aux[item]
|
|
863
1225
|
}
|
|
@@ -893,7 +1255,7 @@ const core = {
|
|
|
893
1255
|
if (!layer) continue;
|
|
894
1256
|
if (layer.indentation < wrapper.reference) break;
|
|
895
1257
|
|
|
896
|
-
sections[layer.section] +=
|
|
1258
|
+
if (!VOID_TAGS.has(layer.tag)) sections[layer.section] +=
|
|
897
1259
|
layer.whiteSpace + `</${layer.tag}>\n`;
|
|
898
1260
|
|
|
899
1261
|
state.layers.pop();
|
|
@@ -905,7 +1267,7 @@ const core = {
|
|
|
905
1267
|
for (let j = state.layers.length - 1; j >= 0; j--) {
|
|
906
1268
|
if (j === -1) continue;
|
|
907
1269
|
|
|
908
|
-
sections[state.layers[j].section] +=
|
|
1270
|
+
if (!VOID_TAGS.has(state.layers[j].tag)) sections[state.layers[j].section] +=
|
|
909
1271
|
common.getWhiteSpace(state.layers[j].indentation) + `</${state.layers[j].tag}>\n`;
|
|
910
1272
|
|
|
911
1273
|
state.layers.pop();
|
|
@@ -966,7 +1328,7 @@ const core = {
|
|
|
966
1328
|
sections.parsedyr.extensions += item + '\n';
|
|
967
1329
|
}
|
|
968
1330
|
|
|
969
|
-
for (let value of ['header', 'body', 'footer', 'scripts']) {
|
|
1331
|
+
for (let value of ['wrapperheader', 'header', 'body', 'footer', 'scripts']) {
|
|
970
1332
|
if (!sections[value]) sections[value] = '';
|
|
971
1333
|
if (!sections.yr[value]) sections.yr[value] = '';
|
|
972
1334
|
|
|
@@ -1037,7 +1399,7 @@ const core = {
|
|
|
1037
1399
|
|
|
1038
1400
|
parsedItem = JSON.parse(`{${parsedItem}}`);
|
|
1039
1401
|
|
|
1040
|
-
for (let value of ['header', 'body', 'footer', 'scripts']) {
|
|
1402
|
+
for (let value of ['wrapperheader', 'header', 'body', 'footer', 'scripts']) {
|
|
1041
1403
|
if (sections[`parsed${value}`].includes(`${parsedItem.id}`)) {
|
|
1042
1404
|
parsedItem.attributes = sections
|
|
1043
1405
|
.wrappers[`${parsedItem.category}/${parsedItem.option}`].vars.attributes;
|
|
@@ -1172,7 +1534,7 @@ const core = {
|
|
|
1172
1534
|
}
|
|
1173
1535
|
}
|
|
1174
1536
|
|
|
1175
|
-
for (let value of ['header', 'body', 'footer', 'scripts']) {
|
|
1537
|
+
for (let value of ['wrapperheader', 'header', 'body', 'footer', 'scripts']) {
|
|
1176
1538
|
if (sections.parsedyr[value].includes(item.replace(/!/g, '')
|
|
1177
1539
|
.trim().toLowerCase())) {
|
|
1178
1540
|
newExtensions += item + '\n';
|
|
@@ -1193,7 +1555,7 @@ const core = {
|
|
|
1193
1555
|
continue;
|
|
1194
1556
|
}
|
|
1195
1557
|
|
|
1196
|
-
for (let key of ['header', 'body', 'footer', 'scripts']) {
|
|
1558
|
+
for (let key of ['wrapperheader', 'header', 'body', 'footer', 'scripts']) {
|
|
1197
1559
|
//if (sections.parsedyr[key].includes(`.${value}`)) {
|
|
1198
1560
|
if (!newCss[item]) newCss[item] = {};
|
|
1199
1561
|
newCss[item][value] = parsedCss[item][value];
|
|
@@ -1208,7 +1570,7 @@ const core = {
|
|
|
1208
1570
|
//const templateRegex = id =>
|
|
1209
1571
|
// new RegExp(`\\{\\{[^}]*?\\.?${id}\\b[^}]*?\\}\\}`);
|
|
1210
1572
|
|
|
1211
|
-
//for (let item of ['header', 'body', 'footer', 'scripts']) {
|
|
1573
|
+
//for (let item of ['wrapperheader', 'header', 'body', 'footer', 'scripts']) {
|
|
1212
1574
|
// for (let value of sections.parsedyr[item].split('\n')) {
|
|
1213
1575
|
// const match = value.match(/(?:\.|\.\{\{)\s*(__[A-Za-z0-9_-]+)/);
|
|
1214
1576
|
// if (!match) continue;
|
|
@@ -1266,6 +1628,9 @@ const core = {
|
|
|
1266
1628
|
if (sections.wrapperjscustom)
|
|
1267
1629
|
sections.parsedjs += '\n' + sections.wrapperjscustom;
|
|
1268
1630
|
|
|
1631
|
+
if (sections.wrapperheader)
|
|
1632
|
+
sections.parsedheader += '\n' + sections.wrapperheader;
|
|
1633
|
+
|
|
1269
1634
|
if (!config.lang) config.lang = 'en-US';
|
|
1270
1635
|
|
|
1271
1636
|
if (config.name) {
|
|
@@ -1277,7 +1642,7 @@ const core = {
|
|
|
1277
1642
|
if (sections.apptests.length > 0 && !sections.parsedbody.includes('class="__')) {
|
|
1278
1643
|
sections.parsedbody += '\n<div class="__cclass"></div>';
|
|
1279
1644
|
|
|
1280
|
-
sections.parsedscripts = `<
|
|
1645
|
+
sections.parsedscripts = `<s` + `cript>
|
|
1281
1646
|
try {
|
|
1282
1647
|
function require(name) {
|
|
1283
1648
|
//return window[name];
|
|
@@ -1289,7 +1654,7 @@ ${sections.parsedjs}
|
|
|
1289
1654
|
${sections.appheader.join('')}
|
|
1290
1655
|
${sections.apptests.join('')}
|
|
1291
1656
|
} catch(error) { console.log(error); }
|
|
1292
|
-
</
|
|
1657
|
+
</s` + `cript>`;
|
|
1293
1658
|
}
|
|
1294
1659
|
|
|
1295
1660
|
sections.parsedhtml = `<!DOCTYPE html>
|
|
@@ -1302,16 +1667,16 @@ ${(config.name) ? ` <link rel="stylesheet" href="./${config.cssname}.css">` : `
|
|
|
1302
1667
|
<body style="display: none">
|
|
1303
1668
|
${sections.parsedbody}
|
|
1304
1669
|
${sections.parsedfooter}
|
|
1305
|
-
</body>
|
|
1306
1670
|
${sections.parsedscripts}
|
|
1307
|
-
<
|
|
1671
|
+
<s` + `cript id="p` + `sj"${(config.name) ? ` src="./${config.jsname}.js">`
|
|
1308
1672
|
: `>\n${sections.parsedjs}\n`
|
|
1309
|
-
}</
|
|
1310
|
-
|
|
1673
|
+
}</s` + `cript>
|
|
1674
|
+
</body>
|
|
1675
|
+
<s` + `cript>
|
|
1311
1676
|
document.addEventListener('DOMContentLoaded', () => {
|
|
1312
1677
|
document.body.style.display = 'block';
|
|
1313
1678
|
});
|
|
1314
|
-
</
|
|
1679
|
+
</s` + `cript>
|
|
1315
1680
|
</html>`;
|
|
1316
1681
|
|
|
1317
1682
|
if (config.name) sections.ui = [
|
|
@@ -1332,4 +1697,13 @@ if (typeof module !== 'undefined' && module.exports)
|
|
|
1332
1697
|
if (typeof window !== 'undefined' && !window.yr) {
|
|
1333
1698
|
const parse = core.parse.bind(core);
|
|
1334
1699
|
window.yr = parse;
|
|
1700
|
+
|
|
1701
|
+
const createLog = (text) => {
|
|
1702
|
+
const parsed = parse(text);
|
|
1703
|
+
console.log(parsed);
|
|
1704
|
+
document.body.innerHTML += `<div>${text}</div>`;
|
|
1705
|
+
document.body.innerHTML += `<div>${parsed.parsedyr.body}</div>`;
|
|
1706
|
+
};
|
|
1707
|
+
|
|
1708
|
+
createLog('><\n_ .teste');
|
|
1335
1709
|
}
|