@markuplint/ml-core 2.0.0-rc.0 → 2.0.0-rc.6

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.
@@ -1,50 +1,86 @@
1
1
  "use strict";
2
- var _Selector_ruleset, _Ruleset_selectorGroup, _StructuredSelector_edge, _StructuredSelector_selector, _SelectorTarget_isAdded, _SelectorTarget_combinatedFrom;
2
+ var _Selector_ruleset, _Ruleset_selectorGroup, _StructuredSelector_edge, _StructuredSelector_selector, _SelectorTarget_tagNameCaseSensitive, _SelectorTarget_isAdded, _SelectorTarget_combinatedFrom;
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- exports.createSelector = void 0;
4
+ exports.compareSpecificity = exports.createSelector = void 0;
5
5
  const tslib_1 = require("tslib");
6
6
  const postcss_selector_parser_1 = (0, tslib_1.__importDefault)(require("postcss-selector-parser"));
7
- function createSelector(selector) {
8
- return new Selector(selector);
7
+ const debug_1 = require("../../debug");
8
+ const log = debug_1.log.extend('selector');
9
+ const resLog = log.extend('result');
10
+ function createSelector(selector, tagNameCaseSensitive) {
11
+ return new Selector(selector, !!tagNameCaseSensitive);
9
12
  }
10
13
  exports.createSelector = createSelector;
14
+ function compareSpecificity(a, b) {
15
+ if (a[0] < b[0]) {
16
+ return -1;
17
+ }
18
+ else if (a[0] > b[0]) {
19
+ return 1;
20
+ }
21
+ else if (a[1] < b[1]) {
22
+ return -1;
23
+ }
24
+ else if (a[1] > b[1]) {
25
+ return 1;
26
+ }
27
+ else if (a[2] < b[2]) {
28
+ return -1;
29
+ }
30
+ else if (a[2] > b[2]) {
31
+ return 1;
32
+ }
33
+ return 0;
34
+ }
35
+ exports.compareSpecificity = compareSpecificity;
11
36
  class Selector {
12
- constructor(selector) {
37
+ constructor(selector, tagNameCaseSensitive) {
13
38
  _Selector_ruleset.set(this, void 0);
14
- (0, tslib_1.__classPrivateFieldSet)(this, _Selector_ruleset, Ruleset.parse(selector), "f");
39
+ (0, tslib_1.__classPrivateFieldSet)(this, _Selector_ruleset, Ruleset.parse(selector, tagNameCaseSensitive), "f");
15
40
  }
16
41
  match(el, caller = el) {
17
- return (0, tslib_1.__classPrivateFieldGet)(this, _Selector_ruleset, "f").match(el, caller);
42
+ const results = (0, tslib_1.__classPrivateFieldGet)(this, _Selector_ruleset, "f").match(el, caller);
43
+ for (const result of results) {
44
+ if (result.matched) {
45
+ return result.specificity;
46
+ }
47
+ }
48
+ return false;
18
49
  }
19
50
  }
20
51
  _Selector_ruleset = new WeakMap();
21
52
  class Ruleset {
22
- constructor(selectors) {
53
+ constructor(selectors, tagNameCaseSensitive) {
23
54
  _Ruleset_selectorGroup.set(this, []);
24
- (0, tslib_1.__classPrivateFieldGet)(this, _Ruleset_selectorGroup, "f").push(...selectors.map(selector => new StructuredSelector(selector)));
55
+ (0, tslib_1.__classPrivateFieldGet)(this, _Ruleset_selectorGroup, "f").push(...selectors.map(selector => new StructuredSelector(selector, tagNameCaseSensitive)));
25
56
  }
26
- static parse(selector) {
57
+ static parse(selector, tagNameCaseSensitive) {
27
58
  const selectors = [];
28
59
  (0, postcss_selector_parser_1.default)(root => {
29
60
  selectors.push(...root.nodes);
30
61
  }).processSync(selector);
31
- return new Ruleset(selectors);
62
+ return new Ruleset(selectors, tagNameCaseSensitive);
32
63
  }
33
64
  match(el, caller) {
34
- return (0, tslib_1.__classPrivateFieldGet)(this, _Ruleset_selectorGroup, "f").some(selector => selector.match(el, caller));
65
+ log('%s', el.raw);
66
+ return (0, tslib_1.__classPrivateFieldGet)(this, _Ruleset_selectorGroup, "f").map(selector => {
67
+ const res = selector.match(el, caller);
68
+ resLog('%s => %o', selector.selector, res);
69
+ return res;
70
+ });
35
71
  }
36
72
  }
37
73
  _Ruleset_selectorGroup = new WeakMap();
38
74
  class StructuredSelector {
39
- constructor(selector) {
75
+ constructor(selector, tagNameCaseSensitive) {
40
76
  _StructuredSelector_edge.set(this, void 0);
41
77
  _StructuredSelector_selector.set(this, void 0);
42
78
  (0, tslib_1.__classPrivateFieldSet)(this, _StructuredSelector_selector, selector, "f");
43
- (0, tslib_1.__classPrivateFieldSet)(this, _StructuredSelector_edge, new SelectorTarget(), "f");
79
+ (0, tslib_1.__classPrivateFieldSet)(this, _StructuredSelector_edge, new SelectorTarget(tagNameCaseSensitive), "f");
44
80
  (0, tslib_1.__classPrivateFieldGet)(this, _StructuredSelector_selector, "f").nodes.forEach(node => {
45
81
  switch (node.type) {
46
82
  case 'combinator': {
47
- const combinatedTarget = new SelectorTarget();
83
+ const combinatedTarget = new SelectorTarget(tagNameCaseSensitive);
48
84
  combinatedTarget.from((0, tslib_1.__classPrivateFieldGet)(this, _StructuredSelector_edge, "f"), node);
49
85
  (0, tslib_1.__classPrivateFieldSet)(this, _StructuredSelector_edge, combinatedTarget, "f");
50
86
  break;
@@ -65,76 +101,146 @@ class StructuredSelector {
65
101
  }
66
102
  });
67
103
  }
104
+ get selector() {
105
+ return (0, tslib_1.__classPrivateFieldGet)(this, _StructuredSelector_selector, "f").nodes.join('');
106
+ }
68
107
  match(el, caller) {
69
108
  return (0, tslib_1.__classPrivateFieldGet)(this, _StructuredSelector_edge, "f").match(el, caller);
70
109
  }
71
110
  }
72
111
  _StructuredSelector_edge = new WeakMap(), _StructuredSelector_selector = new WeakMap();
73
112
  class SelectorTarget {
74
- constructor() {
113
+ constructor(tagNameCaseSensitive) {
75
114
  this.tag = null;
76
115
  this.id = [];
77
116
  this.class = [];
78
117
  this.attr = [];
79
118
  this.pseudo = [];
119
+ _SelectorTarget_tagNameCaseSensitive.set(this, void 0);
80
120
  _SelectorTarget_isAdded.set(this, false);
81
121
  _SelectorTarget_combinatedFrom.set(this, null);
122
+ (0, tslib_1.__classPrivateFieldSet)(this, _SelectorTarget_tagNameCaseSensitive, tagNameCaseSensitive, "f");
82
123
  }
83
124
  match(el, caller) {
84
- const matched = this._matchWithoutCombinateChecking(el, caller);
85
- if (!matched) {
86
- return false;
125
+ const unitCheck = this._matchWithoutCombinateChecking(el, caller);
126
+ if (!unitCheck.matched) {
127
+ return unitCheck;
87
128
  }
88
129
  if (!(0, tslib_1.__classPrivateFieldGet)(this, _SelectorTarget_combinatedFrom, "f")) {
89
- return true;
130
+ return unitCheck;
90
131
  }
91
132
  const { target, combinator } = (0, tslib_1.__classPrivateFieldGet)(this, _SelectorTarget_combinatedFrom, "f");
92
133
  switch (combinator.value) {
93
134
  // Descendant combinator
94
135
  case ' ': {
95
- let ancestor = el.parentNode;
136
+ let ancestor = el.getParentElement();
137
+ let matched = false;
138
+ let specificity;
96
139
  while (ancestor) {
97
- const ancestorMatched = target._matchWithoutCombinateChecking(ancestor, caller);
98
- if (ancestorMatched) {
99
- return target.match(ancestor, caller);
140
+ const res = target.match(ancestor, caller);
141
+ if (!specificity) {
142
+ specificity = [
143
+ unitCheck.specificity[0] + res.specificity[0],
144
+ unitCheck.specificity[1] + res.specificity[1],
145
+ unitCheck.specificity[2] + res.specificity[2],
146
+ ];
147
+ }
148
+ if (res.matched) {
149
+ matched = true;
100
150
  }
101
- ancestor = ancestor.parentNode;
151
+ ancestor = ancestor.getParentElement();
102
152
  }
103
- return false;
153
+ if (!specificity) {
154
+ const res = target.match(el, caller);
155
+ specificity = [
156
+ unitCheck.specificity[0] + res.specificity[0],
157
+ unitCheck.specificity[1] + res.specificity[1],
158
+ unitCheck.specificity[2] + res.specificity[2],
159
+ ];
160
+ }
161
+ return {
162
+ specificity,
163
+ matched,
164
+ };
104
165
  }
105
166
  // Child combinator
106
167
  case '>': {
107
- if (!el.parentNode) {
108
- return false;
168
+ let matched;
169
+ const specificity = unitCheck.specificity;
170
+ const parentNode = el.getParentElement();
171
+ if (parentNode) {
172
+ const res = target.match(parentNode, caller);
173
+ specificity[0] += res.specificity[0];
174
+ specificity[1] += res.specificity[1];
175
+ specificity[2] += res.specificity[2];
176
+ matched = res.matched;
109
177
  }
110
- const parentMatched = target._matchWithoutCombinateChecking(el.parentNode, caller);
111
- if (parentMatched) {
112
- return target.match(el.parentNode, caller);
178
+ else {
179
+ const res = target.match(el, caller);
180
+ specificity[0] += res.specificity[0];
181
+ specificity[1] += res.specificity[1];
182
+ specificity[2] += res.specificity[2];
183
+ matched = false;
113
184
  }
114
- return false;
185
+ return {
186
+ specificity,
187
+ matched,
188
+ };
115
189
  }
116
190
  // Next-sibling combinator
117
191
  case '+': {
118
- if (!el.previousElementSibling) {
119
- return false;
192
+ let matched;
193
+ const specificity = unitCheck.specificity;
194
+ if (el.previousElementSibling) {
195
+ const res = target.match(el.previousElementSibling, caller);
196
+ specificity[0] += res.specificity[0];
197
+ specificity[1] += res.specificity[1];
198
+ specificity[2] += res.specificity[2];
199
+ matched = res.matched;
120
200
  }
121
- const prevMatched = target._matchWithoutCombinateChecking(el.previousElementSibling, caller);
122
- if (prevMatched) {
123
- return target.match(el.previousElementSibling, caller);
201
+ else {
202
+ const res = target.match(el, caller);
203
+ specificity[0] += res.specificity[0];
204
+ specificity[1] += res.specificity[1];
205
+ specificity[2] += res.specificity[2];
206
+ matched = false;
124
207
  }
125
- return false;
208
+ return {
209
+ specificity,
210
+ matched,
211
+ };
126
212
  }
127
- // Subsequent-sibling combinator
213
+ // // Subsequent-sibling combinator
128
214
  case '~': {
129
215
  let prev = el.previousElementSibling;
216
+ let matched = false;
217
+ let specificity;
130
218
  while (prev) {
131
- const prevMatched = target._matchWithoutCombinateChecking(prev, caller);
132
- if (prevMatched) {
133
- return target.match(prev, caller);
219
+ const res = target.match(prev, caller);
220
+ if (!specificity) {
221
+ specificity = [
222
+ unitCheck.specificity[0] + res.specificity[0],
223
+ unitCheck.specificity[1] + res.specificity[1],
224
+ unitCheck.specificity[2] + res.specificity[2],
225
+ ];
226
+ }
227
+ if (res.matched) {
228
+ matched = true;
134
229
  }
135
230
  prev = prev.previousElementSibling;
136
231
  }
137
- return false;
232
+ if (!specificity) {
233
+ const res = target.match(el, caller);
234
+ specificity = [
235
+ unitCheck.specificity[0] + res.specificity[0],
236
+ unitCheck.specificity[1] + res.specificity[1],
237
+ unitCheck.specificity[2] + res.specificity[2],
238
+ ];
239
+ }
240
+ return {
241
+ specificity,
242
+ matched,
243
+ };
138
244
  }
139
245
  // Column combinator
140
246
  case '||': {
@@ -146,27 +252,48 @@ class SelectorTarget {
146
252
  }
147
253
  }
148
254
  _matchWithoutCombinateChecking(el, caller) {
149
- if (!(0, tslib_1.__classPrivateFieldGet)(this, _SelectorTarget_isAdded, "f")) {
150
- return isScope(el, caller);
151
- }
152
- if (this.tag && this.tag.type === 'tag') {
153
- if (this.tag.value.toLowerCase() !== el.nodeName.toLowerCase()) {
154
- return false;
155
- }
255
+ const specificity = [0, 0, 0];
256
+ let matched = true;
257
+ if (!(0, tslib_1.__classPrivateFieldGet)(this, _SelectorTarget_isAdded, "f") && !isScope(el, caller)) {
258
+ matched = false;
156
259
  }
157
260
  if (!this.id.every(id => id.value === el.id)) {
158
- return false;
261
+ matched = false;
159
262
  }
263
+ specificity[0] += this.id.length;
160
264
  if (!this.class.every(className => el.classList.includes(className.value))) {
161
- return false;
265
+ matched = false;
162
266
  }
267
+ specificity[1] += this.class.length;
163
268
  if (!this.attr.every(attr => attrMatch(attr, el))) {
164
- return false;
269
+ matched = false;
165
270
  }
166
- if (!this.pseudo.every(pseudo => pseudoMatch(pseudo, el, caller))) {
167
- return false;
271
+ specificity[1] += this.attr.length;
272
+ for (const pseudo of this.pseudo) {
273
+ const pseudoRes = pseudoMatch(pseudo, el, caller, (0, tslib_1.__classPrivateFieldGet)(this, _SelectorTarget_tagNameCaseSensitive, "f"));
274
+ specificity[0] += pseudoRes.specificity[0];
275
+ specificity[1] += pseudoRes.specificity[1];
276
+ specificity[2] += pseudoRes.specificity[2];
277
+ if (!pseudoRes.matched) {
278
+ matched = false;
279
+ }
168
280
  }
169
- return true;
281
+ if (this.tag && this.tag.type === 'tag') {
282
+ specificity[2] += 1;
283
+ let a = this.tag.value;
284
+ let b = el.nodeName;
285
+ if (!(0, tslib_1.__classPrivateFieldGet)(this, _SelectorTarget_tagNameCaseSensitive, "f")) {
286
+ a = a.toLowerCase();
287
+ b = b.toLowerCase();
288
+ }
289
+ if (a !== b) {
290
+ matched = false;
291
+ }
292
+ }
293
+ return {
294
+ specificity,
295
+ matched,
296
+ };
170
297
  }
171
298
  add(selector) {
172
299
  (0, tslib_1.__classPrivateFieldSet)(this, _SelectorTarget_isAdded, true, "f");
@@ -198,7 +325,7 @@ class SelectorTarget {
198
325
  (0, tslib_1.__classPrivateFieldSet)(this, _SelectorTarget_combinatedFrom, { target, combinator }, "f");
199
326
  }
200
327
  }
201
- _SelectorTarget_isAdded = new WeakMap(), _SelectorTarget_combinatedFrom = new WeakMap();
328
+ _SelectorTarget_tagNameCaseSensitive = new WeakMap(), _SelectorTarget_isAdded = new WeakMap(), _SelectorTarget_combinatedFrom = new WeakMap();
202
329
  function attrMatch(attr, el) {
203
330
  return el.attributes.some(attrOfEl => {
204
331
  if (attr.attribute !== attrOfEl.getName().potential) {
@@ -253,58 +380,94 @@ function attrMatch(attr, el) {
253
380
  return true;
254
381
  });
255
382
  }
256
- function pseudoMatch(pseudo, el, caller) {
383
+ function pseudoMatch(pseudo, el, caller, tagNameCaseSensitive) {
257
384
  switch (pseudo.value) {
258
385
  /**
259
386
  * Below, markuplint Specific Selector
260
387
  */
261
388
  case ':closest': {
262
- const ruleset = new Ruleset(pseudo.nodes);
263
- let parent = el.parentNode;
389
+ const ruleset = new Ruleset(pseudo.nodes, tagNameCaseSensitive);
390
+ const specificity = getSpecificity(ruleset.match(el, caller));
391
+ let parent = el.getParentElement();
264
392
  while (parent) {
265
- if (ruleset.match(parent, caller)) {
266
- return true;
393
+ if (ruleset.match(parent, caller).some(r => r.matched)) {
394
+ return {
395
+ specificity,
396
+ matched: true,
397
+ };
267
398
  }
268
- parent = parent.parentNode;
399
+ parent = parent.getParentElement();
269
400
  }
270
- return false;
401
+ return {
402
+ specificity,
403
+ matched: false,
404
+ };
271
405
  }
272
406
  /**
273
407
  * Below, Selector Level 4
274
408
  */
275
409
  case ':not': {
276
- const ruleset = new Ruleset(pseudo.nodes);
277
- if (ruleset.match(el, caller)) {
278
- return false;
279
- }
280
- break;
410
+ const ruleset = new Ruleset(pseudo.nodes, tagNameCaseSensitive);
411
+ const resList = ruleset.match(el, caller);
412
+ const specificity = getSpecificity(resList);
413
+ const matched = resList.every(r => !r.matched);
414
+ return {
415
+ specificity,
416
+ matched,
417
+ };
281
418
  }
282
419
  case ':is': {
283
- const ruleset = new Ruleset(pseudo.nodes);
284
- if (!ruleset.match(el, caller)) {
285
- return false;
286
- }
287
- break;
420
+ const ruleset = new Ruleset(pseudo.nodes, tagNameCaseSensitive);
421
+ const resList = ruleset.match(el, caller);
422
+ const specificity = getSpecificity(resList);
423
+ const matched = resList.some(r => r.matched);
424
+ return {
425
+ specificity,
426
+ matched,
427
+ };
288
428
  }
289
429
  case ':has': {
290
- const ruleset = new Ruleset(pseudo.nodes);
430
+ const ruleset = new Ruleset(pseudo.nodes, tagNameCaseSensitive);
431
+ const specificity = getSpecificity(ruleset.match(el, caller));
291
432
  const descendants = getDescendants(el);
292
- if (!descendants.some(desc => ruleset.match(desc, caller))) {
293
- return false;
294
- }
295
- break;
433
+ const matched = descendants.some(desc => ruleset.match(desc, caller).some(m => m.matched));
434
+ return {
435
+ specificity,
436
+ matched,
437
+ };
438
+ }
439
+ case ':where': {
440
+ const ruleset = new Ruleset(pseudo.nodes, tagNameCaseSensitive);
441
+ const resList = ruleset.match(el, caller);
442
+ const matched = resList.some(r => r.matched);
443
+ return {
444
+ specificity: [0, 0, 0],
445
+ matched,
446
+ };
296
447
  }
297
448
  case ':scope': {
298
449
  if (!isScope(el, caller)) {
299
- return false;
450
+ return {
451
+ specificity: [0, 1, 0],
452
+ matched: false,
453
+ };
300
454
  }
301
- break;
455
+ return {
456
+ specificity: [0, 1, 0],
457
+ matched: true,
458
+ };
302
459
  }
303
460
  case ':root': {
304
461
  if (!(!el.isInFragmentDocument && el.parentNode === null)) {
305
- return false;
462
+ return {
463
+ specificity: [0, 1, 0],
464
+ matched: false,
465
+ };
306
466
  }
307
- break;
467
+ return {
468
+ specificity: [0, 1, 0],
469
+ matched: true,
470
+ };
308
471
  }
309
472
  case ':enable':
310
473
  case ':disable':
@@ -337,7 +500,6 @@ function pseudoMatch(pseudo, el, caller) {
337
500
  case ':nth-col': {
338
501
  throw new Error(`Unsupported pseudo ${pseudo.toString()} selector yet. If you want it, please request it as the issue (https://github.com/markuplint/markuplint/issues/new).`);
339
502
  }
340
- case ':where':
341
503
  case ':dir':
342
504
  case ':lang':
343
505
  case ':any-link':
@@ -360,7 +522,6 @@ function pseudoMatch(pseudo, el, caller) {
360
522
  throw new Error(`Unsupported pseudo ${pseudo.toString()} selector.`);
361
523
  }
362
524
  }
363
- return true;
364
525
  }
365
526
  function isScope(el, caller) {
366
527
  return el.uuid === (caller === null || caller === void 0 ? void 0 : caller.uuid) || (!el.isInFragmentDocument && el.parentNode === null);
@@ -368,3 +529,21 @@ function isScope(el, caller) {
368
529
  function getDescendants(el, includeSelf = false) {
369
530
  return [...el.children.map(child => getDescendants(child, true)).flat(), ...(includeSelf ? [el] : [])];
370
531
  }
532
+ function getSpecificity(result) {
533
+ let specificity;
534
+ for (const res of result) {
535
+ if (specificity) {
536
+ const order = compareSpecificity(specificity, res.specificity);
537
+ if (order === -1) {
538
+ specificity = res.specificity;
539
+ }
540
+ }
541
+ else {
542
+ specificity = res.specificity;
543
+ }
544
+ }
545
+ if (!specificity) {
546
+ throw new Error('Result is empty');
547
+ }
548
+ return specificity;
549
+ }
@@ -1,9 +1,10 @@
1
+ import type { Specificity } from './helper/selector';
1
2
  import type { AnonymousNode } from './types';
2
3
  import type { AnyRule } from '@markuplint/ml-config';
3
4
  declare type RuleType = 'rules' | 'nodeRules' | 'childNodeRules';
4
5
  declare type MappingLayer = {
5
6
  from: RuleType;
6
- index: number;
7
+ specificity: Specificity;
7
8
  rule: AnyRule;
8
9
  };
9
10
  export declare class RuleMapper<N extends AnonymousNode<any, any> = AnonymousNode<any, any>> {
@@ -4,6 +4,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.RuleMapper = void 0;
5
5
  const tslib_1 = require("tslib");
6
6
  const debug_1 = require("../debug");
7
+ const selector_1 = require("./helper/selector");
7
8
  const ruleMapperLog = debug_1.log.extend('rule-mapper');
8
9
  const ruleMapperNodeLog = ruleMapperLog.extend('node');
9
10
  const ruleMapperNodeRuleLog = ruleMapperNodeLog.extend('rule');
@@ -14,20 +15,25 @@ class RuleMapper {
14
15
  (0, tslib_1.__classPrivateFieldSet)(this, _RuleMapper_nodeList, nodeList, "f");
15
16
  }
16
17
  set(node, ruleName, rule) {
18
+ if (node.type === 'ElementCloseTag') {
19
+ return;
20
+ }
17
21
  const rules = (0, tslib_1.__classPrivateFieldGet)(this, _RuleMapper_ruleMap, "f").get(node.uuid) || {};
18
22
  const currentRule = rules[ruleName];
19
23
  if (currentRule) {
20
- if (currentRule.index <= rule.index) {
21
- ruleMapperLog('Unset %o from %s', currentRule, node);
22
- }
23
- else {
24
- ruleMapperLog("Don't set %o (%d vs %d)", rule, currentRule.index, rule.index);
24
+ const order = (0, selector_1.compareSpecificity)(currentRule.specificity, rule.specificity);
25
+ if (order === 1) {
26
+ ruleMapperLog("Don't set %o ([%s] vs [%s])", rule, currentRule.specificity, rule.specificity);
25
27
  return;
26
28
  }
29
+ ruleMapperLog('Unset %o from %s', currentRule, node);
27
30
  }
28
31
  rules[ruleName] = rule;
29
32
  (0, tslib_1.__classPrivateFieldGet)(this, _RuleMapper_ruleMap, "f").set(node.uuid, rules);
30
- ruleMapperLog('Set %o to %s', rule, node);
33
+ if (node.type === 'Element' && node.closeTag) {
34
+ (0, tslib_1.__classPrivateFieldGet)(this, _RuleMapper_ruleMap, "f").set(node.closeTag.uuid, rules);
35
+ }
36
+ ruleMapperLog('Set to %s from %s (%o): %O', node.raw, rule.from, rule.specificity, rule.rule);
31
37
  }
32
38
  apply() {
33
39
  ruleMapperLog('ruleTree:');
@@ -36,13 +42,13 @@ class RuleMapper {
36
42
  if (!rules) {
37
43
  return;
38
44
  }
39
- const shash = node.type === 'ElementCloseTag' ? '/' : '';
45
+ const slash = node.type === 'ElementCloseTag' ? '/' : '';
40
46
  const nodeName = 'nodeName' in node ? node.nodeName : `#${node.type}`;
41
- ruleMapperNodeLog('<%s%s>', shash, nodeName);
47
+ ruleMapperNodeLog('<%s%s>', slash, nodeName);
42
48
  Object.keys(rules).forEach(ruleName => {
43
49
  const rule = rules[ruleName];
44
50
  node.rules[ruleName] = rule.rule;
45
- ruleMapperNodeRuleLog('[from: %s(%d)] %s: %o', rule.from, rule.index, ruleName, rule.rule);
51
+ ruleMapperNodeRuleLog('[from: %s(%s)] %s: %o', rule.from, rule.specificity, ruleName, rule.rule);
46
52
  });
47
53
  });
48
54
  }
@@ -40,4 +40,5 @@ export default abstract class MLDOMAbstractElement<T extends RuleConfigValue, O
40
40
  */
41
41
  hasMutableChildren(): boolean;
42
42
  isDescendantByUUIDList(uuidList: string[]): boolean;
43
+ toNormalizeString(): string;
43
44
  }
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- var _MLDOMAbstractElement_fixedNodeName;
2
+ var _MLDOMAbstractElement_fixedNodeName, _MLDOMAbstractElement_getChildElementsAndTextNodeWithoutWhitespacesCache, _MLDOMAbstractElement_normalizedString;
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  const tslib_1 = require("tslib");
5
5
  const ml_spec_1 = require("@markuplint/ml-spec");
@@ -15,6 +15,8 @@ class MLDOMAbstractElement extends node_1.default {
15
15
  this.childModels = new Set();
16
16
  this.descendantModels = new Set();
17
17
  _MLDOMAbstractElement_fixedNodeName.set(this, void 0);
18
+ _MLDOMAbstractElement_getChildElementsAndTextNodeWithoutWhitespacesCache.set(this, null);
19
+ _MLDOMAbstractElement_normalizedString.set(this, null);
18
20
  this.nodeName = astNode.nodeName;
19
21
  (0, tslib_1.__classPrivateFieldSet)(this, _MLDOMAbstractElement_fixedNodeName, astNode.nodeName, "f");
20
22
  this.namespaceURI = astNode.namespace;
@@ -113,7 +115,7 @@ class MLDOMAbstractElement extends node_1.default {
113
115
  if (selecor.match(el, this)) {
114
116
  return el;
115
117
  }
116
- el = el.parentNode;
118
+ el = el.getParentElement();
117
119
  } while (el !== null && el.type === 'Element');
118
120
  return null;
119
121
  }
@@ -145,12 +147,15 @@ class MLDOMAbstractElement extends node_1.default {
145
147
  return !!this.getAttributeToken(attrName).length;
146
148
  }
147
149
  matches(selector) {
148
- return (0, helper_1.createSelector)(selector).match(this);
150
+ return !!(0, helper_1.createSelector)(selector).match(this);
149
151
  }
150
152
  fixNodeName(name) {
151
153
  (0, tslib_1.__classPrivateFieldSet)(this, _MLDOMAbstractElement_fixedNodeName, name, "f");
152
154
  }
153
155
  getChildElementsAndTextNodeWithoutWhitespaces() {
156
+ if ((0, tslib_1.__classPrivateFieldGet)(this, _MLDOMAbstractElement_getChildElementsAndTextNodeWithoutWhitespacesCache, "f")) {
157
+ return (0, tslib_1.__classPrivateFieldGet)(this, _MLDOMAbstractElement_getChildElementsAndTextNodeWithoutWhitespacesCache, "f");
158
+ }
154
159
  const filteredNodes = [];
155
160
  this.childNodes.forEach(node => {
156
161
  if (node.type === 'Element') {
@@ -164,6 +169,7 @@ class MLDOMAbstractElement extends node_1.default {
164
169
  filteredNodes.push(...children);
165
170
  }
166
171
  });
172
+ (0, tslib_1.__classPrivateFieldSet)(this, _MLDOMAbstractElement_getChildElementsAndTextNodeWithoutWhitespacesCache, filteredNodes, "f");
167
173
  return filteredNodes;
168
174
  }
169
175
  /**
@@ -173,7 +179,7 @@ class MLDOMAbstractElement extends node_1.default {
173
179
  return this.childNodes.some(node => node.type === 'PSBlock');
174
180
  }
175
181
  isDescendantByUUIDList(uuidList) {
176
- let el = this.parentNode;
182
+ let el = this.getParentElement();
177
183
  if (el === null) {
178
184
  return false;
179
185
  }
@@ -181,10 +187,29 @@ class MLDOMAbstractElement extends node_1.default {
181
187
  if (uuidList.includes(el.uuid)) {
182
188
  return true;
183
189
  }
184
- el = el.parentNode;
190
+ el = el.getParentElement();
185
191
  } while (el !== null && el.type === 'Element');
186
192
  return false;
187
193
  }
194
+ toNormalizeString() {
195
+ if ((0, tslib_1.__classPrivateFieldGet)(this, _MLDOMAbstractElement_normalizedString, "f")) {
196
+ return (0, tslib_1.__classPrivateFieldGet)(this, _MLDOMAbstractElement_normalizedString, "f");
197
+ }
198
+ const children = this.getChildElementsAndTextNodeWithoutWhitespaces();
199
+ const attrs = this.attributes.map(attr => attr.toNormalizeString());
200
+ const attrString = attrs.length ? ' ' + attrs.join('') : '';
201
+ const startTag = `<${this.nodeName}${attrString}>`;
202
+ const childNodes = children.map(node => {
203
+ if (node.type === 'Element') {
204
+ return node.toNormalizeString();
205
+ }
206
+ return node.originRaw;
207
+ });
208
+ const endTag = `</${this.nodeName}>`;
209
+ const normalizedString = `${startTag}${childNodes.join('')}${endTag}`;
210
+ (0, tslib_1.__classPrivateFieldSet)(this, _MLDOMAbstractElement_normalizedString, normalizedString, "f");
211
+ return normalizedString;
212
+ }
188
213
  }
189
214
  exports.default = MLDOMAbstractElement;
190
- _MLDOMAbstractElement_fixedNodeName = new WeakMap();
215
+ _MLDOMAbstractElement_fixedNodeName = new WeakMap(), _MLDOMAbstractElement_getChildElementsAndTextNodeWithoutWhitespacesCache = new WeakMap(), _MLDOMAbstractElement_normalizedString = new WeakMap();