@webround/editor 0.0.0-stage → 0.3.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/blocks.d.ts +90 -0
- package/dist/blocks.js +119 -0
- package/dist/bridge.d.ts +96 -0
- package/dist/bridge.js +970 -0
- package/dist/check/aria.d.ts +19 -0
- package/dist/check/aria.js +106 -0
- package/dist/check/cli.d.ts +3 -0
- package/dist/check/cli.js +30 -0
- package/dist/check/css.d.ts +13 -0
- package/dist/check/css.js +63 -0
- package/dist/check/html.d.ts +8 -0
- package/dist/check/html.js +29 -0
- package/dist/check/index.d.ts +4 -0
- package/dist/check/index.js +5 -0
- package/dist/check/links.d.ts +7 -0
- package/dist/check/links.js +23 -0
- package/dist/check/orphans.d.ts +20 -0
- package/dist/check/orphans.js +57 -0
- package/dist/check/producer-code.d.ts +53 -0
- package/dist/check/producer-code.js +379 -0
- package/dist/check/producer-dom.d.ts +21 -0
- package/dist/check/producer-dom.js +52 -0
- package/dist/check/project.d.ts +20 -0
- package/dist/check/project.js +51 -0
- package/dist/check/rules.d.ts +7 -0
- package/dist/check/rules.js +517 -0
- package/dist/check/types.d.ts +160 -0
- package/dist/check/types.js +22 -0
- package/dist/components/WrAltcha.d.ts +5 -0
- package/dist/components/WrAltcha.js +8 -0
- package/dist/components/WrButton.d.ts +8 -0
- package/dist/components/WrButton.js +34 -0
- package/dist/components/WrForm.d.ts +6 -0
- package/dist/components/WrForm.js +29 -0
- package/dist/components/WrFormPrivacy.d.ts +4 -0
- package/dist/components/WrFormPrivacy.js +7 -0
- package/dist/components/WrFormSuccess.d.ts +4 -0
- package/dist/components/WrFormSuccess.js +12 -0
- package/dist/components/WrIframe.d.ts +12 -0
- package/dist/components/WrIframe.js +30 -0
- package/dist/components/WrImage.d.ts +9 -0
- package/dist/components/WrImage.js +28 -0
- package/dist/components/WrInput.d.ts +8 -0
- package/dist/components/WrInput.js +29 -0
- package/dist/components/WrLink.d.ts +10 -0
- package/dist/components/WrLink.js +38 -0
- package/dist/components/WrNav.d.ts +26 -0
- package/dist/components/WrNav.js +30 -0
- package/dist/components/WrSection.d.ts +11 -0
- package/dist/components/WrSection.js +5 -0
- package/dist/components/WrShared.d.ts +12 -0
- package/dist/components/WrShared.js +20 -0
- package/dist/components/WrText.d.ts +11 -0
- package/dist/components/WrText.js +41 -0
- package/dist/components/WrVideo.d.ts +9 -0
- package/dist/components/WrVideo.js +73 -0
- package/dist/components/text-editor/CodeThemeContext.d.ts +8 -0
- package/dist/components/text-editor/CodeThemeContext.js +10 -0
- package/dist/components/text-editor/ExampleTheme.d.ts +77 -0
- package/dist/components/text-editor/ExampleTheme.js +76 -0
- package/dist/components/text-editor/ToolbarContext.d.ts +17 -0
- package/dist/components/text-editor/ToolbarContext.js +32 -0
- package/dist/components/text-editor/WrTextEditor.d.ts +13 -0
- package/dist/components/text-editor/WrTextEditor.js +48 -0
- package/dist/components/text-editor/common/constants.d.ts +109 -0
- package/dist/components/text-editor/common/constants.js +58 -0
- package/dist/components/text-editor/common/surface.d.ts +3 -0
- package/dist/components/text-editor/common/surface.js +8 -0
- package/dist/components/text-editor/common/utils.d.ts +7 -0
- package/dist/components/text-editor/common/utils.js +78 -0
- package/dist/components/text-editor/hooks/useLexicalCommitOnBlur.d.ts +5 -0
- package/dist/components/text-editor/hooks/useLexicalCommitOnBlur.js +41 -0
- package/dist/components/text-editor/hooks/useLexicalMarkdown.d.ts +33 -0
- package/dist/components/text-editor/hooks/useLexicalMarkdown.js +284 -0
- package/dist/components/text-editor/nodes/CodeBlockNode.d.ts +23 -0
- package/dist/components/text-editor/nodes/CodeBlockNode.js +138 -0
- package/dist/components/text-editor/nodes/HorizontalRuleNode.d.ts +13 -0
- package/dist/components/text-editor/nodes/HorizontalRuleNode.js +22 -0
- package/dist/components/text-editor/plugins/CodeBlockPlugin.d.ts +2 -0
- package/dist/components/text-editor/plugins/CodeBlockPlugin.js +38 -0
- package/dist/components/text-editor/plugins/FontPlugin.d.ts +12 -0
- package/dist/components/text-editor/plugins/FontPlugin.js +114 -0
- package/dist/components/text-editor/plugins/FontSizePlugin.d.ts +7 -0
- package/dist/components/text-editor/plugins/FontSizePlugin.js +105 -0
- package/dist/components/text-editor/plugins/FontWeightPlugin.d.ts +6 -0
- package/dist/components/text-editor/plugins/FontWeightPlugin.js +103 -0
- package/dist/components/text-editor/plugins/HTMLTagPlugin.d.ts +7 -0
- package/dist/components/text-editor/plugins/HTMLTagPlugin.js +82 -0
- package/dist/components/text-editor/plugins/HorizontalRulePlugin.d.ts +2 -0
- package/dist/components/text-editor/plugins/HorizontalRulePlugin.js +35 -0
- package/dist/components/text-editor/plugins/LineSpacingPlugin.d.ts +7 -0
- package/dist/components/text-editor/plugins/LineSpacingPlugin.js +83 -0
- package/dist/components/text-editor/plugins/LinkPlugin.d.ts +8 -0
- package/dist/components/text-editor/plugins/LinkPlugin.js +183 -0
- package/dist/components/text-editor/plugins/ListToolbarPlugin.d.ts +7 -0
- package/dist/components/text-editor/plugins/ListToolbarPlugin.js +40 -0
- package/dist/components/text-editor/plugins/LoadContentPlugin.d.ts +4 -0
- package/dist/components/text-editor/plugins/LoadContentPlugin.js +63 -0
- package/dist/components/text-editor/plugins/MarkdownExportPlugin.d.ts +4 -0
- package/dist/components/text-editor/plugins/MarkdownExportPlugin.js +17 -0
- package/dist/components/text-editor/plugins/MarkdownPastePlugin.d.ts +2 -0
- package/dist/components/text-editor/plugins/MarkdownPastePlugin.js +45 -0
- package/dist/components/text-editor/plugins/SanitizePastePlugin.d.ts +3 -0
- package/dist/components/text-editor/plugins/SanitizePastePlugin.js +40 -0
- package/dist/components/text-editor/plugins/TextAlignPlugin.d.ts +7 -0
- package/dist/components/text-editor/plugins/TextAlignPlugin.js +65 -0
- package/dist/components/text-editor/plugins/TextColorPlugin.d.ts +7 -0
- package/dist/components/text-editor/plugins/TextColorPlugin.js +117 -0
- package/dist/components/text-editor/plugins/ToolbarPlugin.d.ts +10 -0
- package/dist/components/text-editor/plugins/ToolbarPlugin.js +73 -0
- package/dist/components/text-editor/theme-colors.d.ts +11 -0
- package/dist/components/text-editor/theme-colors.js +28 -0
- package/dist/context/WrAppContext.d.ts +35 -0
- package/dist/context/WrAppContext.js +113 -0
- package/dist/context/WrLayout.d.ts +15 -0
- package/dist/context/WrLayout.js +22 -0
- package/dist/context/WrPageContext.d.ts +28 -0
- package/dist/context/WrPageContext.js +282 -0
- package/dist/context/restoreValues.d.ts +2 -0
- package/dist/context/restoreValues.js +6 -0
- package/dist/contrast.d.ts +45 -0
- package/dist/contrast.js +122 -0
- package/dist/drop.d.ts +7 -0
- package/dist/drop.js +51 -0
- package/dist/gaps.d.ts +14 -0
- package/dist/gaps.js +50 -0
- package/dist/hooks/useWrMessage.d.ts +5 -0
- package/dist/hooks/useWrMessage.js +24 -0
- package/dist/hooks/useWrSave.d.ts +2 -0
- package/dist/hooks/useWrSave.js +11 -0
- package/dist/index.css +467 -0
- package/dist/index.d.ts +20 -0
- package/dist/index.js +20 -0
- package/dist/interactive.d.ts +8 -0
- package/dist/interactive.js +13 -0
- package/dist/measure-rules.d.ts +34 -0
- package/dist/measure-rules.js +54 -0
- package/dist/measure.d.ts +11 -0
- package/dist/measure.js +139 -0
- package/dist/messages.d.ts +860 -0
- package/dist/messages.js +2 -0
- package/dist/nav.d.ts +5 -0
- package/dist/nav.js +10 -0
- package/dist/operations/animations-store.d.ts +6 -0
- package/dist/operations/animations-store.js +63 -0
- package/dist/operations/cli.d.ts +3 -0
- package/dist/operations/cli.js +52 -0
- package/dist/operations/comments-store.d.ts +17 -0
- package/dist/operations/comments-store.js +62 -0
- package/dist/operations/context.d.ts +12 -0
- package/dist/operations/context.js +35 -0
- package/dist/operations/define.d.ts +81 -0
- package/dist/operations/define.js +86 -0
- package/dist/operations/index.d.ts +6 -0
- package/dist/operations/index.js +6 -0
- package/dist/operations/ops/check.d.ts +5 -0
- package/dist/operations/ops/check.js +53 -0
- package/dist/operations/ops/comments.d.ts +6 -0
- package/dist/operations/ops/comments.js +133 -0
- package/dist/operations/ops/content.d.ts +16 -0
- package/dist/operations/ops/content.js +73 -0
- package/dist/operations/ops/json.d.ts +4 -0
- package/dist/operations/ops/json.js +27 -0
- package/dist/operations/ops/langs.d.ts +4 -0
- package/dist/operations/ops/langs.js +32 -0
- package/dist/operations/ops/nodes.d.ts +8 -0
- package/dist/operations/ops/nodes.js +270 -0
- package/dist/operations/ops/pages.d.ts +8 -0
- package/dist/operations/ops/pages.js +154 -0
- package/dist/operations/ops/project.d.ts +36 -0
- package/dist/operations/ops/project.js +97 -0
- package/dist/operations/ops/seo.d.ts +17 -0
- package/dist/operations/ops/seo.js +358 -0
- package/dist/operations/ops/style.d.ts +76 -0
- package/dist/operations/ops/style.js +268 -0
- package/dist/operations/ops/stylesets.d.ts +9 -0
- package/dist/operations/ops/stylesets.js +145 -0
- package/dist/operations/ops/theme.d.ts +6 -0
- package/dist/operations/ops/theme.js +304 -0
- package/dist/operations/registry.d.ts +8 -0
- package/dist/operations/registry.js +19 -0
- package/dist/operations/stylesets-store.d.ts +50 -0
- package/dist/operations/stylesets-store.js +216 -0
- package/dist/registry.d.ts +5 -0
- package/dist/registry.js +24 -0
- package/dist/save.d.ts +65 -0
- package/dist/save.js +86 -0
- package/dist/schema.d.ts +69 -0
- package/dist/schema.js +110 -0
- package/dist/scope.d.ts +41 -0
- package/dist/scope.js +44 -0
- package/dist/vite-plugins/ast.d.ts +3 -0
- package/dist/vite-plugins/ast.js +238 -0
- package/dist/vite-plugins/core-swap.d.ts +3 -0
- package/dist/vite-plugins/core-swap.js +57 -0
- package/dist/vite-plugins/create-page.d.ts +4 -0
- package/dist/vite-plugins/create-page.js +59 -0
- package/dist/vite-plugins/guard.d.ts +15 -0
- package/dist/vite-plugins/guard.js +35 -0
- package/dist/vite-plugins/head.d.ts +13 -0
- package/dist/vite-plugins/head.js +53 -0
- package/dist/vite-plugins/index.d.ts +7 -0
- package/dist/vite-plugins/index.js +7 -0
- package/dist/vite-plugins/jsx-tree.d.ts +118 -0
- package/dist/vite-plugins/jsx-tree.js +686 -0
- package/dist/vite-plugins/langs.d.ts +3 -0
- package/dist/vite-plugins/langs.js +44 -0
- package/dist/vite-plugins/operations.d.ts +10 -0
- package/dist/vite-plugins/operations.js +66 -0
- package/dist/vite-plugins/pages-api.d.ts +3 -0
- package/dist/vite-plugins/pages-api.js +112 -0
- package/dist/vite-plugins/pages.d.ts +3 -0
- package/dist/vite-plugins/pages.js +64 -0
- package/dist/vite-plugins/read.d.ts +3 -0
- package/dist/vite-plugins/read.js +45 -0
- package/dist/vite-plugins/seo-files.d.ts +8 -0
- package/dist/vite-plugins/seo-files.js +42 -0
- package/dist/vite-plugins/theme.d.ts +3 -0
- package/dist/vite-plugins/theme.js +207 -0
- package/dist/vite-plugins/update.d.ts +3 -0
- package/dist/vite-plugins/update.js +46 -0
- package/dist/vite-plugins/wr-plugins.d.ts +15 -0
- package/dist/vite-plugins/wr-plugins.js +34 -0
- package/dist/vite-plugins.d.ts +11 -0
- package/dist/vite-plugins.js +518 -0
- package/package.json +96 -5
- package/README.md +0 -3
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare const ARIA_ATTRIBUTES: ReadonlySet<string>;
|
|
2
|
+
export declare const ARIA_ROLES: ReadonlySet<string>;
|
|
3
|
+
/** A role is valid when it is one of these, or one of the digital-publishing (`doc-…`) and graphics (`graphics-…`) modules'. Several roles may be listed: the first the browser knows wins. */
|
|
4
|
+
export declare const isKnownRole: (role: string) => boolean;
|
|
5
|
+
/** The attributes a role cannot be used without (the ones with no default that tell a screen reader what the thing is doing). */
|
|
6
|
+
export declare const REQUIRED_BY_ROLE: Readonly<Record<string, readonly string[]>>;
|
|
7
|
+
/** Elements that take the keyboard focus by themselves. */
|
|
8
|
+
export declare const FOCUSABLE_TAGS: ReadonlySet<string>;
|
|
9
|
+
/** Elements that are only a container: a name on them is not announced unless they have a role. */
|
|
10
|
+
export declare const GENERIC_TAGS: ReadonlySet<string>;
|
|
11
|
+
/** Link texts that say nothing about where the link goes (WCAG 2.4.4), by language: lowercase, without punctuation. */
|
|
12
|
+
export declare const GENERIC_LINK_TEXTS: ReadonlySet<string>;
|
|
13
|
+
/** A link's text the way it is compared: lowercase, no punctuation or arrows, one space between words. */
|
|
14
|
+
export declare const normalizedLinkText: (text: string) => string;
|
|
15
|
+
/** Is this a value `autocomplete` can have: `on`, `off`, or [section-x] [shipping|billing] [home|work|mobile|fax|pager] field [webauthn]. */
|
|
16
|
+
export declare function isValidAutocomplete(value: string): boolean;
|
|
17
|
+
/** The `autocomplete` a field should have, from what it is (its type, its name): undefined when it is not asking about the person or we cannot tell. */
|
|
18
|
+
export declare function expectedAutocomplete(attrs: Record<string, string>): string | undefined;
|
|
19
|
+
//# sourceMappingURL=aria.d.ts.map
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// What WAI-ARIA 1.2 says exists: its attributes, its roles, and what a role cannot do without. Data, not code: the rules read it.
|
|
2
|
+
export const ARIA_ATTRIBUTES = new Set([
|
|
3
|
+
'activedescendant', 'atomic', 'autocomplete', 'braillelabel', 'brailleroledescription', 'busy', 'checked', 'colcount', 'colindex', 'colindextext',
|
|
4
|
+
'colspan', 'controls', 'current', 'describedby', 'description', 'details', 'disabled', 'dropeffect', 'errormessage', 'expanded', 'flowto', 'grabbed',
|
|
5
|
+
'haspopup', 'hidden', 'invalid', 'keyshortcuts', 'label', 'labelledby', 'level', 'live', 'modal', 'multiline', 'multiselectable', 'orientation',
|
|
6
|
+
'owns', 'placeholder', 'posinset', 'pressed', 'readonly', 'relevant', 'required', 'roledescription', 'rowcount', 'rowindex', 'rowindextext',
|
|
7
|
+
'rowspan', 'selected', 'setsize', 'sort', 'valuemax', 'valuemin', 'valuenow', 'valuetext',
|
|
8
|
+
]);
|
|
9
|
+
export const ARIA_ROLES = new Set([
|
|
10
|
+
'alert', 'alertdialog', 'application', 'article', 'banner', 'blockquote', 'button', 'caption', 'cell', 'checkbox', 'code', 'columnheader', 'combobox',
|
|
11
|
+
'complementary', 'contentinfo', 'definition', 'deletion', 'dialog', 'directory', 'document', 'emphasis', 'feed', 'figure', 'form', 'generic', 'grid',
|
|
12
|
+
'gridcell', 'group', 'heading', 'img', 'insertion', 'link', 'list', 'listbox', 'listitem', 'log', 'main', 'marquee', 'math', 'meter', 'menu', 'menubar',
|
|
13
|
+
'menuitem', 'menuitemcheckbox', 'menuitemradio', 'navigation', 'none', 'note', 'option', 'paragraph', 'presentation', 'progressbar', 'radio',
|
|
14
|
+
'radiogroup', 'region', 'row', 'rowgroup', 'rowheader', 'scrollbar', 'search', 'searchbox', 'separator', 'slider', 'spinbutton', 'status', 'strong',
|
|
15
|
+
'subscript', 'superscript', 'switch', 'tab', 'table', 'tablist', 'tabpanel', 'term', 'textbox', 'time', 'timer', 'toolbar', 'tooltip', 'tree', 'treegrid',
|
|
16
|
+
'treeitem',
|
|
17
|
+
]);
|
|
18
|
+
/** A role is valid when it is one of these, or one of the digital-publishing (`doc-…`) and graphics (`graphics-…`) modules'. Several roles may be listed: the first the browser knows wins. */
|
|
19
|
+
export const isKnownRole = (role) => ARIA_ROLES.has(role) || /^(doc|graphics)-[a-z]+$/.test(role);
|
|
20
|
+
/** The attributes a role cannot be used without (the ones with no default that tell a screen reader what the thing is doing). */
|
|
21
|
+
export const REQUIRED_BY_ROLE = {
|
|
22
|
+
checkbox: ['checked'],
|
|
23
|
+
switch: ['checked'],
|
|
24
|
+
radio: ['checked'],
|
|
25
|
+
menuitemcheckbox: ['checked'],
|
|
26
|
+
menuitemradio: ['checked'],
|
|
27
|
+
combobox: ['expanded', 'controls'],
|
|
28
|
+
heading: ['level'],
|
|
29
|
+
slider: ['valuenow'],
|
|
30
|
+
scrollbar: ['controls', 'valuenow'],
|
|
31
|
+
spinbutton: ['valuenow'],
|
|
32
|
+
option: ['selected'],
|
|
33
|
+
};
|
|
34
|
+
/** Elements that take the keyboard focus by themselves. */
|
|
35
|
+
export const FOCUSABLE_TAGS = new Set(['button', 'select', 'textarea', 'summary']);
|
|
36
|
+
/** Elements that are only a container: a name on them is not announced unless they have a role. */
|
|
37
|
+
export const GENERIC_TAGS = new Set(['div', 'span', 'p']);
|
|
38
|
+
/** Link texts that say nothing about where the link goes (WCAG 2.4.4), by language: lowercase, without punctuation. */
|
|
39
|
+
export const GENERIC_LINK_TEXTS = new Set([
|
|
40
|
+
'click here', 'click', 'here', 'read more', 'more', 'learn more', 'more info', 'link', 'this link', 'details', 'continue',
|
|
41
|
+
'clicca qui', 'clicca', 'qui', 'leggi di più', 'leggi di piu', 'scopri di più', 'scopri di piu', 'altro', 'maggiori informazioni', 'dettagli', 'continua',
|
|
42
|
+
'cliquez ici', 'ici', 'en savoir plus', 'lire la suite', 'plus', 'plus d’infos', "plus d'infos", 'détails',
|
|
43
|
+
'hier klicken', 'hier', 'mehr', 'mehr erfahren', 'weiterlesen', 'mehr lesen', 'details ansehen',
|
|
44
|
+
'haz clic aquí', 'haz clic aqui', 'aquí', 'aqui', 'leer más', 'leer mas', 'más información', 'mas informacion', 'saber más', 'saber mas', 'detalles',
|
|
45
|
+
]);
|
|
46
|
+
/** A link's text the way it is compared: lowercase, no punctuation or arrows, one space between words. */
|
|
47
|
+
export const normalizedLinkText = (text) => text.toLowerCase().replace(/[\p{P}\p{S}]+/gu, ' ').replace(/\s+/g, ' ').trim();
|
|
48
|
+
// ── Autocomplete (WCAG 1.3.5): the fields that ask for something about the person say what, in the browser's own words ──
|
|
49
|
+
const AUTOFILL_FIELDS = new Set([
|
|
50
|
+
'name', 'honorific-prefix', 'given-name', 'additional-name', 'family-name', 'honorific-suffix', 'nickname', 'email', 'username', 'new-password',
|
|
51
|
+
'current-password', 'one-time-code', 'organization-title', 'organization', 'street-address', 'address-line1', 'address-line2', 'address-line3',
|
|
52
|
+
'address-level4', 'address-level3', 'address-level2', 'address-level1', 'country', 'country-name', 'postal-code', 'cc-name', 'cc-given-name',
|
|
53
|
+
'cc-additional-name', 'cc-family-name', 'cc-number', 'cc-exp', 'cc-exp-month', 'cc-exp-year', 'cc-csc', 'cc-type', 'transaction-currency',
|
|
54
|
+
'transaction-amount', 'language', 'bday', 'bday-day', 'bday-month', 'bday-year', 'sex', 'url', 'photo', 'tel', 'tel-country-code', 'tel-national',
|
|
55
|
+
'tel-area-code', 'tel-local', 'tel-extension', 'impp',
|
|
56
|
+
]);
|
|
57
|
+
const AUTOFILL_CONTACT = new Set(['home', 'work', 'mobile', 'fax', 'pager']);
|
|
58
|
+
/** Is this a value `autocomplete` can have: `on`, `off`, or [section-x] [shipping|billing] [home|work|mobile|fax|pager] field [webauthn]. */
|
|
59
|
+
export function isValidAutocomplete(value) {
|
|
60
|
+
const tokens = value.trim().toLowerCase().split(/\s+/).filter(Boolean);
|
|
61
|
+
if (tokens.length === 0)
|
|
62
|
+
return false;
|
|
63
|
+
if (tokens.length === 1 && (tokens[0] === 'on' || tokens[0] === 'off'))
|
|
64
|
+
return true;
|
|
65
|
+
if (tokens[tokens.length - 1] === 'webauthn')
|
|
66
|
+
tokens.pop();
|
|
67
|
+
while (tokens[0]?.startsWith('section-'))
|
|
68
|
+
tokens.shift();
|
|
69
|
+
if (tokens[0] === 'shipping' || tokens[0] === 'billing')
|
|
70
|
+
tokens.shift();
|
|
71
|
+
if (tokens.length === 2 && AUTOFILL_CONTACT.has(tokens[0]) && ['tel', 'tel-country-code', 'tel-national', 'tel-area-code', 'tel-local', 'tel-extension', 'email', 'impp'].includes(tokens[1]))
|
|
72
|
+
return true;
|
|
73
|
+
return tokens.length === 1 && AUTOFILL_FIELDS.has(tokens[0]);
|
|
74
|
+
}
|
|
75
|
+
/** Field types that hold something a person chooses (a box to tick, a file) rather than something about them. */
|
|
76
|
+
const NOT_ABOUT_THE_PERSON = new Set(['hidden', 'submit', 'button', 'reset', 'image', 'checkbox', 'radio', 'file', 'range', 'color', 'date', 'datetime-local', 'month', 'week', 'time', 'number', 'search']);
|
|
77
|
+
const BY_NAME = [
|
|
78
|
+
[/^(e-?mail|email-?address|mail)$/, 'email'],
|
|
79
|
+
[/^(tel|telephone|phone|phone-?number|mobile|cell|telefono|cellulare)$/, 'tel'],
|
|
80
|
+
[/^(first-?name|given-?name|fname|nome|prenom|vorname)$/, 'given-name'],
|
|
81
|
+
[/^(last-?name|family-?name|surname|lname|cognome|nom|nachname)$/, 'family-name'],
|
|
82
|
+
[/^(full-?name|your-?name|name|nominativo)$/, 'name'],
|
|
83
|
+
[/^(user-?name|login|user|utente)$/, 'username'],
|
|
84
|
+
[/^(street|street-?address|address|address-?line-?1|indirizzo|via)$/, 'street-address'],
|
|
85
|
+
[/^(city|town|citta|città|comune|ville|stadt)$/, 'address-level2'],
|
|
86
|
+
[/^(zip|zip-?code|postal-?code|postcode|cap|code-?postal|plz)$/, 'postal-code'],
|
|
87
|
+
[/^(country|nation|paese|pays|land)$/, 'country-name'],
|
|
88
|
+
[/^(company|organi[sz]ation|azienda|societa|società|ragione-?sociale)$/, 'organization'],
|
|
89
|
+
[/^(cc-?number|card-?number|credit-?card)$/, 'cc-number'],
|
|
90
|
+
[/^(bday|birthday|birth-?date|data-?di-?nascita)$/, 'bday'],
|
|
91
|
+
];
|
|
92
|
+
/** The `autocomplete` a field should have, from what it is (its type, its name): undefined when it is not asking about the person or we cannot tell. */
|
|
93
|
+
export function expectedAutocomplete(attrs) {
|
|
94
|
+
const type = (attrs.type ?? 'text').toLowerCase();
|
|
95
|
+
if (NOT_ABOUT_THE_PERSON.has(type))
|
|
96
|
+
return undefined;
|
|
97
|
+
if (type === 'email')
|
|
98
|
+
return 'email';
|
|
99
|
+
if (type === 'tel')
|
|
100
|
+
return 'tel';
|
|
101
|
+
if (type === 'password')
|
|
102
|
+
return 'current-password';
|
|
103
|
+
const label = (attrs.name ?? '').toLowerCase().replace(/[_\s.]+/g, '-').replace(/\[\]/g, '');
|
|
104
|
+
return BY_NAME.find(([pattern]) => pattern.test(label))?.[1];
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=aria.js.map
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { checkProject } from './project.js';
|
|
4
|
+
import { CHECK_SITE } from './types.js';
|
|
5
|
+
// wr-check [dir] [--json] [--strict]
|
|
6
|
+
// Exits 1 on errors (and on warnings with --strict): the one command a person, a script or an agent runs to know if the site is fine.
|
|
7
|
+
const args = process.argv.slice(2);
|
|
8
|
+
const json = args.includes('--json');
|
|
9
|
+
const strict = args.includes('--strict');
|
|
10
|
+
const root = path.resolve(args.find(a => !a.startsWith('--')) ?? process.cwd());
|
|
11
|
+
const all = checkProject(root);
|
|
12
|
+
// A problem the person silenced is still found, and counted apart: it does not fail the check
|
|
13
|
+
const issues = all.filter(i => !i.muted);
|
|
14
|
+
const silenced = all.length - issues.length;
|
|
15
|
+
if (json) {
|
|
16
|
+
console.log(JSON.stringify(all, null, 2));
|
|
17
|
+
}
|
|
18
|
+
else if (issues.length === 0) {
|
|
19
|
+
console.log(`wr-check: no issues.${silenced ? ` (${silenced} silenced)` : ''}`);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
for (const i of issues) {
|
|
23
|
+
const at = i.where ? `src/${i.where.file}:${i.where.line}` : (i.page === CHECK_SITE ? 'the site' : `page ${i.page}`);
|
|
24
|
+
console.log(`${i.severity === 'error' ? 'error ' : 'warning'} ${at} ${i.message}${i.langs ? ` (${i.langs.join(', ')})` : ''} [${i.rule}]`);
|
|
25
|
+
}
|
|
26
|
+
const errors = issues.filter(i => i.severity === 'error').length;
|
|
27
|
+
console.log(`\n${errors} error(s), ${issues.length - errors} warning(s)${silenced ? `, ${silenced} silenced` : ''}.`);
|
|
28
|
+
}
|
|
29
|
+
process.exit(issues.some(i => i.severity === 'error' || strict) ? 1 : 0);
|
|
30
|
+
//# sourceMappingURL=cli.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface CheckCss {
|
|
2
|
+
/** Rules that remove the outline of a focused element and put nothing in its place (WCAG 2.4.7). */
|
|
3
|
+
focusRemoved: {
|
|
4
|
+
file: string;
|
|
5
|
+
selector: string;
|
|
6
|
+
}[];
|
|
7
|
+
/** Something is animated by the stylesheets (`animation`, `@keyframes`, a `--animate-*` token). */
|
|
8
|
+
animates: boolean;
|
|
9
|
+
/** Some `@media (prefers-reduced-motion)` exists. */
|
|
10
|
+
reducesMotion: boolean;
|
|
11
|
+
}
|
|
12
|
+
export declare function readCss(srcRoot: string): CheckCss;
|
|
13
|
+
//# sourceMappingURL=css.d.ts.map
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import postcss from 'postcss';
|
|
4
|
+
const REMOVES_OUTLINE = (prop, value) => (prop === 'outline' && /^(none|0|0px|transparent)\b/i.test(value.trim()))
|
|
5
|
+
|| (prop === 'outline-style' && /^none\b/i.test(value.trim()))
|
|
6
|
+
|| (prop === 'outline-width' && /^0(px)?\b/.test(value.trim()));
|
|
7
|
+
/** A value that says there is nothing (a shadow of `none`; note that `0 0 0 3px blue` is a shadow, one that starts with a zero offset). */
|
|
8
|
+
const NOTHING = /^(none|initial|unset|inherit|transparent)\b/i;
|
|
9
|
+
/** Anything else that shows where the focus is. */
|
|
10
|
+
const SHOWS_FOCUS = new Set(['box-shadow', 'border', 'border-color', 'border-width', 'background', 'background-color', 'text-decoration', 'outline-color', 'filter']);
|
|
11
|
+
function cssFiles(dir) {
|
|
12
|
+
if (!fs.existsSync(dir))
|
|
13
|
+
return [];
|
|
14
|
+
return fs.readdirSync(dir, { withFileTypes: true }).flatMap(entry => {
|
|
15
|
+
const full = path.join(dir, entry.name);
|
|
16
|
+
return entry.isDirectory() ? cssFiles(full) : entry.name.endsWith('.css') ? [full] : [];
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
export function readCss(srcRoot) {
|
|
20
|
+
const result = { focusRemoved: [], animates: false, reducesMotion: false };
|
|
21
|
+
for (const file of cssFiles(srcRoot)) {
|
|
22
|
+
let root;
|
|
23
|
+
try {
|
|
24
|
+
root = postcss.parse(fs.readFileSync(file, 'utf-8'));
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
continue;
|
|
28
|
+
} // a file half-written: the next check reads it whole
|
|
29
|
+
const relative = path.relative(srcRoot, file).split(path.sep).join('/');
|
|
30
|
+
root.walkAtRules(rule => {
|
|
31
|
+
if (rule.name === 'keyframes')
|
|
32
|
+
result.animates = true;
|
|
33
|
+
if (rule.name === 'media' && /prefers-reduced-motion/i.test(rule.params))
|
|
34
|
+
result.reducesMotion = true;
|
|
35
|
+
});
|
|
36
|
+
root.walkDecls(decl => {
|
|
37
|
+
if (/^animation(-name)?$/.test(decl.prop) && !/^none\b/i.test(decl.value.trim()))
|
|
38
|
+
result.animates = true;
|
|
39
|
+
if (decl.prop.startsWith('--animate-'))
|
|
40
|
+
result.animates = true;
|
|
41
|
+
});
|
|
42
|
+
root.walkRules(rule => {
|
|
43
|
+
if (!/:focus/.test(rule.selector))
|
|
44
|
+
return;
|
|
45
|
+
if (rule.parent?.type === 'atrule' && /forced-colors/.test(rule.parent.params))
|
|
46
|
+
return;
|
|
47
|
+
let removes = false;
|
|
48
|
+
let shows = false;
|
|
49
|
+
rule.walkDecls(decl => {
|
|
50
|
+
if (REMOVES_OUTLINE(decl.prop, decl.value))
|
|
51
|
+
removes = true;
|
|
52
|
+
else if (SHOWS_FOCUS.has(decl.prop) && !NOTHING.test(decl.value.trim()) && !(/^border(-width)?$/.test(decl.prop) && /^0(px)?(\s|$)/.test(decl.value.trim())))
|
|
53
|
+
shows = true;
|
|
54
|
+
else if (decl.prop === 'outline' && !REMOVES_OUTLINE(decl.prop, decl.value))
|
|
55
|
+
shows = true;
|
|
56
|
+
});
|
|
57
|
+
if (removes && !shows)
|
|
58
|
+
result.focusRemoved.push({ file: relative, selector: rule.selector.replace(/\s+/g, ' ').trim() });
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=css.js.map
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type CheckNode } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* What the HTML of a rich text holds that the checks care about: its headings and its links (in document order), then its paragraphs. A text is only a container (a `div`): what it is, a heading or a paragraph, is what the editor wrote inside it. The DOM producer sees
|
|
4
|
+
* them (they are in the page); the code producer only has the string the editor wrote in the JSON (`<h1 class="editor-heading-h1">…`),
|
|
5
|
+
* so it reads them here. Without this a heading made inside a text is invisible to the rules (a page "without h1" that has one).
|
|
6
|
+
*/
|
|
7
|
+
export declare function htmlNodes(html: string): CheckNode[];
|
|
8
|
+
//# sourceMappingURL=html.d.ts.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { stripTags } from './types.js';
|
|
2
|
+
const ATTR = /([a-zA-Z-]+)\s*=\s*"([^"]*)"|([a-zA-Z-]+)\s*=\s*'([^']*)'/g;
|
|
3
|
+
const attrsOf = (source, names) => {
|
|
4
|
+
const found = {};
|
|
5
|
+
for (const [, a, av, b, bv] of source.matchAll(ATTR)) {
|
|
6
|
+
const name = (a ?? b).toLowerCase();
|
|
7
|
+
if (names.includes(name))
|
|
8
|
+
found[name] = av ?? bv;
|
|
9
|
+
}
|
|
10
|
+
return found;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* What the HTML of a rich text holds that the checks care about: its headings and its links (in document order), then its paragraphs. A text is only a container (a `div`): what it is, a heading or a paragraph, is what the editor wrote inside it. The DOM producer sees
|
|
14
|
+
* them (they are in the page); the code producer only has the string the editor wrote in the JSON (`<h1 class="editor-heading-h1">…`),
|
|
15
|
+
* so it reads them here. Without this a heading made inside a text is invisible to the rules (a page "without h1" that has one).
|
|
16
|
+
*/
|
|
17
|
+
export function htmlNodes(html) {
|
|
18
|
+
const nodes = [];
|
|
19
|
+
for (const [, tag, rest, inner] of html.matchAll(/<(h[1-6]|a)\b([^>]*)>([\s\S]*?)<\/\1\s*>/gi)) {
|
|
20
|
+
const name = tag.toLowerCase();
|
|
21
|
+
const attrs = name === 'a' ? attrsOf(rest, ['href', 'aria-label']) : {};
|
|
22
|
+
nodes.push({ kind: 'element', tag: name, attrs, text: stripTags(inner), children: [] });
|
|
23
|
+
}
|
|
24
|
+
// Paragraphs after (a link inside one stays a link of its own: the first pass found it)
|
|
25
|
+
for (const [, inner] of html.matchAll(/<p\b[^>]*>([\s\S]*?)<\/p\s*>/gi))
|
|
26
|
+
nodes.push({ kind: 'element', tag: 'p', attrs: {}, text: stripTags(inner), children: [] });
|
|
27
|
+
return nodes;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=html.js.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// Browser-safe part: the tree, the rules and the DOM producer. The code producer (Node, ts-morph) is `@webround/editor/check/code`.
|
|
2
|
+
export * from './types.js';
|
|
3
|
+
export { RULES, SITE_RULES, runRules, runSiteRules } from './rules.js';
|
|
4
|
+
export { checkPageFromDom, checkPageFromSerialized, serializeDom } from './producer-dom.js';
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { CheckProject } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Does an internal address (`/about`, `/en/about?x=1#top`) lead somewhere in the site: a page (in any language), or a file served as it is?
|
|
4
|
+
* Addresses to other sites, `mailto:`, `tel:` and in-page anchors are not the site's to judge: they lead somewhere as far as this knows.
|
|
5
|
+
*/
|
|
6
|
+
export declare function leadsSomewhere(href: string, project: CheckProject): boolean;
|
|
7
|
+
//# sourceMappingURL=links.d.ts.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { wrBuildLangPath, wrRoutePattern } from '@webround/core/routing';
|
|
2
|
+
const FOREIGN = /^(?:[a-z][a-z0-9+.-]*:|\/\/|#)/i;
|
|
3
|
+
/** A route path as a pattern that matches addresses: `blog/[slug]` matches `/blog/anything` (one segment). */
|
|
4
|
+
const matcherOf = (route) => {
|
|
5
|
+
const pattern = wrRoutePattern(route).split('/').map(part => part.startsWith(':') ? '[^/]+' : part.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')).join('/');
|
|
6
|
+
return new RegExp(`^${pattern}/?$`);
|
|
7
|
+
};
|
|
8
|
+
/**
|
|
9
|
+
* Does an internal address (`/about`, `/en/about?x=1#top`) lead somewhere in the site: a page (in any language), or a file served as it is?
|
|
10
|
+
* Addresses to other sites, `mailto:`, `tel:` and in-page anchors are not the site's to judge: they lead somewhere as far as this knows.
|
|
11
|
+
*/
|
|
12
|
+
export function leadsSomewhere(href, project) {
|
|
13
|
+
const target = href.trim();
|
|
14
|
+
if (!target || FOREIGN.test(target) || !target.startsWith('/'))
|
|
15
|
+
return true;
|
|
16
|
+
const pathname = target.split(/[?#]/)[0] || '/';
|
|
17
|
+
if (project.publicFiles.includes(pathname))
|
|
18
|
+
return true;
|
|
19
|
+
const langs = project.langs;
|
|
20
|
+
const withoutLang = langs ? wrBuildLangPath('default', pathname, langs) : pathname;
|
|
21
|
+
return project.routes.some(route => matcherOf(route).test(withoutLang));
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=links.js.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { OperationContext } from '../operations/define.js';
|
|
2
|
+
export declare function sourceFiles(dir: string): string[];
|
|
3
|
+
/** Every id the code of `src/` spells out, and whether some element computes its id. */
|
|
4
|
+
export declare function idsInCode(ctx: OperationContext): {
|
|
5
|
+
ids: Set<string>;
|
|
6
|
+
dynamicIds: boolean;
|
|
7
|
+
};
|
|
8
|
+
/** The scopes whose JSON holds a page's values: every page, and every shared component (the header, the footer, the ones the site declares). */
|
|
9
|
+
export declare const jsonScopes: (ctx: OperationContext) => string[];
|
|
10
|
+
/** The keys of each scope's JSON that belong to no element of the code. Keys that are not element ids (`_seo`) are never orphans. */
|
|
11
|
+
export declare function findOrphanKeys(ctx: OperationContext): {
|
|
12
|
+
orphans: {
|
|
13
|
+
scope: string;
|
|
14
|
+
keys: string[];
|
|
15
|
+
}[];
|
|
16
|
+
dynamicIds: boolean;
|
|
17
|
+
};
|
|
18
|
+
/** The ids of the form fields some `<label htmlFor="…">` of the code points at (a field with one has a label even if it is not inside it). */
|
|
19
|
+
export declare function idsLabelledInCode(ctx: OperationContext): string[];
|
|
20
|
+
//# sourceMappingURL=orphans.d.ts.map
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { wrPageConfigPath } from '@webround/core/routing';
|
|
4
|
+
import { readJsonFile, readRoutes, sharedScopesOf } from '../operations/ops/project.js';
|
|
5
|
+
// The JSON of a page holds values keyed by the id of the element they belong to. When the element goes (deleted in VS Code, renamed), its key
|
|
6
|
+
// stays, and comes back to life with the old text if the id is ever used again. Finding them means knowing every id the code has — in ALL of
|
|
7
|
+
// `src/`, not only in the page's file: a component in `src/components/` has elements of its own.
|
|
8
|
+
const SOURCE = /\.(tsx|jsx)$/;
|
|
9
|
+
/** `id="x"`, `id='x'`, `id={"x"}`, `id={'x'}`, id={`x`}: an id the code spells out. */
|
|
10
|
+
const LITERAL_ID = /\bid\s*=\s*(?:"([^"\n]+)"|'([^'\n]+)'|\{\s*(?:"([^"\n]+)"|'([^'\n]+)'|`([^`$\n]+)`)\s*\})/g;
|
|
11
|
+
/** An element of ours whose id the code computes (`id={`card-${i}`}`, `id={id}`): which keys it will use is not readable. */
|
|
12
|
+
const COMPUTED_ID = /<Wr[A-Za-z]*\b[^>]*?\bid\s*=\s*\{(?!\s*(?:"[^"\n]*"|'[^'\n]*'|`[^`$\n]*`)\s*\})/;
|
|
13
|
+
export function sourceFiles(dir) {
|
|
14
|
+
if (!fs.existsSync(dir))
|
|
15
|
+
return [];
|
|
16
|
+
return fs.readdirSync(dir, { withFileTypes: true }).flatMap(entry => {
|
|
17
|
+
const full = path.join(dir, entry.name);
|
|
18
|
+
return entry.isDirectory() ? sourceFiles(full) : SOURCE.test(entry.name) ? [full] : [];
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
/** Every id the code of `src/` spells out, and whether some element computes its id. */
|
|
22
|
+
export function idsInCode(ctx) {
|
|
23
|
+
const ids = new Set();
|
|
24
|
+
let dynamicIds = false;
|
|
25
|
+
for (const file of sourceFiles(ctx.srcRoot)) {
|
|
26
|
+
const code = fs.readFileSync(file, 'utf-8');
|
|
27
|
+
for (const match of code.matchAll(LITERAL_ID))
|
|
28
|
+
ids.add(match[1] ?? match[2] ?? match[3] ?? match[4] ?? match[5]);
|
|
29
|
+
if (COMPUTED_ID.test(code))
|
|
30
|
+
dynamicIds = true;
|
|
31
|
+
}
|
|
32
|
+
return { ids, dynamicIds };
|
|
33
|
+
}
|
|
34
|
+
/** The scopes whose JSON holds a page's values: every page, and every shared component (the header, the footer, the ones the site declares). */
|
|
35
|
+
export const jsonScopes = (ctx) => [...Object.keys(readRoutes(ctx)), ...sharedScopesOf(ctx).map(scope => scope.name)];
|
|
36
|
+
/** The keys of each scope's JSON that belong to no element of the code. Keys that are not element ids (`_seo`) are never orphans. */
|
|
37
|
+
export function findOrphanKeys(ctx) {
|
|
38
|
+
const { ids, dynamicIds } = idsInCode(ctx);
|
|
39
|
+
const orphans = [];
|
|
40
|
+
for (const scope of jsonScopes(ctx)) {
|
|
41
|
+
const json = readJsonFile(ctx, wrPageConfigPath(scope));
|
|
42
|
+
const keys = Object.keys(json ?? {}).filter(key => !key.startsWith('_') && !ids.has(key));
|
|
43
|
+
if (keys.length > 0)
|
|
44
|
+
orphans.push({ scope, keys });
|
|
45
|
+
}
|
|
46
|
+
return { orphans, dynamicIds };
|
|
47
|
+
}
|
|
48
|
+
/** The ids of the form fields some `<label htmlFor="…">` of the code points at (a field with one has a label even if it is not inside it). */
|
|
49
|
+
export function idsLabelledInCode(ctx) {
|
|
50
|
+
const ids = new Set();
|
|
51
|
+
for (const file of sourceFiles(ctx.srcRoot)) {
|
|
52
|
+
for (const match of fs.readFileSync(file, 'utf-8').matchAll(/\bhtmlFor\s*=\s*(?:"([^"\n]+)"|'([^'\n]+)'|\{\s*(?:"([^"\n]+)"|'([^'\n]+)')\s*\})/g))
|
|
53
|
+
ids.add(match[1] ?? match[2] ?? match[3] ?? match[4]);
|
|
54
|
+
}
|
|
55
|
+
return [...ids];
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=orphans.js.map
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { OperationContext } from '../operations/define.js';
|
|
2
|
+
import { type ScopeFiles } from '../operations/ops/project.js';
|
|
3
|
+
import { type CheckNode, type CheckPage, type CheckSite } from './types.js';
|
|
4
|
+
/** What reading the tree is for: the checks count what renders; an outline shows what is there, hidden or not. */
|
|
5
|
+
export interface ReadOptions {
|
|
6
|
+
includeHidden?: boolean;
|
|
7
|
+
/** Put the scope's name on every node. */
|
|
8
|
+
scope?: string;
|
|
9
|
+
/** The language to read (`default`, or a code): what a visitor of it reads, with the same fallback to the default one as the components. */
|
|
10
|
+
lang?: string;
|
|
11
|
+
/** Where a shared component a page uses is entered (see `sharedFollower`); without it a component is only transparent. */
|
|
12
|
+
follow?: SharedFollower;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The shared components a page uses (a card, a banner: the ones `config/shared.json` declares) are part of the page: reading enters their
|
|
16
|
+
* file, with their own JSON, where the page uses them. A component is read ONCE per page (`seen`: the same card in a grid, or used twice,
|
|
17
|
+
* is the same elements: reading it twice would make every id a duplicate), and what is wrong in its file is gathered in `syntax`.
|
|
18
|
+
*/
|
|
19
|
+
export interface SharedFollower {
|
|
20
|
+
ctx: OperationContext;
|
|
21
|
+
scopes: ScopeFiles[];
|
|
22
|
+
seen: Set<string>;
|
|
23
|
+
syntax: CheckScope['syntax'];
|
|
24
|
+
}
|
|
25
|
+
/** A follower for ONE page: the shared components a site declares, none seen yet. The header and the footer are read as the scopes they are, not followed. */
|
|
26
|
+
export declare function sharedFollower(ctx: OperationContext): SharedFollower;
|
|
27
|
+
export interface CheckScope {
|
|
28
|
+
name: string;
|
|
29
|
+
file: string;
|
|
30
|
+
nodes: CheckNode[];
|
|
31
|
+
syntax: NonNullable<CheckPage['syntax']>;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* One scope of a site as the neutral tree: the elements of its code, with what its JSON says. Read by the checks (a page is its
|
|
35
|
+
* scopes together) and by whatever has to know what is on a page, in each language (the outline an agent reads).
|
|
36
|
+
*/
|
|
37
|
+
export declare function checkScopeFromCode(ctx: OperationContext, scope: ScopeFiles, options?: ReadOptions): CheckScope;
|
|
38
|
+
/**
|
|
39
|
+
* The pages of a site, as the neutral tree: header + page + footer, the way the visitor of a language sees them (`default` unless asked).
|
|
40
|
+
* The checks run once per language and say, for each problem, in which ones it happens.
|
|
41
|
+
*/
|
|
42
|
+
export declare function checkPagesFromCode(root: string, lang?: string): CheckPage[];
|
|
43
|
+
/**
|
|
44
|
+
* The languages a site is checked in: `key` is what the JSON calls it (`default`, or the code), `code` is what people call it (`it`).
|
|
45
|
+
* Just the default one when the site has a single language.
|
|
46
|
+
*/
|
|
47
|
+
export declare function languagesOf(root: string): {
|
|
48
|
+
key: string;
|
|
49
|
+
code: string;
|
|
50
|
+
}[];
|
|
51
|
+
/** What the checks know of the site as a whole. */
|
|
52
|
+
export declare function checkSiteFromCode(root: string): CheckSite;
|
|
53
|
+
//# sourceMappingURL=producer-code.d.ts.map
|