@itrocks/template 0.1.2 → 0.1.5

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/cjs/template.d.ts CHANGED
@@ -49,9 +49,7 @@ export declare class Template {
49
49
  literalPartStack: string[][];
50
50
  lockLiteral: boolean;
51
51
  addLinks: SortedArray<string>;
52
- doHeadLinks: boolean;
53
52
  doneLinks: SortedArray<string>;
54
- headLinks: SortedArray<string>;
55
53
  headTitle?: string;
56
54
  fileName?: string;
57
55
  filePath?: string;
@@ -74,9 +72,8 @@ export declare class Template {
74
72
  embedHtmlResponse(htmlResponse: HtmlResponse): void;
75
73
  getCleanContext(): {
76
74
  addLinks: SortedArray<string>;
77
- doHeadLinks: boolean;
78
75
  doneLinks: SortedArray<string>;
79
- headLinks: SortedArray<string>;
76
+ included: boolean;
80
77
  index: number;
81
78
  inLiteral: boolean;
82
79
  length: number;
@@ -94,9 +91,8 @@ export declare class Template {
94
91
  };
95
92
  getContext(): {
96
93
  addLinks: SortedArray<string>;
97
- doHeadLinks: boolean;
98
94
  doneLinks: SortedArray<string>;
99
- headLinks: SortedArray<string>;
95
+ included: boolean;
100
96
  index: number;
101
97
  inLiteral: boolean;
102
98
  length: number;
@@ -111,9 +107,10 @@ export declare class Template {
111
107
  includePath(filePath: string): string;
112
108
  isContextClean(): boolean;
113
109
  literalTarget(index: number, isTitle?: boolean): void;
110
+ normalizeLink(link: string): string;
114
111
  parseBuffer(buffer: string): Promise<string>;
115
112
  parseExpression(data: any, open: Open | '<', close: Close, finalClose?: Final): Promise<boolean | undefined>;
116
- parseFile(fileName: string, containerFileName?: string): Promise<string>;
113
+ parseFile(fileName: string, containerFileName?: string | false): Promise<string>;
117
114
  parsePath(expression: string, data: any): Promise<any>;
118
115
  parseVariable(variable: string, data: any): Promise<any>;
119
116
  parseVars(): Promise<string>;
package/cjs/template.js CHANGED
@@ -11,6 +11,7 @@ const node_path_2 = require("node:path");
11
11
  exports.depends = {
12
12
  toString: async (value) => '' + value
13
13
  };
14
+ const DEBUG = false;
14
15
  const done = { done: true };
15
16
  exports.frontScripts = new sorted_array_1.SortedArray();
16
17
  exports.frontScripts.distinct = true;
@@ -52,9 +53,7 @@ class Template {
52
53
  lockLiteral = false;
53
54
  // html head
54
55
  addLinks = new sorted_array_1.SortedArray();
55
- doHeadLinks = false;
56
56
  doneLinks = new sorted_array_1.SortedArray();
57
- headLinks = new sorted_array_1.SortedArray();
58
57
  headTitle;
59
58
  // file
60
59
  fileName;
@@ -81,7 +80,6 @@ class Template {
81
80
  this.containerData = containerData;
82
81
  this.addLinks.distinct = true;
83
82
  this.doneLinks.distinct = true;
84
- this.headLinks.distinct = true;
85
83
  if (containerData) {
86
84
  this.blockStack.push({ blockStart: 0, data: containerData, iteration: done });
87
85
  }
@@ -119,7 +117,7 @@ class Template {
119
117
  if (text !== '') {
120
118
  text = (parts && /^(\$[1-9][0-9]*)+$/.test(text))
121
119
  ? parts.join('')
122
- : this.applyLiterals(text, parts?.map(part => ((typeof part)[0] === 's') ? this.applyLiterals(part) : part));
120
+ : this.applyLiterals(text, parts?.map(part => (((typeof part)[0] === 's') && (part[0] !== '<')) ? this.applyLiterals(part) : part));
123
121
  }
124
122
  return original.substring(0, left) + text + original.substring(right);
125
123
  }
@@ -134,19 +132,25 @@ class Template {
134
132
  if (dependency[0] === '<') {
135
133
  const script = dependency.match(/<script[^>]*\bsrc=["']([^"']+)["']/i)?.[1];
136
134
  if (script) {
137
- exports.frontScripts.insert(script);
135
+ exports.frontScripts.push(script);
138
136
  }
139
- this.headLinks.insert(dependency);
137
+ if (DEBUG)
138
+ console.log('addLink(', dependency, ')');
139
+ this.addLinks.push(dependency);
140
140
  continue;
141
141
  }
142
142
  dependency = (0, node_path_1.normalize)(dependency).slice(app_dir_1.appDir.length);
143
143
  switch (dependency.slice(dependency.lastIndexOf('.') + 1)) {
144
144
  case 'css':
145
- this.headLinks.insert('<link href="' + dependency + '" rel="stylesheet">');
145
+ if (DEBUG)
146
+ console.log('addLink(', '<link href="' + dependency + '" rel="stylesheet">', ')');
147
+ this.addLinks.push('<link href="' + dependency + '" rel="stylesheet">');
146
148
  continue;
147
149
  case 'js':
148
- exports.frontScripts.insert(dependency);
149
- this.headLinks.insert('<script src="' + dependency + '" type="module"></script>');
150
+ exports.frontScripts.push(dependency);
151
+ if (DEBUG)
152
+ console.log('addLink(', '<script src="' + dependency + '" type="module"></script>', ')');
153
+ this.addLinks.push('<script src="' + dependency + '" type="module"></script>');
150
154
  continue;
151
155
  }
152
156
  }
@@ -154,15 +158,12 @@ class Template {
154
158
  getCleanContext() {
155
159
  const addLinks = new sorted_array_1.SortedArray;
156
160
  const doneLinks = new sorted_array_1.SortedArray;
157
- const headLinks = new sorted_array_1.SortedArray;
158
161
  addLinks.distinct = true;
159
162
  doneLinks.distinct = true;
160
- headLinks.distinct = true;
161
163
  return {
162
- addLinks: addLinks,
163
- doHeadLinks: false,
164
- doneLinks: doneLinks,
165
- headLinks: headLinks,
164
+ addLinks,
165
+ doneLinks,
166
+ included: false,
166
167
  index: this.length,
167
168
  inLiteral: this.doLiteral,
168
169
  length: this.source.length,
@@ -180,9 +181,8 @@ class Template {
180
181
  getContext() {
181
182
  return {
182
183
  addLinks: this.addLinks,
183
- doHeadLinks: this.doHeadLinks,
184
184
  doneLinks: this.doneLinks,
185
- headLinks: this.headLinks,
185
+ included: this.included,
186
186
  index: this.index,
187
187
  inLiteral: this.inLiteral,
188
188
  length: this.length,
@@ -196,10 +196,10 @@ class Template {
196
196
  }
197
197
  async include(path, data) {
198
198
  const template = new (Object.getPrototypeOf(this).constructor)(data, this.blockStack[0]?.data);
199
+ template.addLinks = this.addLinks;
199
200
  template.doExpression = this.doExpression;
200
- template.doHeadLinks = true;
201
201
  template.doLiteral = this.doLiteral;
202
- template.doneLinks = this.headLinks;
202
+ template.doneLinks = this.doneLinks;
203
203
  template.included = true;
204
204
  template.onAttribute = this.onAttribute;
205
205
  template.onTagClose = this.onTagClose;
@@ -209,15 +209,13 @@ class Template {
209
209
  const parsed = await template.parseFile(((path[0] === node_path_2.sep) || (path[1] === ':'))
210
210
  ? path
211
211
  : (this.filePath + node_path_2.sep + path));
212
- if (!this.doHeadLinks) {
213
- this.addLinks.push(...template.headLinks);
214
- this.headTitle = template.headTitle;
215
- }
216
- this.headLinks.push(...template.headLinks);
212
+ this.headTitle = template.headTitle;
217
213
  const beginPosition = parsed.indexOf('<!--BEGIN-->');
218
- const endPosition = parsed.indexOf('<!--END-->');
219
- if ((beginPosition === -1) && (parsed[1] === '!') && parsed.startsWith('<!DOCTYPE html>')) {
214
+ const endPosition = parsed.lastIndexOf('<!--END-->');
215
+ if ((beginPosition < 0) && (parsed[1] === '!') && parsed.startsWith('<!DOCTYPE html>')) {
220
216
  if (this.targetReplace === '') {
217
+ if (DEBUG)
218
+ console.log('! targetReplace', path);
221
219
  this.targetReplace = parsed;
222
220
  }
223
221
  return '';
@@ -234,13 +232,10 @@ class Template {
234
232
  isContextClean() {
235
233
  const clean = this.getCleanContext();
236
234
  const context = this.getContext();
237
- return context.doHeadLinks === clean.doHeadLinks
238
- && context.addLinks.distinct === clean.addLinks.distinct
235
+ return context.addLinks.distinct === clean.addLinks.distinct
239
236
  && context.addLinks.length === clean.addLinks.length
240
237
  && context.doneLinks.distinct === clean.doneLinks.distinct
241
- && context.doneLinks.length === clean.doneLinks.length
242
- && context.headLinks.distinct === clean.headLinks.distinct
243
- && context.headLinks.length === clean.headLinks.length
238
+ && context.included === clean.included
244
239
  && context.index === clean.index
245
240
  && context.inLiteral === clean.inLiteral
246
241
  && context.literalPartStack.length === clean.literalPartStack.length
@@ -261,27 +256,55 @@ class Template {
261
256
  combined = this.combineLiterals(this.source.substring(this.start, index));
262
257
  this.target += combined;
263
258
  }
264
- if (isTitle && this.doHeadLinks) {
259
+ if (isTitle && this.included) {
265
260
  this.headTitle = combined;
266
261
  }
267
262
  this.start = index;
268
263
  }
264
+ normalizeLink(link) {
265
+ if (link[0] === '/')
266
+ return link;
267
+ const result = (0, node_path_1.normalize)(this.filePath + node_path_2.sep + link).substring(app_dir_1.appDir.length);
268
+ return (node_path_2.sep === '/') ? result : result.replaceAll(node_path_2.sep, '/');
269
+ }
269
270
  async parseBuffer(buffer) {
270
271
  this.prefixes = this.parsers.map(([prefix]) => prefix).join('');
271
272
  this.setSource(buffer);
272
273
  await this.parseVars();
273
- if (this.doHeadLinks) {
274
+ if (this.included) {
274
275
  return this.target;
275
276
  }
276
277
  if (this.addLinks.length) {
277
- const position = this.target.lastIndexOf('>', this.target.indexOf('</head>')) + 1;
278
- this.target = this.target.slice(0, position) + '\n\t' + this.addLinks.join('\n\t') + this.target.slice(position);
279
- }
280
- if (this.headTitle && !this.included) {
281
- const position = this.target.indexOf('>', this.target.indexOf('<title') + 6) + 1;
282
- this.target = this.target.slice(0, position)
283
- + this.headTitle
284
- + this.target.slice(this.target.indexOf('</title>', position));
278
+ let addLink;
279
+ const addLinks = new Array;
280
+ while (addLink = this.addLinks.shift()) {
281
+ for (const attribute of ['href', 'src']) {
282
+ let start = addLink.indexOf(attribute + '=');
283
+ if (start < 0)
284
+ continue;
285
+ start += attribute.length;
286
+ while ((addLink[start] !== '"') && (addLink[start] !== "'")) {
287
+ start++;
288
+ }
289
+ const quote = addLink[start++];
290
+ const stop = addLink.indexOf(quote, start);
291
+ const link = addLink.substring(start, stop);
292
+ if (DEBUG)
293
+ console.log('check(', link, ')');
294
+ if (!this.doneLinks.includes(link)) {
295
+ if (DEBUG)
296
+ console.log('+ addLink(', addLink, ')');
297
+ if (DEBUG)
298
+ console.log('+ doneLink(', link, ')');
299
+ addLinks.push(addLink);
300
+ this.doneLinks.push(link);
301
+ }
302
+ }
303
+ }
304
+ if (addLinks.length) {
305
+ const position = this.target.lastIndexOf('>', this.target.indexOf('</head>')) + 1;
306
+ this.target = this.target.slice(0, position) + '\n\t' + addLinks.join('\n\t') + this.target.slice(position);
307
+ }
285
308
  }
286
309
  return (this.targetReplace !== '') ? this.targetReplace : this.target;
287
310
  }
@@ -382,16 +405,27 @@ class Template {
382
405
  return conditional;
383
406
  }
384
407
  async parseFile(fileName, containerFileName) {
385
- if (containerFileName && !this.included) {
408
+ if (DEBUG)
409
+ console.log('----- parseFile', containerFileName ? 'contained' : 'fetched', this.included ? 'included' : 'final', fileName);
410
+ if (containerFileName) {
386
411
  const data = this.data;
387
412
  this.data = Object.assign({ content: () => this.include(fileName, data) }, this.blockStack[0]?.data);
388
413
  return this.parseFile((0, node_path_1.normalize)(containerFileName));
389
414
  }
390
415
  this.fileName = fileName.substring(fileName.lastIndexOf(node_path_2.sep) + 1);
391
416
  this.filePath = fileName.substring(0, fileName.lastIndexOf(node_path_2.sep));
392
- return this.parseBuffer(await (0, promises_1.readFile)(fileName, 'utf-8'));
417
+ let target = await this.parseBuffer(await (0, promises_1.readFile)(fileName, 'utf-8'));
418
+ if (containerFileName && this.headTitle) {
419
+ const position = target.indexOf('>', target.indexOf('<title') + 6) + 1;
420
+ target = target.slice(0, position)
421
+ + this.headTitle
422
+ + target.slice(target.indexOf('</title>', position));
423
+ }
424
+ return target;
393
425
  }
394
426
  async parsePath(expression, data) {
427
+ if (DEBUG)
428
+ console.log('parsePath', expression);
395
429
  if (expression === '') {
396
430
  return undefined;
397
431
  }
@@ -439,6 +473,8 @@ class Template {
439
473
  return data;
440
474
  }
441
475
  async parseVariable(variable, data) {
476
+ if (DEBUG)
477
+ console.log('parseVariable', variable, 'in', data);
442
478
  if (variable === '') {
443
479
  let dataBack;
444
480
  do {
@@ -503,14 +539,10 @@ class Template {
503
539
  const firstChar = this.source[this.index];
504
540
  if (!this.doExpression
505
541
  || !this.startsExpression(firstChar)
506
- || ((firstChar === 'B')
507
- && this.included
508
- && (this.source.substring(this.index, this.index + 8) === 'BEGIN-->'))
509
- || ((firstChar === 'E')
510
- && this.included
511
- && (this.source.substring(this.index, this.index + 6) === 'END-->'))) {
542
+ || ((firstChar === 'B') && (this.source.substring(this.index, this.index + 8) === 'BEGIN-->'))
543
+ || ((firstChar === 'E') && (this.source.substring(this.index, this.index + 6) === 'END-->'))) {
512
544
  this.index = this.source.indexOf('-->', this.index) + 3;
513
- if (this.index === 2)
545
+ if (this.index < 3)
514
546
  break;
515
547
  if (this.inLiteral && (this.index > this.start)) {
516
548
  this.sourceToTarget();
@@ -576,7 +608,7 @@ class Template {
576
608
  // cdata section
577
609
  if ((char === '[') && (this.source.substring(this.index, this.index + 6) === 'CDATA[')) {
578
610
  this.index = this.source.indexOf(']]>', this.index + 6) + 3;
579
- if (this.index === 2)
611
+ if (this.index < 3)
580
612
  break;
581
613
  }
582
614
  // DOCTYPE
@@ -723,23 +755,25 @@ class Template {
723
755
  this.literalTarget(this.index);
724
756
  }
725
757
  if (inLinkHRef && attributeValue.endsWith('.css')) {
726
- let frontStyle = (0, node_path_1.normalize)(this.filePath + node_path_2.sep + this.source.substring(this.start, this.index))
727
- .substring(app_dir_1.appDir.length);
728
- if (node_path_2.sep !== '/') {
729
- frontStyle = frontStyle.replaceAll(node_path_2.sep, '/');
730
- }
758
+ let frontStyle = this.normalizeLink(this.source.substring(this.start, this.index));
731
759
  this.target += frontStyle;
732
760
  this.start = this.index;
761
+ if (!(inHead && this.included)) {
762
+ if (DEBUG)
763
+ console.log('doneLink(', frontStyle, ')');
764
+ this.doneLinks.push(frontStyle);
765
+ }
733
766
  }
734
767
  if (inScriptSrc && attributeValue.endsWith('.js')) {
735
- let frontScript = (0, node_path_1.normalize)(this.filePath + node_path_2.sep + this.source.substring(this.start, this.index))
736
- .substring(app_dir_1.appDir.length);
737
- if (node_path_2.sep !== '/') {
738
- frontScript = frontScript.replaceAll(node_path_2.sep, '/');
739
- }
740
- exports.frontScripts.insert(frontScript);
768
+ let frontScript = this.normalizeLink(this.source.substring(this.start, this.index));
769
+ exports.frontScripts.push(frontScript);
741
770
  this.target += frontScript;
742
771
  this.start = this.index;
772
+ if (!(inHead && this.included)) {
773
+ if (DEBUG)
774
+ console.log('doneLink(', frontScript, ')');
775
+ this.doneLinks.push(frontScript);
776
+ }
743
777
  }
744
778
  if (this.onAttribute)
745
779
  this.onAttribute(attributeName, attributeValue);
@@ -788,16 +822,18 @@ class Template {
788
822
  if (this.onTagClose)
789
823
  this.onTagClose.call(this, 'script');
790
824
  this.index = this.source.indexOf('</script>', this.index) + 9;
791
- if (this.index === 8)
825
+ if (this.index < 9)
792
826
  break;
793
827
  if (this.inLiteral && (this.index > this.start)) {
794
828
  this.sourceToTarget();
795
829
  }
796
830
  }
797
- if (targetTagIndex > -1) {
831
+ if ((targetTagIndex > -1) && this.included) {
798
832
  this.sourceToTarget();
799
833
  const headLink = this.target.substring(targetTagIndex);
800
- this.headLinks.insert(headLink);
834
+ if (DEBUG)
835
+ console.log('addLink(', headLink, ')');
836
+ this.addLinks.push(headLink);
801
837
  }
802
838
  if (inScript) {
803
839
  continue;
package/esm/template.d.ts CHANGED
@@ -49,9 +49,7 @@ export declare class Template {
49
49
  literalPartStack: string[][];
50
50
  lockLiteral: boolean;
51
51
  addLinks: SortedArray<string>;
52
- doHeadLinks: boolean;
53
52
  doneLinks: SortedArray<string>;
54
- headLinks: SortedArray<string>;
55
53
  headTitle?: string;
56
54
  fileName?: string;
57
55
  filePath?: string;
@@ -74,9 +72,8 @@ export declare class Template {
74
72
  embedHtmlResponse(htmlResponse: HtmlResponse): void;
75
73
  getCleanContext(): {
76
74
  addLinks: SortedArray<string>;
77
- doHeadLinks: boolean;
78
75
  doneLinks: SortedArray<string>;
79
- headLinks: SortedArray<string>;
76
+ included: boolean;
80
77
  index: number;
81
78
  inLiteral: boolean;
82
79
  length: number;
@@ -94,9 +91,8 @@ export declare class Template {
94
91
  };
95
92
  getContext(): {
96
93
  addLinks: SortedArray<string>;
97
- doHeadLinks: boolean;
98
94
  doneLinks: SortedArray<string>;
99
- headLinks: SortedArray<string>;
95
+ included: boolean;
100
96
  index: number;
101
97
  inLiteral: boolean;
102
98
  length: number;
@@ -111,9 +107,10 @@ export declare class Template {
111
107
  includePath(filePath: string): string;
112
108
  isContextClean(): boolean;
113
109
  literalTarget(index: number, isTitle?: boolean): void;
110
+ normalizeLink(link: string): string;
114
111
  parseBuffer(buffer: string): Promise<string>;
115
112
  parseExpression(data: any, open: Open | '<', close: Close, finalClose?: Final): Promise<boolean | undefined>;
116
- parseFile(fileName: string, containerFileName?: string): Promise<string>;
113
+ parseFile(fileName: string, containerFileName?: string | false): Promise<string>;
117
114
  parsePath(expression: string, data: any): Promise<any>;
118
115
  parseVariable(variable: string, data: any): Promise<any>;
119
116
  parseVars(): Promise<string>;
package/esm/template.js CHANGED
@@ -7,6 +7,7 @@ import { sep } from 'node:path';
7
7
  export const depends = {
8
8
  toString: async (value) => '' + value
9
9
  };
10
+ const DEBUG = false;
10
11
  const done = { done: true };
11
12
  export const frontScripts = new SortedArray();
12
13
  frontScripts.distinct = true;
@@ -47,9 +48,7 @@ export class Template {
47
48
  lockLiteral = false;
48
49
  // html head
49
50
  addLinks = new SortedArray();
50
- doHeadLinks = false;
51
51
  doneLinks = new SortedArray();
52
- headLinks = new SortedArray();
53
52
  headTitle;
54
53
  // file
55
54
  fileName;
@@ -76,7 +75,6 @@ export class Template {
76
75
  this.containerData = containerData;
77
76
  this.addLinks.distinct = true;
78
77
  this.doneLinks.distinct = true;
79
- this.headLinks.distinct = true;
80
78
  if (containerData) {
81
79
  this.blockStack.push({ blockStart: 0, data: containerData, iteration: done });
82
80
  }
@@ -114,7 +112,7 @@ export class Template {
114
112
  if (text !== '') {
115
113
  text = (parts && /^(\$[1-9][0-9]*)+$/.test(text))
116
114
  ? parts.join('')
117
- : this.applyLiterals(text, parts?.map(part => ((typeof part)[0] === 's') ? this.applyLiterals(part) : part));
115
+ : this.applyLiterals(text, parts?.map(part => (((typeof part)[0] === 's') && (part[0] !== '<')) ? this.applyLiterals(part) : part));
118
116
  }
119
117
  return original.substring(0, left) + text + original.substring(right);
120
118
  }
@@ -129,19 +127,25 @@ export class Template {
129
127
  if (dependency[0] === '<') {
130
128
  const script = dependency.match(/<script[^>]*\bsrc=["']([^"']+)["']/i)?.[1];
131
129
  if (script) {
132
- frontScripts.insert(script);
130
+ frontScripts.push(script);
133
131
  }
134
- this.headLinks.insert(dependency);
132
+ if (DEBUG)
133
+ console.log('addLink(', dependency, ')');
134
+ this.addLinks.push(dependency);
135
135
  continue;
136
136
  }
137
137
  dependency = normalize(dependency).slice(appDir.length);
138
138
  switch (dependency.slice(dependency.lastIndexOf('.') + 1)) {
139
139
  case 'css':
140
- this.headLinks.insert('<link href="' + dependency + '" rel="stylesheet">');
140
+ if (DEBUG)
141
+ console.log('addLink(', '<link href="' + dependency + '" rel="stylesheet">', ')');
142
+ this.addLinks.push('<link href="' + dependency + '" rel="stylesheet">');
141
143
  continue;
142
144
  case 'js':
143
- frontScripts.insert(dependency);
144
- this.headLinks.insert('<script src="' + dependency + '" type="module"></script>');
145
+ frontScripts.push(dependency);
146
+ if (DEBUG)
147
+ console.log('addLink(', '<script src="' + dependency + '" type="module"></script>', ')');
148
+ this.addLinks.push('<script src="' + dependency + '" type="module"></script>');
145
149
  continue;
146
150
  }
147
151
  }
@@ -149,15 +153,12 @@ export class Template {
149
153
  getCleanContext() {
150
154
  const addLinks = new SortedArray;
151
155
  const doneLinks = new SortedArray;
152
- const headLinks = new SortedArray;
153
156
  addLinks.distinct = true;
154
157
  doneLinks.distinct = true;
155
- headLinks.distinct = true;
156
158
  return {
157
- addLinks: addLinks,
158
- doHeadLinks: false,
159
- doneLinks: doneLinks,
160
- headLinks: headLinks,
159
+ addLinks,
160
+ doneLinks,
161
+ included: false,
161
162
  index: this.length,
162
163
  inLiteral: this.doLiteral,
163
164
  length: this.source.length,
@@ -175,9 +176,8 @@ export class Template {
175
176
  getContext() {
176
177
  return {
177
178
  addLinks: this.addLinks,
178
- doHeadLinks: this.doHeadLinks,
179
179
  doneLinks: this.doneLinks,
180
- headLinks: this.headLinks,
180
+ included: this.included,
181
181
  index: this.index,
182
182
  inLiteral: this.inLiteral,
183
183
  length: this.length,
@@ -191,10 +191,10 @@ export class Template {
191
191
  }
192
192
  async include(path, data) {
193
193
  const template = new (Object.getPrototypeOf(this).constructor)(data, this.blockStack[0]?.data);
194
+ template.addLinks = this.addLinks;
194
195
  template.doExpression = this.doExpression;
195
- template.doHeadLinks = true;
196
196
  template.doLiteral = this.doLiteral;
197
- template.doneLinks = this.headLinks;
197
+ template.doneLinks = this.doneLinks;
198
198
  template.included = true;
199
199
  template.onAttribute = this.onAttribute;
200
200
  template.onTagClose = this.onTagClose;
@@ -204,15 +204,13 @@ export class Template {
204
204
  const parsed = await template.parseFile(((path[0] === sep) || (path[1] === ':'))
205
205
  ? path
206
206
  : (this.filePath + sep + path));
207
- if (!this.doHeadLinks) {
208
- this.addLinks.push(...template.headLinks);
209
- this.headTitle = template.headTitle;
210
- }
211
- this.headLinks.push(...template.headLinks);
207
+ this.headTitle = template.headTitle;
212
208
  const beginPosition = parsed.indexOf('<!--BEGIN-->');
213
- const endPosition = parsed.indexOf('<!--END-->');
214
- if ((beginPosition === -1) && (parsed[1] === '!') && parsed.startsWith('<!DOCTYPE html>')) {
209
+ const endPosition = parsed.lastIndexOf('<!--END-->');
210
+ if ((beginPosition < 0) && (parsed[1] === '!') && parsed.startsWith('<!DOCTYPE html>')) {
215
211
  if (this.targetReplace === '') {
212
+ if (DEBUG)
213
+ console.log('! targetReplace', path);
216
214
  this.targetReplace = parsed;
217
215
  }
218
216
  return '';
@@ -229,13 +227,10 @@ export class Template {
229
227
  isContextClean() {
230
228
  const clean = this.getCleanContext();
231
229
  const context = this.getContext();
232
- return context.doHeadLinks === clean.doHeadLinks
233
- && context.addLinks.distinct === clean.addLinks.distinct
230
+ return context.addLinks.distinct === clean.addLinks.distinct
234
231
  && context.addLinks.length === clean.addLinks.length
235
232
  && context.doneLinks.distinct === clean.doneLinks.distinct
236
- && context.doneLinks.length === clean.doneLinks.length
237
- && context.headLinks.distinct === clean.headLinks.distinct
238
- && context.headLinks.length === clean.headLinks.length
233
+ && context.included === clean.included
239
234
  && context.index === clean.index
240
235
  && context.inLiteral === clean.inLiteral
241
236
  && context.literalPartStack.length === clean.literalPartStack.length
@@ -256,27 +251,55 @@ export class Template {
256
251
  combined = this.combineLiterals(this.source.substring(this.start, index));
257
252
  this.target += combined;
258
253
  }
259
- if (isTitle && this.doHeadLinks) {
254
+ if (isTitle && this.included) {
260
255
  this.headTitle = combined;
261
256
  }
262
257
  this.start = index;
263
258
  }
259
+ normalizeLink(link) {
260
+ if (link[0] === '/')
261
+ return link;
262
+ const result = normalize(this.filePath + sep + link).substring(appDir.length);
263
+ return (sep === '/') ? result : result.replaceAll(sep, '/');
264
+ }
264
265
  async parseBuffer(buffer) {
265
266
  this.prefixes = this.parsers.map(([prefix]) => prefix).join('');
266
267
  this.setSource(buffer);
267
268
  await this.parseVars();
268
- if (this.doHeadLinks) {
269
+ if (this.included) {
269
270
  return this.target;
270
271
  }
271
272
  if (this.addLinks.length) {
272
- const position = this.target.lastIndexOf('>', this.target.indexOf('</head>')) + 1;
273
- this.target = this.target.slice(0, position) + '\n\t' + this.addLinks.join('\n\t') + this.target.slice(position);
274
- }
275
- if (this.headTitle && !this.included) {
276
- const position = this.target.indexOf('>', this.target.indexOf('<title') + 6) + 1;
277
- this.target = this.target.slice(0, position)
278
- + this.headTitle
279
- + this.target.slice(this.target.indexOf('</title>', position));
273
+ let addLink;
274
+ const addLinks = new Array;
275
+ while (addLink = this.addLinks.shift()) {
276
+ for (const attribute of ['href', 'src']) {
277
+ let start = addLink.indexOf(attribute + '=');
278
+ if (start < 0)
279
+ continue;
280
+ start += attribute.length;
281
+ while ((addLink[start] !== '"') && (addLink[start] !== "'")) {
282
+ start++;
283
+ }
284
+ const quote = addLink[start++];
285
+ const stop = addLink.indexOf(quote, start);
286
+ const link = addLink.substring(start, stop);
287
+ if (DEBUG)
288
+ console.log('check(', link, ')');
289
+ if (!this.doneLinks.includes(link)) {
290
+ if (DEBUG)
291
+ console.log('+ addLink(', addLink, ')');
292
+ if (DEBUG)
293
+ console.log('+ doneLink(', link, ')');
294
+ addLinks.push(addLink);
295
+ this.doneLinks.push(link);
296
+ }
297
+ }
298
+ }
299
+ if (addLinks.length) {
300
+ const position = this.target.lastIndexOf('>', this.target.indexOf('</head>')) + 1;
301
+ this.target = this.target.slice(0, position) + '\n\t' + addLinks.join('\n\t') + this.target.slice(position);
302
+ }
280
303
  }
281
304
  return (this.targetReplace !== '') ? this.targetReplace : this.target;
282
305
  }
@@ -377,16 +400,27 @@ export class Template {
377
400
  return conditional;
378
401
  }
379
402
  async parseFile(fileName, containerFileName) {
380
- if (containerFileName && !this.included) {
403
+ if (DEBUG)
404
+ console.log('----- parseFile', containerFileName ? 'contained' : 'fetched', this.included ? 'included' : 'final', fileName);
405
+ if (containerFileName) {
381
406
  const data = this.data;
382
407
  this.data = Object.assign({ content: () => this.include(fileName, data) }, this.blockStack[0]?.data);
383
408
  return this.parseFile(normalize(containerFileName));
384
409
  }
385
410
  this.fileName = fileName.substring(fileName.lastIndexOf(sep) + 1);
386
411
  this.filePath = fileName.substring(0, fileName.lastIndexOf(sep));
387
- return this.parseBuffer(await readFile(fileName, 'utf-8'));
412
+ let target = await this.parseBuffer(await readFile(fileName, 'utf-8'));
413
+ if (containerFileName && this.headTitle) {
414
+ const position = target.indexOf('>', target.indexOf('<title') + 6) + 1;
415
+ target = target.slice(0, position)
416
+ + this.headTitle
417
+ + target.slice(target.indexOf('</title>', position));
418
+ }
419
+ return target;
388
420
  }
389
421
  async parsePath(expression, data) {
422
+ if (DEBUG)
423
+ console.log('parsePath', expression);
390
424
  if (expression === '') {
391
425
  return undefined;
392
426
  }
@@ -434,6 +468,8 @@ export class Template {
434
468
  return data;
435
469
  }
436
470
  async parseVariable(variable, data) {
471
+ if (DEBUG)
472
+ console.log('parseVariable', variable, 'in', data);
437
473
  if (variable === '') {
438
474
  let dataBack;
439
475
  do {
@@ -498,14 +534,10 @@ export class Template {
498
534
  const firstChar = this.source[this.index];
499
535
  if (!this.doExpression
500
536
  || !this.startsExpression(firstChar)
501
- || ((firstChar === 'B')
502
- && this.included
503
- && (this.source.substring(this.index, this.index + 8) === 'BEGIN-->'))
504
- || ((firstChar === 'E')
505
- && this.included
506
- && (this.source.substring(this.index, this.index + 6) === 'END-->'))) {
537
+ || ((firstChar === 'B') && (this.source.substring(this.index, this.index + 8) === 'BEGIN-->'))
538
+ || ((firstChar === 'E') && (this.source.substring(this.index, this.index + 6) === 'END-->'))) {
507
539
  this.index = this.source.indexOf('-->', this.index) + 3;
508
- if (this.index === 2)
540
+ if (this.index < 3)
509
541
  break;
510
542
  if (this.inLiteral && (this.index > this.start)) {
511
543
  this.sourceToTarget();
@@ -571,7 +603,7 @@ export class Template {
571
603
  // cdata section
572
604
  if ((char === '[') && (this.source.substring(this.index, this.index + 6) === 'CDATA[')) {
573
605
  this.index = this.source.indexOf(']]>', this.index + 6) + 3;
574
- if (this.index === 2)
606
+ if (this.index < 3)
575
607
  break;
576
608
  }
577
609
  // DOCTYPE
@@ -718,23 +750,25 @@ export class Template {
718
750
  this.literalTarget(this.index);
719
751
  }
720
752
  if (inLinkHRef && attributeValue.endsWith('.css')) {
721
- let frontStyle = normalize(this.filePath + sep + this.source.substring(this.start, this.index))
722
- .substring(appDir.length);
723
- if (sep !== '/') {
724
- frontStyle = frontStyle.replaceAll(sep, '/');
725
- }
753
+ let frontStyle = this.normalizeLink(this.source.substring(this.start, this.index));
726
754
  this.target += frontStyle;
727
755
  this.start = this.index;
756
+ if (!(inHead && this.included)) {
757
+ if (DEBUG)
758
+ console.log('doneLink(', frontStyle, ')');
759
+ this.doneLinks.push(frontStyle);
760
+ }
728
761
  }
729
762
  if (inScriptSrc && attributeValue.endsWith('.js')) {
730
- let frontScript = normalize(this.filePath + sep + this.source.substring(this.start, this.index))
731
- .substring(appDir.length);
732
- if (sep !== '/') {
733
- frontScript = frontScript.replaceAll(sep, '/');
734
- }
735
- frontScripts.insert(frontScript);
763
+ let frontScript = this.normalizeLink(this.source.substring(this.start, this.index));
764
+ frontScripts.push(frontScript);
736
765
  this.target += frontScript;
737
766
  this.start = this.index;
767
+ if (!(inHead && this.included)) {
768
+ if (DEBUG)
769
+ console.log('doneLink(', frontScript, ')');
770
+ this.doneLinks.push(frontScript);
771
+ }
738
772
  }
739
773
  if (this.onAttribute)
740
774
  this.onAttribute(attributeName, attributeValue);
@@ -783,16 +817,18 @@ export class Template {
783
817
  if (this.onTagClose)
784
818
  this.onTagClose.call(this, 'script');
785
819
  this.index = this.source.indexOf('</script>', this.index) + 9;
786
- if (this.index === 8)
820
+ if (this.index < 9)
787
821
  break;
788
822
  if (this.inLiteral && (this.index > this.start)) {
789
823
  this.sourceToTarget();
790
824
  }
791
825
  }
792
- if (targetTagIndex > -1) {
826
+ if ((targetTagIndex > -1) && this.included) {
793
827
  this.sourceToTarget();
794
828
  const headLink = this.target.substring(targetTagIndex);
795
- this.headLinks.insert(headLink);
829
+ if (DEBUG)
830
+ console.log('addLink(', headLink, ')');
831
+ this.addLinks.push(headLink);
796
832
  }
797
833
  if (inScript) {
798
834
  continue;
package/package.json CHANGED
@@ -69,5 +69,5 @@
69
69
  "test": "test/test"
70
70
  },
71
71
  "types": "./esm/template.d.ts",
72
- "version": "0.1.2"
72
+ "version": "0.1.5"
73
73
  }