wikiparser-node 0.11.0 → 1.0.0-beta.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 (251) hide show
  1. package/dist/index.d.ts +59 -113
  2. package/dist/index.js +307 -0
  3. package/dist/lib/element.d.ts +122 -108
  4. package/dist/lib/element.js +656 -0
  5. package/dist/lib/node.d.ts +115 -221
  6. package/dist/lib/node.js +473 -0
  7. package/dist/lib/ranges.d.ts +27 -26
  8. package/dist/lib/ranges.js +130 -0
  9. package/dist/lib/text.d.ts +36 -28
  10. package/dist/lib/text.js +215 -0
  11. package/dist/lib/title.d.ts +25 -12
  12. package/dist/lib/title.js +100 -0
  13. package/dist/mixin/attributesParent.js +90 -0
  14. package/dist/mixin/fixed.js +29 -0
  15. package/dist/mixin/hidden.js +19 -0
  16. package/dist/mixin/singleLine.js +23 -0
  17. package/dist/mixin/sol.js +41 -0
  18. package/dist/parser/brackets.js +117 -0
  19. package/dist/parser/commentAndExt.js +48 -0
  20. package/dist/parser/converter.js +31 -0
  21. package/dist/parser/externalLinks.js +22 -0
  22. package/dist/parser/hrAndDoubleUnderscore.js +33 -0
  23. package/dist/parser/html.js +29 -0
  24. package/dist/parser/links.js +86 -0
  25. package/dist/parser/list.js +51 -0
  26. package/dist/parser/magicLinks.js +32 -0
  27. package/dist/parser/quotes.js +57 -0
  28. package/dist/parser/selector.js +158 -0
  29. package/dist/parser/table.js +108 -0
  30. package/dist/src/arg.d.ts +47 -23
  31. package/dist/src/arg.js +196 -0
  32. package/dist/src/atom.d.ts +12 -0
  33. package/dist/src/atom.js +22 -0
  34. package/dist/src/attribute.d.ts +74 -33
  35. package/dist/src/attribute.js +433 -0
  36. package/dist/src/attributes.d.ts +61 -55
  37. package/dist/src/attributes.js +371 -0
  38. package/dist/src/converter.d.ts +45 -71
  39. package/dist/src/converter.js +135 -0
  40. package/dist/src/converterFlags.d.ts +64 -39
  41. package/dist/src/converterFlags.js +235 -0
  42. package/dist/src/converterRule.d.ts +49 -27
  43. package/dist/src/converterRule.js +255 -0
  44. package/dist/src/extLink.d.ts +41 -38
  45. package/dist/src/extLink.js +154 -0
  46. package/dist/src/gallery.d.ts +59 -18
  47. package/dist/src/gallery.js +132 -0
  48. package/dist/src/heading.d.ts +60 -22
  49. package/dist/src/heading.js +135 -0
  50. package/dist/src/hidden.d.ts +20 -0
  51. package/dist/src/hidden.js +24 -0
  52. package/dist/src/html.d.ts +83 -29
  53. package/dist/src/html.js +242 -0
  54. package/dist/src/imageParameter.d.ts +59 -40
  55. package/dist/src/imageParameter.js +251 -0
  56. package/dist/src/imagemap.d.ts +65 -21
  57. package/dist/src/imagemap.js +164 -0
  58. package/dist/src/imagemapLink.d.ts +46 -14
  59. package/dist/src/imagemapLink.js +38 -0
  60. package/dist/src/index.d.ts +71 -105
  61. package/dist/src/index.js +826 -0
  62. package/dist/src/link/base.d.ts +71 -0
  63. package/dist/src/link/base.js +225 -0
  64. package/dist/src/link/category.d.ts +10 -11
  65. package/dist/src/link/category.js +26 -0
  66. package/dist/src/link/file.d.ts +61 -39
  67. package/dist/src/link/file.js +242 -0
  68. package/dist/src/link/galleryImage.d.ts +34 -12
  69. package/dist/src/link/galleryImage.js +98 -0
  70. package/dist/src/link/index.d.ts +25 -63
  71. package/dist/src/link/index.js +136 -0
  72. package/dist/src/magicLink.d.ts +22 -15
  73. package/dist/src/magicLink.js +126 -0
  74. package/dist/src/nested.d.ts +47 -0
  75. package/dist/src/nested.js +84 -0
  76. package/dist/src/nowiki/base.d.ts +39 -0
  77. package/dist/src/nowiki/base.js +29 -0
  78. package/dist/src/nowiki/comment.d.ts +31 -20
  79. package/dist/src/nowiki/comment.js +61 -0
  80. package/dist/src/nowiki/dd.d.ts +17 -11
  81. package/dist/src/nowiki/dd.js +50 -0
  82. package/dist/src/nowiki/doubleUnderscore.d.ts +28 -13
  83. package/dist/src/nowiki/doubleUnderscore.js +45 -0
  84. package/dist/src/nowiki/hr.d.ts +28 -10
  85. package/dist/src/nowiki/hr.js +33 -0
  86. package/dist/src/nowiki/index.d.ts +17 -23
  87. package/dist/src/nowiki/index.js +21 -0
  88. package/dist/src/nowiki/list.d.ts +15 -7
  89. package/dist/src/nowiki/list.js +11 -0
  90. package/dist/src/nowiki/noinclude.d.ts +20 -7
  91. package/dist/src/nowiki/noinclude.js +22 -0
  92. package/dist/src/nowiki/quote.d.ts +25 -10
  93. package/dist/src/nowiki/quote.js +55 -0
  94. package/dist/src/onlyinclude.d.ts +28 -12
  95. package/dist/src/onlyinclude.js +64 -0
  96. package/dist/src/paramTag/index.d.ts +40 -17
  97. package/dist/src/paramTag/index.js +76 -0
  98. package/dist/src/paramTag/inputbox.d.ts +8 -7
  99. package/dist/src/paramTag/inputbox.js +19 -0
  100. package/dist/src/parameter.d.ts +62 -41
  101. package/dist/src/parameter.js +201 -0
  102. package/dist/src/pre.d.ts +32 -0
  103. package/dist/src/pre.js +39 -0
  104. package/dist/src/syntax.d.ts +17 -14
  105. package/dist/src/syntax.js +65 -0
  106. package/dist/src/table/base.d.ts +55 -0
  107. package/dist/src/table/base.js +77 -0
  108. package/dist/src/table/index.d.ts +123 -156
  109. package/dist/src/table/index.js +811 -0
  110. package/dist/src/table/td.d.ts +90 -67
  111. package/dist/src/table/td.js +276 -0
  112. package/dist/src/table/tr.d.ts +30 -85
  113. package/dist/src/table/tr.js +48 -0
  114. package/dist/src/table/trBase.d.ts +72 -0
  115. package/dist/src/table/trBase.js +153 -0
  116. package/dist/src/tagPair/ext.d.ts +47 -11
  117. package/dist/src/tagPair/ext.js +127 -0
  118. package/dist/src/tagPair/include.d.ts +32 -13
  119. package/dist/src/tagPair/include.js +40 -0
  120. package/dist/src/tagPair/index.d.ts +44 -29
  121. package/dist/src/tagPair/index.js +111 -0
  122. package/dist/src/transclude.d.ts +88 -85
  123. package/dist/src/transclude.js +739 -0
  124. package/dist/util/base.js +26 -0
  125. package/dist/util/debug.js +52 -0
  126. package/dist/util/diff.js +69 -0
  127. package/dist/util/lint.js +38 -0
  128. package/dist/util/string.js +103 -0
  129. package/errors/README +1 -0
  130. package/i18n/zh-hans.json +1 -0
  131. package/i18n/zh-hant.json +1 -0
  132. package/package.json +11 -14
  133. package/printed/README +1 -0
  134. package/dist/mixin/attributeParent.d.ts +0 -9
  135. package/dist/mixin/fixedToken.d.ts +0 -8
  136. package/dist/mixin/hidden.d.ts +0 -8
  137. package/dist/mixin/singleLine.d.ts +0 -8
  138. package/dist/mixin/sol.d.ts +0 -8
  139. package/dist/parser/brackets.d.ts +0 -12
  140. package/dist/parser/commentAndExt.d.ts +0 -8
  141. package/dist/parser/converter.d.ts +0 -7
  142. package/dist/parser/externalLinks.d.ts +0 -7
  143. package/dist/parser/hrAndDoubleUnderscore.d.ts +0 -11
  144. package/dist/parser/html.d.ts +0 -7
  145. package/dist/parser/links.d.ts +0 -7
  146. package/dist/parser/list.d.ts +0 -7
  147. package/dist/parser/magicLinks.d.ts +0 -7
  148. package/dist/parser/quotes.d.ts +0 -7
  149. package/dist/parser/selector.d.ts +0 -12
  150. package/dist/parser/table.d.ts +0 -11
  151. package/dist/src/atom/hidden.d.ts +0 -5
  152. package/dist/src/atom/index.d.ts +0 -15
  153. package/dist/src/charinsert.d.ts +0 -32
  154. package/dist/src/hasNowiki/index.d.ts +0 -14
  155. package/dist/src/hasNowiki/pre.d.ts +0 -13
  156. package/dist/src/nested/choose.d.ts +0 -13
  157. package/dist/src/nested/combobox.d.ts +0 -13
  158. package/dist/src/nested/index.d.ts +0 -18
  159. package/dist/src/nested/references.d.ts +0 -13
  160. package/dist/tool/index.d.ts +0 -420
  161. package/dist/util/base.d.ts +0 -10
  162. package/dist/util/debug.d.ts +0 -20
  163. package/dist/util/diff.d.ts +0 -8
  164. package/dist/util/lint.d.ts +0 -28
  165. package/dist/util/string.d.ts +0 -55
  166. package/index.js +0 -333
  167. package/lib/element.js +0 -618
  168. package/lib/node.js +0 -730
  169. package/lib/ranges.js +0 -130
  170. package/lib/text.js +0 -265
  171. package/lib/title.js +0 -83
  172. package/mixin/attributeParent.js +0 -117
  173. package/mixin/fixedToken.js +0 -40
  174. package/mixin/hidden.js +0 -21
  175. package/mixin/singleLine.js +0 -31
  176. package/mixin/sol.js +0 -54
  177. package/parser/brackets.js +0 -128
  178. package/parser/commentAndExt.js +0 -62
  179. package/parser/converter.js +0 -46
  180. package/parser/externalLinks.js +0 -33
  181. package/parser/hrAndDoubleUnderscore.js +0 -49
  182. package/parser/html.js +0 -42
  183. package/parser/links.js +0 -94
  184. package/parser/list.js +0 -59
  185. package/parser/magicLinks.js +0 -41
  186. package/parser/quotes.js +0 -64
  187. package/parser/selector.js +0 -180
  188. package/parser/table.js +0 -114
  189. package/src/arg.js +0 -207
  190. package/src/atom/hidden.js +0 -13
  191. package/src/atom/index.js +0 -43
  192. package/src/attribute.js +0 -472
  193. package/src/attributes.js +0 -453
  194. package/src/charinsert.js +0 -97
  195. package/src/converter.js +0 -176
  196. package/src/converterFlags.js +0 -284
  197. package/src/converterRule.js +0 -256
  198. package/src/extLink.js +0 -180
  199. package/src/gallery.js +0 -149
  200. package/src/hasNowiki/index.js +0 -44
  201. package/src/hasNowiki/pre.js +0 -40
  202. package/src/heading.js +0 -134
  203. package/src/html.js +0 -254
  204. package/src/imageParameter.js +0 -303
  205. package/src/imagemap.js +0 -199
  206. package/src/imagemapLink.js +0 -41
  207. package/src/index.js +0 -938
  208. package/src/link/category.js +0 -44
  209. package/src/link/file.js +0 -287
  210. package/src/link/galleryImage.js +0 -120
  211. package/src/link/index.js +0 -388
  212. package/src/magicLink.js +0 -151
  213. package/src/nested/choose.js +0 -24
  214. package/src/nested/combobox.js +0 -23
  215. package/src/nested/index.js +0 -96
  216. package/src/nested/references.js +0 -23
  217. package/src/nowiki/comment.js +0 -71
  218. package/src/nowiki/dd.js +0 -59
  219. package/src/nowiki/doubleUnderscore.js +0 -56
  220. package/src/nowiki/hr.js +0 -41
  221. package/src/nowiki/index.js +0 -56
  222. package/src/nowiki/list.js +0 -16
  223. package/src/nowiki/noinclude.js +0 -28
  224. package/src/nowiki/quote.js +0 -69
  225. package/src/onlyinclude.js +0 -64
  226. package/src/paramTag/index.js +0 -89
  227. package/src/paramTag/inputbox.js +0 -35
  228. package/src/parameter.js +0 -239
  229. package/src/syntax.js +0 -91
  230. package/src/table/index.js +0 -985
  231. package/src/table/td.js +0 -343
  232. package/src/table/tr.js +0 -319
  233. package/src/tagPair/ext.js +0 -146
  234. package/src/tagPair/include.js +0 -50
  235. package/src/tagPair/index.js +0 -131
  236. package/src/transclude.js +0 -843
  237. package/tool/index.js +0 -1209
  238. package/typings/api.d.ts +0 -9
  239. package/typings/array.d.ts +0 -29
  240. package/typings/event.d.ts +0 -22
  241. package/typings/index.d.ts +0 -118
  242. package/typings/node.d.ts +0 -35
  243. package/typings/parser.d.ts +0 -12
  244. package/typings/table.d.ts +0 -10
  245. package/typings/token.d.ts +0 -31
  246. package/typings/tool.d.ts +0 -6
  247. package/util/base.js +0 -17
  248. package/util/debug.js +0 -73
  249. package/util/diff.js +0 -76
  250. package/util/lint.js +0 -57
  251. package/util/string.js +0 -126
