UNPKG

6.77 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.collectSpellingDiagnostics = void 0;
4const utils_1 = require("../utils");
5const ruleId = 'spelling';
6// Note that these will be composed, so cannot contain backreferences
7const matchers = [
8 {
9 pattern: /\*this\* object/gu,
10 message: 'prefer "*this* value"',
11 },
12 {
13 pattern: /1's complement/gu,
14 message: 'prefer "one\'s complement"',
15 },
16 {
17 pattern: /2's complement/gu,
18 message: 'prefer "two\'s complement"',
19 },
20 {
21 pattern: /\*0\*(?!<sub>ℤ<\/sub>)/gu,
22 message: 'the Number value 0 should be written "*+0*", to unambiguously exclude "*-0*"',
23 },
24 {
25 pattern: /[+-]?(?:&[a-z]+;|0x[0-9A-Fa-f]+|[0-9]+(?:\.[0-9]+)?)<sub>𝔽<\/sub>/gu,
26 message: 'literal Number values should be bolded',
27 },
28 {
29 pattern: /[+-]?[0-9]+<sub>ℤ<\/sub>/gu,
30 message: 'literal BigInt values should be bolded',
31 },
32 {
33 pattern: /\*[+-]?(?:&[a-z]+;|0x[0-9A-Fa-f]+|[0-9]+(?:\.[0-9]+)?)\*(?!<sub>[𝔽ℤ]<\/sub>)/gu,
34 message: 'literal Number or BigInt values should be followed by <sub>𝔽</sub> or <sub>ℤ</sub> respectively',
35 },
36 {
37 pattern: /(?<=\*)\+(?:0x[1-9A-Fa-f]|[1-9])/gu,
38 message: 'positive numeric values other than 0 should not have a leading plus sign (+)',
39 },
40 {
41 // this needs its own rule to catch +0 as a real number
42 // (but not similar text such as expanded-year dates like +000000-01-01
43 // or UTC offsets like +00:00)
44 pattern: /(?<=^|\s)\+[0-9](?![0-9]*[-:])/gu,
45 message: 'positive real numbers should not have a leading plus sign (+)',
46 },
47 {
48 pattern: /(?<![+-])&infin;/gu,
49 message: '&infin; should always be written with a leading + or -',
50 },
51 {
52 pattern: /(?<= )[+-]\*(?:&[a-z]+;|0x[0-9A-Fa-f]+|[0-9]+(?:\.[0-9]+)?)\*/gu,
53 message: 'the sign character for a numeric literal should be within the `*`s',
54 },
55 {
56 pattern: /(?<=\bmathematical value )for\b/gu,
57 message: 'the mathematical value "of", not "for"',
58 },
59 {
60 pattern: /(?<=\b[Nn]umber value )of\b/gu,
61 message: 'the Number value "for", not "of"',
62 },
63 {
64 pattern: /\bnumber value\b/gu,
65 message: '"Number value", not "number value"',
66 },
67 {
68 // it would be best to somehow literally check against en-GB-oxendict,
69 // but absent that we use the sample list from
70 // https://en.wikipedia.org/wiki/American_and_British_English_spelling_differences#-our%2C_-or
71 pattern: /\b(?:[Bb]ehaviors?|[Ff]lavors?|[Hh]arbors?|[Hh]onors?|[Hh]umors?|[Ll]abors?|[Nn]eighbors?|[Rr]umors?|[Ss]plendors?)\b/gu,
72 message: 'ECMA-262 uses Oxford spelling ("behaviour", etc.)',
73 },
74 {
75 pattern: /[Ii]ndexes/gu,
76 message: 'prefer "indices"',
77 },
78 {
79 pattern: /\b[Nn]onnegative\b/gu,
80 message: 'prefer "non-negative"',
81 },
82 {
83 pattern: /\b[Nn]onzero\b/gu,
84 message: 'prefer "non-zero"',
85 },
86 {
87 pattern: /[Tt]he empty string/gu,
88 message: 'prefer "the empty String"',
89 },
90 {
91 pattern: /[ \t]+\n/gu,
92 message: 'trailing spaces are not allowed',
93 },
94 {
95 pattern: /(?<=(^|[^\n])\n\n)\n+/gu,
96 message: 'no more than one blank line is allowed',
97 },
98 {
99 pattern: /(?<=<emu-clause.*>\n)\n\s*<h1>/gu,
100 message: "there should not be a blank line between a clause's opening tag and its header",
101 },
102 {
103 pattern: /(?<=(^|[^\n])\n)\n+[ \t]*<\/emu-clause>/gu,
104 message: 'there should not be a blank line between the last line of a clause and its closing tag',
105 },
106 {
107 pattern: /\r/gu,
108 message: 'only Unix-style (LF) linebreaks are allowed',
109 },
110 {
111 pattern: /(?<=\b[Ss]teps? )\d/gu,
112 message: 'prefer using labeled steps and <emu-xref> tags over hardcoding step numbers',
113 },
114 {
115 pattern: /(?<=\b[Cc]lauses? )\d/gu,
116 message: 'clauses should be referenced using <emu-xref> tags rather than hardcoding clause numbers',
117 },
118 {
119 pattern: /(?<=\S) +(?! |<\/(td|th|dd|dt)>)/gu,
120 message: 'multiple consecutive spaces are not allowed',
121 },
122 {
123 pattern: /(?<=<[a-z]+( [a-z]+(="[^"\n]+")?)*>)(?<!(td|th|dd|dt|ins|del)>) /gu,
124 message: 'tags should not contain leading whitespace',
125 },
126 {
127 pattern: /(?<=[^ \n]) +<\/(?!td|th|dd|dt|ins|del)/gu,
128 message: 'tags should not contain trailing whitespace',
129 },
130 {
131 pattern: /(?<=&lt; ?\*)\+0\*/gu,
132 message: '"less than" comparisons against floating-point zero should use negative zero',
133 },
134 {
135 pattern: /(?<=&gt; ?\*)-0\*/gu,
136 message: '"greater than" comparisons against floating-point zero should use positive zero',
137 },
138 {
139 pattern: /(?<=&[lg]e; ?\*)[+-]0\*/gu,
140 message: 'comparisons against floating-point zero should use strict comparisons (< or >); guard the equals case with "is"',
141 },
142 {
143 pattern: /(÷|&divide;)/gu,
144 message: 'division should be written as "/", not "÷", per ISO 80000-2',
145 },
146];
147function collectSpellingDiagnostics(report, mainSource, imports) {
148 const composed = new RegExp(matchers.map(m => `(?:${m.pattern.source})`).join('|'), 'u');
149 const toTest = [{ source: mainSource }].concat(imports);
150 for (const { source, importLocation } of toTest) {
151 // The usual case will be to have no errors, so we have a fast path for that case.
152 // We only fall back to slower individual tests if there is at least one error.
153 if (composed.test(source)) {
154 let reported = false;
155 for (const { pattern, message } of matchers) {
156 let match = pattern.exec(source);
157 while (match !== null) {
158 reported = true;
159 const { line, column } = (0, utils_1.offsetToLineAndColumn)(source, match.index);
160 report({
161 type: 'raw',
162 ruleId,
163 line,
164 column,
165 message,
166 source,
167 file: importLocation,
168 });
169 match = pattern.exec(source);
170 }
171 }
172 if (!reported) {
173 throw new Error('Ecmarkup has a bug: the spell checker reported an error, but could not find one. Please report this at https://github.com/tc39/ecmarkup/issues/new.');
174 }
175 }
176 }
177}
178exports.collectSpellingDiagnostics = collectSpellingDiagnostics;