wikiparser-node 1.21.2 → 1.22.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.
Files changed (97) hide show
  1. package/README.md +9 -5
  2. package/bundle/bundle-es8.min.js +25 -25
  3. package/bundle/bundle-lsp.min.js +26 -26
  4. package/bundle/bundle.min.js +25 -25
  5. package/config/default.json +15 -11
  6. package/config/enwiki.json +1 -1
  7. package/config/jawiki.json +1 -1
  8. package/config/minimum.json +2 -3
  9. package/config/moegirl.json +152 -15
  10. package/config/zhwiki.json +1 -1
  11. package/dist/addon/token.js +3 -0
  12. package/dist/base.d.mts +16 -9
  13. package/dist/base.d.ts +16 -9
  14. package/dist/bin/config.js +23 -11
  15. package/dist/index.d.ts +33 -4
  16. package/dist/index.js +37 -2
  17. package/dist/lib/element.d.ts +4 -4
  18. package/dist/lib/element.js +6 -5
  19. package/dist/lib/lintConfig.d.ts +13 -0
  20. package/dist/lib/lintConfig.js +278 -0
  21. package/dist/lib/lsp.d.ts +7 -7
  22. package/dist/lib/lsp.js +18 -20
  23. package/dist/lib/node.d.ts +1 -1
  24. package/dist/lib/node.js +646 -606
  25. package/dist/lib/range.d.ts +2 -2
  26. package/dist/lib/range.js +2 -2
  27. package/dist/lib/text.js +76 -62
  28. package/dist/lib/title.d.ts +11 -4
  29. package/dist/lib/title.js +16 -6
  30. package/dist/mixin/attributesParent.d.ts +6 -6
  31. package/dist/mixin/attributesParent.js +4 -4
  32. package/dist/mixin/cached.d.ts +5 -0
  33. package/dist/mixin/cached.js +22 -0
  34. package/dist/mixin/clone.d.ts +5 -0
  35. package/dist/mixin/clone.js +23 -0
  36. package/dist/mixin/hidden.js +68 -18
  37. package/dist/mixin/sol.js +1 -1
  38. package/dist/parser/commentAndExt.js +6 -4
  39. package/dist/parser/converter.js +1 -1
  40. package/dist/parser/html.js +3 -3
  41. package/dist/parser/table.js +2 -2
  42. package/dist/src/arg.js +24 -17
  43. package/dist/src/atom.js +76 -31
  44. package/dist/src/attribute.js +79 -39
  45. package/dist/src/attributes.d.ts +7 -7
  46. package/dist/src/attributes.js +417 -366
  47. package/dist/src/commented.js +81 -35
  48. package/dist/src/converter.js +13 -7
  49. package/dist/src/converterFlags.js +33 -22
  50. package/dist/src/converterRule.js +263 -216
  51. package/dist/src/extLink.js +21 -16
  52. package/dist/src/gallery.js +44 -27
  53. package/dist/src/heading.js +48 -43
  54. package/dist/src/hidden.js +14 -9
  55. package/dist/src/html.js +92 -60
  56. package/dist/src/imageParameter.js +13 -6
  57. package/dist/src/imagemap.js +32 -25
  58. package/dist/src/index.d.ts +2 -2
  59. package/dist/src/index.js +61 -50
  60. package/dist/src/link/base.d.ts +1 -1
  61. package/dist/src/link/base.js +35 -23
  62. package/dist/src/link/file.js +409 -354
  63. package/dist/src/link/galleryImage.js +9 -5
  64. package/dist/src/link/index.d.ts +1 -1
  65. package/dist/src/link/index.js +8 -4
  66. package/dist/src/link/redirectTarget.js +7 -3
  67. package/dist/src/magicLink.js +39 -26
  68. package/dist/src/nested.js +122 -74
  69. package/dist/src/nowiki/base.js +5 -2
  70. package/dist/src/nowiki/comment.js +5 -1
  71. package/dist/src/nowiki/index.js +4 -4
  72. package/dist/src/nowiki/quote.js +32 -46
  73. package/dist/src/onlyinclude.js +17 -9
  74. package/dist/src/paramTag/index.js +21 -14
  75. package/dist/src/parameter.js +26 -20
  76. package/dist/src/pre.js +91 -45
  77. package/dist/src/syntax.js +14 -10
  78. package/dist/src/table/index.js +554 -501
  79. package/dist/src/table/td.d.ts +1 -1
  80. package/dist/src/table/td.js +91 -82
  81. package/dist/src/table/trBase.js +183 -130
  82. package/dist/src/tagPair/ext.js +38 -23
  83. package/dist/src/tagPair/include.js +5 -5
  84. package/dist/src/tagPair/index.js +2 -3
  85. package/dist/src/tagPair/translate.js +150 -103
  86. package/dist/src/transclude.d.ts +15 -1
  87. package/dist/src/transclude.js +56 -21
  88. package/dist/util/html.js +46 -41
  89. package/dist/util/lint.js +7 -9
  90. package/dist/util/sharable.js +1 -1
  91. package/dist/util/sharable.mjs +2 -2
  92. package/dist/util/string.js +13 -7
  93. package/extensions/dist/base.js +9 -2
  94. package/extensions/typings.d.ts +2 -1
  95. package/i18n/zh-hans.json +1 -1
  96. package/i18n/zh-hant.json +1 -1
  97. package/package.json +20 -15