@@ -0,0 +1,371 @@
1
+ "use strict";
2
+ const lint_1 = require("../util/lint");
3
+ const string_1 = require("../util/string");
4
+ const Parser = require("../index");
5
+ const Token = require(".");
6
+ const AtomToken = require("./atom");
7
+ const AttributeToken = require("./attribute");
8
+ const stages = { 'ext-attrs': 0, 'html-attrs': 2, 'table-attrs': 3 };
9
+ /**
10
+ * 扩展和HTML标签属性
11
+ * @classdesc `{childNodes: ...AtomToken|AttributeToken}`
12
+ */
13
+ class AttributesToken extends Token {
14
+ /** getAttrs()方法的getter写法 */
15
+ get attributes() {
16
+ return this.getAttrs();
17
+ }
18
+ /** 以字符串表示的class属性 */
19
+ get className() {
20
+ const attr = this.getAttr('class');
21
+ return typeof attr === 'string' ? attr : '';
22
+ }
23
+ set className(className) {
24
+ this.setAttr('class', className);
25
+ }
26
+ /** 以Set表示的class属性 */
27
+ get classList() {
28
+ return new Set(this.className.split(/\s/u));
29
+ }
30
+ /** id属性 */
31
+ get id() {
32
+ const attr = this.getAttr('id');
33
+ return typeof attr === 'string' ? attr : '';
34
+ }
35
+ set id(id) {
36
+ this.setAttr('id', id);
37
+ }
38
+ /** 是否含有无效属性 */
39
+ get sanitized() {
40
+ return this.getDirtyAttrs().length === 0;
41
+ }
42
+ /**
43
+ * @browser
44
+ * @param attr 标签属性
45
+ * @param type 标签类型
46
+ * @param name 标签名
47
+ */
48
+ constructor(attr, type, name, config = Parser.getConfig(), accum = []) {
49
+ super(undefined, config, true, accum, {
50
+ AtomToken: ':', AttributeToken: ':',
51
+ });
52
+ this.type = type;
53
+ this.setAttribute('name', name);
54
+ if (attr) {
55
+ const regex = new RegExp(`([^\\s/](?:(?!\0\\d+~\x7F)[^\\s/=])*)` // 属性名
56
+ + '(?:'
57
+ + '((?:\\s|\0\\d+c\x7F)*' // `=`前的空白字符
58
+ + '(?:=|\0\\d+~\x7F)' // `=`
59
+ + '(?:\\s|\0\\d+c\x7F)*)' // `=`后的空白字符
60
+ + `(?:(["'])(.*?)(\\3|$)|(\\S*))` // 属性值
61
+ + ')?', 'gsu');
62
+ let out = '', mt = regex.exec(attr), lastIndex = 0;
63
+ const insertDirty = /** 插入无效属性 */ () => {
64
+ if (out) {
65
+ super.insertAt(new AtomToken(out, `${type.slice(0, -1)}-dirty`, config, accum, { [`Stage-${stages[type]}`]: ':' }));
66
+ out = '';
67
+ }
68
+ };
69
+ while (mt) {
70
+ const { index, 0: full, 1: key, 2: equal, 3: quoteStart, 4: quoted, 5: quoteEnd, 6: unquoted, } = mt;
71
+ out += attr.slice(lastIndex, index);
72
+ if (/^(?:[\w:]|\0\d+[t!~{}+-]\x7F)(?:[\w:.-]|\0\d+[t!~{}+-]\x7F)*$/u.test((0, string_1.removeComment)(key).trim())) {
73
+ const value = quoted ?? unquoted, quotes = [quoteStart, quoteEnd],
74
+ token = new AttributeToken(type.slice(0, -1), name, key, equal, value, quotes, config, accum);
75
+ insertDirty();
76
+ super.insertAt(token);
77
+ }
78
+ else {
79
+ out += full;
80
+ }
81
+ ({ lastIndex } = regex);
82
+ mt = regex.exec(attr);
83
+ }
84
+ out += attr.slice(lastIndex);
85
+ insertDirty();
86
+ }
87
+ }
88
+ /** @private */
89
+ afterBuild() {
90
+ if (this.type === 'table-attrs') {
91
+ const { parentNode } = this;
92
+ this.setAttribute('name', parentNode?.type === 'td' && parentNode.subtype === 'caption' ? 'caption' : parentNode?.type);
93
+ }
94
+ }
95
+ /**
96
+ * 所有指定属性名的AttributeToken
97
+ * @browser
98
+ * @param key 属性名
99
+ */
100
+ getAttrTokens(key) {
101
+ return typeof key === 'string'
102
+ ? this.childNodes.filter(child => child instanceof AttributeToken && child.name === key.toLowerCase().trim())
103
+ : this.typeError('getAttrTokens', 'String');
104
+ }
105
+ /**
106
+ * 指定属性名的最后一个AttributeToken
107
+ * @browser
108
+ * @param key 属性名
109
+ */
110
+ getAttrToken(key) {
111
+ const tokens = this.getAttrTokens(key);
112
+ return tokens.at(-1);
113
+ }
114
+ /**
115
+ * 获取标签属性
116
+ * @browser
117
+ * @param key 属性键
118
+ */
119
+ getAttr(key) {
120
+ return this.getAttrToken(key)?.getValue();
121
+ }
122
+ /**
123
+ * @override
124
+ * @browser
125
+ */
126
+ lint(start = this.getAbsoluteIndex()) {
127
+ const errors = super.lint(start), { parentNode, length, childNodes } = this, attrs = {}, duplicated = new Set();
128
+ let rect;
129
+ if (parentNode?.type === 'html' && parentNode.closing && this.text().trim()) {
130
+ rect = { start, ...this.getRootNode().posFromIndex(start) };
131
+ errors.push((0, lint_1.generateForSelf)(this, rect, 'attributes of a closing tag'));
132
+ }
133
+ for (let i = 0; i < length; i++) {
134
+ const attr = childNodes[i];
135
+ if (attr instanceof AtomToken && attr.text().trim()) {
136
+ rect ??= { start, ...this.getRootNode().posFromIndex(start) };
137
+ errors.push({
138
+ ...(0, lint_1.generateForChild)(attr, rect, 'containing invalid attribute'),
139
+ excerpt: childNodes.slice(i).map(String).join('').slice(0, 50),
140
+ });
141
+ }
142
+ else if (attr instanceof AttributeToken) {
143
+ const { name } = attr;
144
+ if (Object.hasOwn(attrs, name)) {
145
+ duplicated.add(name);
146
+ attrs[name].push(attr);
147
+ }
148
+ else if (name !== 'class') {
149
+ attrs[name] = [attr];
150
+ }
151
+ }
152
+ }
153
+ if (duplicated.size > 0) {
154
+ rect ??= { start, ...this.getRootNode().posFromIndex(start) };
155
+ for (const key of duplicated) {
156
+ errors.push(...attrs[key].map(attr => (0, lint_1.generateForChild)(attr, rect, Parser.msg('duplicated $1 attribute', key))));
157
+ }
158
+ }
159
+ return errors;
160
+ }
161
+ /**
162
+ * @override
163
+ * @browser
164
+ */
165
+ print() {
166
+ return String(this)
167
+ ? `<span class="wpb-${this.type}">${this.childNodes.map(child => child.print(child instanceof AtomToken && child.text().trim() ? { class: 'hidden' } : undefined)).join('')}</span>`
168
+ : '';
169
+ }
170
+ /** 清理标签属性 */
171
+ sanitize() {
172
+ let dirty = false;
173
+ for (let i = this.length - 1; i >= 0; i--) {
174
+ const child = this.childNodes[i];
175
+ if (child instanceof AtomToken && child.text().trim()) {
176
+ dirty = true;
177
+ this.removeAt(i);
178
+ }
179
+ }
180
+ if (!Parser.running && dirty) {
181
+ Parser.warn(`${this.constructor.name}.sanitize 方法将清理无效属性!`);
182
+ }
183
+ }
184
+ /** @override */
185
+ cloneNode() {
186
+ const cloned = this.cloneChildNodes();
187
+ return Parser.run(() => {
188
+ const token = new AttributesToken(undefined, this.type, this.name, this.getAttribute('config'));
189
+ token.append(...cloned);
190
+ return token;
191
+ });
192
+ }
193
+ /** 所有无效属性 */
194
+ getDirtyAttrs() {
195
+ return this.childNodes.filter(child => child instanceof AtomToken && child.text().trim());
196
+ }
197
+ /**
198
+ * @override
199
+ * @param token 待插入的子节点
200
+ * @param i 插入位置
201
+ * @throws `RangeError` 不是AttributeToken或标签不匹配
202
+ */
203
+ insertAt(token, i = this.length) {
204
+ if (!(token instanceof AttributeToken)) {
205
+ throw new RangeError(`${this.constructor.name}只能插入AttributeToken!`);
206
+ }
207
+ else if (token.type !== this.type.slice(0, -1) || token.tag !== this.name) {
208
+ throw new RangeError(`待插入的AttributeToken只可用于${token.tag}标签!`);
209
+ }
210
+ else if (i === this.length) {
211
+ const { lastChild } = this;
212
+ if (lastChild instanceof AttributeToken) {
213
+ lastChild.close();
214
+ }
215
+ }
216
+ else {
217
+ token.close();
218
+ }
219
+ if (this.closest('parameter')) {
220
+ token.escape();
221
+ }
222
+ super.insertAt(token, i);
223
+ const { previousVisibleSibling, nextVisibleSibling } = token, type = `${this.type.slice(0, -1)}-dirty`, config = this.getAttribute('config'), acceptable = { [`Stage-${stages[this.type]}`]: ':' };
224
+ if (nextVisibleSibling && !/^\s/u.test(String(nextVisibleSibling))) {
225
+ super.insertAt(Parser.run(() => new AtomToken(' ', type, config, [], acceptable)), i + 1);
226
+ }
227
+ if (previousVisibleSibling && !/\s$/u.test(String(previousVisibleSibling))) {
228
+ super.insertAt(Parser.run(() => new AtomToken(' ', type, config, [], acceptable)), i);
229
+ }
230
+ return token;
231
+ }
232
+ /**
233
+ * 设置标签属性
234
+ * @param key 属性键
235
+ * @param value 属性值
236
+ * @throws `RangeError` 扩展标签属性不能包含">"
237
+ * @throws `RangeError` 无效的属性名
238
+ */
239
+ setAttr(key, value) {
240
+ if (typeof key !== 'string' || typeof value !== 'string' && typeof value !== 'boolean') {
241
+ this.typeError('setAttr', 'String', 'Boolean');
242
+ }
243
+ else if (this.type === 'ext-attrs' && typeof value === 'string' && value.includes('>')) {
244
+ throw new RangeError('扩展标签属性不能包含 ">"!');
245
+ }
246
+ const k = key.toLowerCase().trim(), attr = this.getAttrToken(k);
247
+ if (attr) {
248
+ attr.setValue(value);
249
+ return;
250
+ }
251
+ else if (value === false) {
252
+ return;
253
+ }
254
+ const config = this.getAttribute('config'), include = this.getAttribute('include'), parsedKey = this.type === 'ext-attrs'
255
+ ? k
256
+ : Parser.run(() => String(new Token(k, config).parseOnce(0, include).parseOnce()));
257
+ if (!/^(?:[\w:]|\0\d+[t!~{}+-]\x7F)(?:[\w:.-]|\0\d+[t!~{}+-]\x7F)*$/u.test(parsedKey)) {
258
+ throw new RangeError(`无效的属性名:${k}!`);
259
+ }
260
+ const newAttr = Parser.run(() => new AttributeToken(this.type.slice(0, -1), this.name, k, value === true ? '' : '=', value === true ? '' : value, ['"', '"'], config));
261
+ this.insertAt(newAttr);
262
+ }
263
+ /** @private */
264
+ matchesAttr(key, equal, val = '', i) {
265
+ if (!equal) {
266
+ return this.hasAttr(key);
267
+ }
268
+ else if (!this.hasAttr(key)) {
269
+ return equal === '!=';
270
+ }
271
+ const v = (0, string_1.toCase)(val, i), attr = this.getAttr(key), thisVal = (0, string_1.toCase)(attr === true ? '' : attr, i);
272
+ switch (equal) {
273
+ case '~=':
274
+ return attr !== true && thisVal.split(/\s/u).includes(v);
275
+ case '|=': // 允许`val === ''`
276
+ return thisVal === v || thisVal.startsWith(`${v}-`);
277
+ case '^=':
278
+ return attr !== true && thisVal.startsWith(v);
279
+ case '$=':
280
+ return attr !== true && thisVal.endsWith(v);
281
+ case '*=':
282
+ return attr !== true && thisVal.includes(v);
283
+ case '!=':
284
+ return thisVal !== v;
285
+ default: // `=`
286
+ return thisVal === v;
287
+ }
288
+ }
289
+ /**
290
+ * 标签是否具有某属性
291
+ * @param key 属性键
292
+ */
293
+ hasAttr(key) {
294
+ return typeof key === 'string'
295
+ ? this.getAttrTokens(key).length > 0
296
+ : this.typeError('hasAttr', 'String');
297
+ }
298
+ /** 获取全部的标签属性名 */
299
+ getAttrNames() {
300
+ return new Set(this.childNodes.filter(child => child instanceof AttributeToken).map(({ name }) => name));
301
+ }
302
+ /** 标签是否具有任意属性 */
303
+ hasAttrs() {
304
+ return this.getAttrNames().size > 0;
305
+ }
306
+ /** 获取全部标签属性 */
307
+ getAttrs() {
308
+ const attrs = this.childNodes.filter(child => child instanceof AttributeToken);
309
+ return Object.fromEntries(attrs.map(({ name, value }) => [name, value]));
310
+ }
311
+ /**
312
+ * 移除标签属性
313
+ * @param key 属性键
314
+ */
315
+ removeAttr(key) {
316
+ for (const attr of this.getAttrTokens(key)) {
317
+ attr.remove();
318
+ }
319
+ }
320
+ /**
321
+ * 开关标签属性
322
+ * @param key 属性键
323
+ * @param force 强制开启或关闭
324
+ * @throws `RangeError` 不为Boolean类型的属性值
325
+ */
326
+ toggleAttr(key, force) {
327
+ if (typeof key !== 'string') {
328
+ this.typeError('toggleAttr', 'String');
329
+ }
330
+ const k = key.toLowerCase().trim(), attr = this.getAttrToken(k);
331
+ if (attr && attr.getValue() !== true) {
332
+ throw new RangeError(`${k} 属性的值不为 Boolean!`);
333
+ }
334
+ else if (attr) {
335
+ attr.setValue(force === true);
336
+ }
337
+ else if (force !== false) {
338
+ this.setAttr(k, true);
339
+ }
340
+ }
341
+ /**
342
+ * 生成引导空格
343
+ * @param str 属性字符串
344
+ */
345
+ #leadingSpace(str) {
346
+ const { type } = this, leadingRegex = { 'ext-attrs': /^\s/u, 'html-attrs': /^[/\s]/u };
347
+ return str && type !== 'table-attrs' && !leadingRegex[type].test(str) ? ' ' : '';
348
+ }
349
+ /** @override */
350
+ toString(selector) {
351
+ if (this.type === 'table-attrs') {
352
+ (0, string_1.normalizeSpace)(this);
353
+ }
354
+ const str = super.toString(selector);
355
+ return `${this.#leadingSpace(str)}${str}`;
356
+ }
357
+ /** @private */
358
+ getPadding() {
359
+ return this.#leadingSpace(super.toString()).length;
360
+ }
361
+ /** @override */
362
+ text() {
363
+ if (this.type === 'table-attrs') {
364
+ (0, string_1.normalizeSpace)(this);
365
+ }
366
+ const str = (0, string_1.text)(this.childNodes.filter(child => child instanceof AttributeToken), ' ');
367
+ return `${this.#leadingSpace(str)}${str}`;
368
+ }
369
+ }
370
+ Parser.classes['AttributesToken'] = __filename;
371
+ module.exports = AttributesToken;
@@ -1,103 +1,77 @@
1
- export = ConverterToken;
1
+ import * as Parser from '../index';
2
+ import Token = require('.');
3
+ import ConverterFlagsToken = require('./converterFlags');
4
+ import ConverterRuleToken = require('./converterRule');
2
5
  /**
3
6
  * 转换
4
7
  * @classdesc `{childNodes: [ConverterFlagsToken, ...ConverterRuleToken]}`
5
8
  */
