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.
- package/README.md +9 -5
- package/bundle/bundle-es8.min.js +25 -25
- package/bundle/bundle-lsp.min.js +26 -26
- package/bundle/bundle.min.js +25 -25
- package/config/default.json +15 -11
- package/config/enwiki.json +1 -1
- package/config/jawiki.json +1 -1
- package/config/minimum.json +2 -3
- package/config/moegirl.json +152 -15
- package/config/zhwiki.json +1 -1
- package/dist/addon/token.js +3 -0
- package/dist/base.d.mts +16 -9
- package/dist/base.d.ts +16 -9
- package/dist/bin/config.js +23 -11
- package/dist/index.d.ts +33 -4
- package/dist/index.js +37 -2
- package/dist/lib/element.d.ts +4 -4
- package/dist/lib/element.js +6 -5
- package/dist/lib/lintConfig.d.ts +13 -0
- package/dist/lib/lintConfig.js +278 -0
- package/dist/lib/lsp.d.ts +7 -7
- package/dist/lib/lsp.js +18 -20
- package/dist/lib/node.d.ts +1 -1
- package/dist/lib/node.js +646 -606
- package/dist/lib/range.d.ts +2 -2
- package/dist/lib/range.js +2 -2
- package/dist/lib/text.js +76 -62
- package/dist/lib/title.d.ts +11 -4
- package/dist/lib/title.js +16 -6
- package/dist/mixin/attributesParent.d.ts +6 -6
- package/dist/mixin/attributesParent.js +4 -4
- package/dist/mixin/cached.d.ts +5 -0
- package/dist/mixin/cached.js +22 -0
- package/dist/mixin/clone.d.ts +5 -0
- package/dist/mixin/clone.js +23 -0
- package/dist/mixin/hidden.js +68 -18
- package/dist/mixin/sol.js +1 -1
- package/dist/parser/commentAndExt.js +6 -4
- package/dist/parser/converter.js +1 -1
- package/dist/parser/html.js +3 -3
- package/dist/parser/table.js +2 -2
- package/dist/src/arg.js +24 -17
- package/dist/src/atom.js +76 -31
- package/dist/src/attribute.js +79 -39
- package/dist/src/attributes.d.ts +7 -7
- package/dist/src/attributes.js +417 -366
- package/dist/src/commented.js +81 -35
- package/dist/src/converter.js +13 -7
- package/dist/src/converterFlags.js +33 -22
- package/dist/src/converterRule.js +263 -216
- package/dist/src/extLink.js +21 -16
- package/dist/src/gallery.js +44 -27
- package/dist/src/heading.js +48 -43
- package/dist/src/hidden.js +14 -9
- package/dist/src/html.js +92 -60
- package/dist/src/imageParameter.js +13 -6
- package/dist/src/imagemap.js +32 -25
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.js +61 -50
- package/dist/src/link/base.d.ts +1 -1
- package/dist/src/link/base.js +35 -23
- package/dist/src/link/file.js +409 -354
- package/dist/src/link/galleryImage.js +9 -5
- package/dist/src/link/index.d.ts +1 -1
- package/dist/src/link/index.js +8 -4
- package/dist/src/link/redirectTarget.js +7 -3
- package/dist/src/magicLink.js +39 -26
- package/dist/src/nested.js +122 -74
- package/dist/src/nowiki/base.js +5 -2
- package/dist/src/nowiki/comment.js +5 -1
- package/dist/src/nowiki/index.js +4 -4
- package/dist/src/nowiki/quote.js +32 -46
- package/dist/src/onlyinclude.js +17 -9
- package/dist/src/paramTag/index.js +21 -14
- package/dist/src/parameter.js +26 -20
- package/dist/src/pre.js +91 -45
- package/dist/src/syntax.js +14 -10
- package/dist/src/table/index.js +554 -501
- package/dist/src/table/td.d.ts +1 -1
- package/dist/src/table/td.js +91 -82
- package/dist/src/table/trBase.js +183 -130
- package/dist/src/tagPair/ext.js +38 -23
- package/dist/src/tagPair/include.js +5 -5
- package/dist/src/tagPair/index.js +2 -3
- package/dist/src/tagPair/translate.js +150 -103
- package/dist/src/transclude.d.ts +15 -1
- package/dist/src/transclude.js +56 -21
- package/dist/util/html.js +46 -41
- package/dist/util/lint.js +7 -9
- package/dist/util/sharable.js +1 -1
- package/dist/util/sharable.mjs +2 -2
- package/dist/util/string.js +13 -7
- package/extensions/dist/base.js +9 -2
- package/extensions/typings.d.ts +2 -1
- package/i18n/zh-hans.json +1 -1
- package/i18n/zh-hant.json +1 -1
- package/package.json +20 -15
package/dist/src/attributes.js
CHANGED
|
@@ -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
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
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
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
const
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
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
|
-
|
|
147
|
-
insertDirty();
|
|
137
|
+
return this.#classList;
|
|
148
138
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
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
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
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
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
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
|
-
|
|
269
|
+
attrs.set(name, [attr]);
|
|
235
270
|
}
|
|
236
|
-
|
|
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
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
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
|
-
|
|
275
|
-
|
|
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
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
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
|
-
|
|
297
|
-
|
|
298
|
-
|
|
338
|
+
cloneNode() {
|
|
339
|
+
// @ts-expect-error abstract class
|
|
340
|
+
return new AttributesToken(undefined, this.type, this.name, this.getAttribute('config'));
|
|
299
341
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
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
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
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
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
404
|
+
/**
|
|
405
|
+
* Get all attribute names
|
|
406
|
+
*
|
|
407
|
+
* 获取全部的属性名
|
|
408
|
+
*/
|
|
409
|
+
getAttrNames() {
|
|
410
|
+
return new Set(this.getAttrTokens().map(({ name }) => name));
|
|
316
411
|
}
|
|
317
|
-
|
|
318
|
-
|
|
412
|
+
/**
|
|
413
|
+
* Get all attributes
|
|
414
|
+
*
|
|
415
|
+
* 获取全部属性
|
|
416
|
+
*/
|
|
417
|
+
getAttrs() {
|
|
418
|
+
return Object.fromEntries(this.getAttrTokens().map(({ name, value }) => [name, value]));
|
|
319
419
|
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
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
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
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
|
-
|
|
339
|
-
|
|
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
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
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
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
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
|
-
|
|
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
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
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
|
-
|
|
424
|
-
|
|
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;
|