@@ -1,4 +1,38 @@
1
1
  "use strict";
2
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
3
+ var useValue = arguments.length > 2;
4
+ for (var i = 0; i < initializers.length; i++) {
5
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
6
+ }
7
+ return useValue ? value : void 0;
8
+ };
9
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
10
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
11
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
12
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
13
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
14
+ var _, done = false;
15
+ for (var i = decorators.length - 1; i >= 0; i--) {
16
+ var context = {};
17
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
18
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
19
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
20
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
21
+ if (kind === "accessor") {
22
+ if (result === void 0) continue;
23
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
24
+ if (_ = accept(result.get)) descriptor.get = _;
25
+ if (_ = accept(result.set)) descriptor.set = _;
26
+ if (_ = accept(result.init)) initializers.unshift(_);
27
+ }
28
+ else if (_ = accept(result)) {
29
+ if (kind === "field") initializers.unshift(_);
30
+ else descriptor[key] = _;
31
+ }
32
+ }
33
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
34
+ done = true;
35
+ };
2
36
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
37
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
38
  };
@@ -15,6 +49,8 @@ const attribute_1 = require("./attribute");
15
49
  const html_1 = require("../util/html");
16
50
  const debug_1 = require("../util/debug");
17
51
  const constants_1 = require("../util/constants");
52
+ const clone_1 = require("../mixin/clone");
53
+ const cached_1 = require("../mixin/cached");
18
54
  const stages = { 'ext-attrs': 0, 'html-attrs': 2, 'table-attrs': 3 };
