@khanacademy/perseus-linter 0.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.
Files changed (53) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/es/index.js +3152 -0
  3. package/dist/es/index.js.map +1 -0
  4. package/dist/index.d.ts +2 -0
  5. package/dist/index.js +3129 -0
  6. package/dist/index.js.flow +2 -0
  7. package/dist/index.js.map +1 -0
  8. package/package.json +31 -0
  9. package/src/README.md +41 -0
  10. package/src/__tests__/matcher_test.js +498 -0
  11. package/src/__tests__/rule_test.js +102 -0
  12. package/src/__tests__/rules_test.js +488 -0
  13. package/src/__tests__/selector-parser_test.js +52 -0
  14. package/src/__tests__/tree-transformer_test.js +446 -0
  15. package/src/index.js +281 -0
  16. package/src/proptypes.js +29 -0
  17. package/src/rule.js +412 -0
  18. package/src/rules/absolute-url.js +24 -0
  19. package/src/rules/all-rules.js +72 -0
  20. package/src/rules/blockquoted-math.js +10 -0
  21. package/src/rules/blockquoted-widget.js +10 -0
  22. package/src/rules/double-spacing-after-terminal.js +12 -0
  23. package/src/rules/extra-content-spacing.js +12 -0
  24. package/src/rules/heading-level-1.js +14 -0
  25. package/src/rules/heading-level-skip.js +20 -0
  26. package/src/rules/heading-sentence-case.js +11 -0
  27. package/src/rules/heading-title-case.js +63 -0
  28. package/src/rules/image-alt-text.js +21 -0
  29. package/src/rules/image-in-table.js +10 -0
  30. package/src/rules/image-spaces-around-urls.js +35 -0
  31. package/src/rules/image-widget.js +50 -0
  32. package/src/rules/link-click-here.js +11 -0
  33. package/src/rules/lint-utils.js +48 -0
  34. package/src/rules/long-paragraph.js +14 -0
  35. package/src/rules/math-adjacent.js +10 -0
  36. package/src/rules/math-align-extra-break.js +11 -0
  37. package/src/rules/math-align-linebreaks.js +43 -0
  38. package/src/rules/math-empty.js +10 -0
  39. package/src/rules/math-font-size.js +12 -0
  40. package/src/rules/math-frac.js +10 -0
  41. package/src/rules/math-nested.js +11 -0
  42. package/src/rules/math-starts-with-space.js +12 -0
  43. package/src/rules/math-text-empty.js +10 -0
  44. package/src/rules/math-without-dollars.js +14 -0
  45. package/src/rules/nested-lists.js +11 -0
  46. package/src/rules/profanity.js +10 -0
  47. package/src/rules/table-missing-cells.js +20 -0
  48. package/src/rules/unbalanced-code-delimiters.js +14 -0
  49. package/src/rules/unescaped-dollar.js +10 -0
  50. package/src/rules/widget-in-table.js +10 -0
  51. package/src/selector.js +505 -0
  52. package/src/tree-transformer.js +587 -0
  53. package/src/types.js +10 -0