6
- declare class ConverterToken extends Token {
7
- /**
8
- * @param {string[]} flags 转换类型标记
9
- * @param {string[]} rules 转换规则
10
- * @param {import('../../typings/token').accum} accum
11
- */
12
- constructor(flags: string[], rules: string[], config?: import("../../typings/token").ParserConfig, accum?: import('../../typings/token').accum);
13
- /**
14
- * 是否无转换
15
- * @this {ConverterToken & {lastChild: ConverterRuleToken}}
16
- */
9
+ declare abstract class ConverterToken extends Token {
10
+ /** @browser */
11
+ readonly type = "converter";
12
+ childNodes: [ConverterFlagsToken, ...ConverterRuleToken[]];
13
+ abstract get children(): [ConverterFlagsToken, ...ConverterRuleToken[]];
14
+ abstract get firstChild(): ConverterFlagsToken;
15
+ abstract get firstElementChild(): ConverterFlagsToken;
16
+ abstract get lastChild(): ConverterFlagsToken | ConverterRuleToken;
17
+ abstract get lastElementChild(): ConverterFlagsToken | ConverterRuleToken;
18
+ /** 是否不转换 */
17
19
  get noConvert(): boolean;
18
- /** flags */
20
+ /** 所有转换类型标记 */
19
21
  get flags(): Set<string>;
20
22
  /**
21
- * @override
22
- * @param {string} selector
23
- * @returns {string}
23
+ * @browser
24
+ * @param flags 转换类型标记
25
+ * @param rules 转换规则
24
26
  */
25
- override toString(selector: string): string;
27
+ constructor(flags: string[], rules: [string, ...string[]], config?: Parser.Config, accum?: Token[]);
26
28
  /**
27
29
  * @override
28
- * @returns {string}
30
+ * @browser
29
31
  */
30
- override text(): string;
32
+ toString(selector?: string): string;
31
33
  /**
32
34
  * @override
33
- * @param {number} i 子节点位置
35
+ * @browser
34
36
  */
35
- override getGaps(i?: number): 1 | 0;
36
- /** @override */
37
- override print(): string;
38
- /** @override */
39
- override cloneNode(): ConverterToken;
37
+ text(): string;
40
38
  /**
41
- * 获取所有转换类型标记
42
- * @this {{firstChild: ConverterFlagsToken}}
43
- */
44
- getAllFlags(this: {
45
- firstChild: ConverterFlagsToken;
46
- }): Set<string>;
47
- /**
48
- * 获取有效的转换类型标记
49
- * @this {{firstChild: ConverterFlagsToken}}
50
- */
51
- getEffectiveFlags(this: {
52
- firstChild: ConverterFlagsToken;
53
- }): Set<string>;
54
- /**
55
- * 获取未知的转换类型标记
56
- * @this {{firstChild: ConverterFlagsToken}}
39
+ * @override
40
+ * @browser
57
41
  */
58
- getUnknownFlags(this: {
59
- firstChild: ConverterFlagsToken;
60
- }): Set<string>;
42
+ print(): string;
43
+ /** @override */
44
+ cloneNode(): this;
45
+ /** 获取所有转换类型标记 */
46
+ getAllFlags(): Set<string>;
47
+ /** 获取有效的转换类型标记 */
48
+ getEffectiveFlags(): Set<string>;
49
+ /** 获取未知的转换类型标记 */
50
+ getUnknownFlags(): Set<string>;
61
51
  /**
62
52
  * 是否具有某转换类型标记
63
- * @this {{firstChild: ConverterFlagsToken}}
64
- * @param {string} flag 转换类型标记
53
+ * @param flag 转换类型标记
65
54
  */
66
- hasFlag(this: {
67
- firstChild: ConverterFlagsToken;
68
- }, flag: string): boolean;
55
+ hasFlag(flag: string): boolean;
69
56
  /**
70
57
  * 是否具有某有效的转换类型标记
71
- * @this {{firstChild: ConverterFlagsToken}}
72
- * @param {string} flag 转换类型标记
58
+ * @param flag 转换类型标记
73
59
  */
74
- hasEffectiveFlag(this: {
75
- firstChild: ConverterFlagsToken;
76
- }, flag: string): boolean;
60
+ hasEffectiveFlag(flag: string): boolean;
77
61
  /**
78
62
  * 移除转换类型标记
79
- * @this {{firstChild: ConverterFlagsToken}}
80
- * @param {string} flag 转换类型标记
63
+ * @param flag 转换类型标记
81
64
  */
82
- removeFlag(this: {
83
- firstChild: ConverterFlagsToken;
84
- }, flag: string): void;
65
+ removeFlag(flag: string): void;
85
66
  /**
86
67
  * 设置转换类型标记
87
- * @this {{firstChild: ConverterFlagsToken}}
88
- * @param {string} flag 转换类型标记
68
+ * @param flag 转换类型标记
89
69
  */
90
- setFlag(this: {
91
- firstChild: ConverterFlagsToken;
92
- }, flag: string): void;
70
+ setFlag(flag: string): void;
93
71
  /**
94
72
  * 开关某转换类型标记
95
- * @this {{firstChild: ConverterFlagsToken}}
96
- * @param {string} flag 转换类型标记
73
+ * @param flag 转换类型标记
97
74
  */
98
- toggleFlag(this: {
99
- firstChild: ConverterFlagsToken;
100
- }, flag: string): void;
75
+ toggleFlag(flag: string): void;
101
76
  }
102
- import Token = require(".");
103
- import ConverterFlagsToken = require("./converterFlags");
77
+ export = ConverterToken;
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ const string_1 = require("../util/string");
3
+ const Parser = require("../index");
4
+ const Token = require(".");
5
+ const ConverterFlagsToken = require("./converterFlags");
6
+ const ConverterRuleToken = require("./converterRule");
7
+ /**
8
+ * 转换
9
+ * @classdesc `{childNodes: [ConverterFlagsToken, ...ConverterRuleToken]}`
10
+ */
11
+ class ConverterToken extends Token {
12
+ /** @browser */
13
+ type = 'converter';
14
+ /** 是否不转换 */
15
+ get noConvert() {
16
+ return this.hasFlag('R') || this.length === 2 && this.lastChild.length === 1;
17
+ }
18
+ /** 所有转换类型标记 */
19
+ get flags() {
20
+ return this.getAllFlags();
21
+ }
22
+ /**
23
+ * @browser
24
+ * @param flags 转换类型标记
25
+ * @param rules 转换规则
26
+ */
27
+ constructor(flags, rules, config = Parser.getConfig(), accum = []) {
28
+ super(undefined, config, true, accum);
29
+ this.append(new ConverterFlagsToken(flags, config, accum));
30
+ const [firstRule] = rules, hasColon = firstRule.includes(':'),
31
+ firstRuleToken = new ConverterRuleToken(firstRule, hasColon, config, accum);
32
+ if (hasColon && firstRuleToken.length === 1) {
33
+ this.insertAt(new ConverterRuleToken(rules.join(';'), false, config, accum));
34
+ }
35
+ else {
36
+ this.append(firstRuleToken,
37
+ ...rules.slice(1).map(rule => new ConverterRuleToken(rule, true, config, accum)));
38
+ }
39
+ this.protectChildren(0);
40
+ }
41
+ /**
42
+ * @override
43
+ * @browser
44
+ */
45
+ toString(selector) {
46
+ const { childNodes: [flags, ...rules] } = this;
47
+ return selector && this.matches(selector)
48
+ ? ''
49
+ : `-{${flags.toString(selector)}${flags.length > 0 ? '|' : ''}${rules.map(rule => rule.toString(selector)).join(';')}}-`;
50
+ }
51
+ /**
52
+ * @override
53
+ * @browser
54
+ */
55
+ text() {
56
+ const { childNodes: [flags, ...rules] } = this;
57
+ return `-{${flags.text()}|${(0, string_1.text)(rules, ';')}}-`;
58
+ }
59
+ /** @private */
60
+ getPadding() {
61
+ return 2;
62
+ }
63
+ /** @private */
64
+ getGaps(i = 0) {
65
+ const j = i < 0 ? i + this.length : i;
66
+ return j || this.firstChild.length > 0 ? 1 : 0;
67
+ }
68
+ /**
69
+ * @override
70
+ * @browser
71
+ */
72
+ print() {
73
+ const { childNodes: [flags, ...rules] } = this;
74
+ return `<span class="wpb-converter">-{${flags.print()}${flags.length > 0 ? '|' : ''}${(0, string_1.print)(rules, { sep: ';' })}}-</span>`;
75
+ }
76
+ /** @override */
77
+ cloneNode() {
78
+ const [flags, ...rules] = this.cloneChildNodes();
79
+ return Parser.run(() => {
80
+ const token = new ConverterToken([], [], this.getAttribute('config'));
81
+ token.firstChild.safeReplaceWith(flags);
82
+ token.append(...rules);
83
+ return token;
84
+ });
85
+ }
86
+ /** 获取所有转换类型标记 */
87
+ getAllFlags() {
88
+ return this.firstChild.getAllFlags();
89
+ }
90
+ /** 获取有效的转换类型标记 */
91
+ getEffectiveFlags() {
92
+ return this.firstChild.getEffectiveFlags();
93
+ }
94
+ /** 获取未知的转换类型标记 */
95
+ getUnknownFlags() {
96
+ return this.firstChild.getUnknownFlags();
97
+ }
98
+ /**
99
+ * 是否具有某转换类型标记
100
+ * @param flag 转换类型标记
101
+ */
102
+ hasFlag(flag) {
103
+ return this.firstChild.hasFlag(flag);
104
+ }
105
+ /**
106
+ * 是否具有某有效的转换类型标记
107
+ * @param flag 转换类型标记
108
+ */
109
+ hasEffectiveFlag(flag) {
110
+ return this.firstChild.hasEffectiveFlag(flag);
111
+ }
112
+ /**
113
+ * 移除转换类型标记
114
+ * @param flag 转换类型标记
115
+ */
116
+ removeFlag(flag) {
117
+ this.firstChild.removeFlag(flag);
118
+ }
119
+ /**
120
+ * 设置转换类型标记
121
+ * @param flag 转换类型标记
122
+ */
123
+ setFlag(flag) {
124
+ this.firstChild.setFlag(flag);
125
+ }
126
+ /**
127
+ * 开关某转换类型标记
128
+ * @param flag 转换类型标记
129
+ */
130
+ toggleFlag(flag) {
131
+ this.firstChild.toggleFlag(flag);
132
+ }
133
+ }
134
+ Parser.classes['ConverterToken'] = __filename;
135
+ module.exports = ConverterToken;