19
55
  /**
20
56
  * 将属性类型转换为单属性类型
@@ -40,404 +76,419 @@ catch /* istanbul ignore next */ {
40
76
  * 扩展和HTML标签属性
41
77
  * @classdesc `{childNodes: (AtomToken|AttributeToken)[]}`
42
78
  */
43
- class AttributesToken extends index_2.Token {
44
- #type;
45
- #classList;
46
- /* NOT FOR BROWSER END */
47
- get type() {
48
- return this.#type;
49
- }
50
- /* NOT FOR BROWSER */
51
- /** all attributes / 全部属性 */
52
- get attributes() {
53
- return this.getAttrs();
54
- }
55
- set attributes(attrs) {
56
- this.replaceChildren();
57
- this.setAttr(attrs);
58
- }
59
- /** class attribute in string / 以字符串表示的class属性 */
60
- get className() {
61
- const attr = this.getAttr('class');
62
- return typeof attr === 'string' ? attr : '';
63
- }
64
- set className(className) {
65
- this.setAttr('class', className || false);
66
- }
67
- /** class attribute in Set / 以Set表示的class属性 */
68
- get classList() {
69
- if (!this.#classList) {
70
- this.#classList = new Set(this.className.split(/\s/u));
71
- /**
72
- * 更新classList
73
- * @param prop 方法名
74
- */
75
- const factory = (prop) => ({
76
- value: /** @ignore */ (...args) => {
77
- const result = Set.prototype[prop].apply(this.#classList, args);
78
- this.setAttr('class', [...this.#classList].join(' '));
79
- return result;
80
- },
81
- });
82
- Object.defineProperties(this.#classList, {
83
- add: factory('add'),
84
- delete: factory('delete'),
85
- clear: factory('clear'),
86
- });
79
+ let AttributesToken = (() => {
80
+ let _classSuper = index_2.Token;
81
+ let _instanceExtraInitializers = [];
82
+ let _cloneNode_decorators;
83
+ let _toHtmlInternal_decorators;
84
+ return class AttributesToken extends _classSuper {
85
+ static {
86
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
87
+ _cloneNode_decorators = [clone_1.clone];
88
+ _toHtmlInternal_decorators = [(0, cached_1.cached)()];
89
+ __esDecorate(this, null, _cloneNode_decorators, { kind: "method", name: "cloneNode", static: false, private: false, access: { has: obj => "cloneNode" in obj, get: obj => obj.cloneNode }, metadata: _metadata }, null, _instanceExtraInitializers);
90
+ __esDecorate(this, null, _toHtmlInternal_decorators, { kind: "method", name: "toHtmlInternal", static: false, private: false, access: { has: obj => "toHtmlInternal" in obj, get: obj => obj.toHtmlInternal }, metadata: _metadata }, null, _instanceExtraInitializers);
91
+ if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
87
92
  }
88
- return this.#classList;
89
- }
90
- /** id attribute / id属性 */
91
- get id() {
92
- const attr = this.getAttr('id');
93
- return typeof attr === 'string' ? attr : '';
94
- }
95
- set id(id) {
96
- this.setAttr('id', id || false);
97
- }
98
- /** whether to contain invalid attributes / 是否含有无效属性 */
99
- get sanitized() {
100
- return this.childNodes.filter(child => child instanceof atom_1.AtomToken && child.text().trim()).length === 0;
101
- }
102
- set sanitized(sanitized) {
103
- if (sanitized) {
104
- this.sanitize();
93
+ #type = __runInitializers(this, _instanceExtraInitializers);
94
+ #classList;
95
+ /* NOT FOR BROWSER END */
96
+ get type() {
97
+ return this.#type;
105
98
  }
106
- }
107
- /* NOT FOR BROWSER END */
108
- /**
109
- * @param attr 标签属性
110
- * @param type 标签类型
111
- * @param name 标签名
112
- */
113
- constructor(attr, type, name, config, accum = []) {
114
- super(undefined, config, accum, {
115
- AtomToken: ':', AttributeToken: ':',
116
- });
117
- this.#type = type;
118
- this.setAttribute('name', name);
119
- if (attr) {
120
- const regex = /([^\s/](?:(?!\0\d+~\x7F)[^\s/=])*)(?:((?:\s(?:\s|\0\d+[cn]\x7F)*)?(?:=|\0\d+~\x7F)(?:\s|\0\d+[cn]\x7F)*)(?:(["'])([\s\S]*?)(\3|$)|(\S*)))?/gu;
121
- let out = '', mt = regex.exec(attr), lastIndex = 0;
122
- const insertDirty = /** 插入无效属性 */ () => {
123
- if (out) {
124
- super.insertAt(new atom_1.AtomToken(out, toDirty(type), config, accum, {
125
- [`Stage-${stages[type]}`]: ':',
126
- }));
127
- out = '';
128
- }
129
- };
130
- while (mt) {
131
- const { index, 0: full, 1: key, 2: equal, 3: quoteStart, 4: quoted, 5: quoteEnd, 6: unquoted } = mt;
132
- out += attr.slice(lastIndex, index);
133
- if (/^(?:[\w:]|\0\d+t\x7F)(?:[\w:.-]|\0\d+t\x7F)*$/u.test((0, string_1.removeComment)(key).trim())) {
134
- const value = quoted ?? unquoted, quotes = [quoteStart, quoteEnd],
135
- // @ts-expect-error abstract class
136
- token = new attribute_1.AttributeToken(toAttributeType(type), name, key, equal, value, quotes, config, accum);
137
- insertDirty();
138
- super.insertAt(token);
139
- }
140
- else {
141
- out += full;
142
- }
143
- ({ lastIndex } = regex);
144
- mt = regex.exec(attr);
99
+ /* NOT FOR BROWSER */
100
+ /** all attributes / 全部属性 */
101
+ get attributes() {
102
+ return this.getAttrs();
103
+ }
104
+ set attributes(attrs) {
105
+ this.replaceChildren();
106
+ this.setAttr(attrs);
107
+ }
108
+ /** class attribute in string / 以字符串表示的class属性 */
109
+ get className() {
110
+ const attr = this.getAttr('class');
111
+ return typeof attr === 'string' ? attr : '';
112
+ }
113
+ set className(className) {
114
+ this.setAttr('class', className || false);
115
+ }
116
+ /** class attribute in Set / 以Set表示的class属性 */
117
+ get classList() {
118
+ if (!this.#classList) {
119
+ this.#classList = new Set(this.className.split(/\s/u));
120
+ /**
121
+ * 更新classList
122
+ * @param prop 方法名
123
+ */
124
+ const factory = (prop) => ({
125
+ value: /** @ignore */ (...args) => {
126
+ const result = Set.prototype[prop].apply(this.#classList, args);
127
+ this.setAttr('class', [...this.#classList].join(' '));
128
+ return result;
129
+ },
130
+ });
131
+ Object.defineProperties(this.#classList, {
132
+ add: factory('add'),
133
+ delete: factory('delete'),
134
+ clear: factory('clear'),
135
+ });
145
136
  }
146
- out += attr.slice(lastIndex);
147
- insertDirty();
137
+ return this.#classList;
148
138
  }
149
- }
150
- /** @private */
151
- afterBuild() {
152
- const { parentNode } = this;
153
- if (parentNode?.is('td')) {
154
- this.setAttribute('name', parentNode.subtype);
139
+ /** id attribute / id属性 */
140
+ get id() {
141
+ const attr = this.getAttr('id');
142
+ return typeof attr === 'string' ? attr : '';
155
143
  }
156
- super.afterBuild();
157
- }
158
- /**
159
- * Get all AttributeTokens with the specified attribute name
160
- *
161
- * 所有指定属性名的AttributeToken
162
- * @param key attribute name / 属性名
163
- */
164
- getAttrTokens(key) {
165
- return this.childNodes.filter((child) => child instanceof attribute_1.AttributeToken && (!key || child.name === (0, string_1.trimLc)(key)));
166
- }
167
- /**
168
- * Get the last AttributeToken with the specified attribute name
169
- *
170
- * 指定属性名的最后一个AttributeToken
171
- * @param key attribute name / 属性名
172
- */
173
- getAttrToken(key) {
174
- const tokens = this.getAttrTokens(key);
175
- return tokens[tokens.length - 1];
176
- }
177
- /**
178
- * Get the attribute
179
- *
180
- * 获取指定属性
181
- * @param key attribute name / 属性键
182
- */
183
- getAttr(key) {
184
- return this.getAttrToken(key)?.getValue();
185
- }
186
- /** 是否位于闭合标签内 */
187
- #lint() {
188
- const { parentNode } = this;
189
- return parentNode?.type === 'html' && parentNode.closing && this.text().trim() !== '';
190
- }
191
- /** @private */
192
- lint(start = this.getAbsoluteIndex(), re) {
193
- const errors = super.lint(start, re), { parentNode, childNodes } = this, attrs = new Map(), duplicated = new Set(), rect = new rect_1.BoundingRect(this, start);
194
- if (this.#lint()) {
195
- const e = (0, lint_1.generateForSelf)(this, rect, 'no-ignored', 'attributes of a closing tag'), index = parentNode.getAbsoluteIndex();
196
- e.suggestions = [
197
- { desc: 'remove', range: [start, e.endIndex], text: '' },
198
- { desc: 'open', range: [index + 1, index + 2], text: '' },
199
- ];
200
- errors.push(e);
201
- }
202
- for (const attr of childNodes) {
203
- if (attr instanceof attribute_1.AttributeToken) {
204
- const { name } = attr;
205
- if (attrs.has(name)) {
206
- duplicated.add(name);
207
- attrs.get(name).push(attr);
208
- }
209
- else {
210
- attrs.set(name, [attr]);
211
- }
144
+ set id(id) {
145
+ this.setAttr('id', id || false);
146
+ }
147
+ /** whether to contain invalid attributes / 是否含有无效属性 */
148
+ get sanitized() {
149
+ return this.childNodes.filter(child => child instanceof atom_1.AtomToken && child.text().trim()).length === 0;
150
+ }
151
+ set sanitized(sanitized) {
152
+ if (sanitized) {
153
+ this.sanitize();
212
154
  }
213
- else {
214
- const str = attr.text().trim();
215
- if (str) {
216
- const e = (0, lint_1.generateForChild)(attr, rect, 'no-ignored', 'containing invalid attribute', wordRegex.test(str) ? 'error' : 'warning');
217
- e.suggestions = [{ desc: 'remove', range: [e.startIndex, e.endIndex], text: ' ' }];
218
- errors.push(e);
155
+ }
156
+ /* NOT FOR BROWSER END */
157
+ /**
158
+ * @param attr 标签属性
159
+ * @param type 标签类型
160
+ * @param name 标签名
161
+ */
162
+ constructor(attr, type, name, config, accum = []) {
163
+ super(undefined, config, accum, {
164
+ AtomToken: ':', AttributeToken: ':',
165
+ });
166
+ this.#type = type;
167
+ this.setAttribute('name', name);
168
+ if (attr) {
169
+ const regex = /([^\s/](?:(?!\0\d+~\x7F)[^\s/=])*)(?:((?:\s(?:\s|\0\d+[cn]\x7F)*)?(?:=|\0\d+~\x7F)(?:\s|\0\d+[cn]\x7F)*)(?:(["'])([\s\S]*?)(\3|$)|(\S*)))?/gu;
170
+ let out = '', mt = regex.exec(attr), lastIndex = 0;
171
+ const insertDirty = /** 插入无效属性 */ () => {
172
+ if (out) {
173
+ super.insertAt(new atom_1.AtomToken(out, toDirty(type), config, accum, {
174
+ [`Stage-${stages[type]}`]: ':',
175
+ }));
176
+ out = '';
177
+ }
178
+ };
179
+ while (mt) {
180
+ const { index, 0: full, 1: key, 2: equal, 3: quoteStart, 4: quoted, 5: quoteEnd, 6: unquoted } = mt;
181
+ out += attr.slice(lastIndex, index);
182
+ if (/^(?:[\w:]|\0\d+t\x7F)(?:[\w:.-]|\0\d+t\x7F)*$/u.test((0, string_1.removeComment)(key).trim())) {
183
+ const value = quoted ?? unquoted, quotes = [quoteStart, quoteEnd],
184
+ // @ts-expect-error abstract class
185
+ token = new attribute_1.AttributeToken(toAttributeType(type), name, key, equal, value, quotes, config, accum);
186
+ insertDirty();
187
+ super.insertAt(token);
188
+ }
189
+ else {
190
+ out += full;
191
+ }
192
+ ({ lastIndex } = regex);
193
+ mt = regex.exec(attr);
219
194
  }
195
+ out += attr.slice(lastIndex);
196
+ insertDirty();
220
197
  }
221
198
  }
222
- if (duplicated.size > 0) {
223
- for (const key of duplicated) {
224
- const pairs = attrs.get(key).map(attr => {
225
- const value = attr.getValue();
226
- return [attr, value === true ? '' : value];
227
- });
228
- errors.push(...pairs.map(([attr, value], i) => {
229
- const e = (0, lint_1.generateForChild)(attr, rect, 'no-duplicate', index_1.default.msg('duplicated $1 attribute', key)), remove = { desc: 'remove', range: [e.startIndex, e.endIndex], text: '' };
230
- if (!value || pairs.slice(0, i).some(([, v]) => v === value)) {
231
- e.fix = remove;
199
+ /** @private */
200
+ afterBuild() {
201
+ const { parentNode } = this;
202
+ if (parentNode?.is('td')) {
203
+ this.setAttribute('name', parentNode.subtype);
204
+ }
205
+ super.afterBuild();
206
+ }
207
+ /**
208
+ * Get all AttributeTokens with the specified attribute name
209
+ *
210
+ * 所有指定属性名的AttributeToken
211
+ * @param key attribute name / 属性名
212
+ */
213
+ getAttrTokens(key) {
214
+ return this.childNodes.filter((child) => child instanceof attribute_1.AttributeToken && (!key || child.name === (0, string_1.trimLc)(key)));
215
+ }
216
+ /**
217
+ * Check if the token has a certain attribute
218
+ *
219
+ * 是否具有某属性
220
+ * @param key attribute name / 属性键
221
+ */
222
+ hasAttr(key) {
223
+ return this.getAttrTokens(key).length > 0;
224
+ }
225
+ /**
226
+ * Get the last AttributeToken with the specified attribute name
227
+ *
228
+ * 指定属性名的最后一个AttributeToken
229
+ * @param key attribute name / 属性名
230
+ */
231
+ getAttrToken(key) {
232
+ const tokens = this.getAttrTokens(key);
233
+ return tokens[tokens.length - 1];
234
+ }
235
+ /**
236
+ * Get the attribute
237
+ *
238
+ * 获取指定属性
239
+ * @param key attribute name / 属性键
240
+ */
241
+ getAttr(key) {
242
+ return this.getAttrToken(key)?.getValue();
243
+ }
244
+ /** 是否位于闭合标签内 */
245
+ #lint() {
246
+ const { parentNode } = this;
247
+ return parentNode?.type === 'html' && parentNode.closing && this.text().trim() !== '';
248
+ }
249
+ /** @private */
250
+ lint(start = this.getAbsoluteIndex(), re) {
251
+ const errors = super.lint(start, re), { parentNode, childNodes } = this, attrs = new Map(), duplicated = new Set(), rect = new rect_1.BoundingRect(this, start), rules = ['no-ignored', 'no-duplicate'], s = ['closingTag', 'invalidAttributes', 'nonWordAttributes']
252
+ .map(k => index_1.default.lintConfig.getSeverity(rules[0], k));
253
+ if (s[0] && this.#lint()) {
254
+ const e = (0, lint_1.generateForSelf)(this, rect, rules[0], 'attributes of a closing tag', s[0]), index = parentNode.getAbsoluteIndex();
255
+ e.suggestions = [
256
+ { desc: 'remove', range: [start, e.endIndex], text: '' },
257
+ { desc: 'open', range: [index + 1, index + 2], text: '' },
258
+ ];
259
+ errors.push(e);
260
+ }
261
+ for (const attr of childNodes) {
262
+ if (attr instanceof attribute_1.AttributeToken) {
263
+ const { name } = attr;
264
+ if (attrs.has(name)) {
265
+ duplicated.add(name);
266
+ attrs.get(name).push(attr);
232
267
  }
233
268
  else {
234
- e.suggestions = [remove];
269
+ attrs.set(name, [attr]);
235
270
  }
236
- return e;
237
- }));
271
+ }
272
+ else {
273
+ const str = attr.text().trim(), severity = s[wordRegex.test(str) ? 1 : 2];
274
+ if (str && severity) {
275
+ const e = (0, lint_1.generateForChild)(attr, rect, rules[0], 'containing invalid attribute', severity);
276
+ e.suggestions = [{ desc: 'remove', range: [e.startIndex, e.endIndex], text: ' ' }];
277
+ errors.push(e);
278
+ }
279
+ }
238
280
  }
281
+ const severity = index_1.default.lintConfig.getSeverity(rules[1], 'attribute');
282
+ if (severity && duplicated.size > 0) {
283
+ for (const key of duplicated) {
284
+ const pairs = attrs.get(key).map(attr => {
285
+ const value = attr.getValue();
286
+ return [attr, value === true ? '' : value];
287
+ });
288
+ errors.push(...pairs.map(([attr, value], i) => {
289
+ const e = (0, lint_1.generateForChild)(attr, rect, rules[1], index_1.default.msg('duplicated $1 attribute', key), severity), remove = { desc: 'remove', range: [e.startIndex, e.endIndex], text: '' };
290
+ if (!value || pairs.slice(0, i).some(([, v]) => v === value)) {
291
+ e.fix = remove;
292
+ }
293
+ else {
294
+ e.suggestions = [remove];
295
+ }
296
+ return e;
297
+ }));
298
+ }
299
+ }
300
+ return errors;
239
301
  }
240
- return errors;
241
- }
242
- /* PRINT ONLY */
243
- /** @private */
244
- getAttribute(key) {
245
- /* NOT FOR BROWSER */
246
- if (key === 'padding') {
247
- return this.#leadingSpace(super.toString()).length;
248
- }
249
- /* NOT FOR BROWSER END */
250
- return key === 'invalid' ? this.#lint() : super.getAttribute(key);
251
- }
252
- /** @private */
253
- print() {
254
- return this.toString()
255
- ? `<span class="wpb-${this.type}${this.#lint() ? ' wpb-invalid' : ''}">${this.childNodes.map(child => child.print(child instanceof atom_1.AtomToken ? { class: child.toString().trim() && 'attr-dirty' } : undefined)).join('')}</span>`
256
- : '';
257
- }
258
- /* PRINT ONLY END */
259
- /* NOT FOR BROWSER */
260
- /**
261
- * Sanitize invalid attributes
262
- *
263
- * 清理无效属性
264
- */
265
- sanitize() {
266
- let dirty = false;
267
- for (let i = this.length - 1; i >= 0; i--) {
268
- const child = this.childNodes[i];
269
- if (child instanceof atom_1.AtomToken && child.text().trim()) {
270
- dirty = true;
271
- this.removeAt(i);
302
+ /* PRINT ONLY */
303
+ /** @private */
304
+ getAttribute(key) {
305
+ /* NOT FOR BROWSER */
306
+ if (key === 'padding') {
307
+ return this.#leadingSpace(super.toString()).length;
272
308
  }
309
+ /* NOT FOR BROWSER END */
310
+ return key === 'invalid' ? this.#lint() : super.getAttribute(key);
273
311
  }
274
- if (!debug_1.Shadow.running && dirty) {
275
- index_1.default.warn('AttributesToken.sanitize will remove invalid attributes!');
312
+ /** @private */
313
+ print() {
314
+ return this.toString()
315
+ ? `<span class="wpb-${this.type}${this.#lint() ? ' wpb-invalid' : ''}">${this.childNodes.map(child => child.print(child instanceof atom_1.AtomToken ? { class: child.toString().trim() && 'attr-dirty' } : undefined)).join('')}</span>`
316
+ : '';
276
317
  }
277
- }
278
- cloneNode() {
279
- return (0, html_1.cloneNode)(this,
280
- // @ts-expect-error abstract class
281
- () => new AttributesToken(undefined, this.type, this.name, this.getAttribute('config')));
282
- }
283
- /**
284
- * @override
285
- * @param token node to be inserted / 待插入的子节点
286
- * @param i position to be inserted at / 插入位置
287
- * @throws `RangeError` 标签不匹配
288
- */
289
- insertAt(token, i = this.length) {
290
- if (!(token instanceof attribute_1.AttributeToken)) {
291
- if (!debug_1.Shadow.running && token.toString().trim()) {
292
- this.constructorError('can only insert AttributeToken');
318
+ /* PRINT ONLY END */
319
+ /* NOT FOR BROWSER */
320
+ /**
321
+ * Sanitize invalid attributes
322
+ *
323
+ * 清理无效属性
324
+ */
325
+ sanitize() {
326
+ let dirty = false;
327
+ for (let i = this.length - 1; i >= 0; i--) {
328
+ const child = this.childNodes[i];
329
+ if (child instanceof atom_1.AtomToken && child.text().trim()) {
330
+ dirty = true;
331
+ this.removeAt(i);
332
+ }
333
+ }
334
+ if (!debug_1.Shadow.running && dirty) {
335
+ index_1.default.warn('AttributesToken.sanitize will remove invalid attributes!');
293
336
  }
294
- return super.insertAt(token, i);
295
337
  }
296
- const { type, name, length } = this;
297
- if (token.type !== type.slice(0, -1) || token.tag !== name) {
298
- throw new RangeError(`The AttributeToken to be inserted can only be used for <${token.tag}> tag!`);
338
+ cloneNode() {
339
+ // @ts-expect-error abstract class
340
+ return new AttributesToken(undefined, this.type, this.name, this.getAttribute('config'));
299
341
  }
300
- else if (i === length) {
301
- const { lastChild } = this;
302
- if (lastChild instanceof attribute_1.AttributeToken) {
303
- lastChild.close();
342
+ /**
343
+ * @override
344
+ * @param token node to be inserted / 待插入的子节点
345
+ * @param i position to be inserted at / 插入位置
346
+ * @throws `RangeError` 标签不匹配
347
+ */
348
+ insertAt(token, i = this.length) {
349
+ if (!(token instanceof attribute_1.AttributeToken)) {
350
+ if (!debug_1.Shadow.running && token.toString().trim()) {
351
+ this.constructorError('can only insert AttributeToken');
352
+ }
353
+ return super.insertAt(token, i);
304
354
  }
355
+ const { type, name, length } = this;
356
+ if (token.type !== type.slice(0, -1) || token.tag !== name) {
357
+ throw new RangeError(`The AttributeToken to be inserted can only be used for <${token.tag}> tag!`);
358
+ }
359
+ else if (i === length) {
360
+ const { lastChild } = this;
361
+ if (lastChild instanceof attribute_1.AttributeToken) {
362
+ lastChild.close();
363
+ }
364
+ }
365
+ else {
366
+ token.close();
367
+ }
368
+ if (this.closest('parameter')) {
369
+ token.escape();
370
+ }
371
+ super.insertAt(token, i);
372
+ const { previousVisibleSibling, nextVisibleSibling } = token, dirtyType = toDirty(type), config = this.getAttribute('config'), acceptable = { [`Stage-${stages[type]}`]: ':' };
373
+ if (nextVisibleSibling && !/^\s/u.test(nextVisibleSibling.toString())) {
374
+ super.insertAt(debug_1.Shadow.run(() => new atom_1.AtomToken(' ', dirtyType, config, [], acceptable)), i + 1);
375
+ }
376
+ if (previousVisibleSibling && !/\s$/u.test(previousVisibleSibling.toString())) {
377
+ super.insertAt(debug_1.Shadow.run(() => new atom_1.AtomToken(' ', dirtyType, config, [], acceptable)), i);
378
+ }
379
+ return token;
305
380
  }
306
- else {
307
- token.close();
308
- }
309
- if (this.closest('parameter')) {
310
- token.escape();
381
+ setAttr(keyOrProp, value) {
382
+ if (typeof keyOrProp === 'object') {
383
+ for (const [key, val] of Object.entries(keyOrProp)) {
384
+ this.setAttr(key, val);
385
+ }
386
+ return;
387
+ }
388
+ const { type, name } = this;
389
+ if (type === 'ext-attrs' && typeof value === 'string' && value.includes('>')) {
390
+ throw new RangeError('Attributes of an extension tag cannot contain ">"!');
391
+ }
392
+ const key = (0, string_1.trimLc)(keyOrProp), attr = this.getAttrToken(key);
393
+ if (attr) {
394
+ attr.setValue(value);
395
+ return;
396
+ }
397
+ else if (value === false) {
398
+ return;
399
+ }
400
+ // @ts-expect-error abstract class
401
+ const token = debug_1.Shadow.run(() => new attribute_1.AttributeToken(toAttributeType(type), name, key, value === true ? '' : '=', value === true ? '' : value, ['"', '"'], this.getAttribute('config')));
402
+ this.insertAt(token);
311
403
  }
312
- super.insertAt(token, i);
313
- const { previousVisibleSibling, nextVisibleSibling } = token, dirtyType = toDirty(type), config = this.getAttribute('config'), acceptable = { [`Stage-${stages[type]}`]: ':' };
314
- if (nextVisibleSibling && !/^\s/u.test(nextVisibleSibling.toString())) {
315
- super.insertAt(debug_1.Shadow.run(() => new atom_1.AtomToken(' ', dirtyType, config, [], acceptable)), i + 1);
404
+ /**
405
+ * Get all attribute names
406
+ *
407
+ * 获取全部的属性名
408
+ */
409
+ getAttrNames() {
410
+ return new Set(this.getAttrTokens().map(({ name }) => name));
316
411
  }
317
- if (previousVisibleSibling && !/\s$/u.test(previousVisibleSibling.toString())) {
318
- super.insertAt(debug_1.Shadow.run(() => new atom_1.AtomToken(' ', dirtyType, config, [], acceptable)), i);
412
+ /**
413
+ * Get all attributes
414
+ *
415
+ * 获取全部属性
416
+ */
417
+ getAttrs() {
418
+ return Object.fromEntries(this.getAttrTokens().map(({ name, value }) => [name, value]));
319
419
  }
320
- return token;
321
- }
322
- setAttr(keyOrProp, value) {
323
- if (typeof keyOrProp === 'object') {
324
- for (const [key, val] of Object.entries(keyOrProp)) {
325
- this.setAttr(key, val);
420
+ /**
421
+ * Remove an attribute
422
+ *
423
+ * 移除指定属性
424
+ * @param key attribute name / 属性键
425
+ */
426
+ removeAttr(key) {
427
+ for (const attr of this.getAttrTokens(key)) {
428
+ attr.remove();
326
429
  }
327
- return;
328
430
  }
329
- const { type, name } = this;
330
- if (type === 'ext-attrs' && typeof value === 'string' && value.includes('>')) {
331
- throw new RangeError('Attributes of an extension tag cannot contain ">"!');
332
- }
333
- const key = (0, string_1.trimLc)(keyOrProp), attr = this.getAttrToken(key);
334
- if (attr) {
335
- attr.setValue(value);
336
- return;
431
+ /**
432
+ * Toggle the specified attribute
433
+ *
434
+ * 开关指定属性
435
+ * @param key attribute name / 属性键
436
+ * @param force whether to force enabling or disabling / 强制开启或关闭
437
+ * @throws `RangeError` 不为Boolean类型的属性值
438
+ */
439
+ toggleAttr(key, force) {
440
+ key = (0, string_1.trimLc)(key);
441
+ const attr = this.getAttrToken(key);
442
+ if (attr && attr.getValue() !== true) {
443
+ throw new RangeError(`${key} attribute is not Boolean!`);
444
+ }
445
+ else if (attr) {
446
+ attr.setValue(force === true);
447
+ }
448
+ else if (force !== false) {
449
+ this.setAttr(key, true);
450
+ }
337
451
  }
338
- else if (value === false) {
339
- return;
452
+ /**
453
+ * 生成引导空格
454
+ * @param str 属性字符串
455
+ */
456
+ #leadingSpace(str) {
457
+ const { type } = this, leadingRegex = { 'ext-attrs': /^\s/u, 'html-attrs': /^[/\s]/u };
458
+ return str && type !== 'table-attrs' && !leadingRegex[type].test(str) ? ' ' : '';
340
459
  }
341
- // @ts-expect-error abstract class
342
- const token = debug_1.Shadow.run(() => new attribute_1.AttributeToken(toAttributeType(type), name, key, value === true ? '' : '=', value === true ? '' : value, ['"', '"'], this.getAttribute('config')));
343
- this.insertAt(token);
344
- }
345
- /**
346
- * Check if the token has a certain attribute
347
- *
348
- * 是否具有某属性
349
- * @param key attribute name / 属性键
350
- */
351
- hasAttr(key) {
352
- return this.getAttrTokens(key).length > 0;
353
- }
354
- /**
355
- * Get all attribute names
356
- *
357
- * 获取全部的属性名
358
- */
359
- getAttrNames() {
360
- return new Set(this.getAttrTokens().map(({ name }) => name));
361
- }
362
- /**
363
- * Get all attributes
364
- *
365
- * 获取全部属性
366
- */
367
- getAttrs() {
368
- return Object.fromEntries(this.getAttrTokens().map(({ name, value }) => [name, value]));
369
- }
370
- /**
371
- * Remove an attribute
372
- *
373
- * 移除指定属性
374
- * @param key attribute name / 属性键
375
- */
376
- removeAttr(key) {
377
- for (const attr of this.getAttrTokens(key)) {
378
- attr.remove();
460
+ /** @private */
461
+ toString(skip) {
462
+ if (this.type === 'table-attrs') {
463
+ (0, string_1.normalizeSpace)(this);
464
+ }
465
+ const str = super.toString(skip);
466
+ return this.#leadingSpace(str) + str;
379
467
  }
380
- }
381
- /**
382
- * Toggle the specified attribute
383
- *
384
- * 开关指定属性
385
- * @param key attribute name / 属性键
386
- * @param force whether to force enabling or disabling / 强制开启或关闭
387
- * @throws `RangeError` 不为Boolean类型的属性值
388
- */
389
- toggleAttr(key, force) {
390
- key = (0, string_1.trimLc)(key);
391
- const attr = this.getAttrToken(key);
392
- if (attr && attr.getValue() !== true) {
393
- throw new RangeError(`${key} attribute is not Boolean!`);
394
- }
395
- else if (attr) {
396
- attr.setValue(force === true);
397
- }
398
- else if (force !== false) {
399
- this.setAttr(key, true);
468
+ /** @private */
469
+ text() {
470
+ if (this.type === 'table-attrs') {
471
+ (0, string_1.normalizeSpace)(this);
472
+ }
473
+ const str = (0, string_1.text)(this.childNodes.filter(child => child instanceof attribute_1.AttributeToken), ' ');
474
+ return this.#leadingSpace(str) + str;
400
475
  }
401
- }
402
- /**
403
- * 生成引导空格
404
- * @param str 属性字符串
405
- */
406
- #leadingSpace(str) {
407
- const { type } = this, leadingRegex = { 'ext-attrs': /^\s/u, 'html-attrs': /^[/\s]/u };
408
- return str && type !== 'table-attrs' && !leadingRegex[type].test(str) ? ' ' : '';
409
- }
410
- /** @private */
411
- toString(skip) {
412
- if (this.type === 'table-attrs') {
413
- (0, string_1.normalizeSpace)(this);
476
+ /** @private */
477
+ toHtmlInternal() {
478
+ const map = new Map(this.childNodes.filter(child => child instanceof attribute_1.AttributeToken).map(child => [child.name, child]));
479
+ return map.size === 0 ? '' : ` ${(0, html_1.html)([...map.values()], ' ')}`;
414
480
  }
415
- const str = super.toString(skip);
416
- return this.#leadingSpace(str) + str;
417
- }
418
- /** @private */
419
- text() {
420
- if (this.type === 'table-attrs') {
421
- (0, string_1.normalizeSpace)(this);
481
+ /**
482
+ * Get the value of a style property
483
+ *
484
+ * 获取某一样式属性的值
485
+ * @param key style property / 样式属性
486
+ * @param value style property value / 样式属性值
487
+ */
488
+ css(key, value) {
489
+ return this.getAttrToken('style')?.css(key, value);
422
490
  }
423
- const str = (0, string_1.text)(this.childNodes.filter(child => child instanceof attribute_1.AttributeToken), ' ');
424
- return this.#leadingSpace(str) + str;
425
- }
426
- /** @private */
427
- toHtmlInternal() {
428
- const map = new Map(this.childNodes.filter(child => child instanceof attribute_1.AttributeToken).map(child => [child.name, child]));
429
- return map.size === 0 ? '' : ` ${(0, html_1.html)([...map.values()], ' ')}`;
430
- }
431
- /**
432
- * Get the value of a style property
433
- *
434
- * 获取某一样式属性的值
435
- * @param key style property / 样式属性
436
- * @param value style property value / 样式属性值
437
- */
438
- css(key, value) {
439
- return this.getAttrToken('style')?.css(key, value);
440
- }
441
- }
491
+ };
492
+ })();
442
493
  exports.AttributesToken = AttributesToken;
443
494
  constants_1.classes['AttributesToken'] = __filename;