isml-linter 5.39.1 → 5.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1177 -1142
- package/LICENSE +21 -21
- package/README.md +245 -245
- package/bin/isml-linter.js +32 -32
- package/ismllinter.config.js +33 -33
- package/package.json +53 -53
- package/scaffold_files/ismllinter.config.js +47 -47
- package/src/Builder.js +15 -15
- package/src/Constants.js +139 -139
- package/src/IsmlLinter.js +255 -255
- package/src/enums/ParseStatus.js +5 -5
- package/src/enums/SfccTagContainer.js +287 -287
- package/src/isml_tree/ContainerNode.js +38 -38
- package/src/isml_tree/IsmlNode.js +692 -658
- package/src/isml_tree/MaskUtils.js +421 -419
- package/src/isml_tree/ParseUtils.js +515 -434
- package/src/isml_tree/TreeBuilder.js +273 -271
- package/src/publicApi.js +24 -24
- package/src/rules/line_by_line/enforce-isprint.js +53 -53
- package/src/rules/line_by_line/enforce-require.js +35 -35
- package/src/rules/line_by_line/lowercase-filename.js +29 -29
- package/src/rules/line_by_line/max-lines.js +37 -37
- package/src/rules/line_by_line/no-br.js +36 -36
- package/src/rules/line_by_line/no-git-conflict.js +43 -43
- package/src/rules/line_by_line/no-import-package.js +34 -34
- package/src/rules/line_by_line/no-inline-style.js +34 -34
- package/src/rules/line_by_line/no-isscript.js +34 -34
- package/src/rules/line_by_line/no-space-only-lines.js +47 -47
- package/src/rules/line_by_line/no-tabs.js +38 -38
- package/src/rules/line_by_line/no-trailing-spaces.js +52 -52
- package/src/rules/prototypes/RulePrototype.js +79 -79
- package/src/rules/prototypes/SingleLineRulePrototype.js +47 -47
- package/src/rules/prototypes/TreeRulePrototype.js +84 -84
- package/src/rules/tree/align-isset.js +87 -87
- package/src/rules/tree/contextual-attrs.js +105 -105
- package/src/rules/tree/custom-tags.js +54 -54
- package/src/rules/tree/disallow-tags.js +39 -39
- package/src/rules/tree/empty-eof.js +66 -66
- package/src/rules/tree/enforce-security.js +85 -85
- package/src/rules/tree/eslint-to-isscript.js +179 -179
- package/src/rules/tree/indent.js +856 -853
- package/src/rules/tree/leading-iscache.js +39 -43
- package/src/rules/tree/leading-iscontent.js +35 -39
- package/src/rules/tree/max-depth.js +54 -54
- package/src/rules/tree/no-deprecated-attrs.js +67 -67
- package/src/rules/tree/no-embedded-isml.js +17 -17
- package/src/rules/tree/no-hardcode.js +51 -51
- package/src/rules/tree/no-iselse-slash.js +35 -35
- package/src/rules/tree/no-redundant-context.js +134 -134
- package/src/rules/tree/no-require-in-loop.js +63 -63
- package/src/rules/tree/one-element-per-line.js +82 -76
- package/src/util/CommandLineUtils.js +19 -19
- package/src/util/ConfigUtils.js +219 -219
- package/src/util/ConsoleUtils.js +327 -327
- package/src/util/CustomTagContainer.js +45 -45
- package/src/util/ExceptionUtils.js +149 -136
- package/src/util/FileUtils.js +79 -79
- package/src/util/GeneralUtils.js +60 -60
- package/src/util/NativeExtensionUtils.js +6 -6
- package/src/util/RuleUtils.js +295 -295
- package/src/util/TempRuleUtils.js +232 -232
|
@@ -1,658 +1,692 @@
|
|
|
1
|
-
const MAX_TEXT_DISPLAY_SIZE = 30;
|
|
2
|
-
|
|
3
|
-
const ConfigUtils = require('../util/ConfigUtils');
|
|
4
|
-
const Constants = require('../Constants');
|
|
5
|
-
const SfccTagContainer = require('../enums/SfccTagContainer');
|
|
6
|
-
const ParseUtils = require('./ParseUtils');
|
|
7
|
-
const MaskUtils = require('./MaskUtils');
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
* @param {
|
|
16
|
-
* @param {Number}
|
|
17
|
-
* @param {Number}
|
|
18
|
-
* @param {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
this.
|
|
23
|
-
this.
|
|
24
|
-
this.
|
|
25
|
-
this.
|
|
26
|
-
this.
|
|
27
|
-
this.
|
|
28
|
-
this.
|
|
29
|
-
this.
|
|
30
|
-
this.
|
|
31
|
-
this.
|
|
32
|
-
this.
|
|
33
|
-
this.
|
|
34
|
-
this.
|
|
35
|
-
this.
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
this.
|
|
42
|
-
this.
|
|
43
|
-
this.
|
|
44
|
-
this.
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
this.
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
//
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
newNode.
|
|
141
|
-
newNode.
|
|
142
|
-
this.children.
|
|
143
|
-
this.
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
value.
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
// For
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
this.
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
this.children.splice(index,
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
const
|
|
514
|
-
const
|
|
515
|
-
|
|
516
|
-
const
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
const
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
const
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
1
|
+
const MAX_TEXT_DISPLAY_SIZE = 30;
|
|
2
|
+
|
|
3
|
+
const ConfigUtils = require('../util/ConfigUtils');
|
|
4
|
+
const Constants = require('../Constants');
|
|
5
|
+
const SfccTagContainer = require('../enums/SfccTagContainer');
|
|
6
|
+
const ParseUtils = require('./ParseUtils');
|
|
7
|
+
const MaskUtils = require('./MaskUtils');
|
|
8
|
+
const ExceptionUtils = require('../util/ExceptionUtils');
|
|
9
|
+
|
|
10
|
+
let ID_COUNTER = 0;
|
|
11
|
+
|
|
12
|
+
class IsmlNode {
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @param {String} head node opening tag value, including attributes
|
|
16
|
+
* @param {Number} lineNumber node starting line number
|
|
17
|
+
* @param {Number} columnNumber node starting column number
|
|
18
|
+
* @param {Number} globalPos node starting position since the beginning of the file
|
|
19
|
+
* @param {Boolean} isEmbeddedNode whether the node is part of an embedded "sub tree", as a tag attribute
|
|
20
|
+
*/
|
|
21
|
+
constructor(head = '(root)', lineNumber = 0, columnNumber, globalPos, isEmbeddedNode) {
|
|
22
|
+
this.id = ID_COUNTER++;
|
|
23
|
+
this.head = head; // '<div class="my_class">'
|
|
24
|
+
this.lineNumber = lineNumber; // 7
|
|
25
|
+
this.columnNumber = columnNumber; // 12
|
|
26
|
+
this.endLineNumber = lineNumber + ParseUtils.getLineBreakQty(head.trim()); // 9
|
|
27
|
+
this.globalPos = globalPos; // 184
|
|
28
|
+
this.depth = 0; // Isml dom tree node depth
|
|
29
|
+
this.tail = ''; // '</div>'
|
|
30
|
+
this.tailLineNumber = null; // 9
|
|
31
|
+
this.tailColumnNumber = null; // 12
|
|
32
|
+
this.tailGlobalPos = null; // 207
|
|
33
|
+
this.parent = null; // Parent isml node;
|
|
34
|
+
this.children = []; // Child isml nodes;
|
|
35
|
+
this.childNo = 0;
|
|
36
|
+
this.isEmbeddedNode = !!isEmbeddedNode;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Tail is the element corresponding closing tag, such as </div>
|
|
40
|
+
setTail(value, lineNumber, columnNumber, globalPos) {
|
|
41
|
+
this.tail += value;
|
|
42
|
+
this.tailLineNumber = lineNumber;
|
|
43
|
+
this.tailColumnNumber = columnNumber;
|
|
44
|
+
this.tailGlobalPos = globalPos;
|
|
45
|
+
this.tailEndLineNumber = lineNumber;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Returns a string. Examples: 'div', 'isprint', 'doctype';
|
|
49
|
+
getType() {
|
|
50
|
+
if (this.parent && this.parent.isOfType('iscomment')) {
|
|
51
|
+
return 'text';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const head = this.head.trim();
|
|
55
|
+
|
|
56
|
+
if (head.startsWith('<!--')) {
|
|
57
|
+
return 'html_comment';
|
|
58
|
+
} else if (this.isDocType()) {
|
|
59
|
+
return 'doctype';
|
|
60
|
+
} else if (this.isDynamicElement()) {
|
|
61
|
+
return 'dynamic_element';
|
|
62
|
+
} else if (this.isContainer()) {
|
|
63
|
+
return 'container';
|
|
64
|
+
} else if (!head) {
|
|
65
|
+
return 'empty';
|
|
66
|
+
} else if (head === '(root)') {
|
|
67
|
+
return 'root';
|
|
68
|
+
} else if (!this.isTag()) {
|
|
69
|
+
return 'text';
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const regex = /<[a-zA-Z\d_-]*(\s|>|\/)/g;
|
|
73
|
+
|
|
74
|
+
return head.match(regex)[0].slice(1, -1);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
getLastLineNumber() {
|
|
78
|
+
return this.tailLineNumber ?
|
|
79
|
+
this.tailLineNumber :
|
|
80
|
+
this.endLineNumber;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
isDocType() {
|
|
84
|
+
return this.head.toLowerCase().trim().startsWith('<!doctype ');
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Checks if the node type is dynamically set, such in:
|
|
88
|
+
// <${aPdictVariable} />
|
|
89
|
+
isDynamicElement() {
|
|
90
|
+
return this.head.trim().startsWith('<${');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
isInSameLineAsParent() {
|
|
94
|
+
return this.parent && !this.parent.isContainer() && this.parent.lineNumber === this.lineNumber;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
isInSameLineAsParentEnd() {
|
|
98
|
+
return this.parent && !this.parent.isContainer() && this.parent.endLineNumber === this.lineNumber;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
isMultiLineOpeningTag() {
|
|
102
|
+
return this.isTag() && ParseUtils.getLineBreakQty(this.head.trim()) > 0;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
isInSameLineAsPreviousSibling() {
|
|
106
|
+
const previousSibling = this.getPreviousSibling();
|
|
107
|
+
return previousSibling && previousSibling.getLastLineNumber() === this.lineNumber;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Gets an array of attributes. For <div class="my_class_1 my my_class_2" style="fancy">, returns:
|
|
112
|
+
*
|
|
113
|
+
* [
|
|
114
|
+
* {
|
|
115
|
+
* name : 'class',
|
|
116
|
+
* value : 'my_class_1 my my_class_2',
|
|
117
|
+
* valueList : ['my_class_1', 'my_class_2']
|
|
118
|
+
* },
|
|
119
|
+
* {
|
|
120
|
+
* name : 'style',
|
|
121
|
+
* value : 'fancy',
|
|
122
|
+
* valueList : ['fancy']
|
|
123
|
+
* }
|
|
124
|
+
* ]
|
|
125
|
+
*/
|
|
126
|
+
getAttributeList() {
|
|
127
|
+
if (!this.isHtmlTag() && !this.isIsmlTag() || this.isConditionalComment()) {
|
|
128
|
+
return [];
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return getAttributes(this);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
getAttr(name) {
|
|
135
|
+
return this.getAttributeList().find( attr => attr.label === name );
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
addChild(newNode) {
|
|
139
|
+
if (newNode.head.trim()) {
|
|
140
|
+
newNode.depth = this.depth + 1;
|
|
141
|
+
newNode.parent = this;
|
|
142
|
+
newNode.childNo = this.children.length;
|
|
143
|
+
this.children.push(newNode);
|
|
144
|
+
this.newestChildNode = newNode;
|
|
145
|
+
} else {
|
|
146
|
+
this.tail = newNode.head + this.tail;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
newNode.isEmbeddedNode = this.isEmbeddedNode;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
getLastChild() { return this.children[this.children.length - 1]; }
|
|
153
|
+
getChildrenQty() { return this.children.length; }
|
|
154
|
+
hasChildren() { return this.children.length > 0; }
|
|
155
|
+
|
|
156
|
+
getIndentationSize() {
|
|
157
|
+
return getNodeIndentationSize(this, true);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
getTailIndentationSize() {
|
|
161
|
+
return getNodeIndentationSize(this, false);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
isRoot() { return !this.parent; }
|
|
165
|
+
|
|
166
|
+
// Always returns false. It is true only for the container elements, please check ContainerNode class;
|
|
167
|
+
isContainer() { return false; }
|
|
168
|
+
|
|
169
|
+
isContainerChild() {
|
|
170
|
+
return this.parent && this.parent.isContainer();
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
isScriptContent() {
|
|
174
|
+
return this.parent && this.parent.isOfType('isscript');
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
isTag() {
|
|
178
|
+
const value = this.head.trim();
|
|
179
|
+
|
|
180
|
+
return value.startsWith('<') &&
|
|
181
|
+
value.endsWith('>');
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
isHtmlTag() {
|
|
185
|
+
const value = this.head.trim();
|
|
186
|
+
|
|
187
|
+
return value.startsWith('<') &&
|
|
188
|
+
!value.startsWith('<is') &&
|
|
189
|
+
value.endsWith('>');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
isIsmlTag() {
|
|
193
|
+
return this.head.trim().startsWith('<is');
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
isStandardIsmlTag() {
|
|
197
|
+
return !!SfccTagContainer[this.getType()];
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
isCustomIsmlTag() {
|
|
201
|
+
return this.isIsmlTag() && !this.isStandardIsmlTag();
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
isDescendantOf(nodeType) {
|
|
205
|
+
let iterator = this.parent;
|
|
206
|
+
|
|
207
|
+
while (iterator !== null) {
|
|
208
|
+
if (iterator.isOfType(nodeType)) {
|
|
209
|
+
return true;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
iterator = iterator.parent;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return false;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// For an unwrapped ${someVariable} element, returns true;
|
|
219
|
+
// For tags and hardcoded strings , returns false;
|
|
220
|
+
isExpression() {
|
|
221
|
+
const value = this.head.trim();
|
|
222
|
+
|
|
223
|
+
return value.startsWith('${') &&
|
|
224
|
+
value.endsWith('}');
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
isIsmlComment() {
|
|
228
|
+
const value = this.head.trim();
|
|
229
|
+
|
|
230
|
+
return value === '<iscomment>';
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
isIsscriptContent() {
|
|
234
|
+
return this.parent && this.parent.getType() === 'isscript';
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
isHtmlComment() {
|
|
238
|
+
const value = this.head.trim();
|
|
239
|
+
|
|
240
|
+
return value.startsWith('<!--') &&
|
|
241
|
+
value.endsWith('-->');
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
isConditionalComment() {
|
|
245
|
+
const value = this.head.trim();
|
|
246
|
+
|
|
247
|
+
return value.startsWith('<!--[');
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
isCommentContent() {
|
|
251
|
+
return this.parent && this.parent.isIsmlComment();
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
isHardCodedText() {
|
|
255
|
+
return !this.isRoot()
|
|
256
|
+
&& !this.isContainer()
|
|
257
|
+
&& !this.isConditionalComment()
|
|
258
|
+
&& !this.isTag()
|
|
259
|
+
&& !this.isExpression();
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
getPreviousSibling() {
|
|
263
|
+
if (!this.parent || !this.parent.isContainer() && this.isFirstChild() || this.parent.isContainer() && this.parent.isFirstChild() && this.isFirstChild()) {
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
const sibling = this.parent.isContainer() && this.isFirstChild() ?
|
|
268
|
+
this.parent.parent.children[this.parent.childNo - 1] :
|
|
269
|
+
this.parent.children[this.childNo - 1];
|
|
270
|
+
|
|
271
|
+
if (sibling.isContainer()) {
|
|
272
|
+
return sibling.children[0];
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return sibling;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
getNextSibling() {
|
|
279
|
+
if (!this.parent || this.parent.children.length < this.childNo) {
|
|
280
|
+
return null;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
const sibling = this.parent.children[this.childNo + 1];
|
|
284
|
+
|
|
285
|
+
if (sibling.isContainer()) {
|
|
286
|
+
return sibling.children[0];
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
return sibling;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
getTrailingValue() {
|
|
293
|
+
return this.tail || this.head;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Checks if node is HTML 5 void element;
|
|
297
|
+
isVoidElement() {
|
|
298
|
+
const config = ConfigUtils.load();
|
|
299
|
+
|
|
300
|
+
return !config.disableHtml5 && Constants.voidElementsArray.indexOf(this.getType()) >= 0;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// For <div /> , returns true;
|
|
304
|
+
// For <div></div>, returns false;
|
|
305
|
+
isSelfClosing() {
|
|
306
|
+
return !this.isContainer() && (
|
|
307
|
+
this.isDocType() ||
|
|
308
|
+
this.isVoidElement() ||
|
|
309
|
+
this.isHtmlComment() ||
|
|
310
|
+
this.isTag() && this.head.trim().endsWith('/>')) ||
|
|
311
|
+
this.isCustomIsmlTag() ||
|
|
312
|
+
this.isIsmlTag() && SfccTagContainer[this.getType()] && SfccTagContainer[this.getType()]['self-closing'];
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
isOfType(type) {
|
|
316
|
+
return typeof type === 'string' ?
|
|
317
|
+
!this.isRoot() && this.getType() === type :
|
|
318
|
+
type.some( elem => elem === this.getType());
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
isOneOfTypes(typeArray) {
|
|
322
|
+
for (let i = 0; i < typeArray.length; i++) {
|
|
323
|
+
if (this.isOfType(typeArray[i])) {
|
|
324
|
+
return true;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return false;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
isEmpty() {
|
|
332
|
+
return !this.head.trim();
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
isFirstChild() {
|
|
336
|
+
if (this.isRoot()) {
|
|
337
|
+
return false;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
const firstChild = this.parent.children[0];
|
|
341
|
+
|
|
342
|
+
return this.lineNumber === firstChild.lineNumber &&
|
|
343
|
+
this.head === firstChild.head;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
isLastChild() {
|
|
347
|
+
return !this.parent || this.parent.getLastChild() === this;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
removeChild(node) {
|
|
351
|
+
let index = null;
|
|
352
|
+
|
|
353
|
+
for (let i = 0; i < this.children.length; i++) {
|
|
354
|
+
const child = this.children[i];
|
|
355
|
+
|
|
356
|
+
if (child.id === node.id) {
|
|
357
|
+
index = i;
|
|
358
|
+
break;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
const removedNode = this.children[index];
|
|
363
|
+
this.children.splice(index, 1);
|
|
364
|
+
return removedNode;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
// No position or line number is set. To get
|
|
368
|
+
// it, it is necessary to re-parse the tree;
|
|
369
|
+
addChildNodeToPos(node, index) {
|
|
370
|
+
node.parent = this;
|
|
371
|
+
node.depth = this.depth + 1;
|
|
372
|
+
this.children.splice(index, 0, node);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
getRoot() {
|
|
376
|
+
let rootNode = this;
|
|
377
|
+
|
|
378
|
+
while (rootNode.parent) {
|
|
379
|
+
rootNode = rootNode.parent;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
return rootNode;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
toString(stream = '') {
|
|
386
|
+
|
|
387
|
+
if (!this.isContainer() && this.isEmpty() && !this.isLastChild()) {
|
|
388
|
+
return stream;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
if (!this.isRoot() && !this.isContainer()) {
|
|
392
|
+
stream += this.head;
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
for (let i = 0; i < this.children.length; i++) {
|
|
396
|
+
const child = this.children[i];
|
|
397
|
+
stream = child.toString(stream);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
if (!this.isRoot() && !this.isContainer()) {
|
|
401
|
+
stream += this.tail;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
return stream;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Used for debugging purposes only;
|
|
408
|
+
print() {
|
|
409
|
+
const indentSize = this.depth;
|
|
410
|
+
let indentation = '';
|
|
411
|
+
|
|
412
|
+
for (let i = 0; i < indentSize; ++i) {
|
|
413
|
+
indentation += ' ';
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
console.log(this.depth + ' :: ' + this.lineNumber + ' :: ' + indentation + getDisplayText(this));
|
|
417
|
+
|
|
418
|
+
for (let i = 0; i < this.children.length; i++) {
|
|
419
|
+
this.children[i].print();
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* PRIVATE FUNCTIONS
|
|
426
|
+
*
|
|
427
|
+
* The following are "private" spyOnAllFunctions, which
|
|
428
|
+
* will be available for use only within IsmlNode methods;
|
|
429
|
+
*/
|
|
430
|
+
|
|
431
|
+
const getAttributes = node => {
|
|
432
|
+
const trimmedHead = node.head.trim();
|
|
433
|
+
const nodeHead = trimmedHead.substring(1, trimmedHead.length - 1);
|
|
434
|
+
const firstSpaceAfterTagPos = ParseUtils.getFirstEmptyCharPos(trimmedHead);
|
|
435
|
+
const leadingEmptySpaceQty = ParseUtils.getNextNonEmptyCharPos(nodeHead);
|
|
436
|
+
const afterTagContent = nodeHead.substring(leadingEmptySpaceQty + firstSpaceAfterTagPos);
|
|
437
|
+
const stringifiedAttributeList = getStringifiedAttributeArray(afterTagContent);
|
|
438
|
+
const attributeList = [];
|
|
439
|
+
|
|
440
|
+
for (let i = 0; i < stringifiedAttributeList.length; i++) {
|
|
441
|
+
const attr = parseAttribute(node, stringifiedAttributeList, i);
|
|
442
|
+
attributeList.push(attr);
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
return attributeList;
|
|
446
|
+
};
|
|
447
|
+
|
|
448
|
+
// Used for debugging purposes only;
|
|
449
|
+
const getDisplayText = node => {
|
|
450
|
+
let displayText = node.head;
|
|
451
|
+
|
|
452
|
+
displayText = displayText
|
|
453
|
+
.replace(new RegExp(Constants.EOL, 'g'), '')
|
|
454
|
+
.replace(/ +(?= )/g, '');
|
|
455
|
+
|
|
456
|
+
if (node.head.length > MAX_TEXT_DISPLAY_SIZE - 3) {
|
|
457
|
+
displayText = displayText.substring(0, MAX_TEXT_DISPLAY_SIZE - 3) + '...';
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
return displayText.trim();
|
|
461
|
+
};
|
|
462
|
+
|
|
463
|
+
const getProcessedContent = content => {
|
|
464
|
+
let processedContent = content;
|
|
465
|
+
|
|
466
|
+
processedContent = MaskUtils.maskExpressionContent(processedContent);
|
|
467
|
+
processedContent = MaskUtils.maskIsifTagContent(processedContent);
|
|
468
|
+
processedContent = MaskUtils.maskIsprintTagContent(processedContent);
|
|
469
|
+
processedContent = MaskUtils.maskJsonContent(processedContent);
|
|
470
|
+
processedContent = MaskUtils.maskQuoteContent(processedContent);
|
|
471
|
+
processedContent = processedContent.replace(new RegExp(Constants.EOL, 'g'), ' ');
|
|
472
|
+
|
|
473
|
+
if (processedContent.endsWith('/')) {
|
|
474
|
+
processedContent = processedContent.slice(0, -1) + ' ';
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
return processedContent;
|
|
478
|
+
};
|
|
479
|
+
|
|
480
|
+
const getStringifiedAttributeArray = content => {
|
|
481
|
+
const maskedContent = getProcessedContent(content);
|
|
482
|
+
const attrStartPosList = [];
|
|
483
|
+
const result = [];
|
|
484
|
+
|
|
485
|
+
const maskedAttributeList = maskedContent
|
|
486
|
+
.replace(/><+/g, '> <')
|
|
487
|
+
.replace(/\s\s+/g, ' ')
|
|
488
|
+
.split(' ')
|
|
489
|
+
.filter(attr => attr);
|
|
490
|
+
|
|
491
|
+
for (let i = 0; i < maskedContent.length; i++) {
|
|
492
|
+
if (i === 0 && maskedContent[i] !== ' ') {
|
|
493
|
+
attrStartPosList.push(i);
|
|
494
|
+
} else if (maskedContent[i - 1] === ' ' && maskedContent[i] !== ' ' || maskedContent[i - 1] === '>' && maskedContent[i] === '<') {
|
|
495
|
+
attrStartPosList.push(i);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
for (let i = 0; i < maskedAttributeList.length; i++) {
|
|
500
|
+
let fullAttribute = content.substring(attrStartPosList[i] - 1, attrStartPosList[i] + maskedAttributeList[i].length).trim();
|
|
501
|
+
|
|
502
|
+
if (fullAttribute.endsWith('/')) {
|
|
503
|
+
fullAttribute = fullAttribute.slice(0, -1) + ' ';
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
result.push(fullAttribute);
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
return result;
|
|
510
|
+
};
|
|
511
|
+
|
|
512
|
+
const parseAttribute = (node, attributeList, index) => {
|
|
513
|
+
const attribute = attributeList[index];
|
|
514
|
+
const isAttributeANestedIsmlTag = attribute.startsWith('<is');
|
|
515
|
+
const isExpressionAttribute = attribute.startsWith('${') && attribute.endsWith('}');
|
|
516
|
+
const trimmedAttribute = attribute.trim();
|
|
517
|
+
const trimmedNodeHead = node.head.trim();
|
|
518
|
+
const localPos = getAttributeLocalPos(node, trimmedNodeHead, trimmedAttribute);
|
|
519
|
+
const leadingContent = trimmedNodeHead.substring(0, localPos);
|
|
520
|
+
const leadingLineBreakQty = ParseUtils.getLineBreakQty(leadingContent);
|
|
521
|
+
const isInSameLineAsTagName = leadingLineBreakQty === 0;
|
|
522
|
+
const assignmentCharPos = trimmedAttribute.indexOf('=');
|
|
523
|
+
const name = assignmentCharPos >= 0 ? trimmedAttribute.substring(0, assignmentCharPos) : trimmedAttribute;
|
|
524
|
+
const value = assignmentCharPos >= 0 ? trimmedAttribute.substring(assignmentCharPos + 2, trimmedAttribute.length - 1) : null;
|
|
525
|
+
const valueList = getAttributeValueList(value);
|
|
526
|
+
const attrLocalPos = trimmedNodeHead.indexOf(trimmedAttribute);
|
|
527
|
+
const valueLocalPos = trimmedAttribute.indexOf(value);
|
|
528
|
+
const lineNumber = node.lineNumber + leadingLineBreakQty;
|
|
529
|
+
const globalPos = node.globalPos + localPos + leadingLineBreakQty - lineNumber + 1;
|
|
530
|
+
const hasMultilineValue = value && value.indexOf(Constants.EOL) >= 0;
|
|
531
|
+
const isFirstValueInSameLineAsAttributeName = value && ParseUtils.getLeadingLineBreakQty(value) === 0;
|
|
532
|
+
const quoteChar = getQuoteChar(trimmedAttribute);
|
|
533
|
+
const attributeNameFirstLine = name.split(Constants.EOL)[0];
|
|
534
|
+
|
|
535
|
+
const columnNumber = isInSameLineAsTagName ?
|
|
536
|
+
node.columnNumber + leadingContent.length :
|
|
537
|
+
leadingContent.length - leadingContent.lastIndexOf(Constants.EOL);
|
|
538
|
+
|
|
539
|
+
const isFirstInLine = !isInSameLineAsTagName
|
|
540
|
+
&& trimmedNodeHead
|
|
541
|
+
.split(Constants.EOL)
|
|
542
|
+
.find(attrLine => attrLine.indexOf(attributeNameFirstLine) >= 0)
|
|
543
|
+
.trim()
|
|
544
|
+
.indexOf(attributeNameFirstLine) === 0;
|
|
545
|
+
|
|
546
|
+
if (isAttributeANestedIsmlTag || isExpressionAttribute) {
|
|
547
|
+
return {
|
|
548
|
+
name : trimmedAttribute,
|
|
549
|
+
value : null,
|
|
550
|
+
valueList : null,
|
|
551
|
+
localPos,
|
|
552
|
+
globalPos,
|
|
553
|
+
lineNumber,
|
|
554
|
+
columnNumber,
|
|
555
|
+
index,
|
|
556
|
+
isInSameLineAsTagName,
|
|
557
|
+
isFirstInLine,
|
|
558
|
+
isFirstValueInSameLineAsAttributeName,
|
|
559
|
+
isExpressionAttribute,
|
|
560
|
+
hasMultilineValue,
|
|
561
|
+
isNestedIsmlTag : isAttributeANestedIsmlTag,
|
|
562
|
+
length : trimmedAttribute.length + ParseUtils.getLineBreakQty(trimmedAttribute),
|
|
563
|
+
fullContent : trimmedAttribute,
|
|
564
|
+
quoteChar,
|
|
565
|
+
node
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
} else {
|
|
569
|
+
return {
|
|
570
|
+
name,
|
|
571
|
+
value,
|
|
572
|
+
valueList,
|
|
573
|
+
localPos,
|
|
574
|
+
globalPos,
|
|
575
|
+
lineNumber,
|
|
576
|
+
columnNumber,
|
|
577
|
+
index,
|
|
578
|
+
isInSameLineAsTagName,
|
|
579
|
+
isFirstInLine,
|
|
580
|
+
isFirstValueInSameLineAsAttributeName,
|
|
581
|
+
isExpressionAttribute,
|
|
582
|
+
hasMultilineValue,
|
|
583
|
+
isNestedIsmlTag: isAttributeANestedIsmlTag,
|
|
584
|
+
length : trimmedAttribute.length,
|
|
585
|
+
attrGlobalPos : node.globalPos + attrLocalPos,
|
|
586
|
+
valueGlobalPos : node.globalPos + valueLocalPos,
|
|
587
|
+
fullContent : trimmedAttribute,
|
|
588
|
+
quoteChar,
|
|
589
|
+
node
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
};
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* Two attributes can have the same name, and that is handled here;
|
|
596
|
+
*/
|
|
597
|
+
const getAttributeLocalPos = (node, trimmedNodeHead, trimmedAttribute) => {
|
|
598
|
+
const maskedTrimmedAttribute = MaskUtils.maskQuoteContent(trimmedAttribute);
|
|
599
|
+
const maskedTrimmedNodeHead = MaskUtils.maskQuoteContent(trimmedNodeHead);
|
|
600
|
+
|
|
601
|
+
let attributeLocalPos = maskedTrimmedNodeHead.indexOf(maskedTrimmedAttribute);
|
|
602
|
+
const isCorrectAttribute = trimmedNodeHead.indexOf(trimmedAttribute) === attributeLocalPos;
|
|
603
|
+
let remainingNodeHead = maskedTrimmedNodeHead.substring(attributeLocalPos + 1);
|
|
604
|
+
|
|
605
|
+
const maxLoops = 500;
|
|
606
|
+
let loopQty = 0;
|
|
607
|
+
|
|
608
|
+
while (!isCorrectAttribute) {
|
|
609
|
+
const tempLocalPos = remainingNodeHead.indexOf(maskedTrimmedAttribute) + 1;
|
|
610
|
+
|
|
611
|
+
attributeLocalPos += tempLocalPos;
|
|
612
|
+
|
|
613
|
+
const remainingContent = trimmedNodeHead.substring(attributeLocalPos);
|
|
614
|
+
|
|
615
|
+
if (remainingContent.startsWith(trimmedAttribute)) {
|
|
616
|
+
break;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
remainingNodeHead = remainingNodeHead.substring(tempLocalPos);
|
|
620
|
+
|
|
621
|
+
loopQty++;
|
|
622
|
+
|
|
623
|
+
if (loopQty >= maxLoops) {
|
|
624
|
+
throw ExceptionUtils.parseError(
|
|
625
|
+
node.getType(),
|
|
626
|
+
node.lineNumber,
|
|
627
|
+
node.globalPos,
|
|
628
|
+
node.head.length,
|
|
629
|
+
node.getRoot().tree.templatePath
|
|
630
|
+
);
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
return attributeLocalPos;
|
|
635
|
+
};
|
|
636
|
+
|
|
637
|
+
const getNodeIndentationSize = (node, isNodeHead) => {
|
|
638
|
+
|
|
639
|
+
if (node.isContainer()) {
|
|
640
|
+
return 0;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
const content = isNodeHead ? node.head : node.tail;
|
|
644
|
+
const precedingEmptySpacesLength = content.search(/\S|$/);
|
|
645
|
+
const fullPrecedingEmptySpaces = content.substring(0, precedingEmptySpacesLength);
|
|
646
|
+
const lineBreakLastPos = Math.max(fullPrecedingEmptySpaces.lastIndexOf(Constants.EOL), 0);
|
|
647
|
+
const precedingEmptySpaces = content.substring(lineBreakLastPos, precedingEmptySpacesLength).replace(new RegExp(Constants.EOL, 'g'), '');
|
|
648
|
+
const lastLineBreakPos = Math.max(precedingEmptySpaces.lastIndexOf(Constants.EOL), 0);
|
|
649
|
+
const indentationSize = precedingEmptySpaces.substring(lastLineBreakPos).length;
|
|
650
|
+
|
|
651
|
+
return Math.max(indentationSize, 0);
|
|
652
|
+
};
|
|
653
|
+
|
|
654
|
+
const getAttributeValueList = fullContent => {
|
|
655
|
+
|
|
656
|
+
if (!fullContent) {
|
|
657
|
+
return null;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
const maskedFullContent = MaskUtils.maskIgnorableContent(fullContent).trim();
|
|
661
|
+
const maskedValueList = maskedFullContent.split(/[\s\n]+/).filter( val => val );
|
|
662
|
+
const trimmedFullContent = fullContent.trim();
|
|
663
|
+
const valueList = [];
|
|
664
|
+
|
|
665
|
+
for (let i = 0; i < maskedValueList.length; i++) {
|
|
666
|
+
const maskedValueElement = maskedValueList[i];
|
|
667
|
+
const index = maskedFullContent.indexOf(maskedValueElement);
|
|
668
|
+
const value = trimmedFullContent.substring(index, index + maskedValueElement.length);
|
|
669
|
+
|
|
670
|
+
valueList.push(value);
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
return valueList;
|
|
674
|
+
};
|
|
675
|
+
|
|
676
|
+
const getQuoteChar = trimmedAttribute => {
|
|
677
|
+
const assignmentCharPos = trimmedAttribute.indexOf('=');
|
|
678
|
+
|
|
679
|
+
if (assignmentCharPos >= 0) {
|
|
680
|
+
if (trimmedAttribute.substring(assignmentCharPos + 1).startsWith('\'')) {
|
|
681
|
+
return '\'';
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
if (trimmedAttribute.substring(assignmentCharPos + 1).startsWith('"')) {
|
|
685
|
+
return '"';
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
return '';
|
|
690
|
+
};
|
|
691
|
+
|
|
692
|
+
module.exports = IsmlNode;
|