@@ -0,0 +1,3152 @@
1
+ import { PerseusError, Errors } from '@khanacademy/perseus-error';
2
+
3
+ function ownKeys(object, enumerableOnly) {
4
+ var keys = Object.keys(object);
5
+
6
+ if (Object.getOwnPropertySymbols) {
7
+ var symbols = Object.getOwnPropertySymbols(object);
8
+ enumerableOnly && (symbols = symbols.filter(function (sym) {
9
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
10
+ })), keys.push.apply(keys, symbols);
11
+ }
12
+
13
+ return keys;
14
+ }
15
+
16
+ function _objectSpread2(target) {
17
+ for (var i = 1; i < arguments.length; i++) {
18
+ var source = null != arguments[i] ? arguments[i] : {};
19
+ i % 2 ? ownKeys(Object(source), !0).forEach(function (key) {
20
+ _defineProperty(target, key, source[key]);
21
+ }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) {
22
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
23
+ });
24
+ }
25
+
26
+ return target;
27
+ }
28
+
29
+ function _defineProperty(obj, key, value) {
30
+ if (key in obj) {
31
+ Object.defineProperty(obj, key, {
32
+ value: value,
33
+ enumerable: true,
34
+ configurable: true,
35
+ writable: true
36
+ });
37
+ } else {
38
+ obj[key] = value;
39
+ }
40
+
41
+ return obj;
42
+ }
43
+
44
+ /**
45
+ * This is the base class for all Selector types. The key method that all
46
+ * selector subclasses must implement is match(). It takes a TraversalState
47
+ * object (from a TreeTransformer traversal) and tests whether the selector
48
+ * matches at the current node. See the comment at the start of this file for
49
+ * more details on the match() method.
50
+ */
51
+ class Selector {
52
+ static parse(selectorText) {
53
+ return new Parser(selectorText).parse();
54
+ }
55
+ /**
56
+ * Return an array of the nodes that matched or null if no match.
57
+ * This is the base class so we just throw an exception. All Selector
58
+ * subclasses must provide an implementation of this method.
59
+ */
60
+
61
+
62
+ match(state) {
63
+ throw new PerseusError("Selector subclasses must implement match()", Errors.NotAllowed);
64
+ }
65
+ /**
66
+ * Selector subclasses all define a toString() method primarily
67
+ * because it makes it easy to write parser tests.
68
+ */
69
+
70
+
71
+ toString() {
72
+ return "Unknown selector class";
73
+ }
74
+
75
+ }
76
+ /**
77
+ * This class implements a parser for the selector grammar. Pass the source
78
+ * text to the Parser() constructor, and then call the parse() method to
79
+ * obtain a corresponding Selector object. parse() throws an exception
80
+ * if there are syntax errors in the selector.
81
+ *
82
+ * This class is not exported, and you don't need to use it directly.
83
+ * Instead call the static Selector.parse() method.
84
+ */
85
+
86
+ class Parser {
87
+ // We do lexing with a simple regular expression
88
+ // The array of tokens
89
+ // Which token in the array we're looking at now
90
+ constructor(s) {
91
+ _defineProperty(this, "tokens", void 0);
92
+
93
+ _defineProperty(this, "tokenIndex", void 0);
94
+
95
+ // Normalize whitespace:
96
+ // - remove leading and trailing whitespace
97
+ // - replace runs of whitespace with single space characters
98
+ s = s.trim().replace(/\s+/g, " "); // Convert the string to an array of tokens. Note that the TOKENS
99
+ // pattern ignores spaces that do not appear before identifiers
100
+ // or the * wildcard.
101
+
102
+ this.tokens = s.match(Parser.TOKENS) || [];
103
+ this.tokenIndex = 0;
104
+ } // Return the next token or the empty string if there are no more
105
+
106
+
107
+ nextToken() {
108
+ return this.tokens[this.tokenIndex] || "";
109
+ } // Increment the token index to "consume" the token we were looking at
110
+ // and move on to the next one.
111
+
112
+
113
+ consume() {
114
+ this.tokenIndex++;
115
+ } // Return true if the current token is an identifier or false otherwise
116
+
117
+
118
+ isIdentifier() {
119
+ // The Parser.TOKENS regexp ensures that we only have to check
120
+ // the first character of a token to know what kind of token it is.
121
+ var c = this.tokens[this.tokenIndex][0];
122
+ return c >= "a" && c <= "z" || c >= "A" && c <= "Z";
123
+ } // Consume space tokens until the next token is not a space.
124
+
125
+
126
+ skipSpace() {
127
+ while (this.nextToken() === " ") {
128
+ this.consume();
129
+ }
130
+ } // Parse a comma-separated sequence of tree selectors. This is the
131
+ // entry point for the Parser class and the only method that clients
132
+ // ever need to call.
133
+
134
+
135
+ parse() {
136
+ // We expect at least one tree selector
137
+ var ts = this.parseTreeSelector(); // Now see what's next
138
+
139
+ var token = this.nextToken(); // If there is no next token then we're done parsing and can return
140
+ // the tree selector object we got above
141
+
142
+ if (!token) {
143
+ return ts;
144
+ } // Otherwise, there is more go come and we're going to need a
145
+ // list of tree selectors
146
+
147
+
148
+ var treeSelectors = [ts];
149
+
150
+ while (token) {
151
+ // The only character we allow after a tree selector is a comma
152
+ if (token === ",") {
153
+ this.consume();
154
+ } else {
155
+ throw new ParseError("Expected comma");
156
+ } // And if we saw a comma, then it must be followed by another
157
+ // tree selector
158
+
159
+
160
+ treeSelectors.push(this.parseTreeSelector());
161
+ token = this.nextToken();
162
+ } // If we parsed more than one tree selector, return them in a
163
+ // SelectorList object.
164
+
165
+
166
+ return new SelectorList(treeSelectors);
167
+ } // Parse a sequence of node selectors linked together with
168
+ // hierarchy combinators: space, >, + and ~.
169
+
170
+
171
+ parseTreeSelector() {
172
+ this.skipSpace(); // Ignore space after a comma, for example
173
+ // A tree selector must begin with a node selector
174
+
175
+ var ns = this.parseNodeSelector();
176
+
177
+ for (;;) {
178
+ // Now check the next token. If there is none, or if it is a
179
+ // comma, then we're done with the treeSelector. Otherwise
180
+ // we expect a combinator followed by another node selector.
181
+ // If we don't see a combinator, we throw an error. If we
182
+ // do see a combinator and another node selector then we
183
+ // combine the current node selector with the new node selector
184
+ // using a Selector subclass that depends on the combinator.
185
+ var token = this.nextToken();
186
+
187
+ if (!token || token === ",") {
188
+ break;
189
+ } else if (token === " ") {
190
+ this.consume();
191
+ ns = new AncestorCombinator(ns, this.parseNodeSelector());
192
+ } else if (token === ">") {
193
+ this.consume();
194
+ ns = new ParentCombinator(ns, this.parseNodeSelector());
195
+ } else if (token === "+") {
196
+ this.consume();
197
+ ns = new PreviousCombinator(ns, this.parseNodeSelector());
198
+ } else if (token === "~") {
199
+ this.consume();
200
+ ns = new SiblingCombinator(ns, this.parseNodeSelector());
201
+ } else {
202
+ throw new ParseError("Unexpected token: " + token);
203
+ }
204
+ }
205
+
206
+ return ns;
207
+ } // Parse a single node selector.
208
+ // For now, this is just a node type or a wildcard.
209
+ //
210
+ // TODO(davidflanagan): we may need to extend this with attribute
211
+ // selectors like 'heading[level=3]', or with pseudo-classes like
212
+ // paragraph:first-child
213
+
214
+
215
+ parseNodeSelector() {
216
+ // First, skip any whitespace
217
+ this.skipSpace();
218
+ var t = this.nextToken();
219
+
220
+ if (t === "*") {
221
+ this.consume();
222
+ return new AnyNode();
223
+ }
224
+
225
+ if (this.isIdentifier()) {
226
+ this.consume();
227
+ return new TypeSelector(t);
228
+ }
229
+
230
+ throw new ParseError("Expected node type");
231
+ }
232
+
233
+ } // We break the input string into tokens with this regexp. Token types
234
+ // are identifiers, integers, punctuation and spaces. Note that spaces
235
+ // tokens are only returned when they appear before an identifier or
236
+ // wildcard token and are otherwise omitted.
237
+
238
+
239
+ _defineProperty(Parser, "TOKENS", void 0);
240
+
241
+ Parser.TOKENS = /([a-zA-Z][\w-]*)|(\d+)|[^\s]|(\s(?=[a-zA-Z\*]))/g;
242
+ /**
243
+ * This is a trivial Error subclass that the Parser uses to signal parse errors
244
+ */
245
+
246
+ class ParseError extends Error {
247
+ constructor(message) {
248
+ super(message);
249
+ }
250
+
251
+ }
252
+ /**
253
+ * This Selector subclass is a list of selectors. It matches a node if any of
254
+ * the selectors on the list matches the node. It considers the selectors in
255
+ * order, and returns the array of nodes returned by whichever one matches
256
+ * first.
257
+ */
258
+
259
+
260
+ class SelectorList extends Selector {
261
+ constructor(selectors) {
262
+ super();
263
+
264
+ _defineProperty(this, "selectors", void 0);
265
+
266
+ this.selectors = selectors;
267
+ }
268
+
269
+ match(state) {
270
+ for (var i = 0; i < this.selectors.length; i++) {
271
+ var s = this.selectors[i];
272
+ var result = s.match(state);
273
+
274
+ if (result) {
275
+ return result;
276
+ }
277
+ }
278
+
279
+ return null;
280
+ }
281
+
282
+ toString() {
283
+ var result = "";
284
+
285
+ for (var i = 0; i < this.selectors.length; i++) {
286
+ result += i > 0 ? ", " : "";
287
+ result += this.selectors[i].toString();
288
+ }
289
+
290
+ return result;
291
+ }
292
+
293
+ }
294
+ /**
295
+ * This trivial Selector subclass implements the '*' wildcard and
296
+ * matches any node.
297
+ */
298
+
299
+
300
+ class AnyNode extends Selector {
301
+ match(state) {
302
+ return [state.currentNode()];
303
+ }
304
+
305
+ toString() {
306
+ return "*";
307
+ }
308
+
309
+ }
310
+ /**
311
+ * This selector subclass implements the <IDENTIFIER> part of the grammar.
312
+ * it matches any node whose `type` property is a specified string
313
+ */
314
+
315
+
316
+ class TypeSelector extends Selector {
317
+ constructor(type) {
318
+ super();
319
+
320
+ _defineProperty(this, "type", void 0);
321
+
322
+ this.type = type;
323
+ }
324
+
325
+ match(state) {
326
+ var node = state.currentNode();
327
+
328
+ if (node.type === this.type) {
329
+ return [node];
330
+ }
331
+
332
+ return null;
333
+ }
334
+
335
+ toString() {
336
+ return this.type;
337
+ }
338
+
339
+ }
340
+ /**
341
+ * This selector subclass is the superclass of the classes that implement
342
+ * matching for the four combinators. It defines left and right properties for
343
+ * the two selectors that are to be combined, but does not define a match
344
+ * method.
345
+ */
346
+
347
+
348
+ class SelectorCombinator extends Selector {
349
+ constructor(left, right) {
350
+ super();
351
+
352
+ _defineProperty(this, "left", void 0);
353
+
354
+ _defineProperty(this, "right", void 0);
355
+
356
+ this.left = left;
357
+ this.right = right;
358
+ }
359
+
360
+ }
361
+ /**
362
+ * This Selector subclass implements the space combinator. It matches if the
363
+ * right selector matches the current node and the left selector matches some
364
+ * ancestor of the current node.
365
+ */
366
+
367
+
368
+ class AncestorCombinator extends SelectorCombinator {
369
+ constructor(left, right) {
370
+ super(left, right);
371
+ }
372
+
373
+ match(state) {
374
+ var rightResult = this.right.match(state);
375
+
376
+ if (rightResult) {
377
+ state = state.clone();
378
+
379
+ while (state.hasParent()) {
380
+ state.goToParent();
381
+ var leftResult = this.left.match(state);
382
+
383
+ if (leftResult) {
384
+ return leftResult.concat(rightResult);
385
+ }
386
+ }
387
+ }
388
+
389
+ return null;
390
+ }
391
+
392
+ toString() {
393
+ return this.left.toString() + " " + this.right.toString();
394
+ }
395
+
396
+ }
397
+ /**
398
+ * This Selector subclass implements the > combinator. It matches if the
399
+ * right selector matches the current node and the left selector matches
400
+ * the parent of the current node.
401
+ */
402
+
403
+
404
+ class ParentCombinator extends SelectorCombinator {
405
+ constructor(left, right) {
406
+ super(left, right);
407
+ }
408
+
409
+ match(state) {
410
+ var rightResult = this.right.match(state);
411
+
412
+ if (rightResult) {
413
+ if (state.hasParent()) {
414
+ state = state.clone();
415
+ state.goToParent();
416
+ var leftResult = this.left.match(state);
417
+
418
+ if (leftResult) {
419
+ return leftResult.concat(rightResult);
420
+ }
421
+ }
422
+ }
423
+
424
+ return null;
425
+ }
426
+
427
+ toString() {
428
+ return this.left.toString() + " > " + this.right.toString();
429
+ }
430
+
431
+ }
432
+ /**
433
+ * This Selector subclass implements the + combinator. It matches if the
434
+ * right selector matches the current node and the left selector matches
435
+ * the immediate previous sibling of the current node.
436
+ */
437
+
438
+
439
+ class PreviousCombinator extends SelectorCombinator {
440
+ constructor(left, right) {
441
+ super(left, right);
442
+ }
443
+
444
+ match(state) {
445
+ var rightResult = this.right.match(state);
446
+
447
+ if (rightResult) {
448
+ if (state.hasPreviousSibling()) {
449
+ state = state.clone();
450
+ state.goToPreviousSibling();
451
+ var leftResult = this.left.match(state);
452
+
453
+ if (leftResult) {
454
+ return leftResult.concat(rightResult);
455
+ }
456
+ }
457
+ }
458
+
459
+ return null;
460
+ }
461
+
462
+ toString() {
463
+ return this.left.toString() + " + " + this.right.toString();
464
+ }
465
+
466
+ }
467
+ /**
468
+ * This Selector subclass implements the ~ combinator. It matches if the
469
+ * right selector matches the current node and the left selector matches
470
+ * any previous sibling of the current node.
471
+ */
472
+
473
+
474
+ class SiblingCombinator extends SelectorCombinator {
475
+ constructor(left, right) {
476
+ super(left, right);
477
+ }
478
+
479
+ match(state) {
480
+ var rightResult = this.right.match(state);
481
+
482
+ if (rightResult) {
483
+ state = state.clone();
484
+
485
+ while (state.hasPreviousSibling()) {
486
+ state.goToPreviousSibling();
487
+ var leftResult = this.left.match(state);
488
+
489
+ if (leftResult) {
490
+ return leftResult.concat(rightResult);
491
+ }
492
+ }
493
+ }
494
+
495
+ return null;
496
+ }
497
+
498
+ toString() {
499
+ return this.left.toString() + " ~ " + this.right.toString();
500
+ }
501
+
502
+ }
503
+
504
+ /**
505
+ * A Rule object describes a Gorgon lint rule. See the comment at the top of
506
+ * this file for detailed description.
507
+ */
508
+ class Rule {
509
+ // The name of the rule
510
+ // The severity of the rule
511
+ // The specified selector or the DEFAULT_SELECTOR
512
+ // A regular expression if one was specified
513
+ // The lint-testing function or a default
514
+ // Checks to see if we should apply a rule or not
515
+ // The error message for use with the default function
516
+ // The comment at the top of this file has detailed docs for
517
+ // this constructor and its arguments
518
+ constructor(name, severity, selector, pattern, lint, applies) {
519
+ var _this = this;
520
+
521
+ _defineProperty(this, "name", void 0);
522
+
523
+ _defineProperty(this, "severity", void 0);
524
+
525
+ _defineProperty(this, "selector", void 0);
526
+
527
+ _defineProperty(this, "pattern", void 0);
528
+
529
+ _defineProperty(this, "lint", void 0);
530
+
531
+ _defineProperty(this, "applies", void 0);
532
+
533
+ _defineProperty(this, "message", void 0);
534
+
535
+ if (!selector && !pattern) {
536
+ throw new PerseusError("Lint rules must have a selector or pattern", Errors.InvalidInput, {
537
+ metadata: {
538
+ name
539
+ }
540
+ });
541
+ }
542
+
543
+ this.name = name || "unnamed rule";
544
+ this.severity = severity || Rule.Severity.BULK_WARNING;
545
+ this.selector = selector || Rule.DEFAULT_SELECTOR;
546
+ this.pattern = pattern || null; // If we're called with an error message instead of a function then
547
+ // use a default function that will return the message.
548
+
549
+ if (typeof lint === "function") {
550
+ this.lint = lint;
551
+ this.message = null;
552
+ } else {
553
+ this.lint = function () {
554
+ return _this._defaultLintFunction(...arguments);
555
+ };
556
+
557
+ this.message = lint;
558
+ }
559
+
560
+ this.applies = applies || function () {
561
+ return true;
562
+ };
563
+ } // A factory method for use with rules described in JSON files
564
+ // See the documentation at the start of this file for details.
565
+
566
+
567
+ static makeRule(options) {
568
+ return new Rule(options.name, options.severity, options.selector ? Selector.parse(options.selector) : null, Rule.makePattern(options.pattern), options.lint || options.message, options.applies);
569
+ } // Check the node n to see if it violates this lint rule. A return value
570
+ // of false means there is no lint. A returned object indicates a lint
571
+ // error. See the documentation at the top of this file for details.
572
+
573
+
574
+ check(node, traversalState, content, context) {
575
+ // First, see if we match the selector.
576
+ // If no selector was passed to the constructor, we use a
577
+ // default selector that matches text nodes.
578
+ var selectorMatch = this.selector.match(traversalState); // If the selector did not match, then we're done
579
+
580
+ if (!selectorMatch) {
581
+ return null;
582
+ } // If the selector matched, then see if the pattern matches
583
+
584
+
585
+ var patternMatch;
586
+
587
+ if (this.pattern) {
588
+ patternMatch = content.match(this.pattern);
589
+ } else {
590
+ // If there is no pattern, then just match all of the content.
591
+ // Use a fake RegExp match object to represent this default match.
592
+ patternMatch = Rule.FakePatternMatch(content, content, 0);
593
+ } // If there was a pattern and it didn't match, then we're done
594
+
595
+
596
+ if (!patternMatch) {
597
+ return null;
598
+ }
599
+
600
+ try {
601
+ // If we get here, then the selector and pattern have matched
602
+ // so now we call the lint function to see if there is lint.
603
+ var error = this.lint(traversalState, content, selectorMatch, patternMatch, context);
604
+
605
+ if (!error) {
606
+ return null; // No lint; we're done
607
+ }
608
+
609
+ if (typeof error === "string") {
610
+ // If the lint function returned a string we assume it
611
+ // applies to the entire content of the node and return it.
612
+ return {
613
+ rule: this.name,
614
+ severity: this.severity,
615
+ message: error,
616
+ start: 0,
617
+ end: content.length
618
+ };
619
+ } // If the lint function returned an object, then we just
620
+ // add the rule name to the message, start and end.
621
+
622
+
623
+ return {
624
+ rule: this.name,
625
+ severity: this.severity,
626
+ message: error.message,
627
+ start: error.start,
628
+ end: error.end
629
+ };
630
+ } catch (e) {
631
+ // If the lint function threw an exception we handle that as
632
+ // a special type of lint. We want the user to see the lint
633
+ // warning in this case (even though it is out of their control)
634
+ // so that the bug gets reported. Otherwise we'd never know that
635
+ // a rule was failing.
636
+ return {
637
+ rule: "lint-rule-failure",
638
+ message: "Exception in rule ".concat(this.name, ": ").concat(e.message, "\nStack trace:\n").concat(e.stack),
639
+ start: 0,
640
+ end: content.length
641
+ };
642
+ }
643
+ } // This internal method is the default lint function that we use when a
644
+ // rule is defined without a function. This is useful for rules where the
645
+ // selector and/or pattern match are enough to indicate lint. This
646
+ // function unconditionally returns the error message that was passed in
647
+ // place of a function, but also adds start and end properties that
648
+ // specify which particular portion of the node content matched the
649
+ // pattern.
650
+
651
+
652
+ _defaultLintFunction(state, content, selectorMatch, patternMatch, context) {
653
+ return {
654
+ message: this.message || "",
655
+ start: patternMatch.index,
656
+ end: patternMatch.index + patternMatch[0].length
657
+ };
658
+ } // The makeRule() factory function uses this static method to turn its
659
+ // argument into a RegExp. If the argument is already a RegExp, we just
660
+ // return it. Otherwise, we compile it into a RegExp and return that.
661
+ // The reason this is necessary is that Rule.makeRule() is designed for
662
+ // use with data from JSON files and JSON files can't include RegExp
663
+ // literals. Strings passed to this function do not need to be delimited
664
+ // with / characters unless you want to include flags for the RegExp.
665
+ //
666
+ // Examples:
667
+ //
668
+ // input "" ==> output null
669
+ // input /foo/ ==> output /foo/
670
+ // input "foo" ==> output /foo/
671
+ // input "/foo/i" ==> output /foo/i
672
+ //
673
+
674
+
675
+ static makePattern(pattern) {
676
+ if (!pattern) {
677
+ return null;
678
+ }
679
+
680
+ if (pattern instanceof RegExp) {
681
+ return pattern;
682
+ }
683
+
684
+ if (pattern[0] === "/") {
685
+ var lastSlash = pattern.lastIndexOf("/");
686
+ var expression = pattern.substring(1, lastSlash);
687
+ var flags = pattern.substring(lastSlash + 1);
688
+ return new RegExp(expression, flags);
689
+ }
690
+
691
+ return new RegExp(pattern);
692
+ } // This static method returns an string array with index and input
693
+ // properties added, in order to simulate the return value of the
694
+ // String.match() method. We use it when a Rule has no pattern and we
695
+ // want to simulate a match on the entire content string.
696
+
697
+
698
+ static FakePatternMatch(input, match, index) {
699
+ var result = [match];
700
+ result.index = index;
701
+ result.input = input;
702
+ return result;
703
+ }
704
+
705
+ }
706
+
707
+ _defineProperty(Rule, "DEFAULT_SELECTOR", void 0);
708
+
709
+ _defineProperty(Rule, "Severity", {
710
+ ERROR: 1,
711
+ WARNING: 2,
712
+ GUIDELINE: 3,
713
+ BULK_WARNING: 4
714
+ });
715
+
716
+ Rule.DEFAULT_SELECTOR = Selector.parse("text");
717
+
718
+ /* eslint-disable no-useless-escape */
719
+ // Return the portion of a URL between // and /. This is the authority
720
+ // portion which is usually just the hostname, but may also include
721
+ // a username, password or port. We don't strip those things out because
722
+ // we typically want to reject any URL that includes them
723
+ var HOSTNAME = /\/\/([^\/]+)/; // Return the hostname of the URL, with any "www." prefix removed.
724
+ // If this is a relative URL with no hostname, return an empty string.
725
+
726
+ function getHostname(url) {
727
+ if (!url) {
728
+ return "";
729
+ }
730
+
731
+ var match = url.match(HOSTNAME);
732
+ return match ? match[1] : "";
733
+ } // This list of domains that count as internal domains is from
734
+
735
+ var AbsoluteUrl = Rule.makeRule({
736
+ name: "absolute-url",
737
+ severity: Rule.Severity.GUIDELINE,
738
+ selector: "link, image",
739
+ lint: function lint(state, content, nodes, match) {
740
+ var url = nodes[0].target;
741
+ var hostname = getHostname(url);
742
+
743
+ if (hostname === "khanacademy.org" || hostname.endsWith(".khanacademy.org")) {
744
+ return "Don't use absolute URLs:\nWhen linking to KA content or images, omit the\nhttps://www.khanacademy.org URL prefix.\nUse a relative URL beginning with / instead.";
745
+ }
746
+ }
747
+ });
748
+
749
+ var BlockquotedMath = Rule.makeRule({
750
+ name: "blockquoted-math",
751
+ severity: Rule.Severity.WARNING,
752
+ selector: "blockQuote math, blockQuote blockMath",
753
+ message: "Blockquoted math:\nmath should not be indented."
754
+ });
755
+
756
+ var BlockquotedWidget = Rule.makeRule({
757
+ name: "blockquoted-widget",
758
+ severity: Rule.Severity.WARNING,
759
+ selector: "blockQuote widget",
760
+ message: "Blockquoted widget:\nwidgets should not be indented."
761
+ });
762
+
763
+ /* eslint-disable no-useless-escape */
764
+ var DoubleSpacingAfterTerminal = Rule.makeRule({
765
+ name: "double-spacing-after-terminal",
766
+ severity: Rule.Severity.BULK_WARNING,
767
+ selector: "paragraph",
768
+ pattern: /[.!\?] {2}/i,
769
+ message: "Use a single space after a sentence-ending period, or\nany other kind of terminal punctuation."
770
+ });
771
+
772
+ var ExtraContentSpacing = Rule.makeRule({
773
+ name: "extra-content-spacing",
774
+ selector: "paragraph",
775
+ pattern: /\s+$/,
776
+ applies: function applies(context) {
777
+ return context.contentType === "article";
778
+ },
779
+ message: "No extra whitespace at the end of content blocks."
780
+ });
781
+
782
+ var HeadingLevel1 = Rule.makeRule({
783
+ name: "heading-level-1",
784
+ severity: Rule.Severity.WARNING,
785
+ selector: "heading",
786
+ lint: function lint(state, content, nodes, match) {
787
+ if (nodes[0].level === 1) {
788
+ return "Don't use level-1 headings:\nBegin headings with two or more # characters.";
789
+ }
790
+ }
791
+ });
792
+
793
+ var HeadingLevelSkip = Rule.makeRule({
794
+ name: "heading-level-skip",
795
+ severity: Rule.Severity.WARNING,
796
+ selector: "heading ~ heading",
797
+ lint: function lint(state, content, nodes, match) {
798
+ var currentHeading = nodes[1];
799
+ var previousHeading = nodes[0]; // A heading can have a level less than, the same as
800
+ // or one more than the previous heading. But going up
801
+ // by 2 or more levels is not right
802
+
803
+ if (currentHeading.level > previousHeading.level + 1) {
804
+ return "Skipped heading level:\nthis heading is level ".concat(currentHeading.level, " but\nthe previous heading was level ").concat(previousHeading.level);
805
+ }
806
+ }
807
+ });
808
+
809
+ var HeadingSentenceCase = Rule.makeRule({
810
+ name: "heading-sentence-case",
811
+ severity: Rule.Severity.GUIDELINE,
812
+ selector: "heading",
813
+ pattern: /^\W*[a-z]/,
814
+ // first letter is lowercase
815
+ message: "First letter is lowercase:\nthe first letter of a heading should be capitalized."
816
+ });
817
+
818
+ // capitalized even in a title-case heading. See
819
+ // http://blog.apastyle.org/apastyle/2012/03/title-case-and-sentence-case-capitalization-in-apa-style.html
820
+
821
+ var littleWords = {
822
+ and: true,
823
+ nor: true,
824
+ but: true,
825
+ the: true,
826
+ for: true
827
+ };
828
+
829
+ function isCapitalized(word) {
830
+ var c = word[0];
831
+ return c === c.toUpperCase();
832
+ }
833
+
834
+ var HeadingTitleCase = Rule.makeRule({
835
+ name: "heading-title-case",
836
+ severity: Rule.Severity.GUIDELINE,
837
+ selector: "heading",
838
+ pattern: /[^\s:]\s+[A-Z]+[a-z]/,
839
+ locale: "en",
840
+ lint: function lint(state, content, nodes, match) {
841
+ // We want to assert that heading text is in sentence case, not
842
+ // title case. The pattern above requires a capital letter at the
843
+ // start of the heading and allows them after a colon, or in
844
+ // acronyms that are all capitalized.
845
+ //
846
+ // But we can't warn just because the pattern matched because
847
+ // proper nouns are also allowed bo be capitalized. We're not
848
+ // going to do dictionary lookup to check for proper nouns, so
849
+ // we try a heuristic: if the title is more than 3 words long
850
+ // and if all the words are capitalized or are on the list of
851
+ // words that don't get capitalized, then we'll assume that
852
+ // the heading is incorrectly in title case and will warn.
853
+ // But if there is at least one non-capitalized long word then
854
+ // we're not in title case and we should not warn.
855
+ //
856
+ // TODO(davidflanagan): if this rule causes a lot of false
857
+ // positives, we should tweak it or remove it. Note that it will
858
+ // fail for headings like "World War II in Russia"
859
+ //
860
+ // TODO(davidflanagan): This rule is specific to English.
861
+ // It is marked with a locale property above, but that is NYI
862
+ //
863
+ // for APA style rules for title case
864
+ var heading = content.trim();
865
+ var words = heading.split(/\s+/); // Remove the first word and the little words
866
+
867
+ words.shift();
868
+ words = words.filter( // eslint-disable-next-line no-prototype-builtins
869
+ w => w.length > 2 && !littleWords.hasOwnProperty(w)); // If there are at least 3 remaining words and all
870
+ // are capitalized, then the heading is in title case.
871
+
872
+ if (words.length >= 3 && words.every(w => isCapitalized(w))) {
873
+ return "Title-case heading:\nThis heading appears to be in title-case, but should be sentence-case.\nOnly capitalize the first letter and proper nouns.";
874
+ }
875
+ }
876
+ });
877
+
878
+ var ImageAltText = Rule.makeRule({
879
+ name: "image-alt-text",
880
+ severity: Rule.Severity.WARNING,
881
+ selector: "image",
882
+ lint: function lint(state, content, nodes, match) {
883
+ var image = nodes[0];
884
+
885
+ if (!image.alt || !image.alt.trim()) {
886
+ return "Images should have alt text:\nfor accessibility, all images should have alt text.\nSpecify alt text inside square brackets after the !.";
887
+ }
888
+
889
+ if (image.alt.length < 8) {
890
+ return "Images should have alt text:\nfor accessibility, all images should have descriptive alt text.\nThis image's alt text is only ".concat(image.alt.length, " characters long.");
891
+ }
892
+ }
893
+ });
894
+
895
+ var ImageInTable = Rule.makeRule({
896
+ name: "image-in-table",
897
+ severity: Rule.Severity.BULK_WARNING,
898
+ selector: "table image",
899
+ message: "Image in table:\ndo not put images inside of tables."
900
+ });
901
+
902
+ var ImageSpacesAroundUrls = Rule.makeRule({
903
+ name: "image-spaces-around-urls",
904
+ severity: Rule.Severity.ERROR,
905
+ selector: "image",
906
+ lint: function lint(state, content, nodes, match, context) {
907
+ var image = nodes[0];
908
+ var url = image.target; // The markdown parser strips leading and trailing spaces for us,
909
+ // but they're still a problem for our translation process, so
910
+ // we need to go check for them in the unparsed source string
911
+ // if we have it.
912
+
913
+ if (context && context.content) {
914
+ // Find the url in the original content and make sure that the
915
+ // character before is '(' and the character after is ')'
916
+ var index = context.content.indexOf(url);
917
+
918
+ if (index === -1) {
919
+ // It is not an error if we didn't find it.
920
+ return;
921
+ }
922
+
923
+ if (context.content[index - 1] !== "(" || context.content[index + url.length] !== ")") {
924
+ return "Whitespace before or after image url:\nFor images, don't include any space or newlines after '(' or before ')'.\nWhitespace in image URLs causes translation difficulties.";
925
+ }
926
+ }
927
+ }
928
+ });
929
+
930
+ // can't match specific widget types directly, this rule implements
931
+ // a number of image widget related rules in one place. This should
932
+ // slightly increase efficiency, but it means that if there is more
933
+ // than one problem with an image widget, the user will only see one
934
+ // problem at a time.
935
+
936
+ var ImageWidget = Rule.makeRule({
937
+ name: "image-widget",
938
+ severity: Rule.Severity.WARNING,
939
+ selector: "widget",
940
+ lint: function lint(state, content, nodes, match, context) {
941
+ // This rule only looks at image widgets
942
+ if (state.currentNode().widgetType !== "image") {
943
+ return;
944
+ } // If it can't find a definition for the widget it does nothing
945
+
946
+
947
+ var widget = context && context.widgets && context.widgets[state.currentNode().id];
948
+
949
+ if (!widget) {
950
+ return;
951
+ } // Make sure there is alt text
952
+
953
+
954
+ var alt = widget.options.alt;
955
+
956
+ if (!alt) {
957
+ return "Images should have alt text:\nfor accessibility, all images should have a text description.\nAdd a description in the \"Alt Text\" box of the image widget.";
958
+ } // Make sure the alt text it is not trivial
959
+
960
+
961
+ if (alt.trim().length < 8) {
962
+ return "Images should have alt text:\nfor accessibility, all images should have descriptive alt text.\nThis image's alt text is only ".concat(alt.trim().length, " characters long.");
963
+ } // Make sure there is no math in the caption
964
+
965
+
966
+ if (widget.options.caption && widget.options.caption.match(/[^\\]\$/)) {
967
+ return "No math in image captions:\nDon't include math expressions in image captions.";
968
+ }
969
+ }
970
+ });
971
+
972
+ var LinkClickHere = Rule.makeRule({
973
+ name: "link-click-here",
974
+ severity: Rule.Severity.WARNING,
975
+ selector: "link",
976
+ pattern: /click here/i,
977
+ message: "Inappropriate link text:\nDo not use the words \"click here\" in links."
978
+ });
979
+
980
+ var LongParagraph = Rule.makeRule({
981
+ name: "long-paragraph",
982
+ severity: Rule.Severity.GUIDELINE,
983
+ selector: "paragraph",
984
+ pattern: /^.{501,}/,
985
+ lint: function lint(state, content, nodes, match) {
986
+ return "Paragraph too long:\nThis paragraph is ".concat(content.length, " characters long.\nShorten it to 500 characters or fewer.");
987
+ }
988
+ });
989
+
990
+ var MathAdjacent = Rule.makeRule({
991
+ name: "math-adjacent",
992
+ severity: Rule.Severity.WARNING,
993
+ selector: "blockMath+blockMath",
994
+ message: "Adjacent math blocks:\ncombine the blocks between \\begin{align} and \\end{align}"
995
+ });
996
+
997
+ var MathAlignExtraBreak = Rule.makeRule({
998
+ name: "math-align-extra-break",
999
+ severity: Rule.Severity.WARNING,
1000
+ selector: "blockMath",
1001
+ pattern: /(\\{2,})\s*\\end{align}/,
1002
+ message: "Extra space at end of block:\nDon't end an align block with backslashes"
1003
+ });
1004
+
1005
+ var MathAlignLinebreaks = Rule.makeRule({
1006
+ name: "math-align-linebreaks",
1007
+ severity: Rule.Severity.WARNING,
1008
+ selector: "blockMath",
1009
+ // Match any align block with double backslashes in it
1010
+ // Use [\s\S]* instead of .* so we match newlines as well.
1011
+ pattern: /\\begin{align}[\s\S]*\\\\[\s\S]+\\end{align}/,
1012
+ // Look for double backslashes and ensure that they are
1013
+ // followed by optional space and another pair of backslashes.
1014
+ // Note that this rule can't know where line breaks belong so
1015
+ // it can't tell whether backslashes are completely missing. It just
1016
+ // enforces that you don't have the wrong number of pairs of backslashes.
1017
+ lint: function lint(state, content, nodes, match) {
1018
+ var text = match[0];
1019
+
1020
+ while (text.length) {
1021
+ var index = text.indexOf("\\\\");
1022
+
1023
+ if (index === -1) {
1024
+ // No more backslash pairs, so we found no lint
1025
+ return null;
1026
+ }
1027
+
1028
+ text = text.substring(index + 2); // Now we expect to find optional spaces, another pair of
1029
+ // backslashes, and more optional spaces not followed immediately
1030
+ // by another pair of backslashes.
1031
+
1032
+ var nextpair = text.match(/^\s*\\\\\s*(?!\\\\)/); // If that does not match then we either have too few or too
1033
+ // many pairs of backslashes.
1034
+
1035
+ if (!nextpair) {
1036
+ return "Use four backslashes between lines of an align block";
1037
+ } // If it did match, then, shorten the string and continue looping
1038
+ // (because a single align block may have multiple lines that
1039
+ // all must be separated by two sets of double backslashes).
1040
+
1041
+
1042
+ text = text.substring(nextpair[0].length);
1043
+ }
1044
+ }
1045
+ });
1046
+
1047
+ var MathEmpty = Rule.makeRule({
1048
+ name: "math-empty",
1049
+ severity: Rule.Severity.WARNING,
1050
+ selector: "math, blockMath",
1051
+ pattern: /^$/,
1052
+ message: "Empty math: don't use $$ in your markdown."
1053
+ });
1054
+
1055
+ var MathFontSize = Rule.makeRule({
1056
+ name: "math-font-size",
1057
+ severity: Rule.Severity.GUIDELINE,
1058
+ selector: "math, blockMath",
1059
+ pattern: /\\(tiny|Tiny|small|large|Large|LARGE|huge|Huge|scriptsize|normalsize)\s*{/,
1060
+ message: "Math font size:\nDon't change the default font size with \\Large{} or similar commands"
1061
+ });
1062
+
1063
+ var MathFrac = Rule.makeRule({
1064
+ name: "math-frac",
1065
+ severity: Rule.Severity.GUIDELINE,
1066
+ selector: "math, blockMath",
1067
+ pattern: /\\frac[ {]/,
1068
+ message: "Use \\dfrac instead of \\frac in your math expressions."
1069
+ });
1070
+
1071
+ var MathNested = Rule.makeRule({
1072
+ name: "math-nested",
1073
+ severity: Rule.Severity.ERROR,
1074
+ selector: "math, blockMath",
1075
+ pattern: /\\text{[^$}]*\$[^$}]*\$[^}]*}/,
1076
+ message: "Nested math:\nDon't nest math expressions inside \\text{} blocks"
1077
+ });
1078
+
1079
+ var MathStartsWithSpace = Rule.makeRule({
1080
+ name: "math-starts-with-space",
1081
+ severity: Rule.Severity.GUIDELINE,
1082
+ selector: "math, blockMath",
1083
+ pattern: /^\s*(~|\\qquad|\\quad|\\,|\\;|\\:|\\ |\\!|\\enspace|\\phantom)/,
1084
+ message: "Math starts with space:\nmath should not be indented. Do not begin math expressions with\nLaTeX space commands like ~, \\;, \\quad, or \\phantom"
1085
+ });
1086
+
1087
+ var MathTextEmpty = Rule.makeRule({
1088
+ name: "math-text-empty",
1089
+ severity: Rule.Severity.WARNING,
1090
+ selector: "math, blockMath",
1091
+ pattern: /\\text{\s*}/,
1092
+ message: "Empty \\text{} block in math expression"
1093
+ });
1094
+
1095
+ // Math and code hold their content directly and do not have text nodes
1096
+ // beneath them (unlike the HTML DOM) so this rule automatically does not
1097
+ // apply inside $$ or ``.
1098
+
1099
+ var MathWithoutDollars = Rule.makeRule({
1100
+ name: "math-without-dollars",
1101
+ severity: Rule.Severity.GUIDELINE,
1102
+ pattern: /\\\w+{[^}]*}|{|}/,
1103
+ message: "This looks like LaTeX:\ndid you mean to put it inside dollar signs?"
1104
+ });
1105
+
1106
+ var NestedLists = Rule.makeRule({
1107
+ name: "nested-lists",
1108
+ severity: Rule.Severity.WARNING,
1109
+ selector: "list list",
1110
+ message: "Nested lists:\nnested lists are hard to read on mobile devices;\ndo not use additional indentation."
1111
+ });
1112
+
1113
+ var Profanity = Rule.makeRule({
1114
+ name: "profanity",
1115
+ // This list could obviously be expanded a lot, but I figured we
1116
+ // could start with https://en.wikipedia.org/wiki/Seven_dirty_words
1117
+ pattern: /\b(shit|piss|fuck|cunt|cocksucker|motherfucker|tits)\b/i,
1118
+ message: "Avoid profanity"
1119
+ });
1120
+
1121
+ var TableMissingCells = Rule.makeRule({
1122
+ name: "table-missing-cells",
1123
+ severity: Rule.Severity.WARNING,
1124
+ selector: "table",
1125
+ lint: function lint(state, content, nodes, match) {
1126
+ var table = nodes[0];
1127
+ var headerLength = table.header.length;
1128
+ var rowLengths = table.cells.map(r => r.length);
1129
+
1130
+ for (var r = 0; r < rowLengths.length; r++) {
1131
+ if (rowLengths[r] !== headerLength) {
1132
+ return "Table rows don't match header:\nThe table header has ".concat(headerLength, " cells, but\nRow ").concat(r + 1, " has ").concat(rowLengths[r], " cells.");
1133
+ }
1134
+ }
1135
+ }
1136
+ });
1137
+
1138
+ // Math and code hold their content directly and do not have text nodes
1139
+ // beneath them (unlike the HTML DOM) so this rule automatically does not
1140
+ // apply inside $$ or ``.
1141
+
1142
+ var UnbalancedCodeDelimiters = Rule.makeRule({
1143
+ name: "unbalanced-code-delimiters",
1144
+ severity: Rule.Severity.ERROR,
1145
+ pattern: /[`~]+/,
1146
+ message: "Unbalanced code delimiters:\ncode blocks should begin and end with the same type and number of delimiters"
1147
+ });
1148
+
1149
+ var UnescapedDollar = Rule.makeRule({
1150
+ name: "unescaped-dollar",
1151
+ severity: Rule.Severity.ERROR,
1152
+ selector: "unescapedDollar",
1153
+ message: "Unescaped dollar sign:\nDollar signs must appear in pairs or be escaped as \\$"
1154
+ });
1155
+
1156
+ var WidgetInTable = Rule.makeRule({
1157
+ name: "widget-in-table",
1158
+ severity: Rule.Severity.BULK_WARNING,
1159
+ selector: "table widget",
1160
+ message: "Widget in table:\ndo not put widgets inside of tables."
1161
+ });
1162
+
1163
+ // TODO(davidflanagan):
1164
+ var AllRules = [AbsoluteUrl, BlockquotedMath, BlockquotedWidget, DoubleSpacingAfterTerminal, ExtraContentSpacing, HeadingLevel1, HeadingLevelSkip, HeadingSentenceCase, HeadingTitleCase, ImageAltText, ImageInTable, LinkClickHere, LongParagraph, MathAdjacent, MathAlignExtraBreak, MathAlignLinebreaks, MathEmpty, MathFontSize, MathFrac, MathNested, MathStartsWithSpace, MathTextEmpty, NestedLists, TableMissingCells, UnescapedDollar, WidgetInTable, Profanity, MathWithoutDollars, UnbalancedCodeDelimiters, ImageSpacesAroundUrls, ImageWidget];
1165
+
1166
+ // that every node has a string-valued `type` property
1167
+
1168
+ // This is the TreeTransformer class described in detail at the
1169
+ // top of this file.
1170
+ class TreeTransformer {
1171
+ // To create a tree transformer, just pass the root node of the tree
1172
+ constructor(root) {
1173
+ _defineProperty(this, "root", void 0);
1174
+
1175
+ this.root = root;
1176
+ } // A utility function for determing whether an arbitrary value is a node
1177
+
1178
+
1179
+ static isNode(n) {
1180
+ return n && typeof n === "object" && typeof n.type === "string";
1181
+ } // Determines whether a value is a node with type "text" and has
1182
+ // a text-valued `content` property.
1183
+
1184
+
1185
+ static isTextNode(n) {
1186
+ return TreeTransformer.isNode(n) && n.type === "text" && typeof n.content === "string";
1187
+ } // This is the main entry point for the traverse() method. See the comment
1188
+ // at the top of this file for a detailed description. Note that this
1189
+ // method just creates a new TraversalState object to use for this
1190
+ // traversal and then invokes the internal _traverse() method to begin the
1191
+ // recursion.
1192
+
1193
+
1194
+ traverse(f) {
1195
+ this._traverse(this.root, new TraversalState(this.root), f);
1196
+ } // Do a post-order traversal of node and its descendants, invoking the
1197
+ // callback function f() once for each node and returning the concatenated
1198
+ // text content of the node and its descendants. f() is passed three
1199
+ // arguments: the current node, a TraversalState object representing the
1200
+ // current state of the traversal, and a string that holds the
1201
+ // concatenated text of the node and its descendants.
1202
+ //
1203
+ // This private method holds all the traversal logic and implementation
1204
+ // details. Note that this method uses the TraversalState object to store
1205
+ // information about the structure of the tree.
1206
+
1207
+
1208
+ _traverse( // eslint-disable-next-line flowtype/no-mutable-array
1209
+ n, state, f) {
1210
+ var content = "";
1211
+
1212
+ if (TreeTransformer.isNode(n)) {
1213
+ // If we were called on a node object, then we handle it
1214
+ // this way.
1215
+ var _node = n; // safe cast; we just tested
1216
+ // Put the node on the stack before recursing on its children
1217
+
1218
+ state._containers.push(_node);
1219
+
1220
+ state._ancestors.push(_node); // Record the node's text content if it has any.
1221
+ // Usually this is for nodes with a type property of "text",
1222
+ // but other nodes types like "math" may also have content.
1223
+ // TODO(mdr): We found a new Flow error when upgrading:
1224
+ // "node.content (property `content` is missing in `TreeNode` [1].)"
1225
+ // $FlowFixMe[prop-missing](0.57.3->0.75.0)
1226
+
1227
+
1228
+ if (typeof _node.content === "string") {
1229
+ content = _node.content;
1230
+ } // Recurse on the node. If there was content above, then there
1231
+ // probably won't be any children to recurse on, but we check
1232
+ // anyway.
1233
+ //
1234
+ // If we wanted to make the traversal completely specific to the
1235
+ // actual Perseus parse trees that we'll be dealing with we could
1236
+ // put a switch statement here to dispatch on the node type
1237
+ // property with specific recursion steps for each known type of
1238
+ // node.
1239
+
1240
+
1241
+ var keys = Object.keys(_node);
1242
+ keys.forEach(key => {
1243
+ // Never recurse on the type property
1244
+ if (key === "type") {
1245
+ return;
1246
+ } // Ignore properties that are null or primitive and only
1247
+ // recurse on objects and arrays. Note that we don't do a
1248
+ // isNode() check here. That is done in the recursive call to
1249
+ // _traverse(). Note that the recursive call on each child
1250
+ // returns the text content of the child and we add that
1251
+ // content to the content for this node. Also note that we
1252
+ // push the name of the property we're recursing over onto a
1253
+ // TraversalState stack.
1254
+
1255
+
1256
+ var value = _node[key];
1257
+
1258
+ if (value && typeof value === "object") {
1259
+ state._indexes.push(key);
1260
+
1261
+ content += this._traverse(value, state, f);
1262
+
1263
+ state._indexes.pop();
1264
+ }
1265
+ }); // Restore the stacks after recursing on the children
1266
+
1267
+ state._currentNode = state._ancestors.pop();
1268
+
1269
+ state._containers.pop(); // And finally call the traversal callback for this node. Note
1270
+ // that this is post-order traversal. We call the callback on the
1271
+ // way back up the tree, not on the way down. That way we already
1272
+ // know all the content contained within the node.
1273
+
1274
+
1275
+ f(_node, state, content);
1276
+ } else if (Array.isArray(n)) {
1277
+ // If we were called on an array instead of a node, then
1278
+ // this is the code we use to recurse.
1279
+ var nodes = n; // Push the array onto the stack. This will allow the
1280
+ // TraversalState object to locate siblings of this node.
1281
+
1282
+ state._containers.push(nodes); // Now loop through this array and recurse on each element in it.
1283
+ // Before recursing on an element, we push its array index on a
1284
+ // TraversalState stack so that the TraversalState sibling methods
1285
+ // can work. Note that TraversalState methods can alter the length
1286
+ // of the array, and change the index of the current node, so we
1287
+ // are careful here to test the array length on each iteration and
1288
+ // to reset the index when we pop the stack. Also note that we
1289
+ // concatentate the text content of the children.
1290
+
1291
+
1292
+ var index = 0;
1293
+
1294
+ while (index < nodes.length) {
1295
+ state._indexes.push(index);
1296
+
1297
+ content += this._traverse(nodes[index], state, f); // Casting to convince Flow that this is a number
1298
+
1299
+ index = state._indexes.pop() + 1;
1300
+ } // Pop the array off the stack. Note, however, that we do not call
1301
+ // the traversal callback on the array. That function is only
1302
+ // called for nodes, not arrays of nodes.
1303
+
1304
+
1305
+ state._containers.pop();
1306
+ } // The _traverse() method always returns the text content of
1307
+ // this node and its children. This is the one piece of state that
1308
+ // is not tracked in the TraversalState object.
1309
+
1310
+
1311
+ return content;
1312
+ }
1313
+
1314
+ } // An instance of this class is passed to the callback function for
1315
+ // each node traversed. The class itself is not exported, but its
1316
+ // methods define the API available to the traversal callback.
1317
+
1318
+ /**
1319
+ * This class represents the state of a tree traversal. An instance is created
1320
+ * by the traverse() method of the TreeTransformer class to maintain the state
1321
+ * for that traversal, and the instance is passed to the traversal callback
1322
+ * function for each node that is traversed. This class is not intended to be
1323
+ * instantiated directly, but is exported so that its type can be used for
1324
+ * Flow annotaions.
1325
+ **/
1326
+
1327
+ class TraversalState {
1328
+ // The root node of the tree being traversed
1329
+ // These are internal state properties. Use the accessor methods defined
1330
+ // below instead of using these properties directly. Note that the
1331
+ // _containers and _indexes stacks can have two different types of
1332
+ // elements, depending on whether we just recursed on an array or on a
1333
+ // node. This is hard for Flow to deal with, so you'll see a number of
1334
+ // Flow casts through the any type when working with these two properties.
1335
+ // eslint-disable-next-line flowtype/no-mutable-array
1336
+ // The constructor just stores the root node and creates empty stacks.
1337
+ constructor(root) {
1338
+ _defineProperty(this, "root", void 0);
1339
+
1340
+ _defineProperty(this, "_currentNode", void 0);
1341
+
1342
+ _defineProperty(this, "_containers", void 0);
1343
+
1344
+ _defineProperty(this, "_indexes", void 0);
1345
+
1346
+ _defineProperty(this, "_ancestors", void 0);
1347
+
1348
+ this.root = root; // When the callback is called, this property will hold the
1349
+ // node that is currently being traversed.
1350
+
1351
+ this._currentNode = null; // This is a stack of the objects and arrays that we've
1352
+ // traversed through before reaching the currentNode.
1353
+ // It is different than the ancestors array.
1354
+
1355
+ this._containers = new Stack(); // This stack has the same number of elements as the _containers
1356
+ // stack. The last element of this._indexes[] is the index of
1357
+ // the current node in the object or array that is the last element
1358
+ // of this._containers[]. If the last element of this._containers[] is
1359
+ // an array, then the last element of this stack will be a number.
1360
+ // Otherwise if the last container is an object, then the last index
1361
+ // will be a string property name.
1362
+
1363
+ this._indexes = new Stack(); // This is a stack of the ancestor nodes of the current one.
1364
+ // It is different than the containers[] stack because it only
1365
+ // includes nodes, not arrays.
1366
+
1367
+ this._ancestors = new Stack();
1368
+ }
1369
+ /**
1370
+ * Return the current node in the traversal. Any time the traversal
1371
+ * callback is called, this method will return the name value as the
1372
+ * first argument to the callback.
1373
+ */
1374
+
1375
+
1376
+ currentNode() {
1377
+ return this._currentNode || this.root;
1378
+ }
1379
+ /**
1380
+ * Return the parent of the current node, if there is one, or null.
1381
+ */
1382
+
1383
+
1384
+ parent() {
1385
+ return this._ancestors.top();
1386
+ }
1387
+ /**
1388
+ * Return an array of ancestor nodes. The first element of this array is
1389
+ * the same as this.parent() and the last element is the root node. If we
1390
+ * are currently at the root node, the the returned array will be empty.
1391
+ * This method makes a copy of the internal state, so modifications to the
1392
+ * returned array have no effect on the traversal.
1393
+ */
1394
+
1395
+
1396
+ ancestors() {
1397
+ return this._ancestors.values();
1398
+ }
1399
+ /**
1400
+ * Return the next sibling of this node, if it has one, or null otherwise.
1401
+ */
1402
+
1403
+
1404
+ nextSibling() {
1405
+ var siblings = this._containers.top(); // If we're at the root of the tree or if the parent is an
1406
+ // object instead of an array, then there are no siblings.
1407
+
1408
+
1409
+ if (!siblings || !Array.isArray(siblings)) {
1410
+ return null;
1411
+ } // The top index is a number because the top container is an array
1412
+
1413
+
1414
+ var index = this._indexes.top();
1415
+
1416
+ if (siblings.length > index + 1) {
1417
+ return siblings[index + 1];
1418
+ }
1419
+
1420
+ return null; // There is no next sibling
1421
+ }
1422
+ /**
1423
+ * Return the previous sibling of this node, if it has one, or null
1424
+ * otherwise.
1425
+ */
1426
+
1427
+
1428
+ previousSibling() {
1429
+ var siblings = this._containers.top(); // If we're at the root of the tree or if the parent is an
1430
+ // object instead of an array, then there are no siblings.
1431
+
1432
+
1433
+ if (!siblings || !Array.isArray(siblings)) {
1434
+ return null;
1435
+ } // The top index is a number because the top container is an array
1436
+
1437
+
1438
+ var index = this._indexes.top();
1439
+
1440
+ if (index > 0) {
1441
+ return siblings[index - 1];
1442
+ }
1443
+
1444
+ return null; // There is no previous sibling
1445
+ }
1446
+ /**
1447
+ * Remove the next sibling node (if there is one) from the tree. Returns
1448
+ * the removed sibling or null. This method makes it easy to traverse a
1449
+ * tree and concatenate adjacent text nodes into a single node.
1450
+ */
1451
+
1452
+
1453
+ removeNextSibling() {
1454
+ var siblings = this._containers.top();
1455
+
1456
+ if (siblings && Array.isArray(siblings)) {
1457
+ // top index is a number because top container is an array
1458
+ var index = this._indexes.top();
1459
+
1460
+ if (siblings.length > index + 1) {
1461
+ return siblings.splice(index + 1, 1)[0];
1462
+ }
1463
+ }
1464
+
1465
+ return null;
1466
+ }
1467
+ /**
1468
+ * Replace the current node in the tree with the specified nodes. If no
1469
+ * nodes are passed, this is a node deletion. If one node (or array) is
1470
+ * passed, this is a 1-for-1 replacement. If more than one node is passed
1471
+ * then this is a combination of deletion and insertion. The new node or
1472
+ * nodes will not be traversed, so this method can safely be used to
1473
+ * reparent the current node node beneath a new parent.
1474
+ *
1475
+ * This method throws an error if you attempt to replace the root node of
1476
+ * the tree.
1477
+ */
1478
+
1479
+
1480
+ replace() {
1481
+ var parent = this._containers.top();
1482
+
1483
+ if (!parent) {
1484
+ throw new PerseusError("Can't replace the root of the tree", Errors.Internal);
1485
+ } // The top of the container stack is either an array or an object
1486
+ // and the top of the indexes stack is a corresponding array index
1487
+ // or object property. This is hard for Flow, so we have to do some
1488
+ // unsafe casting and be careful when we use which cast version
1489
+
1490
+
1491
+ for (var _len = arguments.length, replacements = new Array(_len), _key = 0; _key < _len; _key++) {
1492
+ replacements[_key] = arguments[_key];
1493
+ }
1494
+
1495
+ if (Array.isArray(parent)) {
1496
+ var index = this._indexes.top(); // For an array parent we just splice the new nodes in
1497
+
1498
+
1499
+ parent.splice(index, 1, ...replacements); // Adjust the index to account for the changed array length.
1500
+ // We don't want to traverse any of the newly inserted nodes.
1501
+
1502
+ this._indexes.pop();
1503
+
1504
+ this._indexes.push(index + replacements.length - 1);
1505
+ } else {
1506
+ var property = this._indexes.top(); // For an object parent we care how many new nodes there are
1507
+
1508
+
1509
+ if (replacements.length === 0) {
1510
+ // Deletion
1511
+ delete parent[property];
1512
+ } else if (replacements.length === 1) {
1513
+ // Replacement
1514
+ parent[property] = replacements[0];
1515
+ } else {
1516
+ // Replace one node with an array of nodes
1517
+ parent[property] = replacements;
1518
+ }
1519
+ }
1520
+ }
1521
+ /**
1522
+ * Returns true if the current node has a previous sibling and false
1523
+ * otherwise. If this method returns false, then previousSibling() will
1524
+ * return null, and goToPreviousSibling() will throw an error.
1525
+ */
1526
+
1527
+
1528
+ hasPreviousSibling() {
1529
+ return Array.isArray(this._containers.top()) && this._indexes.top() > 0;
1530
+ }
1531
+ /**
1532
+ * Modify this traversal state object to have the state it would have had
1533
+ * when visiting the previous sibling. Note that you may want to use
1534
+ * clone() to make a copy before modifying the state object like this.
1535
+ * This mutator method is not typically used during ordinary tree
1536
+ * traversals, but is used by the Selector class for matching multi-node
1537
+ * selectors.
1538
+ */
1539
+
1540
+
1541
+ goToPreviousSibling() {
1542
+ if (!this.hasPreviousSibling()) {
1543
+ throw new PerseusError("goToPreviousSibling(): node has no previous sibling", Errors.Internal);
1544
+ }
1545
+
1546
+ this._currentNode = this.previousSibling(); // Since we know that we have a previous sibling, we know that
1547
+ // the value on top of the stack is a number, but we have to do
1548
+ // this unsafe cast because Flow doesn't know that.
1549
+
1550
+ var index = this._indexes.pop();
1551
+
1552
+ this._indexes.push(index - 1);
1553
+ }
1554
+ /**
1555
+ * Returns true if the current node has an ancestor and false otherwise.
1556
+ * If this method returns false, then the parent() method will return
1557
+ * null and goToParent() will throw an error
1558
+ */
1559
+
1560
+
1561
+ hasParent() {
1562
+ return this._ancestors.size() !== 0;
1563
+ }
1564
+ /**
1565
+ * Modify this object to look like it will look when we (later) visit the
1566
+ * parent node of this node. You should not modify the instance passed to
1567
+ * the tree traversal callback. Instead, make a copy with the clone()
1568
+ * method and modify that. This mutator method is not typically used
1569
+ * during ordinary tree traversals, but is used by the Selector class for
1570
+ * matching multi-node selectors that involve parent and ancestor
1571
+ * selectors.
1572
+ */
1573
+
1574
+
1575
+ goToParent() {
1576
+ if (!this.hasParent()) {
1577
+ throw new PerseusError("goToParent(): node has no ancestor", Errors.NotAllowed);
1578
+ }
1579
+
1580
+ this._currentNode = this._ancestors.pop(); // We need to pop the containers and indexes stacks at least once
1581
+ // and more as needed until we restore the invariant that
1582
+ // this._containers.top()[this.indexes.top()] === this._currentNode
1583
+ //
1584
+
1585
+ while (this._containers.size() && // This is safe, but easier to just disable flow than do casts
1586
+ // $FlowFixMe[incompatible-use]
1587
+ this._containers.top()[this._indexes.top()] !== this._currentNode) {
1588
+ this._containers.pop();
1589
+
1590
+ this._indexes.pop();
1591
+ }
1592
+ }
1593
+ /**
1594
+ * Return a new TraversalState object that is a copy of this one.
1595
+ * This method is useful in conjunction with the mutating methods
1596
+ * goToParent() and goToPreviousSibling().
1597
+ */
1598
+
1599
+
1600
+ clone() {
1601
+ var clone = new TraversalState(this.root);
1602
+ clone._currentNode = this._currentNode;
1603
+ clone._containers = this._containers.clone();
1604
+ clone._indexes = this._indexes.clone();
1605
+ clone._ancestors = this._ancestors.clone();
1606
+ return clone;
1607
+ }
1608
+ /**
1609
+ * Returns true if this TraversalState object is equal to that
1610
+ * TraversalState object, or false otherwise. This method exists
1611
+ * primarily for use by our unit tests.
1612
+ */
1613
+
1614
+
1615
+ equals(that) {
1616
+ return this.root === that.root && this._currentNode === that._currentNode && this._containers.equals(that._containers) && this._indexes.equals(that._indexes) && this._ancestors.equals(that._ancestors);
1617
+ }
1618
+
1619
+ }
1620
+ /**
1621
+ * This class is an internal utility that just treats an array as a stack
1622
+ * and gives us a top() method so we don't have to write expressions like
1623
+ * `ancestors[ancestors.length-1]`. The values() method automatically
1624
+ * copies the internal array so we don't have to worry about client code
1625
+ * modifying our internal stacks. The use of this Stack abstraction makes
1626
+ * the TraversalState class simpler in a number of places.
1627
+ */
1628
+
1629
+ class Stack {
1630
+ // eslint-disable-next-line flowtype/no-mutable-array
1631
+ constructor(array) {
1632
+ _defineProperty(this, "stack", void 0);
1633
+
1634
+ this.stack = array ? array.slice(0) : [];
1635
+ }
1636
+ /** Push a value onto the stack. */
1637
+
1638
+
1639
+ push(v) {
1640
+ this.stack.push(v);
1641
+ }
1642
+ /** Pop a value off of the stack. */
1643
+
1644
+
1645
+ pop() {
1646
+ return this.stack.pop();
1647
+ }
1648
+ /** Return the top value of the stack without popping it. */
1649
+
1650
+
1651
+ top() {
1652
+ return this.stack[this.stack.length - 1];
1653
+ }
1654
+ /** Return a copy of the stack as an array */
1655
+
1656
+
1657
+ values() {
1658
+ return this.stack.slice(0);
1659
+ }
1660
+ /** Return the number of elements in the stack */
1661
+
1662
+
1663
+ size() {
1664
+ return this.stack.length;
1665
+ }
1666
+ /** Return a string representation of the stack */
1667
+
1668
+
1669
+ toString() {
1670
+ return this.stack.toString();
1671
+ }
1672
+ /** Return a shallow copy of the stack */
1673
+
1674
+
1675
+ clone() {
1676
+ return new Stack(this.stack);
1677
+ }
1678
+ /**
1679
+ * Compare this stack to another and return true if the contents of
1680
+ * the two arrays are the same.
1681
+ */
1682
+
1683
+
1684
+ equals(that) {
1685
+ if (!that || !that.stack || that.stack.length !== this.stack.length) {
1686
+ return false;
1687
+ }
1688
+
1689
+ for (var i = 0; i < this.stack.length; i++) {
1690
+ if (this.stack[i] !== that.stack[i]) {
1691
+ return false;
1692
+ }
1693
+ }
1694
+
1695
+ return true;
1696
+ }
1697
+
1698
+ }
1699
+
1700
+ var propTypes = {exports: {}};
1701
+
1702
+ var reactIs = {exports: {}};
1703
+
1704
+ var reactIs_production_min = {};
1705
+
1706
+ /** @license React v16.13.1
1707
+ * react-is.production.min.js
1708
+ *
1709
+ * Copyright (c) Facebook, Inc. and its affiliates.
1710
+ *
1711
+ * This source code is licensed under the MIT license found in the
1712
+ * LICENSE file in the root directory of this source tree.
1713
+ */
1714
+
1715
+ var hasRequiredReactIs_production_min;
1716
+
1717
+ function requireReactIs_production_min () {
1718
+ if (hasRequiredReactIs_production_min) return reactIs_production_min;
1719
+ hasRequiredReactIs_production_min = 1;
1720
+ var b="function"===typeof Symbol&&Symbol.for,c=b?Symbol.for("react.element"):60103,d=b?Symbol.for("react.portal"):60106,e=b?Symbol.for("react.fragment"):60107,f=b?Symbol.for("react.strict_mode"):60108,g=b?Symbol.for("react.profiler"):60114,h=b?Symbol.for("react.provider"):60109,k=b?Symbol.for("react.context"):60110,l=b?Symbol.for("react.async_mode"):60111,m=b?Symbol.for("react.concurrent_mode"):60111,n=b?Symbol.for("react.forward_ref"):60112,p=b?Symbol.for("react.suspense"):60113,q=b?
1721
+ Symbol.for("react.suspense_list"):60120,r=b?Symbol.for("react.memo"):60115,t=b?Symbol.for("react.lazy"):60116,v=b?Symbol.for("react.block"):60121,w=b?Symbol.for("react.fundamental"):60117,x=b?Symbol.for("react.responder"):60118,y=b?Symbol.for("react.scope"):60119;
1722
+ function z(a){if("object"===typeof a&&null!==a){var u=a.$$typeof;switch(u){case c:switch(a=a.type,a){case l:case m:case e:case g:case f:case p:return a;default:switch(a=a&&a.$$typeof,a){case k:case n:case t:case r:case h:return a;default:return u}}case d:return u}}}function A(a){return z(a)===m}reactIs_production_min.AsyncMode=l;reactIs_production_min.ConcurrentMode=m;reactIs_production_min.ContextConsumer=k;reactIs_production_min.ContextProvider=h;reactIs_production_min.Element=c;reactIs_production_min.ForwardRef=n;reactIs_production_min.Fragment=e;reactIs_production_min.Lazy=t;reactIs_production_min.Memo=r;reactIs_production_min.Portal=d;
1723
+ reactIs_production_min.Profiler=g;reactIs_production_min.StrictMode=f;reactIs_production_min.Suspense=p;reactIs_production_min.isAsyncMode=function(a){return A(a)||z(a)===l};reactIs_production_min.isConcurrentMode=A;reactIs_production_min.isContextConsumer=function(a){return z(a)===k};reactIs_production_min.isContextProvider=function(a){return z(a)===h};reactIs_production_min.isElement=function(a){return "object"===typeof a&&null!==a&&a.$$typeof===c};reactIs_production_min.isForwardRef=function(a){return z(a)===n};reactIs_production_min.isFragment=function(a){return z(a)===e};reactIs_production_min.isLazy=function(a){return z(a)===t};
1724
+ reactIs_production_min.isMemo=function(a){return z(a)===r};reactIs_production_min.isPortal=function(a){return z(a)===d};reactIs_production_min.isProfiler=function(a){return z(a)===g};reactIs_production_min.isStrictMode=function(a){return z(a)===f};reactIs_production_min.isSuspense=function(a){return z(a)===p};
1725
+ reactIs_production_min.isValidElementType=function(a){return "string"===typeof a||"function"===typeof a||a===e||a===m||a===g||a===f||a===p||a===q||"object"===typeof a&&null!==a&&(a.$$typeof===t||a.$$typeof===r||a.$$typeof===h||a.$$typeof===k||a.$$typeof===n||a.$$typeof===w||a.$$typeof===x||a.$$typeof===y||a.$$typeof===v)};reactIs_production_min.typeOf=z;
1726
+ return reactIs_production_min;
1727
+ }
1728
+
1729
+ var reactIs_development = {};
1730
+
1731
+ /** @license React v16.13.1
1732
+ * react-is.development.js
1733
+ *
1734
+ * Copyright (c) Facebook, Inc. and its affiliates.
1735
+ *
1736
+ * This source code is licensed under the MIT license found in the
1737
+ * LICENSE file in the root directory of this source tree.
1738
+ */
1739
+
1740
+ var hasRequiredReactIs_development;
1741
+
1742
+ function requireReactIs_development () {
1743
+ if (hasRequiredReactIs_development) return reactIs_development;
1744
+ hasRequiredReactIs_development = 1;
1745
+
1746
+
1747
+
1748
+ if (process.env.NODE_ENV !== "production") {
1749
+ (function() {
1750
+
1751
+ // The Symbol used to tag the ReactElement-like types. If there is no native Symbol
1752
+ // nor polyfill, then a plain number is used for performance.
1753
+ var hasSymbol = typeof Symbol === 'function' && Symbol.for;
1754
+ var REACT_ELEMENT_TYPE = hasSymbol ? Symbol.for('react.element') : 0xeac7;
1755
+ var REACT_PORTAL_TYPE = hasSymbol ? Symbol.for('react.portal') : 0xeaca;
1756
+ var REACT_FRAGMENT_TYPE = hasSymbol ? Symbol.for('react.fragment') : 0xeacb;
1757
+ var REACT_STRICT_MODE_TYPE = hasSymbol ? Symbol.for('react.strict_mode') : 0xeacc;
1758
+ var REACT_PROFILER_TYPE = hasSymbol ? Symbol.for('react.profiler') : 0xead2;
1759
+ var REACT_PROVIDER_TYPE = hasSymbol ? Symbol.for('react.provider') : 0xeacd;
1760
+ var REACT_CONTEXT_TYPE = hasSymbol ? Symbol.for('react.context') : 0xeace; // TODO: We don't use AsyncMode or ConcurrentMode anymore. They were temporary
1761
+ // (unstable) APIs that have been removed. Can we remove the symbols?
1762
+
1763
+ var REACT_ASYNC_MODE_TYPE = hasSymbol ? Symbol.for('react.async_mode') : 0xeacf;
1764
+ var REACT_CONCURRENT_MODE_TYPE = hasSymbol ? Symbol.for('react.concurrent_mode') : 0xeacf;
1765
+ var REACT_FORWARD_REF_TYPE = hasSymbol ? Symbol.for('react.forward_ref') : 0xead0;
1766
+ var REACT_SUSPENSE_TYPE = hasSymbol ? Symbol.for('react.suspense') : 0xead1;
1767
+ var REACT_SUSPENSE_LIST_TYPE = hasSymbol ? Symbol.for('react.suspense_list') : 0xead8;
1768
+ var REACT_MEMO_TYPE = hasSymbol ? Symbol.for('react.memo') : 0xead3;
1769
+ var REACT_LAZY_TYPE = hasSymbol ? Symbol.for('react.lazy') : 0xead4;
1770
+ var REACT_BLOCK_TYPE = hasSymbol ? Symbol.for('react.block') : 0xead9;
1771
+ var REACT_FUNDAMENTAL_TYPE = hasSymbol ? Symbol.for('react.fundamental') : 0xead5;
1772
+ var REACT_RESPONDER_TYPE = hasSymbol ? Symbol.for('react.responder') : 0xead6;
1773
+ var REACT_SCOPE_TYPE = hasSymbol ? Symbol.for('react.scope') : 0xead7;
1774
+
1775
+ function isValidElementType(type) {
1776
+ return typeof type === 'string' || typeof type === 'function' || // Note: its typeof might be other than 'symbol' or 'number' if it's a polyfill.
1777
+ type === REACT_FRAGMENT_TYPE || type === REACT_CONCURRENT_MODE_TYPE || type === REACT_PROFILER_TYPE || type === REACT_STRICT_MODE_TYPE || type === REACT_SUSPENSE_TYPE || type === REACT_SUSPENSE_LIST_TYPE || typeof type === 'object' && type !== null && (type.$$typeof === REACT_LAZY_TYPE || type.$$typeof === REACT_MEMO_TYPE || type.$$typeof === REACT_PROVIDER_TYPE || type.$$typeof === REACT_CONTEXT_TYPE || type.$$typeof === REACT_FORWARD_REF_TYPE || type.$$typeof === REACT_FUNDAMENTAL_TYPE || type.$$typeof === REACT_RESPONDER_TYPE || type.$$typeof === REACT_SCOPE_TYPE || type.$$typeof === REACT_BLOCK_TYPE);
1778
+ }
1779
+
1780
+ function typeOf(object) {
1781
+ if (typeof object === 'object' && object !== null) {
1782
+ var $$typeof = object.$$typeof;
1783
+
1784
+ switch ($$typeof) {
1785
+ case REACT_ELEMENT_TYPE:
1786
+ var type = object.type;
1787
+
1788
+ switch (type) {
1789
+ case REACT_ASYNC_MODE_TYPE:
1790
+ case REACT_CONCURRENT_MODE_TYPE:
1791
+ case REACT_FRAGMENT_TYPE:
1792
+ case REACT_PROFILER_TYPE:
1793
+ case REACT_STRICT_MODE_TYPE:
1794
+ case REACT_SUSPENSE_TYPE:
1795
+ return type;
1796
+
1797
+ default:
1798
+ var $$typeofType = type && type.$$typeof;
1799
+
1800
+ switch ($$typeofType) {
1801
+ case REACT_CONTEXT_TYPE:
1802
+ case REACT_FORWARD_REF_TYPE:
1803
+ case REACT_LAZY_TYPE:
1804
+ case REACT_MEMO_TYPE:
1805
+ case REACT_PROVIDER_TYPE:
1806
+ return $$typeofType;
1807
+
1808
+ default:
1809
+ return $$typeof;
1810
+ }
1811
+
1812
+ }
1813
+
1814
+ case REACT_PORTAL_TYPE:
1815
+ return $$typeof;
1816
+ }
1817
+ }
1818
+
1819
+ return undefined;
1820
+ } // AsyncMode is deprecated along with isAsyncMode
1821
+
1822
+ var AsyncMode = REACT_ASYNC_MODE_TYPE;
1823
+ var ConcurrentMode = REACT_CONCURRENT_MODE_TYPE;
1824
+ var ContextConsumer = REACT_CONTEXT_TYPE;
1825
+ var ContextProvider = REACT_PROVIDER_TYPE;
1826
+ var Element = REACT_ELEMENT_TYPE;
1827
+ var ForwardRef = REACT_FORWARD_REF_TYPE;
1828
+ var Fragment = REACT_FRAGMENT_TYPE;
1829
+ var Lazy = REACT_LAZY_TYPE;
1830
+ var Memo = REACT_MEMO_TYPE;
1831
+ var Portal = REACT_PORTAL_TYPE;
1832
+ var Profiler = REACT_PROFILER_TYPE;
1833
+ var StrictMode = REACT_STRICT_MODE_TYPE;
1834
+ var Suspense = REACT_SUSPENSE_TYPE;
1835
+ var hasWarnedAboutDeprecatedIsAsyncMode = false; // AsyncMode should be deprecated
1836
+
1837
+ function isAsyncMode(object) {
1838
+ {
1839
+ if (!hasWarnedAboutDeprecatedIsAsyncMode) {
1840
+ hasWarnedAboutDeprecatedIsAsyncMode = true; // Using console['warn'] to evade Babel and ESLint
1841
+
1842
+ console['warn']('The ReactIs.isAsyncMode() alias has been deprecated, ' + 'and will be removed in React 17+. Update your code to use ' + 'ReactIs.isConcurrentMode() instead. It has the exact same API.');
1843
+ }
1844
+ }
1845
+
1846
+ return isConcurrentMode(object) || typeOf(object) === REACT_ASYNC_MODE_TYPE;
1847
+ }
1848
+ function isConcurrentMode(object) {
1849
+ return typeOf(object) === REACT_CONCURRENT_MODE_TYPE;
1850
+ }
1851
+ function isContextConsumer(object) {
1852
+ return typeOf(object) === REACT_CONTEXT_TYPE;
1853
+ }
1854
+ function isContextProvider(object) {
1855
+ return typeOf(object) === REACT_PROVIDER_TYPE;
1856
+ }
1857
+ function isElement(object) {
1858
+ return typeof object === 'object' && object !== null && object.$$typeof === REACT_ELEMENT_TYPE;
1859
+ }
1860
+ function isForwardRef(object) {
1861
+ return typeOf(object) === REACT_FORWARD_REF_TYPE;
1862
+ }
1863
+ function isFragment(object) {
1864
+ return typeOf(object) === REACT_FRAGMENT_TYPE;
1865
+ }
1866
+ function isLazy(object) {
1867
+ return typeOf(object) === REACT_LAZY_TYPE;
1868
+ }
1869
+ function isMemo(object) {
1870
+ return typeOf(object) === REACT_MEMO_TYPE;
1871
+ }
1872
+ function isPortal(object) {
1873
+ return typeOf(object) === REACT_PORTAL_TYPE;
1874
+ }
1875
+ function isProfiler(object) {
1876
+ return typeOf(object) === REACT_PROFILER_TYPE;
1877
+ }
1878
+ function isStrictMode(object) {
1879
+ return typeOf(object) === REACT_STRICT_MODE_TYPE;
1880
+ }
1881
+ function isSuspense(object) {
1882
+ return typeOf(object) === REACT_SUSPENSE_TYPE;
1883
+ }
1884
+
1885
+ reactIs_development.AsyncMode = AsyncMode;
1886
+ reactIs_development.ConcurrentMode = ConcurrentMode;
1887
+ reactIs_development.ContextConsumer = ContextConsumer;
1888
+ reactIs_development.ContextProvider = ContextProvider;
1889
+ reactIs_development.Element = Element;
1890
+ reactIs_development.ForwardRef = ForwardRef;
1891
+ reactIs_development.Fragment = Fragment;
1892
+ reactIs_development.Lazy = Lazy;
1893
+ reactIs_development.Memo = Memo;
1894
+ reactIs_development.Portal = Portal;
1895
+ reactIs_development.Profiler = Profiler;
1896
+ reactIs_development.StrictMode = StrictMode;
1897
+ reactIs_development.Suspense = Suspense;
1898
+ reactIs_development.isAsyncMode = isAsyncMode;
1899
+ reactIs_development.isConcurrentMode = isConcurrentMode;
1900
+ reactIs_development.isContextConsumer = isContextConsumer;
1901
+ reactIs_development.isContextProvider = isContextProvider;
1902
+ reactIs_development.isElement = isElement;
1903
+ reactIs_development.isForwardRef = isForwardRef;
1904
+ reactIs_development.isFragment = isFragment;
1905
+ reactIs_development.isLazy = isLazy;
1906
+ reactIs_development.isMemo = isMemo;
1907
+ reactIs_development.isPortal = isPortal;
1908
+ reactIs_development.isProfiler = isProfiler;
1909
+ reactIs_development.isStrictMode = isStrictMode;
1910
+ reactIs_development.isSuspense = isSuspense;
1911
+ reactIs_development.isValidElementType = isValidElementType;
1912
+ reactIs_development.typeOf = typeOf;
1913
+ })();
1914
+ }
1915
+ return reactIs_development;
1916
+ }
1917
+
1918
+ var hasRequiredReactIs;
1919
+
1920
+ function requireReactIs () {
1921
+ if (hasRequiredReactIs) return reactIs.exports;
1922
+ hasRequiredReactIs = 1;
1923
+ (function (module) {
1924
+
1925
+ if (process.env.NODE_ENV === 'production') {
1926
+ module.exports = requireReactIs_production_min();
1927
+ } else {
1928
+ module.exports = requireReactIs_development();
1929
+ }
1930
+ } (reactIs));
1931
+ return reactIs.exports;
1932
+ }
1933
+
1934
+ /*
1935
+ object-assign
1936
+ (c) Sindre Sorhus
1937
+ @license MIT
1938
+ */
1939
+
1940
+ var objectAssign;
1941
+ var hasRequiredObjectAssign;
1942
+
1943
+ function requireObjectAssign () {
1944
+ if (hasRequiredObjectAssign) return objectAssign;
1945
+ hasRequiredObjectAssign = 1;
1946
+ /* eslint-disable no-unused-vars */
1947
+ var getOwnPropertySymbols = Object.getOwnPropertySymbols;
1948
+ var hasOwnProperty = Object.prototype.hasOwnProperty;
1949
+ var propIsEnumerable = Object.prototype.propertyIsEnumerable;
1950
+
1951
+ function toObject(val) {
1952
+ if (val === null || val === undefined) {
1953
+ throw new TypeError('Object.assign cannot be called with null or undefined');
1954
+ }
1955
+
1956
+ return Object(val);
1957
+ }
1958
+
1959
+ function shouldUseNative() {
1960
+ try {
1961
+ if (!Object.assign) {
1962
+ return false;
1963
+ }
1964
+
1965
+ // Detect buggy property enumeration order in older V8 versions.
1966
+
1967
+ // https://bugs.chromium.org/p/v8/issues/detail?id=4118
1968
+ var test1 = new String('abc'); // eslint-disable-line no-new-wrappers
1969
+ test1[5] = 'de';
1970
+ if (Object.getOwnPropertyNames(test1)[0] === '5') {
1971
+ return false;
1972
+ }
1973
+
1974
+ // https://bugs.chromium.org/p/v8/issues/detail?id=3056
1975
+ var test2 = {};
1976
+ for (var i = 0; i < 10; i++) {
1977
+ test2['_' + String.fromCharCode(i)] = i;
1978
+ }
1979
+ var order2 = Object.getOwnPropertyNames(test2).map(function (n) {
1980
+ return test2[n];
1981
+ });
1982
+ if (order2.join('') !== '0123456789') {
1983
+ return false;
1984
+ }
1985
+
1986
+ // https://bugs.chromium.org/p/v8/issues/detail?id=3056
1987
+ var test3 = {};
1988
+ 'abcdefghijklmnopqrst'.split('').forEach(function (letter) {
1989
+ test3[letter] = letter;
1990
+ });
1991
+ if (Object.keys(Object.assign({}, test3)).join('') !==
1992
+ 'abcdefghijklmnopqrst') {
1993
+ return false;
1994
+ }
1995
+
1996
+ return true;
1997
+ } catch (err) {
1998
+ // We don't expect any of the above to throw, but better to be safe.
1999
+ return false;
2000
+ }
2001
+ }
2002
+
2003
+ objectAssign = shouldUseNative() ? Object.assign : function (target, source) {
2004
+ var from;
2005
+ var to = toObject(target);
2006
+ var symbols;
2007
+
2008
+ for (var s = 1; s < arguments.length; s++) {
2009
+ from = Object(arguments[s]);
2010
+
2011
+ for (var key in from) {
2012
+ if (hasOwnProperty.call(from, key)) {
2013
+ to[key] = from[key];
2014
+ }
2015
+ }
2016
+
2017
+ if (getOwnPropertySymbols) {
2018
+ symbols = getOwnPropertySymbols(from);
2019
+ for (var i = 0; i < symbols.length; i++) {
2020
+ if (propIsEnumerable.call(from, symbols[i])) {
2021
+ to[symbols[i]] = from[symbols[i]];
2022
+ }
2023
+ }
2024
+ }
2025
+ }
2026
+
2027
+ return to;
2028
+ };
2029
+ return objectAssign;
2030
+ }
2031
+
2032
+ /**
2033
+ * Copyright (c) 2013-present, Facebook, Inc.
2034
+ *
2035
+ * This source code is licensed under the MIT license found in the
2036
+ * LICENSE file in the root directory of this source tree.
2037
+ */
2038
+
2039
+ var ReactPropTypesSecret_1;
2040
+ var hasRequiredReactPropTypesSecret;
2041
+
2042
+ function requireReactPropTypesSecret () {
2043
+ if (hasRequiredReactPropTypesSecret) return ReactPropTypesSecret_1;
2044
+ hasRequiredReactPropTypesSecret = 1;
2045
+
2046
+ var ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED';
2047
+
2048
+ ReactPropTypesSecret_1 = ReactPropTypesSecret;
2049
+ return ReactPropTypesSecret_1;
2050
+ }
2051
+
2052
+ var has;
2053
+ var hasRequiredHas;
2054
+
2055
+ function requireHas () {
2056
+ if (hasRequiredHas) return has;
2057
+ hasRequiredHas = 1;
2058
+ has = Function.call.bind(Object.prototype.hasOwnProperty);
2059
+ return has;
2060
+ }
2061
+
2062
+ /**
2063
+ * Copyright (c) 2013-present, Facebook, Inc.
2064
+ *
2065
+ * This source code is licensed under the MIT license found in the
2066
+ * LICENSE file in the root directory of this source tree.
2067
+ */
2068
+
2069
+ var checkPropTypes_1;
2070
+ var hasRequiredCheckPropTypes;
2071
+
2072
+ function requireCheckPropTypes () {
2073
+ if (hasRequiredCheckPropTypes) return checkPropTypes_1;
2074
+ hasRequiredCheckPropTypes = 1;
2075
+
2076
+ var printWarning = function() {};
2077
+
2078
+ if (process.env.NODE_ENV !== 'production') {
2079
+ var ReactPropTypesSecret = requireReactPropTypesSecret();
2080
+ var loggedTypeFailures = {};
2081
+ var has = requireHas();
2082
+
2083
+ printWarning = function(text) {
2084
+ var message = 'Warning: ' + text;
2085
+ if (typeof console !== 'undefined') {
2086
+ console.error(message);
2087
+ }
2088
+ try {
2089
+ // --- Welcome to debugging React ---
2090
+ // This error was thrown as a convenience so that you can use this stack
2091
+ // to find the callsite that caused this warning to fire.
2092
+ throw new Error(message);
2093
+ } catch (x) { /**/ }
2094
+ };
2095
+ }
2096
+
2097
+ /**
2098
+ * Assert that the values match with the type specs.
2099
+ * Error messages are memorized and will only be shown once.
2100
+ *
2101
+ * @param {object} typeSpecs Map of name to a ReactPropType
2102
+ * @param {object} values Runtime values that need to be type-checked
2103
+ * @param {string} location e.g. "prop", "context", "child context"
2104
+ * @param {string} componentName Name of the component for error messages.
2105
+ * @param {?Function} getStack Returns the component stack.
2106
+ * @private
2107
+ */
2108
+ function checkPropTypes(typeSpecs, values, location, componentName, getStack) {
2109
+ if (process.env.NODE_ENV !== 'production') {
2110
+ for (var typeSpecName in typeSpecs) {
2111
+ if (has(typeSpecs, typeSpecName)) {
2112
+ var error;
2113
+ // Prop type validation may throw. In case they do, we don't want to
2114
+ // fail the render phase where it didn't fail before. So we log it.
2115
+ // After these have been cleaned up, we'll let them throw.
2116
+ try {
2117
+ // This is intentionally an invariant that gets caught. It's the same
2118
+ // behavior as without this statement except with a better message.
2119
+ if (typeof typeSpecs[typeSpecName] !== 'function') {
2120
+ var err = Error(
2121
+ (componentName || 'React class') + ': ' + location + ' type `' + typeSpecName + '` is invalid; ' +
2122
+ 'it must be a function, usually from the `prop-types` package, but received `' + typeof typeSpecs[typeSpecName] + '`.' +
2123
+ 'This often happens because of typos such as `PropTypes.function` instead of `PropTypes.func`.'
2124
+ );
2125
+ err.name = 'Invariant Violation';
2126
+ throw err;
2127
+ }
2128
+ error = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, ReactPropTypesSecret);
2129
+ } catch (ex) {
2130
+ error = ex;
2131
+ }
2132
+ if (error && !(error instanceof Error)) {
2133
+ printWarning(
2134
+ (componentName || 'React class') + ': type specification of ' +
2135
+ location + ' `' + typeSpecName + '` is invalid; the type checker ' +
2136
+ 'function must return `null` or an `Error` but returned a ' + typeof error + '. ' +
2137
+ 'You may have forgotten to pass an argument to the type checker ' +
2138
+ 'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' +
2139
+ 'shape all require an argument).'
2140
+ );
2141
+ }
2142
+ if (error instanceof Error && !(error.message in loggedTypeFailures)) {
2143
+ // Only monitor this failure once because there tends to be a lot of the
2144
+ // same error.
2145
+ loggedTypeFailures[error.message] = true;
2146
+
2147
+ var stack = getStack ? getStack() : '';
2148
+
2149
+ printWarning(
2150
+ 'Failed ' + location + ' type: ' + error.message + (stack != null ? stack : '')
2151
+ );
2152
+ }
2153
+ }
2154
+ }
2155
+ }
2156
+ }
2157
+
2158
+ /**
2159
+ * Resets warning cache when testing.
2160
+ *
2161
+ * @private
2162
+ */
2163
+ checkPropTypes.resetWarningCache = function() {
2164
+ if (process.env.NODE_ENV !== 'production') {
2165
+ loggedTypeFailures = {};
2166
+ }
2167
+ };
2168
+
2169
+ checkPropTypes_1 = checkPropTypes;
2170
+ return checkPropTypes_1;
2171
+ }
2172
+
2173
+ /**
2174
+ * Copyright (c) 2013-present, Facebook, Inc.
2175
+ *
2176
+ * This source code is licensed under the MIT license found in the
2177
+ * LICENSE file in the root directory of this source tree.
2178
+ */
2179
+
2180
+ var factoryWithTypeCheckers;
2181
+ var hasRequiredFactoryWithTypeCheckers;
2182
+
2183
+ function requireFactoryWithTypeCheckers () {
2184
+ if (hasRequiredFactoryWithTypeCheckers) return factoryWithTypeCheckers;
2185
+ hasRequiredFactoryWithTypeCheckers = 1;
2186
+
2187
+ var ReactIs = requireReactIs();
2188
+ var assign = requireObjectAssign();
2189
+
2190
+ var ReactPropTypesSecret = requireReactPropTypesSecret();
2191
+ var has = requireHas();
2192
+ var checkPropTypes = requireCheckPropTypes();
2193
+
2194
+ var printWarning = function() {};
2195
+
2196
+ if (process.env.NODE_ENV !== 'production') {
2197
+ printWarning = function(text) {
2198
+ var message = 'Warning: ' + text;
2199
+ if (typeof console !== 'undefined') {
2200
+ console.error(message);
2201
+ }
2202
+ try {
2203
+ // --- Welcome to debugging React ---
2204
+ // This error was thrown as a convenience so that you can use this stack
2205
+ // to find the callsite that caused this warning to fire.
2206
+ throw new Error(message);
2207
+ } catch (x) {}
2208
+ };
2209
+ }
2210
+
2211
+ function emptyFunctionThatReturnsNull() {
2212
+ return null;
2213
+ }
2214
+
2215
+ factoryWithTypeCheckers = function(isValidElement, throwOnDirectAccess) {
2216
+ /* global Symbol */
2217
+ var ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator;
2218
+ var FAUX_ITERATOR_SYMBOL = '@@iterator'; // Before Symbol spec.
2219
+
2220
+ /**
2221
+ * Returns the iterator method function contained on the iterable object.
2222
+ *
2223
+ * Be sure to invoke the function with the iterable as context:
2224
+ *
2225
+ * var iteratorFn = getIteratorFn(myIterable);
2226
+ * if (iteratorFn) {
2227
+ * var iterator = iteratorFn.call(myIterable);
2228
+ * ...
2229
+ * }
2230
+ *
2231
+ * @param {?object} maybeIterable
2232
+ * @return {?function}
2233
+ */
2234
+ function getIteratorFn(maybeIterable) {
2235
+ var iteratorFn = maybeIterable && (ITERATOR_SYMBOL && maybeIterable[ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]);
2236
+ if (typeof iteratorFn === 'function') {
2237
+ return iteratorFn;
2238
+ }
2239
+ }
2240
+
2241
+ /**
2242
+ * Collection of methods that allow declaration and validation of props that are
2243
+ * supplied to React components. Example usage:
2244
+ *
2245
+ * var Props = require('ReactPropTypes');
2246
+ * var MyArticle = React.createClass({
2247
+ * propTypes: {
2248
+ * // An optional string prop named "description".
2249
+ * description: Props.string,
2250
+ *
2251
+ * // A required enum prop named "category".
2252
+ * category: Props.oneOf(['News','Photos']).isRequired,
2253
+ *
2254
+ * // A prop named "dialog" that requires an instance of Dialog.
2255
+ * dialog: Props.instanceOf(Dialog).isRequired
2256
+ * },
2257
+ * render: function() { ... }
2258
+ * });
2259
+ *
2260
+ * A more formal specification of how these methods are used:
2261
+ *
2262
+ * type := array|bool|func|object|number|string|oneOf([...])|instanceOf(...)
2263
+ * decl := ReactPropTypes.{type}(.isRequired)?
2264
+ *
2265
+ * Each and every declaration produces a function with the same signature. This
2266
+ * allows the creation of custom validation functions. For example:
2267
+ *
2268
+ * var MyLink = React.createClass({
2269
+ * propTypes: {
2270
+ * // An optional string or URI prop named "href".
2271
+ * href: function(props, propName, componentName) {
2272
+ * var propValue = props[propName];
2273
+ * if (propValue != null && typeof propValue !== 'string' &&
2274
+ * !(propValue instanceof URI)) {
2275
+ * return new Error(
2276
+ * 'Expected a string or an URI for ' + propName + ' in ' +
2277
+ * componentName
2278
+ * );
2279
+ * }
2280
+ * }
2281
+ * },
2282
+ * render: function() {...}
2283
+ * });
2284
+ *
2285
+ * @internal
2286
+ */
2287
+
2288
+ var ANONYMOUS = '<<anonymous>>';
2289
+
2290
+ // Important!
2291
+ // Keep this list in sync with production version in `./factoryWithThrowingShims.js`.
2292
+ var ReactPropTypes = {
2293
+ array: createPrimitiveTypeChecker('array'),
2294
+ bigint: createPrimitiveTypeChecker('bigint'),
2295
+ bool: createPrimitiveTypeChecker('boolean'),
2296
+ func: createPrimitiveTypeChecker('function'),
2297
+ number: createPrimitiveTypeChecker('number'),
2298
+ object: createPrimitiveTypeChecker('object'),
2299
+ string: createPrimitiveTypeChecker('string'),
2300
+ symbol: createPrimitiveTypeChecker('symbol'),
2301
+
2302
+ any: createAnyTypeChecker(),
2303
+ arrayOf: createArrayOfTypeChecker,
2304
+ element: createElementTypeChecker(),
2305
+ elementType: createElementTypeTypeChecker(),
2306
+ instanceOf: createInstanceTypeChecker,
2307
+ node: createNodeChecker(),
2308
+ objectOf: createObjectOfTypeChecker,
2309
+ oneOf: createEnumTypeChecker,
2310
+ oneOfType: createUnionTypeChecker,
2311
+ shape: createShapeTypeChecker,
2312
+ exact: createStrictShapeTypeChecker,
2313
+ };
2314
+
2315
+ /**
2316
+ * inlined Object.is polyfill to avoid requiring consumers ship their own
2317
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
2318
+ */
2319
+ /*eslint-disable no-self-compare*/
2320
+ function is(x, y) {
2321
+ // SameValue algorithm
2322
+ if (x === y) {
2323
+ // Steps 1-5, 7-10
2324
+ // Steps 6.b-6.e: +0 != -0
2325
+ return x !== 0 || 1 / x === 1 / y;
2326
+ } else {
2327
+ // Step 6.a: NaN == NaN
2328
+ return x !== x && y !== y;
2329
+ }
2330
+ }
2331
+ /*eslint-enable no-self-compare*/
2332
+
2333
+ /**
2334
+ * We use an Error-like object for backward compatibility as people may call
2335
+ * PropTypes directly and inspect their output. However, we don't use real
2336
+ * Errors anymore. We don't inspect their stack anyway, and creating them
2337
+ * is prohibitively expensive if they are created too often, such as what
2338
+ * happens in oneOfType() for any type before the one that matched.
2339
+ */
2340
+ function PropTypeError(message, data) {
2341
+ this.message = message;
2342
+ this.data = data && typeof data === 'object' ? data: {};
2343
+ this.stack = '';
2344
+ }
2345
+ // Make `instanceof Error` still work for returned errors.
2346
+ PropTypeError.prototype = Error.prototype;
2347
+
2348
+ function createChainableTypeChecker(validate) {
2349
+ if (process.env.NODE_ENV !== 'production') {
2350
+ var manualPropTypeCallCache = {};
2351
+ var manualPropTypeWarningCount = 0;
2352
+ }
2353
+ function checkType(isRequired, props, propName, componentName, location, propFullName, secret) {
2354
+ componentName = componentName || ANONYMOUS;
2355
+ propFullName = propFullName || propName;
2356
+
2357
+ if (secret !== ReactPropTypesSecret) {
2358
+ if (throwOnDirectAccess) {
2359
+ // New behavior only for users of `prop-types` package
2360
+ var err = new Error(
2361
+ 'Calling PropTypes validators directly is not supported by the `prop-types` package. ' +
2362
+ 'Use `PropTypes.checkPropTypes()` to call them. ' +
2363
+ 'Read more at http://fb.me/use-check-prop-types'
2364
+ );
2365
+ err.name = 'Invariant Violation';
2366
+ throw err;
2367
+ } else if (process.env.NODE_ENV !== 'production' && typeof console !== 'undefined') {
2368
+ // Old behavior for people using React.PropTypes
2369
+ var cacheKey = componentName + ':' + propName;
2370
+ if (
2371
+ !manualPropTypeCallCache[cacheKey] &&
2372
+ // Avoid spamming the console because they are often not actionable except for lib authors
2373
+ manualPropTypeWarningCount < 3
2374
+ ) {
2375
+ printWarning(
2376
+ 'You are manually calling a React.PropTypes validation ' +
2377
+ 'function for the `' + propFullName + '` prop on `' + componentName + '`. This is deprecated ' +
2378
+ 'and will throw in the standalone `prop-types` package. ' +
2379
+ 'You may be seeing this warning due to a third-party PropTypes ' +
2380
+ 'library. See https://fb.me/react-warning-dont-call-proptypes ' + 'for details.'
2381
+ );
2382
+ manualPropTypeCallCache[cacheKey] = true;
2383
+ manualPropTypeWarningCount++;
2384
+ }
2385
+ }
2386
+ }
2387
+ if (props[propName] == null) {
2388
+ if (isRequired) {
2389
+ if (props[propName] === null) {
2390
+ return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required ' + ('in `' + componentName + '`, but its value is `null`.'));
2391
+ }
2392
+ return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required in ' + ('`' + componentName + '`, but its value is `undefined`.'));
2393
+ }
2394
+ return null;
2395
+ } else {
2396
+ return validate(props, propName, componentName, location, propFullName);
2397
+ }
2398
+ }
2399
+
2400
+ var chainedCheckType = checkType.bind(null, false);
2401
+ chainedCheckType.isRequired = checkType.bind(null, true);
2402
+
2403
+ return chainedCheckType;
2404
+ }
2405
+
2406
+ function createPrimitiveTypeChecker(expectedType) {
2407
+ function validate(props, propName, componentName, location, propFullName, secret) {
2408
+ var propValue = props[propName];
2409
+ var propType = getPropType(propValue);
2410
+ if (propType !== expectedType) {
2411
+ // `propValue` being instance of, say, date/regexp, pass the 'object'
2412
+ // check, but we can offer a more precise error message here rather than
2413
+ // 'of type `object`'.
2414
+ var preciseType = getPreciseType(propValue);
2415
+
2416
+ return new PropTypeError(
2417
+ 'Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + preciseType + '` supplied to `' + componentName + '`, expected ') + ('`' + expectedType + '`.'),
2418
+ {expectedType: expectedType}
2419
+ );
2420
+ }
2421
+ return null;
2422
+ }
2423
+ return createChainableTypeChecker(validate);
2424
+ }
2425
+
2426
+ function createAnyTypeChecker() {
2427
+ return createChainableTypeChecker(emptyFunctionThatReturnsNull);
2428
+ }
2429
+
2430
+ function createArrayOfTypeChecker(typeChecker) {
2431
+ function validate(props, propName, componentName, location, propFullName) {
2432
+ if (typeof typeChecker !== 'function') {
2433
+ return new PropTypeError('Property `' + propFullName + '` of component `' + componentName + '` has invalid PropType notation inside arrayOf.');
2434
+ }
2435
+ var propValue = props[propName];
2436
+ if (!Array.isArray(propValue)) {
2437
+ var propType = getPropType(propValue);
2438
+ return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected an array.'));
2439
+ }
2440
+ for (var i = 0; i < propValue.length; i++) {
2441
+ var error = typeChecker(propValue, i, componentName, location, propFullName + '[' + i + ']', ReactPropTypesSecret);
2442
+ if (error instanceof Error) {
2443
+ return error;
2444
+ }
2445
+ }
2446
+ return null;
2447
+ }
2448
+ return createChainableTypeChecker(validate);
2449
+ }
2450
+
2451
+ function createElementTypeChecker() {
2452
+ function validate(props, propName, componentName, location, propFullName) {
2453
+ var propValue = props[propName];
2454
+ if (!isValidElement(propValue)) {
2455
+ var propType = getPropType(propValue);
2456
+ return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected a single ReactElement.'));
2457
+ }
2458
+ return null;
2459
+ }
2460
+ return createChainableTypeChecker(validate);
2461
+ }
2462
+
2463
+ function createElementTypeTypeChecker() {
2464
+ function validate(props, propName, componentName, location, propFullName) {
2465
+ var propValue = props[propName];
2466
+ if (!ReactIs.isValidElementType(propValue)) {
2467
+ var propType = getPropType(propValue);
2468
+ return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected a single ReactElement type.'));
2469
+ }
2470
+ return null;
2471
+ }
2472
+ return createChainableTypeChecker(validate);
2473
+ }
2474
+
2475
+ function createInstanceTypeChecker(expectedClass) {
2476
+ function validate(props, propName, componentName, location, propFullName) {
2477
+ if (!(props[propName] instanceof expectedClass)) {
2478
+ var expectedClassName = expectedClass.name || ANONYMOUS;
2479
+ var actualClassName = getClassName(props[propName]);
2480
+ return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + actualClassName + '` supplied to `' + componentName + '`, expected ') + ('instance of `' + expectedClassName + '`.'));
2481
+ }
2482
+ return null;
2483
+ }
2484
+ return createChainableTypeChecker(validate);
2485
+ }
2486
+
2487
+ function createEnumTypeChecker(expectedValues) {
2488
+ if (!Array.isArray(expectedValues)) {
2489
+ if (process.env.NODE_ENV !== 'production') {
2490
+ if (arguments.length > 1) {
2491
+ printWarning(
2492
+ 'Invalid arguments supplied to oneOf, expected an array, got ' + arguments.length + ' arguments. ' +
2493
+ 'A common mistake is to write oneOf(x, y, z) instead of oneOf([x, y, z]).'
2494
+ );
2495
+ } else {
2496
+ printWarning('Invalid argument supplied to oneOf, expected an array.');
2497
+ }
2498
+ }
2499
+ return emptyFunctionThatReturnsNull;
2500
+ }
2501
+
2502
+ function validate(props, propName, componentName, location, propFullName) {
2503
+ var propValue = props[propName];
2504
+ for (var i = 0; i < expectedValues.length; i++) {
2505
+ if (is(propValue, expectedValues[i])) {
2506
+ return null;
2507
+ }
2508
+ }
2509
+
2510
+ var valuesString = JSON.stringify(expectedValues, function replacer(key, value) {
2511
+ var type = getPreciseType(value);
2512
+ if (type === 'symbol') {
2513
+ return String(value);
2514
+ }
2515
+ return value;
2516
+ });
2517
+ return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of value `' + String(propValue) + '` ' + ('supplied to `' + componentName + '`, expected one of ' + valuesString + '.'));
2518
+ }
2519
+ return createChainableTypeChecker(validate);
2520
+ }
2521
+
2522
+ function createObjectOfTypeChecker(typeChecker) {
2523
+ function validate(props, propName, componentName, location, propFullName) {
2524
+ if (typeof typeChecker !== 'function') {
2525
+ return new PropTypeError('Property `' + propFullName + '` of component `' + componentName + '` has invalid PropType notation inside objectOf.');
2526
+ }
2527
+ var propValue = props[propName];
2528
+ var propType = getPropType(propValue);
2529
+ if (propType !== 'object') {
2530
+ return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected an object.'));
2531
+ }
2532
+ for (var key in propValue) {
2533
+ if (has(propValue, key)) {
2534
+ var error = typeChecker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret);
2535
+ if (error instanceof Error) {
2536
+ return error;
2537
+ }
2538
+ }
2539
+ }
2540
+ return null;
2541
+ }
2542
+ return createChainableTypeChecker(validate);
2543
+ }
2544
+
2545
+ function createUnionTypeChecker(arrayOfTypeCheckers) {
2546
+ if (!Array.isArray(arrayOfTypeCheckers)) {
2547
+ process.env.NODE_ENV !== 'production' ? printWarning('Invalid argument supplied to oneOfType, expected an instance of array.') : void 0;
2548
+ return emptyFunctionThatReturnsNull;
2549
+ }
2550
+
2551
+ for (var i = 0; i < arrayOfTypeCheckers.length; i++) {
2552
+ var checker = arrayOfTypeCheckers[i];
2553
+ if (typeof checker !== 'function') {
2554
+ printWarning(
2555
+ 'Invalid argument supplied to oneOfType. Expected an array of check functions, but ' +
2556
+ 'received ' + getPostfixForTypeWarning(checker) + ' at index ' + i + '.'
2557
+ );
2558
+ return emptyFunctionThatReturnsNull;
2559
+ }
2560
+ }
2561
+
2562
+ function validate(props, propName, componentName, location, propFullName) {
2563
+ var expectedTypes = [];
2564
+ for (var i = 0; i < arrayOfTypeCheckers.length; i++) {
2565
+ var checker = arrayOfTypeCheckers[i];
2566
+ var checkerResult = checker(props, propName, componentName, location, propFullName, ReactPropTypesSecret);
2567
+ if (checkerResult == null) {
2568
+ return null;
2569
+ }
2570
+ if (checkerResult.data && has(checkerResult.data, 'expectedType')) {
2571
+ expectedTypes.push(checkerResult.data.expectedType);
2572
+ }
2573
+ }
2574
+ var expectedTypesMessage = (expectedTypes.length > 0) ? ', expected one of type [' + expectedTypes.join(', ') + ']': '';
2575
+ return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`' + expectedTypesMessage + '.'));
2576
+ }
2577
+ return createChainableTypeChecker(validate);
2578
+ }
2579
+
2580
+ function createNodeChecker() {
2581
+ function validate(props, propName, componentName, location, propFullName) {
2582
+ if (!isNode(props[propName])) {
2583
+ return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`, expected a ReactNode.'));
2584
+ }
2585
+ return null;
2586
+ }
2587
+ return createChainableTypeChecker(validate);
2588
+ }
2589
+
2590
+ function invalidValidatorError(componentName, location, propFullName, key, type) {
2591
+ return new PropTypeError(
2592
+ (componentName || 'React class') + ': ' + location + ' type `' + propFullName + '.' + key + '` is invalid; ' +
2593
+ 'it must be a function, usually from the `prop-types` package, but received `' + type + '`.'
2594
+ );
2595
+ }
2596
+
2597
+ function createShapeTypeChecker(shapeTypes) {
2598
+ function validate(props, propName, componentName, location, propFullName) {
2599
+ var propValue = props[propName];
2600
+ var propType = getPropType(propValue);
2601
+ if (propType !== 'object') {
2602
+ return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type `' + propType + '` ' + ('supplied to `' + componentName + '`, expected `object`.'));
2603
+ }
2604
+ for (var key in shapeTypes) {
2605
+ var checker = shapeTypes[key];
2606
+ if (typeof checker !== 'function') {
2607
+ return invalidValidatorError(componentName, location, propFullName, key, getPreciseType(checker));
2608
+ }
2609
+ var error = checker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret);
2610
+ if (error) {
2611
+ return error;
2612
+ }
2613
+ }
2614
+ return null;
2615
+ }
2616
+ return createChainableTypeChecker(validate);
2617
+ }
2618
+
2619
+ function createStrictShapeTypeChecker(shapeTypes) {
2620
+ function validate(props, propName, componentName, location, propFullName) {
2621
+ var propValue = props[propName];
2622
+ var propType = getPropType(propValue);
2623
+ if (propType !== 'object') {
2624
+ return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type `' + propType + '` ' + ('supplied to `' + componentName + '`, expected `object`.'));
2625
+ }
2626
+ // We need to check all keys in case some are required but missing from props.
2627
+ var allKeys = assign({}, props[propName], shapeTypes);
2628
+ for (var key in allKeys) {
2629
+ var checker = shapeTypes[key];
2630
+ if (has(shapeTypes, key) && typeof checker !== 'function') {
2631
+ return invalidValidatorError(componentName, location, propFullName, key, getPreciseType(checker));
2632
+ }
2633
+ if (!checker) {
2634
+ return new PropTypeError(
2635
+ 'Invalid ' + location + ' `' + propFullName + '` key `' + key + '` supplied to `' + componentName + '`.' +
2636
+ '\nBad object: ' + JSON.stringify(props[propName], null, ' ') +
2637
+ '\nValid keys: ' + JSON.stringify(Object.keys(shapeTypes), null, ' ')
2638
+ );
2639
+ }
2640
+ var error = checker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret);
2641
+ if (error) {
2642
+ return error;
2643
+ }
2644
+ }
2645
+ return null;
2646
+ }
2647
+
2648
+ return createChainableTypeChecker(validate);
2649
+ }
2650
+
2651
+ function isNode(propValue) {
2652
+ switch (typeof propValue) {
2653
+ case 'number':
2654
+ case 'string':
2655
+ case 'undefined':
2656
+ return true;
2657
+ case 'boolean':
2658
+ return !propValue;
2659
+ case 'object':
2660
+ if (Array.isArray(propValue)) {
2661
+ return propValue.every(isNode);
2662
+ }
2663
+ if (propValue === null || isValidElement(propValue)) {
2664
+ return true;
2665
+ }
2666
+
2667
+ var iteratorFn = getIteratorFn(propValue);
2668
+ if (iteratorFn) {
2669
+ var iterator = iteratorFn.call(propValue);
2670
+ var step;
2671
+ if (iteratorFn !== propValue.entries) {
2672
+ while (!(step = iterator.next()).done) {
2673
+ if (!isNode(step.value)) {
2674
+ return false;
2675
+ }
2676
+ }
2677
+ } else {
2678
+ // Iterator will provide entry [k,v] tuples rather than values.
2679
+ while (!(step = iterator.next()).done) {
2680
+ var entry = step.value;
2681
+ if (entry) {
2682
+ if (!isNode(entry[1])) {
2683
+ return false;
2684
+ }
2685
+ }
2686
+ }
2687
+ }
2688
+ } else {
2689
+ return false;
2690
+ }
2691
+
2692
+ return true;
2693
+ default:
2694
+ return false;
2695
+ }
2696
+ }
2697
+
2698
+ function isSymbol(propType, propValue) {
2699
+ // Native Symbol.
2700
+ if (propType === 'symbol') {
2701
+ return true;
2702
+ }
2703
+
2704
+ // falsy value can't be a Symbol
2705
+ if (!propValue) {
2706
+ return false;
2707
+ }
2708
+
2709
+ // 19.4.3.5 Symbol.prototype[@@toStringTag] === 'Symbol'
2710
+ if (propValue['@@toStringTag'] === 'Symbol') {
2711
+ return true;
2712
+ }
2713
+
2714
+ // Fallback for non-spec compliant Symbols which are polyfilled.
2715
+ if (typeof Symbol === 'function' && propValue instanceof Symbol) {
2716
+ return true;
2717
+ }
2718
+
2719
+ return false;
2720
+ }
2721
+
2722
+ // Equivalent of `typeof` but with special handling for array and regexp.
2723
+ function getPropType(propValue) {
2724
+ var propType = typeof propValue;
2725
+ if (Array.isArray(propValue)) {
2726
+ return 'array';
2727
+ }
2728
+ if (propValue instanceof RegExp) {
2729
+ // Old webkits (at least until Android 4.0) return 'function' rather than
2730
+ // 'object' for typeof a RegExp. We'll normalize this here so that /bla/
2731
+ // passes PropTypes.object.
2732
+ return 'object';
2733
+ }
2734
+ if (isSymbol(propType, propValue)) {
2735
+ return 'symbol';
2736
+ }
2737
+ return propType;
2738
+ }
2739
+
2740
+ // This handles more types than `getPropType`. Only used for error messages.
2741
+ // See `createPrimitiveTypeChecker`.
2742
+ function getPreciseType(propValue) {
2743
+ if (typeof propValue === 'undefined' || propValue === null) {
2744
+ return '' + propValue;
2745
+ }
2746
+ var propType = getPropType(propValue);
2747
+ if (propType === 'object') {
2748
+ if (propValue instanceof Date) {
2749
+ return 'date';
2750
+ } else if (propValue instanceof RegExp) {
2751
+ return 'regexp';
2752
+ }
2753
+ }
2754
+ return propType;
2755
+ }
2756
+
2757
+ // Returns a string that is postfixed to a warning about an invalid type.
2758
+ // For example, "undefined" or "of type array"
2759
+ function getPostfixForTypeWarning(value) {
2760
+ var type = getPreciseType(value);
2761
+ switch (type) {
2762
+ case 'array':
2763
+ case 'object':
2764
+ return 'an ' + type;
2765
+ case 'boolean':
2766
+ case 'date':
2767
+ case 'regexp':
2768
+ return 'a ' + type;
2769
+ default:
2770
+ return type;
2771
+ }
2772
+ }
2773
+
2774
+ // Returns class name of the object, if any.
2775
+ function getClassName(propValue) {
2776
+ if (!propValue.constructor || !propValue.constructor.name) {
2777
+ return ANONYMOUS;
2778
+ }
2779
+ return propValue.constructor.name;
2780
+ }
2781
+
2782
+ ReactPropTypes.checkPropTypes = checkPropTypes;
2783
+ ReactPropTypes.resetWarningCache = checkPropTypes.resetWarningCache;
2784
+ ReactPropTypes.PropTypes = ReactPropTypes;
2785
+
2786
+ return ReactPropTypes;
2787
+ };
2788
+ return factoryWithTypeCheckers;
2789
+ }
2790
+
2791
+ /**
2792
+ * Copyright (c) 2013-present, Facebook, Inc.
2793
+ *
2794
+ * This source code is licensed under the MIT license found in the
2795
+ * LICENSE file in the root directory of this source tree.
2796
+ */
2797
+
2798
+ var factoryWithThrowingShims;
2799
+ var hasRequiredFactoryWithThrowingShims;
2800
+
2801
+ function requireFactoryWithThrowingShims () {
2802
+ if (hasRequiredFactoryWithThrowingShims) return factoryWithThrowingShims;
2803
+ hasRequiredFactoryWithThrowingShims = 1;
2804
+
2805
+ var ReactPropTypesSecret = requireReactPropTypesSecret();
2806
+
2807
+ function emptyFunction() {}
2808
+ function emptyFunctionWithReset() {}
2809
+ emptyFunctionWithReset.resetWarningCache = emptyFunction;
2810
+
2811
+ factoryWithThrowingShims = function() {
2812
+ function shim(props, propName, componentName, location, propFullName, secret) {
2813
+ if (secret === ReactPropTypesSecret) {
2814
+ // It is still safe when called from React.
2815
+ return;
2816
+ }
2817
+ var err = new Error(
2818
+ 'Calling PropTypes validators directly is not supported by the `prop-types` package. ' +
2819
+ 'Use PropTypes.checkPropTypes() to call them. ' +
2820
+ 'Read more at http://fb.me/use-check-prop-types'
2821
+ );
2822
+ err.name = 'Invariant Violation';
2823
+ throw err;
2824
+ } shim.isRequired = shim;
2825
+ function getShim() {
2826
+ return shim;
2827
+ } // Important!
2828
+ // Keep this list in sync with production version in `./factoryWithTypeCheckers.js`.
2829
+ var ReactPropTypes = {
2830
+ array: shim,
2831
+ bigint: shim,
2832
+ bool: shim,
2833
+ func: shim,
2834
+ number: shim,
2835
+ object: shim,
2836
+ string: shim,
2837
+ symbol: shim,
2838
+
2839
+ any: shim,
2840
+ arrayOf: getShim,
2841
+ element: shim,
2842
+ elementType: shim,
2843
+ instanceOf: getShim,
2844
+ node: shim,
2845
+ objectOf: getShim,
2846
+ oneOf: getShim,
2847
+ oneOfType: getShim,
2848
+ shape: getShim,
2849
+ exact: getShim,
2850
+
2851
+ checkPropTypes: emptyFunctionWithReset,
2852
+ resetWarningCache: emptyFunction
2853
+ };
2854
+
2855
+ ReactPropTypes.PropTypes = ReactPropTypes;
2856
+
2857
+ return ReactPropTypes;
2858
+ };
2859
+ return factoryWithThrowingShims;
2860
+ }
2861
+
2862
+ /**
2863
+ * Copyright (c) 2013-present, Facebook, Inc.
2864
+ *
2865
+ * This source code is licensed under the MIT license found in the
2866
+ * LICENSE file in the root directory of this source tree.
2867
+ */
2868
+
2869
+ if (process.env.NODE_ENV !== 'production') {
2870
+ var ReactIs = requireReactIs();
2871
+
2872
+ // By explicitly using `prop-types` you are opting into new development behavior.
2873
+ // http://fb.me/prop-types-in-prod
2874
+ var throwOnDirectAccess = true;
2875
+ propTypes.exports = requireFactoryWithTypeCheckers()(ReactIs.isElement, throwOnDirectAccess);
2876
+ } else {
2877
+ // By explicitly using `prop-types` you are opting into new production behavior.
2878
+ // http://fb.me/prop-types-in-prod
2879
+ propTypes.exports = requireFactoryWithThrowingShims()();
2880
+ }
2881
+
2882
+ // Define the shape of the linter context object that is passed through the
2883
+ var linterContextProps = propTypes.exports.shape({
2884
+ contentType: propTypes.exports.string,
2885
+ highlightLint: propTypes.exports.bool,
2886
+ paths: propTypes.exports.arrayOf(propTypes.exports.string),
2887
+ stack: propTypes.exports.arrayOf(propTypes.exports.string)
2888
+ });
2889
+ var linterContextDefault = {
2890
+ contentType: "",
2891
+ highlightLint: false,
2892
+ paths: [],
2893
+ stack: []
2894
+ };
2895
+
2896
+ var allLintRules = AllRules.filter(r => r.severity < Rule.Severity.BULK_WARNING);
2897
+ // Run the Gorgon linter over the specified markdown parse tree,
2898
+ // with the specified context object, and
2899
+ // return a (possibly empty) array of lint warning objects. If the
2900
+ // highlight argument is true, this function also modifies the parse
2901
+ // tree to add "lint" nodes that can be visually rendered,
2902
+ // highlighting the problems for the user. The optional rules argument
2903
+ // is an array of Rule objects specifying which lint rules should be
2904
+ // applied to this parse tree. When omitted, a default set of rules is used.
2905
+ //
2906
+ // The context object may have additional properties that some lint
2907
+ // rules require:
2908
+ //
2909
+ // context.content is the source content string that was parsed to create
2910
+ // the parse tree.
2911
+ //
2912
+ // context.widgets is the widgets object associated
2913
+ // with the content string
2914
+ //
2915
+ // TODO: to make this even more general, allow the first argument to be
2916
+ // a string and run the parser over it in that case? (but ignore highlight
2917
+ // in that case). This would allow the one function to be used for both
2918
+ // online linting and batch linting.
2919
+ //
2920
+
2921
+ function runLinter(tree, context, highlight) {
2922
+ var rules = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : allLintRules;
2923
+ var warnings = [];
2924
+ var tt = new TreeTransformer(tree); // The markdown parser often outputs adjacent text nodes. We
2925
+ // coalesce them before linting for efficiency and accuracy.
2926
+
2927
+ tt.traverse((node, state, content) => {
2928
+ if (TreeTransformer.isTextNode(node)) {
2929
+ var next = state.nextSibling();
2930
+
2931
+ while (TreeTransformer.isTextNode(next)) {
2932
+ // $FlowFixMe[prop-missing]
2933
+ // $FlowFixMe[incompatible-use]
2934
+ node.content += next.content;
2935
+ state.removeNextSibling();
2936
+ next = state.nextSibling();
2937
+ }
2938
+ }
2939
+ }); // HTML tables are complicated, and the CSS we use in
2940
+ // ../components/lint.jsx to display lint does not work to
2941
+ // correctly position the lint indicators in the margin when the
2942
+ // lint is inside a table. So as a workaround we keep track of all
2943
+ // the lint that appears within a table and move it up to the
2944
+ // table element itself.
2945
+ //
2946
+ // It is not ideal to have to do this here,
2947
+ // but it is cleaner here than fixing up the lint during rendering
2948
+ // in perseus-markdown.jsx. If our lint display was simpler and
2949
+ // did not require indicators in the margin, this wouldn't be a
2950
+ // problem. Or, if we modified the lint display stuff so that
2951
+ // indicator positioning and tooltip display were both handled
2952
+ // with JavaScript (instead of pure CSS), then we could avoid this
2953
+ // issue too. But using JavaScript has its own downsides: there is
2954
+ // risk that the linter JavaScript would interfere with
2955
+ // widget-related Javascript.
2956
+
2957
+ var tableWarnings = [];
2958
+ var insideTable = false; // Traverse through the nodes of the parse tree. At each node, loop
2959
+ // through the array of lint rules and check whether there is a
2960
+ // lint violation at that node.
2961
+
2962
+ tt.traverse((node, state, content) => {
2963
+ var nodeWarnings = []; // If our rule is only designed to be tested against a particular
2964
+ // content type and we're not in that content type, we don't need to
2965
+ // consider that rule.
2966
+
2967
+ var applicableRules = rules.filter(r => r.applies(context)); // Generate a stack so we can identify our position in the tree in
2968
+ // lint rules
2969
+
2970
+ var stack = [...context.stack];
2971
+ stack.push(node.type);
2972
+
2973
+ var nodeContext = _objectSpread2(_objectSpread2({}, context), {}, {
2974
+ stack: stack.join(".")
2975
+ });
2976
+
2977
+ applicableRules.forEach(rule => {
2978
+ var warning = rule.check(node, state, content, nodeContext);
2979
+
2980
+ if (warning) {
2981
+ // The start and end locations are relative to this
2982
+ // particular node, and so are not generally very useful.
2983
+ // TODO: When the markdown parser saves the node
2984
+ // locations in the source string then we can add
2985
+ // these numbers to that one and get and absolute
2986
+ // character range that will be useful
2987
+ if (warning.start || warning.end) {
2988
+ warning.target = content.substring(warning.start, warning.end);
2989
+ } // Add the warning to the list of all lint we've found
2990
+
2991
+
2992
+ warnings.push(warning); // If we're going to be highlighting lint, then we also
2993
+ // need to keep track of warnings specific to this node.
2994
+
2995
+ if (highlight) {
2996
+ nodeWarnings.push(warning);
2997
+ }
2998
+ }
2999
+ }); // If we're not highlighting lint in the tree, then we're done
3000
+ // traversing this node.
3001
+
3002
+ if (!highlight) {
3003
+ return;
3004
+ } // If the node we are currently at is a table, and there was lint
3005
+ // inside the table, then we want to add that lint here
3006
+
3007
+
3008
+ if (node.type === "table") {
3009
+ if (tableWarnings.length) {
3010
+ nodeWarnings.push(...tableWarnings);
3011
+ } // We're not in a table anymore, and don't have to remember
3012
+ // the warnings for the table
3013
+
3014
+
3015
+ insideTable = false;
3016
+ tableWarnings = [];
3017
+ } else if (!insideTable) {
3018
+ // Otherwise, if we are not already inside a table, check
3019
+ // to see if we've entered one. Because this is a post-order
3020
+ // traversal we'll see the table contents before the table itself.
3021
+ // Note that once we're inside the table, we don't have to
3022
+ // do this check each time... We can just wait until we ascend
3023
+ // up to the table, then we'll know we're out of it.
3024
+ insideTable = state.ancestors().some(n => n.type === "table");
3025
+ } // If we are inside a table and there were any warnings on
3026
+ // this node, then we need to save the warnings for display
3027
+ // on the table itself
3028
+
3029
+
3030
+ if (insideTable && nodeWarnings.length) {
3031
+ tableWarnings.push(...nodeWarnings);
3032
+ } // If there were any warnings on this node, and if we're highlighting
3033
+ // lint, then reparent the node so we can highlight it. Note that
3034
+ // a single node can have multiple warnings. If this happends we
3035
+ // concatenate the warnings and newline separate them. (The lint.jsx
3036
+ // component that displays the warnings may want to convert the
3037
+ // newlines into <br> tags.) We also provide a lint rule name
3038
+ // so that lint.jsx can link to a document that provides more details
3039
+ // on that particular lint rule. If there is more than one warning
3040
+ // we only link to the first rule, however.
3041
+ //
3042
+ // Note that even if we're inside a table, we still reparent the
3043
+ // linty node so that it can be highlighted. We just make a note
3044
+ // of whether this lint is inside a table or not.
3045
+
3046
+
3047
+ if (nodeWarnings.length) {
3048
+ nodeWarnings.sort((a, b) => {
3049
+ return a.severity - b.severity;
3050
+ });
3051
+
3052
+ if (node.type !== "text" || nodeWarnings.length > 1) {
3053
+ // If the linty node is not a text node, or if there is more
3054
+ // than one warning on a text node, then reparent the entire
3055
+ // node under a new lint node and put the warnings there.
3056
+ state.replace({
3057
+ type: "lint",
3058
+ content: node,
3059
+ message: nodeWarnings.map(w => w.message).join("\n\n"),
3060
+ ruleName: nodeWarnings[0].rule,
3061
+ blockHighlight: nodeContext.blockHighlight,
3062
+ insideTable: insideTable,
3063
+ severity: nodeWarnings[0].severity
3064
+ });
3065
+ } else {
3066
+ //
3067
+ // Otherwise, it is a single warning on a text node, and we
3068
+ // only want to highlight the actual linty part of that string
3069
+ // of text. So we want to replace the text node with (in the
3070
+ // general case) three nodes:
3071
+ //
3072
+ // 1) A new text node that holds the non-linty prefix
3073
+ //
3074
+ // 2) A lint node that is the parent of a new text node
3075
+ // that holds the linty part
3076
+ //
3077
+ // 3) A new text node that holds the non-linty suffix
3078
+ //
3079
+ // If the lint begins and/or ends at the boundaries of the
3080
+ // original text node, then nodes 1 and/or 3 won't exist, of
3081
+ // course.
3082
+ //
3083
+ // Note that we could generalize this to work with multple
3084
+ // warnings on a text node as long as the warnings are
3085
+ // non-overlapping. Hopefully, though, multiple warnings in a
3086
+ // single text node will be rare in practice. Also, we don't
3087
+ // have a good way to display multiple lint indicators on a
3088
+ // single line, so keeping them combined in that case might
3089
+ // be the best thing, anyway.
3090
+ //
3091
+ // $FlowFixMe[prop-missing]
3092
+ var _content = node.content; // Text nodes have content
3093
+
3094
+ var warning = nodeWarnings[0]; // There is only one warning.
3095
+ // These are the lint boundaries within the content
3096
+
3097
+ var start = warning.start || 0;
3098
+ var end = warning.end || _content.length;
3099
+
3100
+ var prefix = _content.substring(0, start);
3101
+
3102
+ var lint = _content.substring(start, end);
3103
+
3104
+ var suffix = _content.substring(end);
3105
+
3106
+ var replacements = []; // What we'll replace the node with
3107
+ // The prefix text node, if there is one
3108
+
3109
+ if (prefix) {
3110
+ replacements.push({
3111
+ type: "text",
3112
+ content: prefix
3113
+ });
3114
+ } // The lint node wrapped around the linty text
3115
+
3116
+
3117
+ replacements.push({
3118
+ type: "lint",
3119
+ content: {
3120
+ type: "text",
3121
+ content: lint
3122
+ },
3123
+ message: warning.message,
3124
+ ruleName: warning.rule,
3125
+ insideTable: insideTable,
3126
+ severity: warning.severity
3127
+ }); // The suffix node, if there is one
3128
+
3129
+ if (suffix) {
3130
+ replacements.push({
3131
+ type: "text",
3132
+ content: suffix
3133
+ });
3134
+ } // Now replace the lint text node with the one to three
3135
+ // nodes in the replacement array
3136
+
3137
+
3138
+ state.replace(...replacements);
3139
+ }
3140
+ }
3141
+ });
3142
+ return warnings;
3143
+ }
3144
+ function pushContextStack(context, name) {
3145
+ var stack = context.stack || [];
3146
+ return _objectSpread2(_objectSpread2({}, context), {}, {
3147
+ stack: stack.concat(name)
3148
+ });
3149
+ }
3150
+
3151
+ export { Rule, linterContextDefault, linterContextProps, pushContextStack, allLintRules as rules, runLinter };
3152
+ //# sourceMappingURL=index.js.map