@itrocks/template 0.0.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/template.js ADDED
@@ -0,0 +1,776 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Template = exports.frontScripts = void 0;
4
+ const rename_1 = require("@itrocks/rename");
5
+ const app_dir_1 = require("@itrocks/app-dir");
6
+ const sorted_array_1 = require("@itrocks/sorted-array");
7
+ const promises_1 = require("node:fs/promises");
8
+ const node_path_1 = require("node:path");
9
+ let blockBack;
10
+ let blockStack;
11
+ let doHeadLinks = false;
12
+ let index;
13
+ let length;
14
+ let source;
15
+ let start;
16
+ let tagName;
17
+ let tagStack;
18
+ let target;
19
+ let targetStack;
20
+ let lockLiteral;
21
+ let literalPartStack;
22
+ let literalParts;
23
+ let inLiteral;
24
+ exports.frontScripts = new sorted_array_1.SortedArray();
25
+ exports.frontScripts.distinct = true;
26
+ let doneLinks = new sorted_array_1.SortedArray();
27
+ let headLinks = new sorted_array_1.SortedArray();
28
+ let headTitle = undefined;
29
+ doneLinks.distinct = true;
30
+ headLinks.distinct = true;
31
+ class Template {
32
+ data;
33
+ containerData;
34
+ doExpression = true;
35
+ doLiteral = false;
36
+ fileName;
37
+ filePath;
38
+ included = false;
39
+ // Inline elements are replaced by $1 when in literal.
40
+ // TODO check if this really matches elements displayed inline
41
+ inlineElements = new sorted_array_1.SortedArray('a', 'b', 'big', 'button', 'cite', 'code', 'data', 'del', 'em', 'font', 'i', 'img', 'input', 'ins', 'kbd', 'label', 'mark', 'meter', 'optgroup', 'option', 'output', 'picture', 'q', 'rt', 'samp', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'sup', 'svg', 'time', 'tspan', 'u', 'var', 'wbr');
42
+ // These attribute values are literals.
43
+ literalAttributes = new sorted_array_1.SortedArray('alt', 'enterkeyhint', 'label', 'lang', 'placeholder', 'srcdoc', 'title');
44
+ // These element contents are literals.
45
+ literalElements = new sorted_array_1.SortedArray('a', 'abbr', 'acronym', 'article', 'aside', 'b', 'bdi', 'bdo', 'big', 'blockquote', 'body', 'br', 'button', 'caption', 'center', 'cite', 'data', 'datalist', 'dd', 'del', 'desc', 'details', 'dfn', 'dialog', 'div', 'dt', 'em', 'fieldset', 'figcaption', 'figure', 'font', 'footer', 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'header', 'hr', 'i', 'iframe', 'ins', 'keygen', 'label', 'legend', 'li', 'main', 'mark', 'menuitem', 'meter', 'nav', 'noframes', 'noscript', 'optgroup', 'option', 'p', 'pre', 'q', 'rb', 's', 'section', 'select', 'small', 'span', 'strike', 'strong', 'sub', 'summary', 'sup', 'td', 'template', 'text', 'textarea', 'textpath', 'th', 'time', 'title', 'tspan', 'u', 'wbr');
46
+ onAttribute;
47
+ onTagOpen;
48
+ onTagOpened;
49
+ onTagClose;
50
+ parsers = [];
51
+ // These elements have no closing tag.
52
+ unclosingTags = new sorted_array_1.SortedArray('area', 'base', 'basefont', 'br', 'col', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track');
53
+ constructor(data, containerData) {
54
+ this.data = data;
55
+ this.containerData = containerData;
56
+ blockStack = [];
57
+ if (containerData) {
58
+ blockStack.push({ blockStart: 0, collection: [], data: containerData, iteration: 0, iterations: 1 });
59
+ }
60
+ }
61
+ applyLiterals(text, parts = []) {
62
+ return text.replace(/\$([0-9]+)/g, (_, index) => parts[+index]);
63
+ }
64
+ closeTag(shouldInLiteral, targetIndex) {
65
+ shouldInLiteral ||= inLiteral;
66
+ ({ tagName, inLiteral } = tagStack.pop() ?? { tagName: '', inLiteral: false });
67
+ if (this.onTagClose)
68
+ this.onTagClose.call(this, tagName);
69
+ if ((tagName[0] === 'a') && (tagName === 'address')) {
70
+ lockLiteral = false;
71
+ }
72
+ if (inLiteral && this.inlineElements.includes(tagName)) {
73
+ if (this.literalElements.includes(tagName)) {
74
+ this.literalTarget(targetIndex);
75
+ }
76
+ literalParts = literalPartStack.pop();
77
+ literalParts.push(target + source.substring(start, index));
78
+ start = index;
79
+ target = targetStack.pop() + '$' + literalParts.length;
80
+ shouldInLiteral = false;
81
+ }
82
+ return shouldInLiteral;
83
+ }
84
+ combineLiterals(text, parts) {
85
+ const original = text;
86
+ text = text.trimEnd();
87
+ const right = text.length;
88
+ let left = text.length;
89
+ text = text.trimStart();
90
+ left -= text.length;
91
+ if (text !== '') {
92
+ text = (parts && /^(\$[1-9][0-9]*)+$/.test(text))
93
+ ? parts.join('')
94
+ : this.applyLiterals(text, parts?.map(part => ((typeof part)[0] === 's') ? this.applyLiterals(part) : part));
95
+ }
96
+ return original.substring(0, left) + text + original.substring(right);
97
+ }
98
+ debugEvents() {
99
+ this.onAttribute = (name, value) => console.log('attribute', name, '=', value);
100
+ this.onTagOpen = (name) => console.log('tag.open =', name);
101
+ this.onTagOpened = (name) => console.log('tag.opened =', name);
102
+ this.onTagClose = (name) => console.log('tag.closed =', name);
103
+ }
104
+ getCleanContext() {
105
+ const doneLinks = new sorted_array_1.SortedArray;
106
+ const headLinks = new sorted_array_1.SortedArray;
107
+ doneLinks.distinct = true;
108
+ headLinks.distinct = true;
109
+ return {
110
+ doHeadLinks: false,
111
+ doneLinks: doneLinks,
112
+ headLinks: headLinks,
113
+ index: length,
114
+ length: source.length,
115
+ source: source,
116
+ start: length,
117
+ target: target,
118
+ targetStack: [],
119
+ literalPartStack: [],
120
+ literalParts: [],
121
+ inLiteral: this.doLiteral
122
+ };
123
+ }
124
+ getPosition() {
125
+ return { index, start, target };
126
+ }
127
+ getContext() {
128
+ return {
129
+ doHeadLinks, doneLinks, headLinks, index, length, source, start, target, targetStack,
130
+ literalPartStack, literalParts, inLiteral
131
+ };
132
+ }
133
+ async include(path, data) {
134
+ const back = {
135
+ doHeadLinks, index, length, source, start, tagName, tagStack, target, targetStack,
136
+ literalParts, literalPartStack, inLiteral, lockLiteral
137
+ };
138
+ doHeadLinks = true;
139
+ const template = new (Object.getPrototypeOf(this).constructor)(data, blockStack[0]?.data);
140
+ template.included = true;
141
+ template.doExpression = this.doExpression;
142
+ template.doLiteral = this.doLiteral;
143
+ template.onAttribute = this.onAttribute;
144
+ template.onTagClose = this.onTagClose;
145
+ template.onTagOpen = this.onTagOpen;
146
+ template.onTagOpened = this.onTagOpened;
147
+ template.parsers = this.parsers;
148
+ const parsed = await template.parseFile(((path[0] === node_path_1.sep) || (path[1] === ':')) ? path : (this.filePath + node_path_1.sep + path));
149
+ ({
150
+ doHeadLinks, index, length, source, start, tagName, tagStack, target, targetStack,
151
+ literalParts, literalPartStack, inLiteral, lockLiteral
152
+ } = back);
153
+ return parsed.substring(parsed.indexOf('<!--BEGIN-->') + 12, parsed.indexOf('<!--END-->'));
154
+ }
155
+ isContextClean() {
156
+ const clean = this.getCleanContext();
157
+ const context = this.getContext();
158
+ return context.doHeadLinks === clean.doHeadLinks
159
+ && context.doneLinks.distinct === clean.doneLinks.distinct
160
+ && context.doneLinks.length === clean.doneLinks.length
161
+ && context.headLinks.distinct === clean.headLinks.distinct
162
+ && context.headLinks.length === clean.headLinks.length
163
+ && context.index === clean.index
164
+ && context.length === clean.length
165
+ && context.start === clean.start
166
+ && context.targetStack.length === clean.targetStack.length
167
+ && context.literalPartStack.length === clean.literalPartStack.length
168
+ && context.literalParts.length === clean.literalParts.length
169
+ && context.inLiteral === clean.inLiteral;
170
+ }
171
+ literalTarget(index, isTitle = false) {
172
+ let combined;
173
+ if (literalParts.length) {
174
+ target += source.substring(start, index);
175
+ combined = this.combineLiterals(target, literalParts);
176
+ target = (targetStack.pop() ?? '') + combined;
177
+ literalParts = [];
178
+ }
179
+ else {
180
+ combined = this.combineLiterals(source.substring(start, index));
181
+ target += combined;
182
+ }
183
+ if (isTitle && doHeadLinks) {
184
+ headTitle = combined;
185
+ }
186
+ start = index;
187
+ }
188
+ async parseBuffer(buffer) {
189
+ this.setSource(buffer);
190
+ await this.parseVars();
191
+ if (doHeadLinks) {
192
+ return target;
193
+ }
194
+ if (headLinks.length) {
195
+ const position = target.lastIndexOf('>', target.indexOf('</head>')) + 1;
196
+ target = target.slice(0, position) + '\n\t' + headLinks.join('\n\t') + target.slice(position);
197
+ doneLinks = new sorted_array_1.SortedArray;
198
+ doneLinks.distinct = true;
199
+ headLinks = new sorted_array_1.SortedArray;
200
+ headLinks.distinct = true;
201
+ }
202
+ if (headTitle && !this.included) {
203
+ const position = target.indexOf('>', target.indexOf('<title') + 6) + 1;
204
+ target = target.slice(0, position) + headTitle + target.slice(target.indexOf('</title>', position));
205
+ }
206
+ return target;
207
+ }
208
+ async parseExpression(data, close, finalClose = '') {
209
+ const indexOut = index;
210
+ let open = source[index];
211
+ if (inLiteral && !literalParts.length) {
212
+ targetStack.push(target);
213
+ target = '';
214
+ }
215
+ if (open === '<') {
216
+ index += 3;
217
+ open = '{';
218
+ }
219
+ index++;
220
+ const firstChar = source[index];
221
+ if ((index >= length) || !this.startsExpression(firstChar, open, close)) {
222
+ return;
223
+ }
224
+ let conditional = (firstChar === '?');
225
+ const finalChar = finalClose.length ? finalClose[0] : '';
226
+ let stackPos = targetStack.length;
227
+ if (conditional) {
228
+ index++;
229
+ }
230
+ targetStack.push(target + source.substring(start, indexOut));
231
+ start = index;
232
+ target = '';
233
+ while (index < length) {
234
+ const char = source[index];
235
+ if (char === open) {
236
+ targetStack.push(target + source.substring(start, index));
237
+ index++;
238
+ start = index;
239
+ target = '';
240
+ continue;
241
+ }
242
+ if ((char === close)
243
+ || ((char === finalChar) && (source.substring(index, index + finalClose.length) === finalClose))) {
244
+ let minus = 0;
245
+ if (source[index - 1] === '?') {
246
+ conditional = true;
247
+ minus = 1;
248
+ }
249
+ const expression = target + source.substring(start, index - minus);
250
+ const lastTarget = targetStack.pop();
251
+ const parsed = await this.parsePath(expression, data);
252
+ index += (char === close) ? 1 : finalClose.length;
253
+ start = index;
254
+ target = '';
255
+ if (char === finalChar)
256
+ while (targetStack.length > stackPos) {
257
+ target += targetStack.shift();
258
+ }
259
+ if (inLiteral && (targetStack.length === stackPos)) {
260
+ literalParts.push(parsed);
261
+ target += lastTarget + '$' + literalParts.length;
262
+ return conditional;
263
+ }
264
+ if (lastTarget.length || target.length) {
265
+ target += lastTarget + parsed;
266
+ }
267
+ else {
268
+ target = parsed;
269
+ }
270
+ if (targetStack.length === stackPos) {
271
+ if (conditional && !parsed) {
272
+ if ((typeof target)[0] === 's') {
273
+ target = target.substring(0, target.lastIndexOf(' '));
274
+ while ((index < length) && !' \n\r\t\f'.includes(source[index])) {
275
+ index++;
276
+ start++;
277
+ }
278
+ index--;
279
+ }
280
+ return conditional;
281
+ }
282
+ return conditional;
283
+ }
284
+ continue;
285
+ }
286
+ if ((char === '"') || (char === "'")) {
287
+ index++;
288
+ let c;
289
+ while ((index < length) && ((c = source[index]) !== char)) {
290
+ if (c === '\\')
291
+ index++;
292
+ index++;
293
+ }
294
+ }
295
+ index++;
296
+ }
297
+ // bad close
298
+ stackPos++;
299
+ while (targetStack.length > stackPos) {
300
+ target = targetStack.pop() + open + target;
301
+ }
302
+ target = targetStack.pop() + (finalClose.length ? '<!--' : open) + target;
303
+ return conditional;
304
+ }
305
+ async parseFile(fileName, containerFileName) {
306
+ if (containerFileName && !this.included) {
307
+ const data = this.data;
308
+ this.data = Object.assign({ content: () => this.include(fileName, data) }, blockStack[0]?.data);
309
+ return this.parseFile((0, node_path_1.normalize)(containerFileName));
310
+ }
311
+ this.fileName = fileName.substring(fileName.lastIndexOf(node_path_1.sep) + 1);
312
+ this.filePath = fileName.substring(0, fileName.lastIndexOf(node_path_1.sep));
313
+ return this.parseBuffer(await (0, promises_1.readFile)(fileName, 'utf-8'));
314
+ }
315
+ async parsePath(expression, data) {
316
+ if (expression === '') {
317
+ return undefined;
318
+ }
319
+ if ((expression[0] === '.') && (expression.startsWith('./') || expression.startsWith('../'))) {
320
+ return this.include(expression, data);
321
+ }
322
+ blockBack = 0;
323
+ for (const variable of expression.split('.')) {
324
+ data = await this.parseVariable(variable, data);
325
+ }
326
+ return data;
327
+ }
328
+ async parseVariable(variable, data) {
329
+ if (variable === '') {
330
+ return (typeof data === 'function')
331
+ ? data.call()
332
+ : data;
333
+ }
334
+ if (variable === '*') {
335
+ return (typeof data === 'object') ? Object.values(data) : data;
336
+ }
337
+ const firstChar = variable[0];
338
+ if ((firstChar === 'B') && (variable === 'BEGIN')) {
339
+ return data;
340
+ }
341
+ if (((firstChar === '"') && (variable[variable.length - 1] === '"'))
342
+ || ((firstChar === "'") && (variable[variable.length - 1] === "'"))) {
343
+ return variable.substring(1, variable.length - 1);
344
+ }
345
+ if (firstChar === '-') {
346
+ blockBack++;
347
+ return blockStack[blockStack.length - blockBack].data;
348
+ }
349
+ for (const [prefix, callback] of this.parsers) {
350
+ if (firstChar === prefix) {
351
+ return callback(variable, data);
352
+ }
353
+ }
354
+ if (data[variable] === undefined) {
355
+ data = new rename_1.default(data);
356
+ }
357
+ let value = data[variable];
358
+ return ((typeof value === 'function') && !value.prototype)
359
+ ? value.call(data)
360
+ : value;
361
+ }
362
+ async parseVars() {
363
+ let blockStart = 0;
364
+ let collection = [];
365
+ let data = this.data;
366
+ let inHead = false;
367
+ let iteration = 0;
368
+ let iterations = 0;
369
+ while (index < length) {
370
+ let char = source[index];
371
+ // expression
372
+ if ((char === '{') && this.doExpression) {
373
+ await this.parseExpression(data, '}');
374
+ continue;
375
+ }
376
+ // tag ?
377
+ if (char !== '<') {
378
+ index++;
379
+ continue;
380
+ }
381
+ const tagIndex = index;
382
+ char = source[++index];
383
+ if (char === '!') {
384
+ if (inLiteral) {
385
+ this.literalTarget(tagIndex);
386
+ }
387
+ char = source[++index];
388
+ index++;
389
+ // comment tag
390
+ if ((char === '-') && (source[index] === '-')) {
391
+ index++;
392
+ if (!/[a-z0-9@%{]/i.test(source[index])
393
+ || !this.doExpression
394
+ || ((source[index] === 'B') && this.included && (source.substring(index, index + 8) === 'BEGIN-->'))
395
+ || ((source[index] === 'E') && this.included && (source.substring(index, index + 6) === 'END-->'))) {
396
+ index = source.indexOf('-->', index) + 3;
397
+ if (index === 2)
398
+ break;
399
+ if (inLiteral && (index > start)) {
400
+ this.sourceToTarget();
401
+ }
402
+ continue;
403
+ }
404
+ // end condition / loop block
405
+ if ('eE'.includes(source[index]) && ['end-->', 'END-->'].includes(source.substring(index, index + 6))) {
406
+ target += this.trimEndLine(source.substring(start, tagIndex));
407
+ iteration++;
408
+ if (iteration < iterations) {
409
+ data = collection[iteration];
410
+ index = start = blockStart;
411
+ if (inLiteral && (index > start)) {
412
+ this.sourceToTarget();
413
+ }
414
+ continue;
415
+ }
416
+ ({ blockStart, collection, data, iteration, iterations } = blockStack.pop()
417
+ ?? { blockStart: 0, collection: [], data: undefined, iteration: 0, iterations: 0 });
418
+ index += 6;
419
+ start = index;
420
+ if (inLiteral && (index > start)) {
421
+ this.sourceToTarget();
422
+ }
423
+ continue;
424
+ }
425
+ // begin condition / loop block
426
+ blockStack.push({ blockStart, collection, data, iteration, iterations });
427
+ if (tagIndex > start) {
428
+ target += this.trimEndLine(source.substring(start, tagIndex));
429
+ start = tagIndex;
430
+ }
431
+ const backTarget = target;
432
+ const backInLiteral = inLiteral;
433
+ index = tagIndex;
434
+ target = '';
435
+ inLiteral = false;
436
+ const condition = await this.parseExpression(data, '}', '-->');
437
+ let blockData = condition ? (target ? data : undefined) : target;
438
+ blockStart = index;
439
+ iteration = 0;
440
+ target = backTarget;
441
+ inLiteral = backInLiteral;
442
+ if (Array.isArray(blockData)) {
443
+ collection = blockData;
444
+ data = collection[0];
445
+ iterations = collection.length;
446
+ }
447
+ else {
448
+ collection = [];
449
+ data = blockData;
450
+ iterations = data ? 1 : 0;
451
+ }
452
+ if (!iterations) {
453
+ this.skipBlock();
454
+ continue;
455
+ }
456
+ if (inLiteral && (index > start)) {
457
+ this.sourceToTarget();
458
+ }
459
+ continue;
460
+ }
461
+ // cdata section
462
+ if ((char === '[') && (source.substring(index, index + 6) === 'CDATA[')) {
463
+ index = source.indexOf(']]>', index + 6) + 3;
464
+ if (index === 2)
465
+ break;
466
+ }
467
+ // DOCTYPE
468
+ else {
469
+ index = source.indexOf('>', index) + 1;
470
+ }
471
+ if (inLiteral) {
472
+ this.sourceToTarget();
473
+ }
474
+ continue;
475
+ }
476
+ // tag close
477
+ if (char === '/') {
478
+ index++;
479
+ const closeTagName = source.substring(index, source.indexOf('>', index));
480
+ index += closeTagName.length + 1;
481
+ if (inHead && (closeTagName[0] === 'h') && (closeTagName === 'head')) {
482
+ inHead = false;
483
+ if (!doHeadLinks) {
484
+ doneLinks = headLinks;
485
+ headLinks = new sorted_array_1.SortedArray;
486
+ headLinks.distinct = true;
487
+ }
488
+ }
489
+ let shouldInLiteral = inLiteral;
490
+ if (!this.unclosingTags.includes(closeTagName)) {
491
+ do {
492
+ shouldInLiteral = this.closeTag(shouldInLiteral, tagIndex);
493
+ } while ((tagName !== closeTagName) && tagName.length);
494
+ }
495
+ if (shouldInLiteral) {
496
+ lockLiteral = false;
497
+ this.literalTarget(tagIndex, (tagName[0] === 't') && (tagName === 'title'));
498
+ }
499
+ if (inLiteral && (index > start)) {
500
+ this.sourceToTarget();
501
+ }
502
+ continue;
503
+ }
504
+ // tag open
505
+ while ((index < length) && !' >\n\r\t\f'.includes(source[index]))
506
+ index++;
507
+ tagName = source.substring(tagIndex + 1, index);
508
+ if (this.onTagOpen)
509
+ this.onTagOpen.call(this, tagName);
510
+ while (' \n\r\t\f'.includes(source[index]))
511
+ index++;
512
+ char = tagName[0];
513
+ if ((char === 'h') && (tagName === 'head')) {
514
+ inHead = true;
515
+ }
516
+ const unclosingTag = this.unclosingTags.includes(tagName);
517
+ if (!unclosingTag) {
518
+ tagStack.push({ tagName, inLiteral });
519
+ }
520
+ let inlineElement = false;
521
+ let pushedParts = false;
522
+ if (inLiteral) {
523
+ inlineElement = this.inlineElements.includes(tagName);
524
+ if (inlineElement) {
525
+ if (literalParts.length) {
526
+ targetStack.push(target + source.substring(start, tagIndex));
527
+ }
528
+ else {
529
+ targetStack.push(target, source.substring(start, tagIndex));
530
+ }
531
+ start = tagIndex;
532
+ target = '';
533
+ if (!unclosingTag) {
534
+ literalPartStack.push(literalParts);
535
+ literalParts = [];
536
+ pushedParts = true;
537
+ }
538
+ }
539
+ else {
540
+ this.literalTarget(tagIndex);
541
+ }
542
+ }
543
+ const elementInLiteral = inLiteral;
544
+ // attributes
545
+ let hasTypeSubmit = false;
546
+ const inInput = (char === 'i') && (tagName === 'input');
547
+ const inLink = (char === 'l') && (tagName === 'link');
548
+ const inScript = (char === 's') && (tagName === 'script');
549
+ let targetTagIndex = -1;
550
+ if (inHead && (inLink || inScript)) {
551
+ this.sourceToTarget();
552
+ targetTagIndex = target.lastIndexOf('<');
553
+ }
554
+ while (source[index] !== '>') {
555
+ // attribute name
556
+ const position = index;
557
+ while ((index < length) && !' =>\n\r\t\f'.includes(source[index]))
558
+ index++;
559
+ const attributeName = source.substring(position, index);
560
+ while (' \n\r\t\f'.includes(source[index]))
561
+ index++;
562
+ // attribute value
563
+ if (source[index] === '=') {
564
+ index++;
565
+ while (' \n\r\t\f'.includes(source[index]))
566
+ index++;
567
+ const attributeChar = attributeName[0];
568
+ const [open, close] = ('afhls'.includes(attributeChar)
569
+ && ['action', 'formaction', 'href', 'location', 'src'].includes(attributeName)) ? ['(', ')']
570
+ : ['{', '}'];
571
+ let quote = source[index];
572
+ if ((quote === '"') || (quote === "'")) {
573
+ index++;
574
+ }
575
+ else {
576
+ quote = ' >';
577
+ }
578
+ if ((open === '(') && (source.substring(index, index + 6) === 'app://')) {
579
+ this.sourceToTarget();
580
+ index += 6;
581
+ start = index;
582
+ }
583
+ inLiteral = this.doLiteral && (this.literalAttributes.includes(attributeName)
584
+ || (hasTypeSubmit && (attributeChar === 'v') && (attributeName === 'value')));
585
+ if (inLiteral && !pushedParts && unclosingTag && literalParts.length) {
586
+ literalPartStack.push(literalParts);
587
+ literalParts = [];
588
+ pushedParts = true;
589
+ }
590
+ const inLinkHRef = inLink && (attributeChar === 'h') && (attributeName === 'href');
591
+ const inScriptSrc = inScript && (attributeChar === 's') && (attributeName === 'src');
592
+ if ((inLinkHRef || inScriptSrc || inLiteral) && (index > start)) {
593
+ this.sourceToTarget();
594
+ }
595
+ const position = index;
596
+ const shortQuote = !(quote.length - 1);
597
+ while (index < length) {
598
+ const char = source[index];
599
+ // end of attribute value
600
+ if (shortQuote ? (char === quote) : quote.includes(char)) {
601
+ const attributeValue = source.substring(position, index);
602
+ if (inInput) {
603
+ hasTypeSubmit ||= ((attributeChar === 't') && (attributeValue[0] === 's')
604
+ && (attributeName === 'type') && (attributeValue === 'submit'));
605
+ }
606
+ if (inLiteral) {
607
+ this.literalTarget(index);
608
+ }
609
+ if (inLinkHRef && attributeValue.endsWith('.css')) {
610
+ let frontStyle = (0, node_path_1.normalize)(this.filePath + node_path_1.sep + source.substring(start, index))
611
+ .substring(app_dir_1.default.length);
612
+ if (node_path_1.sep !== '/') {
613
+ frontStyle = frontStyle.replaceAll(node_path_1.sep, '/');
614
+ }
615
+ target += frontStyle;
616
+ start = index;
617
+ }
618
+ if (inScriptSrc && attributeValue.endsWith('.js')) {
619
+ let frontScript = (0, node_path_1.normalize)(this.filePath + node_path_1.sep + source.substring(start, index))
620
+ .substring(app_dir_1.default.length);
621
+ if (node_path_1.sep !== '/') {
622
+ frontScript = frontScript.replaceAll(node_path_1.sep, '/');
623
+ }
624
+ exports.frontScripts.insert(frontScript);
625
+ target += frontScript;
626
+ start = index;
627
+ }
628
+ if (this.onAttribute)
629
+ this.onAttribute(attributeName, attributeValue);
630
+ if (char !== '>')
631
+ index++;
632
+ break;
633
+ }
634
+ // expression in attribute value
635
+ if ((char === open) && this.doExpression) {
636
+ await this.parseExpression(data, close);
637
+ continue;
638
+ }
639
+ index++;
640
+ }
641
+ }
642
+ else if (this.onAttribute)
643
+ this.onAttribute(attributeName, '');
644
+ // next attribute
645
+ while (' \n\r\t\f'.includes(source[index]))
646
+ index++;
647
+ }
648
+ index++;
649
+ if (this.onTagOpened)
650
+ this.onTagOpened.call(this, tagName);
651
+ // skip script content
652
+ if (inScript) {
653
+ if (this.onTagClose)
654
+ this.onTagClose.call(this, 'script');
655
+ index = source.indexOf('</script>', index) + 9;
656
+ if (index === 8)
657
+ break;
658
+ if (inLiteral && (index > start)) {
659
+ this.sourceToTarget();
660
+ }
661
+ }
662
+ if (targetTagIndex > -1) {
663
+ this.sourceToTarget();
664
+ const headLink = target.substring(targetTagIndex);
665
+ if (!doneLinks || !doneLinks.includes(headLink)) {
666
+ headLinks.insert(headLink);
667
+ }
668
+ }
669
+ if (inScript) {
670
+ continue;
671
+ }
672
+ if (unclosingTag) {
673
+ if (pushedParts) {
674
+ literalParts = literalPartStack.pop();
675
+ }
676
+ inLiteral = elementInLiteral;
677
+ if (this.onTagClose)
678
+ this.onTagClose.call(this, tagName);
679
+ if (inLiteral) {
680
+ if (index > start) {
681
+ this.sourceToTarget();
682
+ }
683
+ if (inlineElement) {
684
+ literalParts.push(target);
685
+ target = targetStack.pop() + '$' + literalParts.length;
686
+ }
687
+ }
688
+ }
689
+ else {
690
+ lockLiteral ||= (tagName[0] === 'a') && (tagName === 'address');
691
+ inLiteral = this.doLiteral && !lockLiteral && this.literalElements.includes(tagName);
692
+ if (inLiteral && (index > start)) {
693
+ this.sourceToTarget();
694
+ }
695
+ }
696
+ }
697
+ if (tagStack.length) {
698
+ let shouldInLiteral = inLiteral;
699
+ while (tagStack.length) {
700
+ shouldInLiteral = this.closeTag(shouldInLiteral, length);
701
+ }
702
+ if (shouldInLiteral) {
703
+ this.literalTarget(length);
704
+ }
705
+ return target;
706
+ }
707
+ if (inLiteral) {
708
+ this.literalTarget(index);
709
+ }
710
+ if (start < length) {
711
+ target += source.substring(start);
712
+ start = length;
713
+ }
714
+ return target;
715
+ }
716
+ setSource(setSource, setIndex = 0, setStart, setTarget = '') {
717
+ index = setIndex;
718
+ length = setSource.length;
719
+ source = setSource;
720
+ start = setStart ?? index;
721
+ tagName = '';
722
+ tagStack = [];
723
+ target = setTarget;
724
+ inLiteral = this.doLiteral;
725
+ literalPartStack = [];
726
+ literalParts = [];
727
+ lockLiteral = false;
728
+ targetStack = [];
729
+ }
730
+ skipBlock() {
731
+ if (index > start) {
732
+ this.sourceToTarget();
733
+ }
734
+ let depth = 1;
735
+ while (depth) {
736
+ index = source.indexOf('<!--', index);
737
+ if (index < 0) {
738
+ break;
739
+ }
740
+ index += 4;
741
+ const char = source[index];
742
+ if (!this.startsExpression(char)) {
743
+ continue;
744
+ }
745
+ if ((char === 'e') && (source.substring(index, index + 6) === 'end-->')) {
746
+ depth--;
747
+ continue;
748
+ }
749
+ depth++;
750
+ }
751
+ index -= 4;
752
+ if (index < 0) {
753
+ index = length;
754
+ }
755
+ start = index;
756
+ }
757
+ sourceToTarget() {
758
+ target += source.substring(start, index);
759
+ start = index;
760
+ }
761
+ startsExpression(char, open = '{', close = '}') {
762
+ return RegExp('[a-z0-9"%*.?@\'' + open + close + '-]', 'i').test(char);
763
+ }
764
+ trimEndLine(string) {
765
+ let index = string.length;
766
+ while ((index > 0) && ' \n\r\t\f'.includes(string[index - 1])) {
767
+ index--;
768
+ if (string[index] === '\n') {
769
+ break;
770
+ }
771
+ }
772
+ return string.substring(0, index);
773
+ }
774
+ }
775
+ exports.default = Template;
776
+ exports.Template = Template;