@marko/language-server 1.0.20 → 1.1.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/dist/index.js +887 -126
- package/dist/index.js.map +4 -4
- package/dist/index.mjs +835 -72
- package/dist/index.mjs.map +4 -4
- package/dist/service/html/axe-rules/axe-rules.d.ts +511 -0
- package/dist/service/html/axe-rules/generate-axe-rules.d.ts +1 -0
- package/dist/service/html/axe-rules/separated-rules.d.ts +48 -0
- package/dist/service/html/index.d.ts +3 -0
- package/dist/service/index.d.ts +8 -0
- package/dist/utils/text-documents.d.ts +5 -2
- package/package.json +9 -7
package/dist/index.js
CHANGED
|
@@ -25,7 +25,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
25
25
|
// src/index.ts
|
|
26
26
|
var import_util2 = require("util");
|
|
27
27
|
var import_node = require("vscode-languageserver/node");
|
|
28
|
-
var
|
|
28
|
+
var import_language_tools17 = require("@marko/language-tools");
|
|
29
29
|
|
|
30
30
|
// src/utils/file.ts
|
|
31
31
|
var import_path = __toESM(require("path"));
|
|
@@ -144,67 +144,65 @@ function exists(uri) {
|
|
|
144
144
|
function isOpen(doc) {
|
|
145
145
|
return openDocs.has(doc);
|
|
146
146
|
}
|
|
147
|
-
function
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
147
|
+
function doOpen(params) {
|
|
148
|
+
const ref = params.textDocument;
|
|
149
|
+
const existingDoc = docs.get(ref.uri);
|
|
150
|
+
projectVersion++;
|
|
151
|
+
if (existingDoc) {
|
|
152
|
+
if (existingDoc.version === ref.version) {
|
|
153
|
+
openDocs.add(existingDoc);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
openDocs.delete(existingDoc);
|
|
157
|
+
docs.delete(ref.uri);
|
|
158
|
+
}
|
|
159
|
+
const newDoc = import_vscode_languageserver_textdocument.TextDocument.create(
|
|
160
|
+
ref.uri,
|
|
161
|
+
ref.languageId,
|
|
162
|
+
ref.version,
|
|
163
|
+
ref.text
|
|
164
|
+
);
|
|
165
|
+
openDocs.add(newDoc);
|
|
166
|
+
fileExists.set(ref.uri, true);
|
|
167
|
+
docs.set(ref.uri, newDoc);
|
|
168
|
+
}
|
|
169
|
+
function doChange(params) {
|
|
170
|
+
const ref = params.textDocument;
|
|
171
|
+
const changes = params.contentChanges;
|
|
172
|
+
const doc = docs.get(ref.uri);
|
|
173
|
+
if (changes.length > 0 && ref.version != null && doc) {
|
|
174
|
+
import_vscode_languageserver_textdocument.TextDocument.update(doc, changes, ref.version);
|
|
175
|
+
emitFileChange(doc);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
function doClose(params) {
|
|
179
|
+
const ref = params.textDocument;
|
|
180
|
+
const doc = docs.get(ref.uri);
|
|
181
|
+
if (doc) {
|
|
151
182
|
projectVersion++;
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
openDocs.add(existingDoc);
|
|
155
|
-
return;
|
|
156
|
-
}
|
|
157
|
-
openDocs.delete(existingDoc);
|
|
183
|
+
openDocs.delete(doc);
|
|
184
|
+
if (import_vscode_uri2.URI.parse(ref.uri).scheme !== "file") {
|
|
158
185
|
docs.delete(ref.uri);
|
|
159
186
|
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
if (changes.length > 0 && ref.version != null && doc) {
|
|
175
|
-
import_vscode_languageserver_textdocument.TextDocument.update(doc, changes, ref.version);
|
|
176
|
-
emitFileChange(doc);
|
|
177
|
-
}
|
|
178
|
-
});
|
|
179
|
-
connection4.onDidCloseTextDocument((params) => {
|
|
180
|
-
const ref = params.textDocument;
|
|
181
|
-
const doc = docs.get(ref.uri);
|
|
182
|
-
if (doc) {
|
|
183
|
-
projectVersion++;
|
|
184
|
-
openDocs.delete(doc);
|
|
185
|
-
if (import_vscode_uri2.URI.parse(ref.uri).scheme !== "file") {
|
|
186
|
-
docs.delete(ref.uri);
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
});
|
|
190
|
-
connection4.onDidChangeWatchedFiles(async (params) => {
|
|
191
|
-
for (const change of params.changes) {
|
|
192
|
-
switch (change.type) {
|
|
193
|
-
case import_vscode_languageserver.FileChangeType.Created:
|
|
194
|
-
fileExists.set(change.uri, true);
|
|
195
|
-
break;
|
|
196
|
-
case import_vscode_languageserver.FileChangeType.Deleted:
|
|
197
|
-
case import_vscode_languageserver.FileChangeType.Changed: {
|
|
198
|
-
fileExists.set(change.uri, change.type === import_vscode_languageserver.FileChangeType.Changed);
|
|
199
|
-
const doc = docs.get(change.uri);
|
|
200
|
-
if (doc && !openDocs.has(doc)) {
|
|
201
|
-
docs.delete(change.uri);
|
|
202
|
-
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
function doChangeWatchedFiles(params) {
|
|
190
|
+
for (const change of params.changes) {
|
|
191
|
+
switch (change.type) {
|
|
192
|
+
case import_vscode_languageserver.FileChangeType.Created:
|
|
193
|
+
fileExists.set(change.uri, true);
|
|
194
|
+
break;
|
|
195
|
+
case import_vscode_languageserver.FileChangeType.Deleted:
|
|
196
|
+
case import_vscode_languageserver.FileChangeType.Changed: {
|
|
197
|
+
fileExists.set(change.uri, change.type === import_vscode_languageserver.FileChangeType.Changed);
|
|
198
|
+
const doc = docs.get(change.uri);
|
|
199
|
+
if (doc && !openDocs.has(doc)) {
|
|
200
|
+
docs.delete(change.uri);
|
|
203
201
|
}
|
|
204
202
|
}
|
|
205
203
|
}
|
|
206
|
-
|
|
207
|
-
|
|
204
|
+
}
|
|
205
|
+
emitFileChange(void 0);
|
|
208
206
|
}
|
|
209
207
|
function getLanguageId(uri) {
|
|
210
208
|
const ext = uri.slice(uri.lastIndexOf(".") + 1);
|
|
@@ -229,6 +227,7 @@ function emitFileChange(doc) {
|
|
|
229
227
|
}
|
|
230
228
|
|
|
231
229
|
// src/utils/workspace.ts
|
|
230
|
+
var isInitialized = false;
|
|
232
231
|
var connection;
|
|
233
232
|
var configChangeHandlers = /* @__PURE__ */ new Set();
|
|
234
233
|
var settingsCache = /* @__PURE__ */ new Map();
|
|
@@ -246,11 +245,15 @@ async function getConfig(section) {
|
|
|
246
245
|
function onConfigChange(handler) {
|
|
247
246
|
configChangeHandlers.add(handler);
|
|
248
247
|
}
|
|
249
|
-
function
|
|
248
|
+
function setup(_) {
|
|
250
249
|
connection = _;
|
|
251
250
|
connection.onDidChangeConfiguration(() => {
|
|
252
|
-
|
|
253
|
-
|
|
251
|
+
if (isInitialized) {
|
|
252
|
+
settingsCache.clear();
|
|
253
|
+
emitConfigChange();
|
|
254
|
+
} else {
|
|
255
|
+
isInitialized = true;
|
|
256
|
+
}
|
|
254
257
|
});
|
|
255
258
|
}
|
|
256
259
|
function emitConfigChange() {
|
|
@@ -263,7 +266,7 @@ function emitConfigChange() {
|
|
|
263
266
|
var import_util = require("util");
|
|
264
267
|
var connection2;
|
|
265
268
|
var previousMessagesByType = /* @__PURE__ */ new Map();
|
|
266
|
-
function
|
|
269
|
+
function setup2(_) {
|
|
267
270
|
connection2 = _;
|
|
268
271
|
}
|
|
269
272
|
function displayError(data) {
|
|
@@ -288,8 +291,752 @@ function display(type, data) {
|
|
|
288
291
|
// src/service/index.ts
|
|
289
292
|
var import_vscode_languageserver12 = require("vscode-languageserver");
|
|
290
293
|
|
|
294
|
+
// src/service/html/index.ts
|
|
295
|
+
var import_axe_core = __toESM(require("axe-core"));
|
|
296
|
+
var import_language_tools2 = require("@marko/language-tools");
|
|
297
|
+
var import_jsdom = require("jsdom");
|
|
298
|
+
|
|
299
|
+
// src/service/html/axe-rules/axe-rules.ts
|
|
300
|
+
var keyboard = {
|
|
301
|
+
/**
|
|
302
|
+
* - Ensures every accesskey attribute value is unique
|
|
303
|
+
* - accesskey attribute value should be unique ([url](https://dequeuniversity.com/rules/axe/4.4/accesskeys?application=axeAPI))
|
|
304
|
+
*/
|
|
305
|
+
accesskeys: "accesskeys",
|
|
306
|
+
/**
|
|
307
|
+
* - Ensures each page has at least one mechanism for a user to bypass navigation and jump straight to the content
|
|
308
|
+
* - Page must have means to bypass repeated blocks ([url](https://dequeuniversity.com/rules/axe/4.4/bypass?application=axeAPI))
|
|
309
|
+
*/
|
|
310
|
+
bypass: "bypass",
|
|
311
|
+
/**
|
|
312
|
+
* - Ensures elements in the focus order have a role appropriate for interactive content
|
|
313
|
+
* - Elements in the focus order should have an appropriate role ([url](https://dequeuniversity.com/rules/axe/4.4/focus-order-semantics?application=axeAPI))
|
|
314
|
+
*/
|
|
315
|
+
focusOrderSemantics: "focus-order-semantics",
|
|
316
|
+
/**
|
|
317
|
+
* - Ensures `<frame>` and `<iframe>` elements with focusable content do not have tabindex=-1
|
|
318
|
+
* - Frames with focusable content must not have tabindex=-1 ([url](https://dequeuniversity.com/rules/axe/4.4/frame-focusable-content?application=axeAPI))
|
|
319
|
+
*/
|
|
320
|
+
frameFocusableContent: "frame-focusable-content",
|
|
321
|
+
/**
|
|
322
|
+
* - Ensures interactive controls are not nested as they are not always announced by screen readers or can cause focus problems for assistive technologies
|
|
323
|
+
* - Interactive controls must not be nested ([url](https://dequeuniversity.com/rules/axe/4.4/nested-interactive?application=axeAPI))
|
|
324
|
+
*/
|
|
325
|
+
nestedInteractive: "nested-interactive",
|
|
326
|
+
/**
|
|
327
|
+
* - Ensures all page content is contained by landmarks
|
|
328
|
+
* - All page content should be contained by landmarks ([url](https://dequeuniversity.com/rules/axe/4.4/region?application=axeAPI))
|
|
329
|
+
*/
|
|
330
|
+
region: "region",
|
|
331
|
+
/**
|
|
332
|
+
* - Ensure elements that have scrollable content are accessible by keyboard
|
|
333
|
+
* - Scrollable region must have keyboard access ([url](https://dequeuniversity.com/rules/axe/4.4/scrollable-region-focusable?application=axeAPI))
|
|
334
|
+
*/
|
|
335
|
+
scrollableRegionFocusable: "scrollable-region-focusable",
|
|
336
|
+
/**
|
|
337
|
+
* - Ensure all skip links have a focusable target
|
|
338
|
+
* - The skip-link target should exist and be focusable ([url](https://dequeuniversity.com/rules/axe/4.4/skip-link?application=axeAPI))
|
|
339
|
+
*/
|
|
340
|
+
skipLink: "skip-link",
|
|
341
|
+
/**
|
|
342
|
+
* - Ensures tabindex attribute values are not greater than 0
|
|
343
|
+
* - Elements should not have tabindex greater than zero ([url](https://dequeuniversity.com/rules/axe/4.4/tabindex?application=axeAPI))
|
|
344
|
+
*/
|
|
345
|
+
tabindex: "tabindex"
|
|
346
|
+
};
|
|
347
|
+
var textAlternatives = {
|
|
348
|
+
/**
|
|
349
|
+
* - Ensures `<area>` elements of image maps have alternate text
|
|
350
|
+
* - Active `<area>` elements must have alternate text ([url](https://dequeuniversity.com/rules/axe/4.4/area-alt?application=axeAPI))
|
|
351
|
+
*/
|
|
352
|
+
areaAlt: "area-alt",
|
|
353
|
+
/**
|
|
354
|
+
* - Ensures each HTML document contains a non-empty `<title>` element
|
|
355
|
+
* - Documents must have `<title>` element to aid in navigation ([url](https://dequeuniversity.com/rules/axe/4.4/document-title?application=axeAPI))
|
|
356
|
+
*/
|
|
357
|
+
documentTitle: "document-title",
|
|
358
|
+
/**
|
|
359
|
+
* - Ensures `<iframe>` and `<frame>` elements contain a unique title attribute
|
|
360
|
+
* - Frames should have a unique title attribute ([url](https://dequeuniversity.com/rules/axe/4.4/frame-title-unique?application=axeAPI))
|
|
361
|
+
*/
|
|
362
|
+
frameTitleUnique: "frame-title-unique",
|
|
363
|
+
/**
|
|
364
|
+
* - Ensures `<iframe>` and `<frame>` elements have an accessible name
|
|
365
|
+
* - Frames must have an accessible name ([url](https://dequeuniversity.com/rules/axe/4.4/frame-title?application=axeAPI))
|
|
366
|
+
*/
|
|
367
|
+
frameTitle: "frame-title",
|
|
368
|
+
/**
|
|
369
|
+
* - Ensures `<img>` elements have alternate text or a role of none or presentation
|
|
370
|
+
* - Images must have alternate text ([url](https://dequeuniversity.com/rules/axe/4.4/image-alt?application=axeAPI))
|
|
371
|
+
*/
|
|
372
|
+
imageAlt: "image-alt",
|
|
373
|
+
/**
|
|
374
|
+
* - Ensure image alternative is not repeated as text
|
|
375
|
+
* - Alternative text of images should not be repeated as text ([url](https://dequeuniversity.com/rules/axe/4.4/image-redundant-alt?application=axeAPI))
|
|
376
|
+
*/
|
|
377
|
+
imageRedundantAlt: "image-redundant-alt",
|
|
378
|
+
/**
|
|
379
|
+
* - Ensures `<input type="image">` elements have alternate text
|
|
380
|
+
* - Image buttons must have alternate text ([url](https://dequeuniversity.com/rules/axe/4.4/input-image-alt?application=axeAPI))
|
|
381
|
+
*/
|
|
382
|
+
inputImageAlt: "input-image-alt",
|
|
383
|
+
/**
|
|
384
|
+
* - Ensures `<object>` elements have alternate text
|
|
385
|
+
* - `<object>` elements must have alternate text ([url](https://dequeuniversity.com/rules/axe/4.4/object-alt?application=axeAPI))
|
|
386
|
+
*/
|
|
387
|
+
objectAlt: "object-alt",
|
|
388
|
+
/**
|
|
389
|
+
* - Ensures [role='img'] elements have alternate text
|
|
390
|
+
* - [role='img'] elements must have an alternative text ([url](https://dequeuniversity.com/rules/axe/4.4/role-img-alt?application=axeAPI))
|
|
391
|
+
*/
|
|
392
|
+
roleImgAlt: "role-img-alt",
|
|
393
|
+
/**
|
|
394
|
+
* - Ensures that server-side image maps are not used
|
|
395
|
+
* - Server-side image maps must not be used ([url](https://dequeuniversity.com/rules/axe/4.4/server-side-image-map?application=axeAPI))
|
|
396
|
+
*/
|
|
397
|
+
serverSideImageMap: "server-side-image-map",
|
|
398
|
+
/**
|
|
399
|
+
* - Ensures `<svg>` elements with an img, graphics-document or graphics-symbol role have an accessible text
|
|
400
|
+
* - `<svg>` elements with an img role must have an alternative text ([url](https://dequeuniversity.com/rules/axe/4.4/svg-img-alt?application=axeAPI))
|
|
401
|
+
*/
|
|
402
|
+
svgImgAlt: "svg-img-alt",
|
|
403
|
+
/**
|
|
404
|
+
* - Ensures `<video>` elements have captions
|
|
405
|
+
* - `<video>` elements must have captions ([url](https://dequeuniversity.com/rules/axe/4.4/video-caption?application=axeAPI))
|
|
406
|
+
*/
|
|
407
|
+
videoCaption: "video-caption"
|
|
408
|
+
};
|
|
409
|
+
var aria = {
|
|
410
|
+
/**
|
|
411
|
+
* - Ensures ARIA attributes are allowed for an element's role
|
|
412
|
+
* - Elements must only use allowed ARIA attributes ([url](https://dequeuniversity.com/rules/axe/4.4/aria-allowed-attr?application=axeAPI))
|
|
413
|
+
*/
|
|
414
|
+
ariaAllowedAttr: "aria-allowed-attr",
|
|
415
|
+
/**
|
|
416
|
+
* - Ensures role attribute has an appropriate value for the element
|
|
417
|
+
* - ARIA role should be appropriate for the element ([url](https://dequeuniversity.com/rules/axe/4.4/aria-allowed-role?application=axeAPI))
|
|
418
|
+
*/
|
|
419
|
+
ariaAllowedRole: "aria-allowed-role",
|
|
420
|
+
/**
|
|
421
|
+
* - Ensures every ARIA button, link and menuitem has an accessible name
|
|
422
|
+
* - ARIA commands must have an accessible name ([url](https://dequeuniversity.com/rules/axe/4.4/aria-command-name?application=axeAPI))
|
|
423
|
+
*/
|
|
424
|
+
ariaCommandName: "aria-command-name",
|
|
425
|
+
/**
|
|
426
|
+
* - Ensures every ARIA dialog and alertdialog node has an accessible name
|
|
427
|
+
* - ARIA dialog and alertdialog nodes should have an accessible name ([url](https://dequeuniversity.com/rules/axe/4.4/aria-dialog-name?application=axeAPI))
|
|
428
|
+
*/
|
|
429
|
+
ariaDialogName: "aria-dialog-name",
|
|
430
|
+
/**
|
|
431
|
+
* - Ensures aria-hidden='true' is not present on the document body.
|
|
432
|
+
* - aria-hidden='true' must not be present on the document body ([url](https://dequeuniversity.com/rules/axe/4.4/aria-hidden-body?application=axeAPI))
|
|
433
|
+
*/
|
|
434
|
+
ariaHiddenBody: "aria-hidden-body",
|
|
435
|
+
/**
|
|
436
|
+
* - Ensures every ARIA input field has an accessible name
|
|
437
|
+
* - ARIA input fields must have an accessible name ([url](https://dequeuniversity.com/rules/axe/4.4/aria-input-field-name?application=axeAPI))
|
|
438
|
+
*/
|
|
439
|
+
ariaInputFieldName: "aria-input-field-name",
|
|
440
|
+
/**
|
|
441
|
+
* - Ensures every ARIA meter node has an accessible name
|
|
442
|
+
* - ARIA meter nodes must have an accessible name ([url](https://dequeuniversity.com/rules/axe/4.4/aria-meter-name?application=axeAPI))
|
|
443
|
+
*/
|
|
444
|
+
ariaMeterName: "aria-meter-name",
|
|
445
|
+
/**
|
|
446
|
+
* - Ensures every ARIA progressbar node has an accessible name
|
|
447
|
+
* - ARIA progressbar nodes must have an accessible name ([url](https://dequeuniversity.com/rules/axe/4.4/aria-progressbar-name?application=axeAPI))
|
|
448
|
+
*/
|
|
449
|
+
ariaProgressbarName: "aria-progressbar-name",
|
|
450
|
+
/**
|
|
451
|
+
* - Ensures elements with ARIA roles have all required ARIA attributes
|
|
452
|
+
* - Required ARIA attributes must be provided ([url](https://dequeuniversity.com/rules/axe/4.4/aria-required-attr?application=axeAPI))
|
|
453
|
+
*/
|
|
454
|
+
ariaRequiredAttr: "aria-required-attr",
|
|
455
|
+
/**
|
|
456
|
+
* - Ensures elements with an ARIA role that require child roles contain them
|
|
457
|
+
* - Certain ARIA roles must contain particular children ([url](https://dequeuniversity.com/rules/axe/4.4/aria-required-children?application=axeAPI))
|
|
458
|
+
*/
|
|
459
|
+
ariaRequiredChildren: "aria-required-children",
|
|
460
|
+
/**
|
|
461
|
+
* - Ensures elements with an ARIA role that require parent roles are contained by them
|
|
462
|
+
* - Certain ARIA roles must be contained by particular parents ([url](https://dequeuniversity.com/rules/axe/4.4/aria-required-parent?application=axeAPI))
|
|
463
|
+
*/
|
|
464
|
+
ariaRequiredParent: "aria-required-parent",
|
|
465
|
+
/**
|
|
466
|
+
* - Ensure aria-roledescription is only used on elements with an implicit or explicit role
|
|
467
|
+
* - aria-roledescription must be on elements with a semantic role ([url](https://dequeuniversity.com/rules/axe/4.4/aria-roledescription?application=axeAPI))
|
|
468
|
+
*/
|
|
469
|
+
ariaRoledescription: "aria-roledescription",
|
|
470
|
+
/**
|
|
471
|
+
* - Ensures all elements with a role attribute use a valid value
|
|
472
|
+
* - ARIA roles used must conform to valid values ([url](https://dequeuniversity.com/rules/axe/4.4/aria-roles?application=axeAPI))
|
|
473
|
+
*/
|
|
474
|
+
ariaRoles: "aria-roles",
|
|
475
|
+
/**
|
|
476
|
+
* - Ensures "role=text" is used on elements with no focusable descendants
|
|
477
|
+
* - "role=text" should have no focusable descendants ([url](https://dequeuniversity.com/rules/axe/4.4/aria-text?application=axeAPI))
|
|
478
|
+
*/
|
|
479
|
+
ariaText: "aria-text",
|
|
480
|
+
/**
|
|
481
|
+
* - Ensures every ARIA toggle field has an accessible name
|
|
482
|
+
* - ARIA toggle fields must have an accessible name ([url](https://dequeuniversity.com/rules/axe/4.4/aria-toggle-field-name?application=axeAPI))
|
|
483
|
+
*/
|
|
484
|
+
ariaToggleFieldName: "aria-toggle-field-name",
|
|
485
|
+
/**
|
|
486
|
+
* - Ensures every ARIA tooltip node has an accessible name
|
|
487
|
+
* - ARIA tooltip nodes must have an accessible name ([url](https://dequeuniversity.com/rules/axe/4.4/aria-tooltip-name?application=axeAPI))
|
|
488
|
+
*/
|
|
489
|
+
ariaTooltipName: "aria-tooltip-name",
|
|
490
|
+
/**
|
|
491
|
+
* - Ensures every ARIA treeitem node has an accessible name
|
|
492
|
+
* - ARIA treeitem nodes should have an accessible name ([url](https://dequeuniversity.com/rules/axe/4.4/aria-treeitem-name?application=axeAPI))
|
|
493
|
+
*/
|
|
494
|
+
ariaTreeitemName: "aria-treeitem-name",
|
|
495
|
+
/**
|
|
496
|
+
* - Ensures all ARIA attributes have valid values
|
|
497
|
+
* - ARIA attributes must conform to valid values ([url](https://dequeuniversity.com/rules/axe/4.4/aria-valid-attr-value?application=axeAPI))
|
|
498
|
+
*/
|
|
499
|
+
ariaValidAttrValue: "aria-valid-attr-value",
|
|
500
|
+
/**
|
|
501
|
+
* - Ensures attributes that begin with aria- are valid ARIA attributes
|
|
502
|
+
* - ARIA attributes must conform to valid names ([url](https://dequeuniversity.com/rules/axe/4.4/aria-valid-attr?application=axeAPI))
|
|
503
|
+
*/
|
|
504
|
+
ariaValidAttr: "aria-valid-attr",
|
|
505
|
+
/**
|
|
506
|
+
* - Ensures table headers have discernible text
|
|
507
|
+
* - Table header text must not be empty ([url](https://dequeuniversity.com/rules/axe/4.4/empty-table-header?application=axeAPI))
|
|
508
|
+
*/
|
|
509
|
+
emptyTableHeader: "empty-table-header",
|
|
510
|
+
/**
|
|
511
|
+
* - Flags elements whose role is none or presentation and which cause the role conflict resolution to trigger.
|
|
512
|
+
* - Elements of role none or presentation should be flagged ([url](https://dequeuniversity.com/rules/axe/4.4/presentation-role-conflict?application=axeAPI))
|
|
513
|
+
*/
|
|
514
|
+
presentationRoleConflict: "presentation-role-conflict"
|
|
515
|
+
};
|
|
516
|
+
var nameRoleValue = {
|
|
517
|
+
/**
|
|
518
|
+
* - Ensures aria-hidden elements are not focusable nor contain focusable elements
|
|
519
|
+
* - ARIA hidden element must not be focusable or contain focusable elements ([url](https://dequeuniversity.com/rules/axe/4.4/aria-hidden-focus?application=axeAPI))
|
|
520
|
+
*/
|
|
521
|
+
ariaHiddenFocus: "aria-hidden-focus",
|
|
522
|
+
/**
|
|
523
|
+
* - Ensures buttons have discernible text
|
|
524
|
+
* - Buttons must have discernible text ([url](https://dequeuniversity.com/rules/axe/4.4/button-name?application=axeAPI))
|
|
525
|
+
*/
|
|
526
|
+
buttonName: "button-name",
|
|
527
|
+
/**
|
|
528
|
+
* - Ensures headings have discernible text
|
|
529
|
+
* - Headings should not be empty ([url](https://dequeuniversity.com/rules/axe/4.4/empty-heading?application=axeAPI))
|
|
530
|
+
*/
|
|
531
|
+
emptyHeading: "empty-heading",
|
|
532
|
+
/**
|
|
533
|
+
* - Ensures input buttons have discernible text
|
|
534
|
+
* - Input buttons must have discernible text ([url](https://dequeuniversity.com/rules/axe/4.4/input-button-name?application=axeAPI))
|
|
535
|
+
*/
|
|
536
|
+
inputButtonName: "input-button-name",
|
|
537
|
+
/**
|
|
538
|
+
* - Ensures links have discernible text
|
|
539
|
+
* - Links must have discernible text ([url](https://dequeuniversity.com/rules/axe/4.4/link-name?application=axeAPI))
|
|
540
|
+
*/
|
|
541
|
+
linkName: "link-name"
|
|
542
|
+
};
|
|
543
|
+
var timeAndMedia = {
|
|
544
|
+
/**
|
|
545
|
+
* - Ensures `<audio>` elements have captions
|
|
546
|
+
* - `<audio>` elements must have a captions track ([url](https://dequeuniversity.com/rules/axe/4.4/audio-caption?application=axeAPI))
|
|
547
|
+
*/
|
|
548
|
+
audioCaption: "audio-caption",
|
|
549
|
+
/**
|
|
550
|
+
* - Ensures `<blink>` elements are not used
|
|
551
|
+
* - `<blink>` elements are deprecated and must not be used ([url](https://dequeuniversity.com/rules/axe/4.4/blink?application=axeAPI))
|
|
552
|
+
*/
|
|
553
|
+
blink: "blink",
|
|
554
|
+
/**
|
|
555
|
+
* - Ensures `<meta http-equiv="refresh">` is not used
|
|
556
|
+
* - Timed refresh must not exist ([url](https://dequeuniversity.com/rules/axe/4.4/meta-refresh?application=axeAPI))
|
|
557
|
+
*/
|
|
558
|
+
metaRefresh: "meta-refresh",
|
|
559
|
+
/**
|
|
560
|
+
* - Ensures `<video>` or `<audio>` elements do not autoplay audio for more than 3 seconds without a control mechanism to stop or mute the audio
|
|
561
|
+
* - `<video>` or `<audio>` elements must not play automatically ([url](https://dequeuniversity.com/rules/axe/4.4/no-autoplay-audio?application=axeAPI))
|
|
562
|
+
*/
|
|
563
|
+
noAutoplayAudio: "no-autoplay-audio"
|
|
564
|
+
};
|
|
565
|
+
var forms = {
|
|
566
|
+
/**
|
|
567
|
+
* - Ensure the autocomplete attribute is correct and suitable for the form field
|
|
568
|
+
* - autocomplete attribute must be used correctly ([url](https://dequeuniversity.com/rules/axe/4.4/autocomplete-valid?application=axeAPI))
|
|
569
|
+
*/
|
|
570
|
+
autocompleteValid: "autocomplete-valid",
|
|
571
|
+
/**
|
|
572
|
+
* - Ensures form field does not have multiple label elements
|
|
573
|
+
* - Form field must not have multiple label elements ([url](https://dequeuniversity.com/rules/axe/4.4/form-field-multiple-labels?application=axeAPI))
|
|
574
|
+
*/
|
|
575
|
+
formFieldMultipleLabels: "form-field-multiple-labels",
|
|
576
|
+
/**
|
|
577
|
+
* - Ensures that every form element has a visible label and is not solely labeled using hidden labels, or the title or aria-describedby attributes
|
|
578
|
+
* - Form elements should have a visible label ([url](https://dequeuniversity.com/rules/axe/4.4/label-title-only?application=axeAPI))
|
|
579
|
+
*/
|
|
580
|
+
labelTitleOnly: "label-title-only",
|
|
581
|
+
/**
|
|
582
|
+
* - Ensures every form element has a label
|
|
583
|
+
* - Form elements must have labels ([url](https://dequeuniversity.com/rules/axe/4.4/label?application=axeAPI))
|
|
584
|
+
*/
|
|
585
|
+
label: "label",
|
|
586
|
+
/**
|
|
587
|
+
* - Ensures select element has an accessible name
|
|
588
|
+
* - Select element must have an accessible name ([url](https://dequeuniversity.com/rules/axe/4.4/select-name?application=axeAPI))
|
|
589
|
+
*/
|
|
590
|
+
selectName: "select-name"
|
|
591
|
+
};
|
|
592
|
+
var structure = {
|
|
593
|
+
/**
|
|
594
|
+
* - Ensure that text spacing set through style attributes can be adjusted with custom stylesheets
|
|
595
|
+
* - Inline text spacing must be adjustable with custom stylesheets ([url](https://dequeuniversity.com/rules/axe/4.4/avoid-inline-spacing?application=axeAPI))
|
|
596
|
+
*/
|
|
597
|
+
avoidInlineSpacing: "avoid-inline-spacing",
|
|
598
|
+
/**
|
|
599
|
+
* - Ensures content is not locked to any specific display orientation, and the content is operable in all display orientations
|
|
600
|
+
* - CSS Media queries must not lock display orientation ([url](https://dequeuniversity.com/rules/axe/4.4/css-orientation-lock?application=axeAPI))
|
|
601
|
+
*/
|
|
602
|
+
cssOrientationLock: "css-orientation-lock",
|
|
603
|
+
/**
|
|
604
|
+
* - Ensures `<dl>` elements are structured correctly
|
|
605
|
+
* - `<dl>` elements must only directly contain properly-ordered `<dt>` and `<dd>` groups, `<script>`, `<template>` or `<div>` elements ([url](https://dequeuniversity.com/rules/axe/4.4/definition-list?application=axeAPI))
|
|
606
|
+
*/
|
|
607
|
+
definitionList: "definition-list",
|
|
608
|
+
/**
|
|
609
|
+
* - Ensures `<dt>` and `<dd>` elements are contained by a `<dl>`
|
|
610
|
+
* - `<dt>` and `<dd>` elements must be contained by a `<dl>` ([url](https://dequeuniversity.com/rules/axe/4.4/dlitem?application=axeAPI))
|
|
611
|
+
*/
|
|
612
|
+
dlitem: "dlitem",
|
|
613
|
+
/**
|
|
614
|
+
* - Ensures `<iframe>` and `<frame>` elements contain the axe-core script
|
|
615
|
+
* - Frames should be tested with axe-core ([url](https://dequeuniversity.com/rules/axe/4.4/frame-tested?application=axeAPI))
|
|
616
|
+
*/
|
|
617
|
+
frameTested: "frame-tested",
|
|
618
|
+
/**
|
|
619
|
+
* - Informs users about hidden content.
|
|
620
|
+
* - Hidden content on the page should be analyzed ([url](https://dequeuniversity.com/rules/axe/4.4/hidden-content?application=axeAPI))
|
|
621
|
+
*/
|
|
622
|
+
hiddenContent: "hidden-content",
|
|
623
|
+
/**
|
|
624
|
+
* - Ensures that lists are structured correctly
|
|
625
|
+
* - `<ul>` and `<ol>` must only directly contain `<li>`, `<script>` or `<template>` elements ([url](https://dequeuniversity.com/rules/axe/4.4/list?application=axeAPI))
|
|
626
|
+
*/
|
|
627
|
+
list: "list",
|
|
628
|
+
/**
|
|
629
|
+
* - Ensures `<li>` elements are used semantically
|
|
630
|
+
* - `<li>` elements must be contained in a `<ul>` or `<ol>` ([url](https://dequeuniversity.com/rules/axe/4.4/listitem?application=axeAPI))
|
|
631
|
+
*/
|
|
632
|
+
listitem: "listitem"
|
|
633
|
+
};
|
|
634
|
+
var parsing = {
|
|
635
|
+
/**
|
|
636
|
+
* - Ensures every id attribute value of active elements is unique
|
|
637
|
+
* - IDs of active elements must be unique ([url](https://dequeuniversity.com/rules/axe/4.4/duplicate-id-active?application=axeAPI))
|
|
638
|
+
*/
|
|
639
|
+
duplicateIdActive: "duplicate-id-active",
|
|
640
|
+
/**
|
|
641
|
+
* - Ensures every id attribute value used in ARIA and in labels is unique
|
|
642
|
+
* - IDs used in ARIA and labels must be unique ([url](https://dequeuniversity.com/rules/axe/4.4/duplicate-id-aria?application=axeAPI))
|
|
643
|
+
*/
|
|
644
|
+
duplicateIdAria: "duplicate-id-aria",
|
|
645
|
+
/**
|
|
646
|
+
* - Ensures every id attribute value is unique
|
|
647
|
+
* - id attribute value must be unique ([url](https://dequeuniversity.com/rules/axe/4.4/duplicate-id?application=axeAPI))
|
|
648
|
+
*/
|
|
649
|
+
duplicateId: "duplicate-id",
|
|
650
|
+
/**
|
|
651
|
+
* - Ensures `<marquee>` elements are not used
|
|
652
|
+
* - `<marquee>` elements are deprecated and must not be used ([url](https://dequeuniversity.com/rules/axe/4.4/marquee?application=axeAPI))
|
|
653
|
+
*/
|
|
654
|
+
marquee: "marquee"
|
|
655
|
+
};
|
|
656
|
+
var semantics = {
|
|
657
|
+
/**
|
|
658
|
+
* - Ensures the order of headings is semantically correct
|
|
659
|
+
* - Heading levels should only increase by one ([url](https://dequeuniversity.com/rules/axe/4.4/heading-order?application=axeAPI))
|
|
660
|
+
*/
|
|
661
|
+
headingOrder: "heading-order",
|
|
662
|
+
/**
|
|
663
|
+
* - Ensure that links with the same accessible name serve a similar purpose
|
|
664
|
+
* - Links with the same name must have a similar purpose ([url](https://dequeuniversity.com/rules/axe/4.4/identical-links-same-purpose?application=axeAPI))
|
|
665
|
+
*/
|
|
666
|
+
identicalLinksSamePurpose: "identical-links-same-purpose",
|
|
667
|
+
/**
|
|
668
|
+
* - Ensures that elements labelled through their content must have their visible text as part of their accessible name
|
|
669
|
+
* - Elements must have their visible text as part of their accessible name ([url](https://dequeuniversity.com/rules/axe/4.4/label-content-name-mismatch?application=axeAPI))
|
|
670
|
+
*/
|
|
671
|
+
labelContentNameMismatch: "label-content-name-mismatch",
|
|
672
|
+
/**
|
|
673
|
+
* - Ensures the banner landmark is at top level
|
|
674
|
+
* - Banner landmark should not be contained in another landmark ([url](https://dequeuniversity.com/rules/axe/4.4/landmark-banner-is-top-level?application=axeAPI))
|
|
675
|
+
*/
|
|
676
|
+
landmarkBannerIsTopLevel: "landmark-banner-is-top-level",
|
|
677
|
+
/**
|
|
678
|
+
* - Ensures the complementary landmark or aside is at top level
|
|
679
|
+
* - Aside should not be contained in another landmark ([url](https://dequeuniversity.com/rules/axe/4.4/landmark-complementary-is-top-level?application=axeAPI))
|
|
680
|
+
*/
|
|
681
|
+
landmarkComplementaryIsTopLevel: "landmark-complementary-is-top-level",
|
|
682
|
+
/**
|
|
683
|
+
* - Ensures the contentinfo landmark is at top level
|
|
684
|
+
* - Contentinfo landmark should not be contained in another landmark ([url](https://dequeuniversity.com/rules/axe/4.4/landmark-contentinfo-is-top-level?application=axeAPI))
|
|
685
|
+
*/
|
|
686
|
+
landmarkContentinfoIsTopLevel: "landmark-contentinfo-is-top-level",
|
|
687
|
+
/**
|
|
688
|
+
* - Ensures the main landmark is at top level
|
|
689
|
+
* - Main landmark should not be contained in another landmark ([url](https://dequeuniversity.com/rules/axe/4.4/landmark-main-is-top-level?application=axeAPI))
|
|
690
|
+
*/
|
|
691
|
+
landmarkMainIsTopLevel: "landmark-main-is-top-level",
|
|
692
|
+
/**
|
|
693
|
+
* - Ensures the document has at most one banner landmark
|
|
694
|
+
* - Document should not have more than one banner landmark ([url](https://dequeuniversity.com/rules/axe/4.4/landmark-no-duplicate-banner?application=axeAPI))
|
|
695
|
+
*/
|
|
696
|
+
landmarkNoDuplicateBanner: "landmark-no-duplicate-banner",
|
|
697
|
+
/**
|
|
698
|
+
* - Ensures the document has at most one contentinfo landmark
|
|
699
|
+
* - Document should not have more than one contentinfo landmark ([url](https://dequeuniversity.com/rules/axe/4.4/landmark-no-duplicate-contentinfo?application=axeAPI))
|
|
700
|
+
*/
|
|
701
|
+
landmarkNoDuplicateContentinfo: "landmark-no-duplicate-contentinfo",
|
|
702
|
+
/**
|
|
703
|
+
* - Ensures the document has at most one main landmark
|
|
704
|
+
* - Document should not have more than one main landmark ([url](https://dequeuniversity.com/rules/axe/4.4/landmark-no-duplicate-main?application=axeAPI))
|
|
705
|
+
*/
|
|
706
|
+
landmarkNoDuplicateMain: "landmark-no-duplicate-main",
|
|
707
|
+
/**
|
|
708
|
+
* - Ensures the document has a main landmark
|
|
709
|
+
* - Document should have one main landmark ([url](https://dequeuniversity.com/rules/axe/4.4/landmark-one-main?application=axeAPI))
|
|
710
|
+
*/
|
|
711
|
+
landmarkOneMain: "landmark-one-main",
|
|
712
|
+
/**
|
|
713
|
+
* - Landmarks should have a unique role or role/label/title (i.e. accessible name) combination
|
|
714
|
+
* - Ensures landmarks are unique ([url](https://dequeuniversity.com/rules/axe/4.4/landmark-unique?application=axeAPI))
|
|
715
|
+
*/
|
|
716
|
+
landmarkUnique: "landmark-unique",
|
|
717
|
+
/**
|
|
718
|
+
* - Ensure bold, italic text and font-size is not used to style `<p>` elements as a heading
|
|
719
|
+
* - Styled `<p>` elements must not be used as headings ([url](https://dequeuniversity.com/rules/axe/4.4/p-as-heading?application=axeAPI))
|
|
720
|
+
*/
|
|
721
|
+
pAsHeading: "p-as-heading",
|
|
722
|
+
/**
|
|
723
|
+
* - Ensure that the page, or at least one of its frames contains a level-one heading
|
|
724
|
+
* - Page should contain a level-one heading ([url](https://dequeuniversity.com/rules/axe/4.4/page-has-heading-one?application=axeAPI))
|
|
725
|
+
*/
|
|
726
|
+
pageHasHeadingOne: "page-has-heading-one"
|
|
727
|
+
};
|
|
728
|
+
var language = {
|
|
729
|
+
/**
|
|
730
|
+
* - Ensures every HTML document has a lang attribute
|
|
731
|
+
* - `<html>` element must have a lang attribute ([url](https://dequeuniversity.com/rules/axe/4.4/html-has-lang?application=axeAPI))
|
|
732
|
+
*/
|
|
733
|
+
htmlHasLang: "html-has-lang",
|
|
734
|
+
/**
|
|
735
|
+
* - Ensures the lang attribute of the `<html>` element has a valid value
|
|
736
|
+
* - `<html>` element must have a valid value for the lang attribute ([url](https://dequeuniversity.com/rules/axe/4.4/html-lang-valid?application=axeAPI))
|
|
737
|
+
*/
|
|
738
|
+
htmlLangValid: "html-lang-valid",
|
|
739
|
+
/**
|
|
740
|
+
* - Ensure that HTML elements with both valid lang and xml:lang attributes agree on the base language of the page
|
|
741
|
+
* - HTML elements with lang and xml:lang must have the same base language ([url](https://dequeuniversity.com/rules/axe/4.4/html-xml-lang-mismatch?application=axeAPI))
|
|
742
|
+
*/
|
|
743
|
+
htmlXmlLangMismatch: "html-xml-lang-mismatch",
|
|
744
|
+
/**
|
|
745
|
+
* - Ensures lang attributes have valid values
|
|
746
|
+
* - lang attribute must have a valid value ([url](https://dequeuniversity.com/rules/axe/4.4/valid-lang?application=axeAPI))
|
|
747
|
+
*/
|
|
748
|
+
validLang: "valid-lang"
|
|
749
|
+
};
|
|
750
|
+
var sensoryAndVisualCues = {
|
|
751
|
+
/**
|
|
752
|
+
* - Ensures `<meta name="viewport">` can scale a significant amount
|
|
753
|
+
* - Users should be able to zoom and scale the text up to 500% ([url](https://dequeuniversity.com/rules/axe/4.4/meta-viewport-large?application=axeAPI))
|
|
754
|
+
*/
|
|
755
|
+
metaViewportLarge: "meta-viewport-large",
|
|
756
|
+
/**
|
|
757
|
+
* - Ensures `<meta name="viewport">` does not disable text scaling and zooming
|
|
758
|
+
* - Zooming and scaling should not be disabled ([url](https://dequeuniversity.com/rules/axe/4.4/meta-viewport?application=axeAPI))
|
|
759
|
+
*/
|
|
760
|
+
metaViewport: "meta-viewport"
|
|
761
|
+
};
|
|
762
|
+
var tables = {
|
|
763
|
+
/**
|
|
764
|
+
* - Ensures the scope attribute is used correctly on tables
|
|
765
|
+
* - scope attribute should be used correctly ([url](https://dequeuniversity.com/rules/axe/4.4/scope-attr-valid?application=axeAPI))
|
|
766
|
+
*/
|
|
767
|
+
scopeAttrValid: "scope-attr-valid",
|
|
768
|
+
/**
|
|
769
|
+
* - Ensure the `<caption>` element does not contain the same text as the summary attribute
|
|
770
|
+
* - tables should not have the same summary and caption ([url](https://dequeuniversity.com/rules/axe/4.4/table-duplicate-name?application=axeAPI))
|
|
771
|
+
*/
|
|
772
|
+
tableDuplicateName: "table-duplicate-name",
|
|
773
|
+
/**
|
|
774
|
+
* - Ensure that tables with a caption use the `<caption>` element.
|
|
775
|
+
* - Data or header cells must not be used to give caption to a data table. ([url](https://dequeuniversity.com/rules/axe/4.4/table-fake-caption?application=axeAPI))
|
|
776
|
+
*/
|
|
777
|
+
tableFakeCaption: "table-fake-caption",
|
|
778
|
+
/**
|
|
779
|
+
* - Ensure that each non-empty data cell in a `<table>` larger than 3 by 3 has one or more table headers
|
|
780
|
+
* - Non-empty `<td>` elements in larger `<table>` must have an associated table header ([url](https://dequeuniversity.com/rules/axe/4.4/td-has-header?application=axeAPI))
|
|
781
|
+
*/
|
|
782
|
+
tdHasHeader: "td-has-header",
|
|
783
|
+
/**
|
|
784
|
+
* - Ensure that each cell in a table that uses the headers attribute refers only to other cells in that table
|
|
785
|
+
* - Table cells that use the headers attribute must only refer to cells in the same table ([url](https://dequeuniversity.com/rules/axe/4.4/td-headers-attr?application=axeAPI))
|
|
786
|
+
*/
|
|
787
|
+
tdHeadersAttr: "td-headers-attr",
|
|
788
|
+
/**
|
|
789
|
+
* - Ensure that `<th>` elements and elements with role=columnheader/rowheader have data cells they describe
|
|
790
|
+
* - Table headers in a data table must refer to data cells ([url](https://dequeuniversity.com/rules/axe/4.4/th-has-data-cells?application=axeAPI))
|
|
791
|
+
*/
|
|
792
|
+
thHasDataCells: "th-has-data-cells"
|
|
793
|
+
};
|
|
794
|
+
|
|
795
|
+
// src/service/html/axe-rules/separated-rules.ts
|
|
796
|
+
var rules = {
|
|
797
|
+
/**
|
|
798
|
+
* These rules can be evaluated against any component.
|
|
799
|
+
*/
|
|
800
|
+
alwaysAllowed: [
|
|
801
|
+
aria.ariaAllowedAttr,
|
|
802
|
+
aria.ariaAllowedRole,
|
|
803
|
+
aria.ariaHiddenBody,
|
|
804
|
+
aria.ariaRoledescription,
|
|
805
|
+
aria.ariaRoles,
|
|
806
|
+
aria.presentationRoleConflict,
|
|
807
|
+
forms.autocompleteValid,
|
|
808
|
+
forms.formFieldMultipleLabels,
|
|
809
|
+
// Could not find error state
|
|
810
|
+
keyboard.accesskeys,
|
|
811
|
+
keyboard.focusOrderSemantics,
|
|
812
|
+
keyboard.tabindex,
|
|
813
|
+
language.htmlLangValid,
|
|
814
|
+
language.htmlXmlLangMismatch,
|
|
815
|
+
language.validLang,
|
|
816
|
+
nameRoleValue.ariaHiddenFocus,
|
|
817
|
+
// Could not find error state
|
|
818
|
+
nameRoleValue.emptyHeading,
|
|
819
|
+
parsing.duplicateIdActive,
|
|
820
|
+
parsing.duplicateIdAria,
|
|
821
|
+
parsing.marquee,
|
|
822
|
+
semantics.identicalLinksSamePurpose,
|
|
823
|
+
// Could not find error state
|
|
824
|
+
semantics.landmarkNoDuplicateBanner,
|
|
825
|
+
semantics.landmarkNoDuplicateContentinfo,
|
|
826
|
+
semantics.landmarkNoDuplicateMain,
|
|
827
|
+
semantics.landmarkUnique,
|
|
828
|
+
sensoryAndVisualCues.metaViewportLarge,
|
|
829
|
+
// Could not find error state
|
|
830
|
+
sensoryAndVisualCues.metaViewport,
|
|
831
|
+
// Could not find error state
|
|
832
|
+
tables.scopeAttrValid,
|
|
833
|
+
// Could not find error state
|
|
834
|
+
textAlternatives.serverSideImageMap,
|
|
835
|
+
// Could not find error state
|
|
836
|
+
timeAndMedia.blink,
|
|
837
|
+
timeAndMedia.metaRefresh,
|
|
838
|
+
// Could not find error state
|
|
839
|
+
timeAndMedia.noAutoplayAudio
|
|
840
|
+
// Could not find error state
|
|
841
|
+
],
|
|
842
|
+
/**
|
|
843
|
+
* These rules can't be resolved with a spread operator
|
|
844
|
+
* in the node's attributes
|
|
845
|
+
*/
|
|
846
|
+
requiresAttrs: [
|
|
847
|
+
aria.ariaRequiredAttr,
|
|
848
|
+
language.htmlHasLang,
|
|
849
|
+
textAlternatives.areaAlt,
|
|
850
|
+
textAlternatives.imageAlt,
|
|
851
|
+
textAlternatives.imageRedundantAlt,
|
|
852
|
+
textAlternatives.inputImageAlt,
|
|
853
|
+
textAlternatives.objectAlt,
|
|
854
|
+
textAlternatives.roleImgAlt,
|
|
855
|
+
textAlternatives.svgImgAlt
|
|
856
|
+
],
|
|
857
|
+
/**
|
|
858
|
+
* These rules can't be resolved with dynamic content
|
|
859
|
+
* in the body of the node
|
|
860
|
+
*/
|
|
861
|
+
requiresChildren: [
|
|
862
|
+
aria.ariaRequiredChildren,
|
|
863
|
+
aria.ariaText,
|
|
864
|
+
aria.ariaValidAttrValue,
|
|
865
|
+
aria.emptyTableHeader,
|
|
866
|
+
keyboard.frameFocusableContent,
|
|
867
|
+
keyboard.skipLink,
|
|
868
|
+
nameRoleValue.ariaHiddenFocus,
|
|
869
|
+
semantics.labelContentNameMismatch,
|
|
870
|
+
structure.definitionList,
|
|
871
|
+
structure.list,
|
|
872
|
+
tables.tableDuplicateName,
|
|
873
|
+
tables.tableFakeCaption,
|
|
874
|
+
tables.thHasDataCells,
|
|
875
|
+
textAlternatives.documentTitle,
|
|
876
|
+
textAlternatives.frameTitleUnique,
|
|
877
|
+
textAlternatives.frameTitle,
|
|
878
|
+
textAlternatives.videoCaption,
|
|
879
|
+
timeAndMedia.audioCaption
|
|
880
|
+
],
|
|
881
|
+
/**
|
|
882
|
+
* These rules can be resolved by changing content in
|
|
883
|
+
* either the node body or its attributes
|
|
884
|
+
*/
|
|
885
|
+
requiresAttrsOrChildren: [
|
|
886
|
+
aria.ariaCommandName,
|
|
887
|
+
aria.ariaDialogName,
|
|
888
|
+
aria.ariaInputFieldName,
|
|
889
|
+
aria.ariaMeterName,
|
|
890
|
+
aria.ariaProgressbarName,
|
|
891
|
+
aria.ariaToggleFieldName,
|
|
892
|
+
aria.ariaTooltipName,
|
|
893
|
+
aria.ariaTreeitemName,
|
|
894
|
+
nameRoleValue.inputButtonName,
|
|
895
|
+
nameRoleValue.linkName
|
|
896
|
+
],
|
|
897
|
+
/**
|
|
898
|
+
* These rules cannot be supported until multiple files
|
|
899
|
+
* are analyzed at once. For now they are ignored.
|
|
900
|
+
*/
|
|
901
|
+
requiresParent: [
|
|
902
|
+
aria.ariaRequiredParent,
|
|
903
|
+
forms.label,
|
|
904
|
+
forms.labelTitleOnly,
|
|
905
|
+
forms.selectName,
|
|
906
|
+
keyboard.bypass,
|
|
907
|
+
keyboard.nestedInteractive,
|
|
908
|
+
keyboard.region,
|
|
909
|
+
semantics.headingOrder,
|
|
910
|
+
semantics.landmarkBannerIsTopLevel,
|
|
911
|
+
semantics.landmarkComplementaryIsTopLevel,
|
|
912
|
+
semantics.landmarkContentinfoIsTopLevel,
|
|
913
|
+
semantics.landmarkMainIsTopLevel,
|
|
914
|
+
semantics.landmarkOneMain,
|
|
915
|
+
semantics.pageHasHeadingOne,
|
|
916
|
+
structure.dlitem,
|
|
917
|
+
structure.listitem,
|
|
918
|
+
tables.tdHasHeader,
|
|
919
|
+
tables.tdHeadersAttr
|
|
920
|
+
],
|
|
921
|
+
/**
|
|
922
|
+
* These rules should not be enforced to all users of
|
|
923
|
+
* the official Marko language server.
|
|
924
|
+
*/
|
|
925
|
+
blacklist: [structure.frameTested, parsing.duplicateId],
|
|
926
|
+
/**
|
|
927
|
+
* These are rules that cannot currently be validated, either
|
|
928
|
+
* because of limitations with JSDom + axe-core or with the
|
|
929
|
+
* current implementation of the language server.
|
|
930
|
+
*/
|
|
931
|
+
cannotValidate: [
|
|
932
|
+
keyboard.scrollableRegionFocusable,
|
|
933
|
+
semantics.pAsHeading,
|
|
934
|
+
structure.avoidInlineSpacing,
|
|
935
|
+
structure.cssOrientationLock,
|
|
936
|
+
structure.hiddenContent
|
|
937
|
+
]
|
|
938
|
+
};
|
|
939
|
+
var separated_rules_default = rules;
|
|
940
|
+
|
|
941
|
+
// src/service/html/index.ts
|
|
942
|
+
var extractCache = /* @__PURE__ */ new WeakMap();
|
|
943
|
+
var HTMLService = {
|
|
944
|
+
commands: {
|
|
945
|
+
"$/showHtmlOutput": async (uri) => {
|
|
946
|
+
const doc = get(uri);
|
|
947
|
+
if (!doc)
|
|
948
|
+
return;
|
|
949
|
+
const { extracted } = extract(doc);
|
|
950
|
+
return {
|
|
951
|
+
language: "html",
|
|
952
|
+
content: extracted.toString()
|
|
953
|
+
};
|
|
954
|
+
}
|
|
955
|
+
},
|
|
956
|
+
async doValidate(doc) {
|
|
957
|
+
const { extracted, nodeDetails } = extract(doc);
|
|
958
|
+
const jsdom = new import_jsdom.JSDOM(extracted.toString(), {
|
|
959
|
+
includeNodeLocations: true
|
|
960
|
+
});
|
|
961
|
+
const { documentElement } = jsdom.window.document;
|
|
962
|
+
const getViolationNodes = async (runOnly) => (await import_axe_core.default.run(documentElement, {
|
|
963
|
+
runOnly,
|
|
964
|
+
rules: {
|
|
965
|
+
"color-contrast": { enabled: false }
|
|
966
|
+
},
|
|
967
|
+
resultTypes: ["violations"],
|
|
968
|
+
elementRef: true
|
|
969
|
+
})).violations.flatMap(
|
|
970
|
+
({ nodes, id }) => nodes.map((node) => ({ ...node, ruleId: id }))
|
|
971
|
+
);
|
|
972
|
+
const release = await acquireMutexLock();
|
|
973
|
+
const violations = await getViolationNodes(separated_rules_default.alwaysAllowed);
|
|
974
|
+
const requiresAttrs = await getViolationNodes(separated_rules_default.requiresAttrs);
|
|
975
|
+
const requiresChildren = await getViolationNodes(separated_rules_default.requiresChildren);
|
|
976
|
+
const requiresAttrsOrChildren = await getViolationNodes(
|
|
977
|
+
separated_rules_default.requiresAttrsOrChildren
|
|
978
|
+
);
|
|
979
|
+
release();
|
|
980
|
+
violations.push(
|
|
981
|
+
...requiresAttrs.filter(
|
|
982
|
+
({ element }) => (element == null ? void 0 : element.dataset.markoNodeId) && !nodeDetails[element.dataset.markoNodeId].hasDynamicAttrs
|
|
983
|
+
)
|
|
984
|
+
);
|
|
985
|
+
violations.push(
|
|
986
|
+
...requiresChildren.filter(
|
|
987
|
+
({ element }) => (element == null ? void 0 : element.dataset.markoNodeId) && !nodeDetails[element.dataset.markoNodeId].hasDynamicBody
|
|
988
|
+
)
|
|
989
|
+
);
|
|
990
|
+
violations.push(
|
|
991
|
+
...requiresAttrsOrChildren.filter(
|
|
992
|
+
({ element }) => (element == null ? void 0 : element.dataset.markoNodeId) && !nodeDetails[element.dataset.markoNodeId].hasDynamicAttrs && !nodeDetails[element.dataset.markoNodeId].hasDynamicBody
|
|
993
|
+
)
|
|
994
|
+
);
|
|
995
|
+
return violations.flatMap((result) => {
|
|
996
|
+
const { element } = result;
|
|
997
|
+
if (!element)
|
|
998
|
+
return [];
|
|
999
|
+
const generatedLoc = jsdom.nodeLocation(element);
|
|
1000
|
+
if (!generatedLoc)
|
|
1001
|
+
return [];
|
|
1002
|
+
const sourceRange = extracted.sourceLocationAt(
|
|
1003
|
+
generatedLoc.startOffset + 1,
|
|
1004
|
+
generatedLoc.startOffset + 1 + element.tagName.length
|
|
1005
|
+
);
|
|
1006
|
+
if (!sourceRange)
|
|
1007
|
+
return [];
|
|
1008
|
+
return [
|
|
1009
|
+
{
|
|
1010
|
+
range: sourceRange,
|
|
1011
|
+
severity: 3,
|
|
1012
|
+
source: `axe-core(${result.ruleId})`,
|
|
1013
|
+
message: result.failureSummary ?? "unknown accessibility issue"
|
|
1014
|
+
}
|
|
1015
|
+
];
|
|
1016
|
+
});
|
|
1017
|
+
}
|
|
1018
|
+
};
|
|
1019
|
+
function extract(doc) {
|
|
1020
|
+
const { parsed } = getMarkoFile(doc);
|
|
1021
|
+
let cached = extractCache.get(parsed);
|
|
1022
|
+
if (!cached) {
|
|
1023
|
+
cached = (0, import_language_tools2.extractHTML)(parsed);
|
|
1024
|
+
extractCache.set(parsed, cached);
|
|
1025
|
+
}
|
|
1026
|
+
return cached;
|
|
1027
|
+
}
|
|
1028
|
+
var lock;
|
|
1029
|
+
async function acquireMutexLock() {
|
|
1030
|
+
const currLock = lock;
|
|
1031
|
+
let resolve;
|
|
1032
|
+
lock = new Promise((_) => resolve = _);
|
|
1033
|
+
await currLock;
|
|
1034
|
+
return resolve;
|
|
1035
|
+
}
|
|
1036
|
+
var html_default = HTMLService;
|
|
1037
|
+
|
|
291
1038
|
// src/service/marko/complete/index.ts
|
|
292
|
-
var
|
|
1039
|
+
var import_language_tools6 = require("@marko/language-tools");
|
|
293
1040
|
|
|
294
1041
|
// src/service/marko/complete/AttrName.ts
|
|
295
1042
|
var import_vscode_languageserver2 = require("vscode-languageserver");
|
|
@@ -397,7 +1144,7 @@ var import_path2 = __toESM(require("path"));
|
|
|
397
1144
|
var import_vscode_languageserver3 = require("vscode-languageserver");
|
|
398
1145
|
|
|
399
1146
|
// src/service/marko/util/is-document-link-attr.ts
|
|
400
|
-
var
|
|
1147
|
+
var import_language_tools3 = require("@marko/language-tools");
|
|
401
1148
|
var linkedAttrs = /* @__PURE__ */ new Map([
|
|
402
1149
|
[
|
|
403
1150
|
"src",
|
|
@@ -419,7 +1166,7 @@ var linkedAttrs = /* @__PURE__ */ new Map([
|
|
|
419
1166
|
]);
|
|
420
1167
|
function isDocumentLinkAttr(code, tag, attr) {
|
|
421
1168
|
var _a, _b;
|
|
422
|
-
return tag.nameText && attr.type ===
|
|
1169
|
+
return tag.nameText && attr.type === import_language_tools3.NodeType.AttrNamed && ((_a = attr.value) == null ? void 0 : _a.type) === import_language_tools3.NodeType.AttrValue && /^['"]$/.test(code[attr.value.value.start]) && ((_b = linkedAttrs.get(code.slice(attr.name.start, attr.name.end))) == null ? void 0 : _b.has(tag.nameText)) || false;
|
|
423
1170
|
}
|
|
424
1171
|
|
|
425
1172
|
// src/utils/file-system.ts
|
|
@@ -625,7 +1372,7 @@ function Import({
|
|
|
625
1372
|
}
|
|
626
1373
|
|
|
627
1374
|
// src/service/marko/complete/OpenTagName.ts
|
|
628
|
-
var
|
|
1375
|
+
var import_language_tools4 = require("@marko/language-tools");
|
|
629
1376
|
function OpenTagName({
|
|
630
1377
|
node,
|
|
631
1378
|
file: { parsed, filename, lookup }
|
|
@@ -633,11 +1380,11 @@ function OpenTagName({
|
|
|
633
1380
|
var _a;
|
|
634
1381
|
const tag = node.parent;
|
|
635
1382
|
const range = parsed.locationAt(node);
|
|
636
|
-
const isAttrTag = tag.type ===
|
|
1383
|
+
const isAttrTag = tag.type === import_language_tools4.NodeType.AttrTag;
|
|
637
1384
|
const result = [];
|
|
638
1385
|
if (isAttrTag) {
|
|
639
1386
|
let parentTag = tag.owner;
|
|
640
|
-
while ((parentTag == null ? void 0 : parentTag.type) ===
|
|
1387
|
+
while ((parentTag == null ? void 0 : parentTag.type) === import_language_tools4.NodeType.AttrTag)
|
|
641
1388
|
parentTag = parentTag.owner;
|
|
642
1389
|
const parentTagDef = parentTag && parentTag.nameText && lookup.getTag(parentTag.nameText);
|
|
643
1390
|
if (parentTagDef) {
|
|
@@ -657,7 +1404,7 @@ function OpenTagName({
|
|
|
657
1404
|
}
|
|
658
1405
|
}
|
|
659
1406
|
} else {
|
|
660
|
-
const skipStatements = !(tag.concise && tag.parent.type ===
|
|
1407
|
+
const skipStatements = !(tag.concise && tag.parent.type === import_language_tools4.NodeType.Program);
|
|
661
1408
|
for (const tag2 of lookup.getTagsSorted()) {
|
|
662
1409
|
if (!(tag2.name === "*" || tag2.isNestedTag || skipStatements && ((_a = tag2.parseOptions) == null ? void 0 : _a.statement) || tag2.name[0] === "_" && /^@?marko[/-]|[\\/]node_modules[\\/]/.test(tag2.filePath))) {
|
|
663
1410
|
const completion = getTagNameCompletion({
|
|
@@ -676,14 +1423,14 @@ function OpenTagName({
|
|
|
676
1423
|
|
|
677
1424
|
// src/service/marko/complete/Tag.ts
|
|
678
1425
|
var import_vscode_languageserver6 = require("vscode-languageserver");
|
|
679
|
-
var
|
|
1426
|
+
var import_language_tools5 = require("@marko/language-tools");
|
|
680
1427
|
var partialCloseTagReg = /<\/(?:[^><]*>)?/iy;
|
|
681
1428
|
function Tag({
|
|
682
1429
|
node,
|
|
683
1430
|
offset,
|
|
684
1431
|
file: { parsed, code }
|
|
685
1432
|
}) {
|
|
686
|
-
const isClosed = node.end !==
|
|
1433
|
+
const isClosed = node.end !== import_language_tools5.UNFINISHED;
|
|
687
1434
|
if (isClosed || node.concise)
|
|
688
1435
|
return;
|
|
689
1436
|
const closingTagStr = `</${node.nameText || ""}>`;
|
|
@@ -734,7 +1481,7 @@ var doComplete = async (doc, params) => {
|
|
|
734
1481
|
const offset = doc.offsetAt(params.position);
|
|
735
1482
|
const node = file.parsed.nodeAt(offset);
|
|
736
1483
|
return {
|
|
737
|
-
items: await ((_a = handlers[
|
|
1484
|
+
items: await ((_a = handlers[import_language_tools6.NodeType[node.type]]) == null ? void 0 : _a.call(handlers, {
|
|
738
1485
|
file,
|
|
739
1486
|
params,
|
|
740
1487
|
offset,
|
|
@@ -746,7 +1493,7 @@ var doComplete = async (doc, params) => {
|
|
|
746
1493
|
|
|
747
1494
|
// src/service/marko/validate.ts
|
|
748
1495
|
var import_path4 = __toESM(require("path"));
|
|
749
|
-
var
|
|
1496
|
+
var import_language_tools7 = require("@marko/language-tools");
|
|
750
1497
|
var import_vscode_languageserver7 = require("vscode-languageserver");
|
|
751
1498
|
var import_babel_utils = require("@marko/babel-utils");
|
|
752
1499
|
var markoErrorRegExp = /^(.+?)\.marko(?:\((\d+)(?:\s*,\s*(\d+))?\))?: (.*)$/gm;
|
|
@@ -754,7 +1501,7 @@ var doValidate = (doc) => {
|
|
|
754
1501
|
const filename = getFSPath(doc);
|
|
755
1502
|
const diagnostics = [];
|
|
756
1503
|
try {
|
|
757
|
-
const { meta } =
|
|
1504
|
+
const { meta } = import_language_tools7.Project.getCompiler(
|
|
758
1505
|
filename && import_path4.default.dirname(filename)
|
|
759
1506
|
).compileSync(doc.getText(), filename || "untitled.marko", {
|
|
760
1507
|
code: false,
|
|
@@ -886,7 +1633,7 @@ function isErrorWithLoc(err) {
|
|
|
886
1633
|
}
|
|
887
1634
|
|
|
888
1635
|
// src/service/marko/hover/index.ts
|
|
889
|
-
var
|
|
1636
|
+
var import_language_tools8 = require("@marko/language-tools");
|
|
890
1637
|
|
|
891
1638
|
// src/utils/constants.ts
|
|
892
1639
|
var START_POSITION = {
|
|
@@ -930,7 +1677,7 @@ var doHover = async (doc, params) => {
|
|
|
930
1677
|
const file = getMarkoFile(doc);
|
|
931
1678
|
const offset = doc.offsetAt(params.position);
|
|
932
1679
|
const node = file.parsed.nodeAt(offset);
|
|
933
|
-
return await ((_a = handlers2[
|
|
1680
|
+
return await ((_a = handlers2[import_language_tools8.NodeType[node.type]]) == null ? void 0 : _a.call(handlers2, {
|
|
934
1681
|
file,
|
|
935
1682
|
params,
|
|
936
1683
|
offset,
|
|
@@ -939,12 +1686,12 @@ var doHover = async (doc, params) => {
|
|
|
939
1686
|
};
|
|
940
1687
|
|
|
941
1688
|
// src/service/marko/definition/index.ts
|
|
942
|
-
var
|
|
1689
|
+
var import_language_tools11 = require("@marko/language-tools");
|
|
943
1690
|
|
|
944
1691
|
// src/service/marko/definition/AttrName.ts
|
|
945
1692
|
var import_fs2 = __toESM(require("fs"));
|
|
946
1693
|
var import_vscode_uri4 = require("vscode-uri");
|
|
947
|
-
var
|
|
1694
|
+
var import_language_tools9 = require("@marko/language-tools");
|
|
948
1695
|
|
|
949
1696
|
// src/utils/regexp-builder.ts
|
|
950
1697
|
function RegExpBuilder(strings, ...expressions) {
|
|
@@ -993,8 +1740,8 @@ function AttrName2({
|
|
|
993
1740
|
tagDefSource
|
|
994
1741
|
);
|
|
995
1742
|
if (match && match.index) {
|
|
996
|
-
range = (0,
|
|
997
|
-
(0,
|
|
1743
|
+
range = (0, import_language_tools9.getLocation)(
|
|
1744
|
+
(0, import_language_tools9.getLines)(tagDefSource),
|
|
998
1745
|
match.index,
|
|
999
1746
|
match.index + match[0].length
|
|
1000
1747
|
);
|
|
@@ -1014,7 +1761,7 @@ function AttrName2({
|
|
|
1014
1761
|
var import_fs3 = __toESM(require("fs"));
|
|
1015
1762
|
var import_path5 = __toESM(require("path"));
|
|
1016
1763
|
var import_vscode_uri5 = require("vscode-uri");
|
|
1017
|
-
var
|
|
1764
|
+
var import_language_tools10 = require("@marko/language-tools");
|
|
1018
1765
|
function OpenTagName3({
|
|
1019
1766
|
node,
|
|
1020
1767
|
file: { parsed, lookup }
|
|
@@ -1022,9 +1769,9 @@ function OpenTagName3({
|
|
|
1022
1769
|
const tag = node.parent;
|
|
1023
1770
|
let tagDef;
|
|
1024
1771
|
let range = START_LOCATION;
|
|
1025
|
-
if (tag.type ===
|
|
1772
|
+
if (tag.type === import_language_tools10.NodeType.AttrTag) {
|
|
1026
1773
|
let parentTag = tag.owner;
|
|
1027
|
-
while ((parentTag == null ? void 0 : parentTag.type) ===
|
|
1774
|
+
while ((parentTag == null ? void 0 : parentTag.type) === import_language_tools10.NodeType.AttrTag)
|
|
1028
1775
|
parentTag = parentTag.owner;
|
|
1029
1776
|
tagDef = parentTag && parentTag.nameText ? lookup.getTag(parentTag.nameText) : void 0;
|
|
1030
1777
|
} else {
|
|
@@ -1043,8 +1790,8 @@ function OpenTagName3({
|
|
|
1043
1790
|
tagDefSource
|
|
1044
1791
|
);
|
|
1045
1792
|
if (match && match.index) {
|
|
1046
|
-
range = (0,
|
|
1047
|
-
(0,
|
|
1793
|
+
range = (0, import_language_tools10.getLocation)(
|
|
1794
|
+
(0, import_language_tools10.getLines)(tagDefSource),
|
|
1048
1795
|
match.index,
|
|
1049
1796
|
match.index + match[0].length
|
|
1050
1797
|
);
|
|
@@ -1070,7 +1817,7 @@ var findDefinition = async (doc, params) => {
|
|
|
1070
1817
|
const file = getMarkoFile(doc);
|
|
1071
1818
|
const offset = doc.offsetAt(params.position);
|
|
1072
1819
|
const node = file.parsed.nodeAt(offset);
|
|
1073
|
-
return await ((_a = handlers3[
|
|
1820
|
+
return await ((_a = handlers3[import_language_tools11.NodeType[node.type]]) == null ? void 0 : _a.call(handlers3, {
|
|
1074
1821
|
file,
|
|
1075
1822
|
params,
|
|
1076
1823
|
offset,
|
|
@@ -1079,7 +1826,7 @@ var findDefinition = async (doc, params) => {
|
|
|
1079
1826
|
};
|
|
1080
1827
|
|
|
1081
1828
|
// src/service/marko/document-links.ts
|
|
1082
|
-
var
|
|
1829
|
+
var import_language_tools12 = require("@marko/language-tools");
|
|
1083
1830
|
var importTagReg2 = /(['"])<((?:[^\1\\>]+|\\.)*)>?\1/g;
|
|
1084
1831
|
var findDocumentLinks = async (doc) => {
|
|
1085
1832
|
return processDoc(doc, extractDocumentLinks);
|
|
@@ -1098,14 +1845,14 @@ function extractDocumentLinks({
|
|
|
1098
1845
|
const { program, read } = parsed;
|
|
1099
1846
|
const visit = (node) => {
|
|
1100
1847
|
switch (node.type) {
|
|
1101
|
-
case
|
|
1848
|
+
case import_language_tools12.NodeType.AttrTag:
|
|
1102
1849
|
if (node.body) {
|
|
1103
1850
|
for (const child of node.body) {
|
|
1104
1851
|
visit(child);
|
|
1105
1852
|
}
|
|
1106
1853
|
}
|
|
1107
1854
|
break;
|
|
1108
|
-
case
|
|
1855
|
+
case import_language_tools12.NodeType.Tag:
|
|
1109
1856
|
if (node.attrs && node.nameText) {
|
|
1110
1857
|
for (const attr of node.attrs) {
|
|
1111
1858
|
if (isDocumentLinkAttr(code, node, attr)) {
|
|
@@ -1131,7 +1878,7 @@ function extractDocumentLinks({
|
|
|
1131
1878
|
}
|
|
1132
1879
|
};
|
|
1133
1880
|
for (const node of program.static) {
|
|
1134
|
-
if (node.type ===
|
|
1881
|
+
if (node.type === import_language_tools12.NodeType.Import) {
|
|
1135
1882
|
importTagReg2.lastIndex = 0;
|
|
1136
1883
|
const value = parsed.read(node);
|
|
1137
1884
|
const match = importTagReg2.exec(value);
|
|
@@ -1159,7 +1906,7 @@ function extractDocumentLinks({
|
|
|
1159
1906
|
|
|
1160
1907
|
// src/service/marko/document-symbols.ts
|
|
1161
1908
|
var import_vscode_languageserver8 = require("vscode-languageserver");
|
|
1162
|
-
var
|
|
1909
|
+
var import_language_tools13 = require("@marko/language-tools");
|
|
1163
1910
|
var findDocumentSymbols = async (doc) => processDoc(doc, extractDocumentSymbols);
|
|
1164
1911
|
function extractDocumentSymbols({
|
|
1165
1912
|
uri,
|
|
@@ -1175,10 +1922,10 @@ function extractDocumentSymbols({
|
|
|
1175
1922
|
const visit = (node) => {
|
|
1176
1923
|
var _a, _b;
|
|
1177
1924
|
switch (node.type) {
|
|
1178
|
-
case
|
|
1179
|
-
case
|
|
1925
|
+
case import_language_tools13.NodeType.Tag:
|
|
1926
|
+
case import_language_tools13.NodeType.AttrTag:
|
|
1180
1927
|
symbols.push({
|
|
1181
|
-
name: (node.type ===
|
|
1928
|
+
name: (node.type === import_language_tools13.NodeType.AttrTag ? (_a = node.nameText) == null ? void 0 : _a.slice(node.nameText.indexOf("@")) : node.nameText) || "<${...}>",
|
|
1182
1929
|
kind: node.nameText && ((_b = lookup.getTag(node.nameText)) == null ? void 0 : _b.html) && import_vscode_languageserver8.SymbolKind.Property || import_vscode_languageserver8.SymbolKind.Class,
|
|
1183
1930
|
location: {
|
|
1184
1931
|
uri,
|
|
@@ -1252,20 +1999,20 @@ var import_tsserverlibrary = __toESM(require("typescript/lib/tsserverlibrary"));
|
|
|
1252
1999
|
var import_vscode_languageserver10 = require("vscode-languageserver");
|
|
1253
2000
|
var import_vscode_uri6 = require("vscode-uri");
|
|
1254
2001
|
var prettier2 = __toESM(require("prettier"));
|
|
1255
|
-
var
|
|
2002
|
+
var import_language_tools15 = require("@marko/language-tools");
|
|
1256
2003
|
|
|
1257
2004
|
// src/ts-plugin/host.ts
|
|
1258
2005
|
var import_path6 = __toESM(require("path"));
|
|
1259
|
-
var
|
|
2006
|
+
var import_language_tools14 = require("@marko/language-tools");
|
|
1260
2007
|
var fsPathReg = /^(?:[./\\]|[A-Z]:)/i;
|
|
1261
2008
|
var modulePartsReg = /^((?:@(?:[^/]+)\/)?(?:[^/]+))(.*)$/;
|
|
1262
|
-
|
|
2009
|
+
import_language_tools14.Project.setDefaultTypePaths({
|
|
1263
2010
|
internalTypesFile: import_path6.default.join(__dirname, "marko.internal.d.ts"),
|
|
1264
2011
|
markoTypesFile: import_path6.default.join(__dirname, "marko.runtime.d.ts")
|
|
1265
2012
|
});
|
|
1266
|
-
function patch(ts2, configFile,
|
|
2013
|
+
function patch(ts2, configFile, extractCache3, resolutionCache, host, ps) {
|
|
1267
2014
|
var _a, _b, _c;
|
|
1268
|
-
const processors =
|
|
2015
|
+
const processors = import_language_tools14.Processors.create({
|
|
1269
2016
|
ts: ts2,
|
|
1270
2017
|
host,
|
|
1271
2018
|
configFile
|
|
@@ -1302,7 +2049,7 @@ function patch(ts2, configFile, extractCache2, resolutionCache, host, ps) {
|
|
|
1302
2049
|
host.getScriptSnapshot = (fileName) => {
|
|
1303
2050
|
const processor = getProcessor(fileName);
|
|
1304
2051
|
if (processor) {
|
|
1305
|
-
let cached =
|
|
2052
|
+
let cached = extractCache3.get(fileName);
|
|
1306
2053
|
if (!cached) {
|
|
1307
2054
|
const code = host.readFile(fileName, "utf-8") || "";
|
|
1308
2055
|
try {
|
|
@@ -1312,7 +2059,7 @@ function patch(ts2, configFile, extractCache2, resolutionCache, host, ps) {
|
|
|
1312
2059
|
cached = { snapshot: ts2.ScriptSnapshot.fromString("") };
|
|
1313
2060
|
}
|
|
1314
2061
|
trackFile(fileName);
|
|
1315
|
-
|
|
2062
|
+
extractCache3.set(fileName, cached);
|
|
1316
2063
|
}
|
|
1317
2064
|
return cached.snapshot;
|
|
1318
2065
|
}
|
|
@@ -1332,7 +2079,7 @@ function patch(ts2, configFile, extractCache2, resolutionCache, host, ps) {
|
|
|
1332
2079
|
host.readDirectory = (path8, extensions, exclude, include, depth) => {
|
|
1333
2080
|
return readDirectory2(
|
|
1334
2081
|
path8,
|
|
1335
|
-
extensions == null ? void 0 : extensions.concat(
|
|
2082
|
+
extensions == null ? void 0 : extensions.concat(import_language_tools14.Processors.extensions),
|
|
1336
2083
|
exclude,
|
|
1337
2084
|
include,
|
|
1338
2085
|
depth
|
|
@@ -1379,12 +2126,12 @@ function patch(ts2, configFile, extractCache2, resolutionCache, host, ps) {
|
|
|
1379
2126
|
}
|
|
1380
2127
|
}
|
|
1381
2128
|
if (resolvedFileName) {
|
|
1382
|
-
if ((0,
|
|
2129
|
+
if ((0, import_language_tools14.isDefinitionFile)(resolvedFileName)) {
|
|
1383
2130
|
if (!host.fileExists(resolvedFileName)) {
|
|
1384
2131
|
resolvedFileName = void 0;
|
|
1385
2132
|
}
|
|
1386
2133
|
} else {
|
|
1387
|
-
const ext = (0,
|
|
2134
|
+
const ext = (0, import_language_tools14.getExt)(resolvedFileName);
|
|
1388
2135
|
const definitionFile = `${resolvedFileName.slice(
|
|
1389
2136
|
0,
|
|
1390
2137
|
-ext.length
|
|
@@ -1432,7 +2179,7 @@ function patch(ts2, configFile, extractCache2, resolutionCache, host, ps) {
|
|
|
1432
2179
|
}
|
|
1433
2180
|
return host;
|
|
1434
2181
|
function getProcessor(fileName) {
|
|
1435
|
-
const ext = (0,
|
|
2182
|
+
const ext = (0, import_language_tools14.getExt)(fileName);
|
|
1436
2183
|
return ext ? processors[ext] : void 0;
|
|
1437
2184
|
}
|
|
1438
2185
|
}
|
|
@@ -1589,7 +2336,7 @@ function escapeBackTicks(text) {
|
|
|
1589
2336
|
|
|
1590
2337
|
// src/service/script/index.ts
|
|
1591
2338
|
var IGNORE_DIAG_REG = /^(?:(?:Expression|Identifier|['"][^\w]['"]) expected|Invalid character)\b/i;
|
|
1592
|
-
var
|
|
2339
|
+
var extractCache2 = /* @__PURE__ */ new Map();
|
|
1593
2340
|
var snapshotCache = /* @__PURE__ */ new Map();
|
|
1594
2341
|
var insertModuleStatementLocCache = /* @__PURE__ */ new WeakMap();
|
|
1595
2342
|
var markoFileReg = /\.marko$/;
|
|
@@ -1638,7 +2385,7 @@ var ScriptService = {
|
|
|
1638
2385
|
return;
|
|
1639
2386
|
const tsProject = getTSProject(filename);
|
|
1640
2387
|
const extracted = processScript(doc, tsProject);
|
|
1641
|
-
const lang =
|
|
2388
|
+
const lang = import_language_tools15.Project.getScriptLang(
|
|
1642
2389
|
filename,
|
|
1643
2390
|
tsProject.markoScriptLang,
|
|
1644
2391
|
import_tsserverlibrary.default,
|
|
@@ -1648,14 +2395,14 @@ var ScriptService = {
|
|
|
1648
2395
|
const content = (() => {
|
|
1649
2396
|
try {
|
|
1650
2397
|
return prettier2.format(generated, {
|
|
1651
|
-
parser: lang ===
|
|
2398
|
+
parser: lang === import_language_tools15.ScriptLang.ts ? "typescript" : "babel"
|
|
1652
2399
|
});
|
|
1653
2400
|
} catch {
|
|
1654
2401
|
return generated;
|
|
1655
2402
|
}
|
|
1656
2403
|
})();
|
|
1657
2404
|
return {
|
|
1658
|
-
language: lang ===
|
|
2405
|
+
language: lang === import_language_tools15.ScriptLang.ts ? "typescript" : "javascript",
|
|
1659
2406
|
content
|
|
1660
2407
|
};
|
|
1661
2408
|
}
|
|
@@ -1667,10 +2414,10 @@ var ScriptService = {
|
|
|
1667
2414
|
onFileChange((doc) => {
|
|
1668
2415
|
if (doc) {
|
|
1669
2416
|
const filename = getFSPath(doc);
|
|
1670
|
-
|
|
2417
|
+
extractCache2.delete(filename);
|
|
1671
2418
|
snapshotCache.delete(filename);
|
|
1672
2419
|
} else {
|
|
1673
|
-
|
|
2420
|
+
extractCache2.clear();
|
|
1674
2421
|
snapshotCache.clear();
|
|
1675
2422
|
}
|
|
1676
2423
|
});
|
|
@@ -2018,12 +2765,12 @@ function processScript(doc, tsProject) {
|
|
|
2018
2765
|
return processDoc(doc, ({ filename, parsed, lookup }) => {
|
|
2019
2766
|
var _a;
|
|
2020
2767
|
const { host, markoScriptLang } = tsProject;
|
|
2021
|
-
return (0,
|
|
2768
|
+
return (0, import_language_tools15.extractScript)({
|
|
2022
2769
|
ts: import_tsserverlibrary.default,
|
|
2023
2770
|
parsed,
|
|
2024
2771
|
lookup,
|
|
2025
|
-
scriptLang:
|
|
2026
|
-
runtimeTypesCode: (_a =
|
|
2772
|
+
scriptLang: import_language_tools15.Project.getScriptLang(filename, markoScriptLang, import_tsserverlibrary.default, host),
|
|
2773
|
+
runtimeTypesCode: (_a = import_language_tools15.Project.getTypeLibs(tsProject.rootDir, import_tsserverlibrary.default, host)) == null ? void 0 : _a.markoTypesCode
|
|
2027
2774
|
});
|
|
2028
2775
|
});
|
|
2029
2776
|
}
|
|
@@ -2034,9 +2781,9 @@ function getInsertModuleStatementOffset(parsed) {
|
|
|
2034
2781
|
let lastImport;
|
|
2035
2782
|
for (const node of program.static) {
|
|
2036
2783
|
switch (node.type) {
|
|
2037
|
-
case
|
|
2784
|
+
case import_language_tools15.NodeType.Export:
|
|
2038
2785
|
return node.start;
|
|
2039
|
-
case
|
|
2786
|
+
case import_language_tools15.NodeType.Import:
|
|
2040
2787
|
lastImport = node;
|
|
2041
2788
|
break;
|
|
2042
2789
|
}
|
|
@@ -2077,7 +2824,7 @@ function docLocationAtTextSpan(doc, { start, length }) {
|
|
|
2077
2824
|
function getTSProject(docFsPath) {
|
|
2078
2825
|
var _a;
|
|
2079
2826
|
let configFile;
|
|
2080
|
-
let markoScriptLang =
|
|
2827
|
+
let markoScriptLang = import_language_tools15.ScriptLang.js;
|
|
2081
2828
|
if (docFsPath) {
|
|
2082
2829
|
configFile = import_tsserverlibrary.default.findConfigFile(
|
|
2083
2830
|
docFsPath,
|
|
@@ -2085,7 +2832,7 @@ function getTSProject(docFsPath) {
|
|
|
2085
2832
|
"tsconfig.json"
|
|
2086
2833
|
);
|
|
2087
2834
|
if (configFile) {
|
|
2088
|
-
markoScriptLang =
|
|
2835
|
+
markoScriptLang = import_language_tools15.ScriptLang.ts;
|
|
2089
2836
|
} else {
|
|
2090
2837
|
configFile = import_tsserverlibrary.default.findConfigFile(
|
|
2091
2838
|
docFsPath,
|
|
@@ -2095,7 +2842,7 @@ function getTSProject(docFsPath) {
|
|
|
2095
2842
|
}
|
|
2096
2843
|
}
|
|
2097
2844
|
const rootDir = configFile && import_path7.default.dirname(configFile) || process.cwd();
|
|
2098
|
-
const cache =
|
|
2845
|
+
const cache = import_language_tools15.Project.getCache(configFile && rootDir);
|
|
2099
2846
|
let projectCache = cache.get(getTSProject);
|
|
2100
2847
|
let cached;
|
|
2101
2848
|
if (projectCache) {
|
|
@@ -2132,7 +2879,7 @@ function getTSProject(docFsPath) {
|
|
|
2132
2879
|
const host = patch(
|
|
2133
2880
|
import_tsserverlibrary.default,
|
|
2134
2881
|
configFile,
|
|
2135
|
-
|
|
2882
|
+
extractCache2,
|
|
2136
2883
|
resolutionCache,
|
|
2137
2884
|
{
|
|
2138
2885
|
getNewLine() {
|
|
@@ -2234,7 +2981,7 @@ function filenameToURI(filename) {
|
|
|
2234
2981
|
}
|
|
2235
2982
|
async function getPreferences(scriptLang) {
|
|
2236
2983
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
2237
|
-
const configName = scriptLang ===
|
|
2984
|
+
const configName = scriptLang === import_language_tools15.ScriptLang.js ? "javascript" : "typescript";
|
|
2238
2985
|
const [preferencesConfig, suggestConfig, inlayHintsConfig] = await Promise.all([
|
|
2239
2986
|
getConfig(`${configName}.preferences`),
|
|
2240
2987
|
getConfig(`${configName}.suggest`),
|
|
@@ -2391,7 +3138,7 @@ function getCanonicalFileName(fileName) {
|
|
|
2391
3138
|
var import_vscode_css_languageservice2 = require("vscode-css-languageservice");
|
|
2392
3139
|
var import_vscode_languageserver11 = require("vscode-languageserver");
|
|
2393
3140
|
var import_vscode_languageserver_textdocument2 = require("vscode-languageserver-textdocument");
|
|
2394
|
-
var
|
|
3141
|
+
var import_language_tools16 = require("@marko/language-tools");
|
|
2395
3142
|
var services = {
|
|
2396
3143
|
".css": import_vscode_css_languageservice2.getCSSLanguageService,
|
|
2397
3144
|
".less": import_vscode_css_languageservice2.getLESSLanguageService,
|
|
@@ -2698,7 +3445,7 @@ function processStyle(doc) {
|
|
|
2698
3445
|
return processDoc(doc, ({ uri, version, parsed, lookup }) => {
|
|
2699
3446
|
var _a;
|
|
2700
3447
|
const result = [];
|
|
2701
|
-
for (const [ext, extracted] of (0,
|
|
3448
|
+
for (const [ext, extracted] of (0, import_language_tools16.extractStyle)({
|
|
2702
3449
|
parsed,
|
|
2703
3450
|
lookup
|
|
2704
3451
|
})) {
|
|
@@ -2782,7 +3529,7 @@ function isTextEdit(edit) {
|
|
|
2782
3529
|
|
|
2783
3530
|
// src/service/index.ts
|
|
2784
3531
|
var REG_MARKDOWN_CHARS = /[\\`*_{}[\]<>()#+.!|-]/g;
|
|
2785
|
-
var plugins = [marko_default, ScriptService, StyleSheetService];
|
|
3532
|
+
var plugins = [marko_default, ScriptService, StyleSheetService, html_default];
|
|
2786
3533
|
var service = {
|
|
2787
3534
|
commands: Object.assign({}, ...plugins.map(({ commands }) => commands)),
|
|
2788
3535
|
async initialize(params) {
|
|
@@ -3125,7 +3872,7 @@ console.error = (...args) => {
|
|
|
3125
3872
|
process.on("uncaughtException", console.error);
|
|
3126
3873
|
process.on("unhandledRejection", console.error);
|
|
3127
3874
|
connection3.onInitialize(async (params) => {
|
|
3128
|
-
|
|
3875
|
+
setup2(connection3);
|
|
3129
3876
|
await service.initialize(params);
|
|
3130
3877
|
return {
|
|
3131
3878
|
capabilities: {
|
|
@@ -3167,9 +3914,23 @@ connection3.onInitialize(async (params) => {
|
|
|
3167
3914
|
}
|
|
3168
3915
|
};
|
|
3169
3916
|
});
|
|
3170
|
-
setup2(connection3);
|
|
3171
|
-
onConfigChange(validateDocs);
|
|
3172
3917
|
setup(connection3);
|
|
3918
|
+
onConfigChange(validateDocs);
|
|
3919
|
+
connection3.onDidOpenTextDocument(async (params) => {
|
|
3920
|
+
doOpen(params);
|
|
3921
|
+
const doc = get(params.textDocument.uri);
|
|
3922
|
+
if (doc) {
|
|
3923
|
+
const diagnostics = await service.doValidate(doc) || [];
|
|
3924
|
+
prevDiags.set(doc, diagnostics);
|
|
3925
|
+
connection3.sendDiagnostics({
|
|
3926
|
+
uri: doc.uri,
|
|
3927
|
+
diagnostics
|
|
3928
|
+
});
|
|
3929
|
+
}
|
|
3930
|
+
});
|
|
3931
|
+
connection3.onDidChangeTextDocument(doChange);
|
|
3932
|
+
connection3.onDidCloseTextDocument(doClose);
|
|
3933
|
+
connection3.onDidChangeWatchedFiles(doChangeWatchedFiles);
|
|
3173
3934
|
onFileChange((changeDoc) => {
|
|
3174
3935
|
if (changeDoc) {
|
|
3175
3936
|
queueDiagnostic();
|
|
@@ -3270,7 +4031,7 @@ for (const command in service.commands) {
|
|
|
3270
4031
|
}
|
|
3271
4032
|
function validateDocs() {
|
|
3272
4033
|
queueDiagnostic();
|
|
3273
|
-
|
|
4034
|
+
import_language_tools17.Project.clearCaches();
|
|
3274
4035
|
}
|
|
3275
4036
|
function queueDiagnostic() {
|
|
3276
4037
|
clearTimeout(diagnosticTimeout);
|