UNPKG

7.72 kBJavaScriptView Raw
1/**
2 * Helpers for validating various text string formats.
3 */
4var StringChecks = /** @class */ (function () {
5 function StringChecks() {
6 }
7 /**
8 * Tests whether the input string is a valid TSDoc tag name; if not, returns an error message.
9 * TSDoc tag names start with an at-sign ("@") followed by ASCII letters using
10 * "camelCase" capitalization.
11 */
12 StringChecks.explainIfInvalidTSDocTagName = function (tagName) {
13 if (tagName[0] !== '@') {
14 return 'A TSDoc tag name must start with an "@" symbol';
15 }
16 if (!StringChecks._tsdocTagNameRegExp.test(tagName)) {
17 return 'A TSDoc tag name must start with a letter and contain only letters and numbers';
18 }
19 return undefined;
20 };
21 /**
22 * Throws an exception if the input string is not a valid TSDoc tag name.
23 * TSDoc tag names start with an at-sign ("@") followed by ASCII letters using
24 * "camelCase" capitalization.
25 */
26 StringChecks.validateTSDocTagName = function (tagName) {
27 var explanation = StringChecks.explainIfInvalidTSDocTagName(tagName);
28 if (explanation) {
29 throw new Error(explanation);
30 }
31 };
32 /**
33 * Tests whether the input string is a URL form supported inside an "@link" tag; if not,
34 * returns an error message.
35 */
36 StringChecks.explainIfInvalidLinkUrl = function (url) {
37 if (url.length === 0) {
38 return 'The URL cannot be empty';
39 }
40 if (!StringChecks._urlSchemeRegExp.test(url)) {
41 return ('An @link URL must begin with a scheme comprised only of letters and numbers followed by "://".' +
42 ' (For general URLs, use an HTML "<a>" tag instead.)');
43 }
44 if (!StringChecks._urlSchemeAfterRegExp.test(url)) {
45 return 'An @link URL must have at least one character after "://"';
46 }
47 return undefined;
48 };
49 /**
50 * Tests whether the input string is a valid HTML element or attribute name.
51 */
52 StringChecks.explainIfInvalidHtmlName = function (htmlName) {
53 if (!StringChecks._htmlNameRegExp.test(htmlName)) {
54 return 'An HTML name must be an ASCII letter followed by zero or more letters, digits, or hyphens';
55 }
56 return undefined;
57 };
58 /**
59 * Throws an exception if the input string is a not valid HTML element or attribute name.
60 */
61 StringChecks.validateHtmlName = function (htmlName) {
62 var explanation = StringChecks.explainIfInvalidHtmlName(htmlName);
63 if (explanation) {
64 throw new Error(explanation);
65 }
66 };
67 /**
68 * Tests whether the input string is a valid NPM package name.
69 */
70 StringChecks.explainIfInvalidPackageName = function (packageName) {
71 if (packageName.length === 0) {
72 return 'The package name cannot be an empty string';
73 }
74 if (!StringChecks._validPackageNameRegExp.test(packageName)) {
75 return "The package name " + JSON.stringify(packageName) + " is not a valid package name";
76 }
77 return undefined;
78 };
79 /**
80 * Tests whether the input string is a valid declaration reference import path.
81 */
82 StringChecks.explainIfInvalidImportPath = function (importPath, prefixedByPackageName) {
83 if (importPath.length > 0) {
84 if (importPath.indexOf('//') >= 0) {
85 return 'An import path must not contain "//"';
86 }
87 if (importPath[importPath.length - 1] === '/') {
88 return 'An import path must not end with "/"';
89 }
90 if (!prefixedByPackageName) {
91 if (importPath[0] === '/') {
92 return 'An import path must not start with "/" unless prefixed by a package name';
93 }
94 }
95 }
96 return undefined;
97 };
98 /**
99 * Returns true if the input string is a TSDoc system selector.
100 */
101 StringChecks.isSystemSelector = function (selector) {
102 return StringChecks._systemSelectors.has(selector);
103 };
104 /**
105 * Tests whether the input string is a valid ECMAScript identifier.
106 * A precise check is extremely complicated and highly dependent on the standard version
107 * and how faithfully the interpreter implements it, so here we use a conservative heuristic.
108 */
109 StringChecks.explainIfInvalidUnquotedIdentifier = function (identifier) {
110 if (identifier.length === 0) {
111 return 'The identifier cannot be an empty string';
112 }
113 if (StringChecks._identifierBadCharRegExp.test(identifier)) {
114 return 'The identifier cannot non-word characters';
115 }
116 if (StringChecks._identifierNumberStartRegExp.test(identifier)) {
117 return 'The identifier must not start with a number';
118 }
119 return undefined;
120 };
121 /**
122 * Tests whether the input string can be used without quotes as a member identifier in a declaration reference.
123 * If not, it should be enclosed in quotes.
124 */
125 StringChecks.explainIfInvalidUnquotedMemberIdentifier = function (identifier) {
126 var explanation = StringChecks.explainIfInvalidUnquotedIdentifier(identifier);
127 if (explanation !== undefined) {
128 return explanation;
129 }
130 if (StringChecks.isSystemSelector(identifier)) {
131 // We do this to avoid confusion about the declaration reference syntax rules.
132 // For example if someone were to see "MyClass.(static:instance)" it would be unclear which
133 // side the colon is the selector.
134 return "The identifier \"" + identifier + "\" must be quoted because it is a TSDoc system selector name";
135 }
136 return undefined;
137 };
138 StringChecks._tsdocTagNameRegExp = /^@[a-z][a-z0-9]*$/i;
139 StringChecks._urlSchemeRegExp = /^[a-z][a-z0-9]*\:\/\//i;
140 StringChecks._urlSchemeAfterRegExp = /^[a-z][a-z0-9]*\:\/\/./i;
141 // HTML element definitions:
142 // https://spec.commonmark.org/0.29/#tag-name
143 // https://www.w3.org/TR/html5/syntax.html#tag-name
144 // https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name
145 //
146 // We use the CommonMark spec:
147 // "A tag name consists of an ASCII letter followed by zero or more ASCII letters, digits, or hyphens (-)."
148 StringChecks._htmlNameRegExp = /^[a-z]+[a-z0-9\-]*$/i;
149 // Note: In addition to letters, numbers, underscores, and dollar signs, modern ECMAScript
150 // also allows Unicode categories such as letters, combining marks, digits, and connector punctuation.
151 // These are mostly supported in all environments except IE11, so if someone wants it, we would accept
152 // a PR to allow them (although the test surface might be somewhat large).
153 StringChecks._identifierBadCharRegExp = /[^a-z0-9_$]/i;
154 // Identifiers most not start with a number.
155 StringChecks._identifierNumberStartRegExp = /^[0-9]/;
156 // For detailed notes about NPM package name syntax, see:
157 // tslint:disable-next-line:max-line-length
158 // https://github.com/Microsoft/web-build-tools/blob/a417ca25c63aca31dba43a34d39cc9cd529b9c78/libraries/node-core-library/src/PackageName.ts
159 StringChecks._validPackageNameRegExp = /^(?:@[a-z0-9\-_\.]+\/)?[a-z0-9\-_\.]+$/i;
160 StringChecks._systemSelectors = new Set([
161 // For classes:
162 'instance',
163 'static',
164 'constructor',
165 // For merged declarations:
166 'class',
167 'enum',
168 'function',
169 'interface',
170 'namespace',
171 'type',
172 'variable'
173 ]);
174 return StringChecks;
175}());
176export { StringChecks };
177//# sourceMappingURL=StringChecks.js.map
\No newline at end of file