@khanacademy/perseus-linter 0.2.4 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/.eslintrc.js +1 -0
  2. package/CHANGELOG.md +18 -0
  3. package/dist/es/index.js +277 -407
  4. package/dist/es/index.js.map +1 -1
  5. package/dist/index.d.ts +7 -2
  6. package/dist/index.js +281 -398
  7. package/dist/index.js.flow +18 -2
  8. package/dist/index.js.map +1 -1
  9. package/dist/proptypes.d.ts +9 -0
  10. package/dist/proptypes.js.flow +17 -0
  11. package/dist/rule.d.ts +170 -0
  12. package/dist/rule.js.flow +86 -0
  13. package/dist/rules/absolute-url.d.ts +3 -0
  14. package/dist/rules/absolute-url.js.flow +9 -0
  15. package/dist/rules/all-rules.d.ts +2 -0
  16. package/dist/rules/all-rules.js.flow +9 -0
  17. package/dist/rules/blockquoted-math.d.ts +3 -0
  18. package/dist/rules/blockquoted-math.js.flow +9 -0
  19. package/dist/rules/blockquoted-widget.d.ts +3 -0
  20. package/dist/rules/blockquoted-widget.js.flow +9 -0
  21. package/dist/rules/double-spacing-after-terminal.d.ts +3 -0
  22. package/dist/rules/double-spacing-after-terminal.js.flow +9 -0
  23. package/dist/rules/extra-content-spacing.d.ts +3 -0
  24. package/dist/rules/extra-content-spacing.js.flow +9 -0
  25. package/dist/rules/heading-level-1.d.ts +3 -0
  26. package/dist/rules/heading-level-1.js.flow +9 -0
  27. package/dist/rules/heading-level-skip.d.ts +3 -0
  28. package/dist/rules/heading-level-skip.js.flow +9 -0
  29. package/dist/rules/heading-sentence-case.d.ts +3 -0
  30. package/dist/rules/heading-sentence-case.js.flow +9 -0
  31. package/dist/rules/heading-title-case.d.ts +3 -0
  32. package/dist/rules/heading-title-case.js.flow +9 -0
  33. package/dist/rules/image-alt-text.d.ts +3 -0
  34. package/dist/rules/image-alt-text.js.flow +9 -0
  35. package/dist/rules/image-in-table.d.ts +3 -0
  36. package/dist/rules/image-in-table.js.flow +9 -0
  37. package/dist/rules/image-spaces-around-urls.d.ts +3 -0
  38. package/dist/rules/image-spaces-around-urls.js.flow +9 -0
  39. package/dist/rules/image-widget.d.ts +3 -0
  40. package/dist/rules/image-widget.js.flow +9 -0
  41. package/dist/rules/link-click-here.d.ts +3 -0
  42. package/dist/rules/link-click-here.js.flow +9 -0
  43. package/dist/rules/lint-utils.d.ts +2 -0
  44. package/dist/rules/lint-utils.js.flow +8 -0
  45. package/dist/rules/long-paragraph.d.ts +3 -0
  46. package/dist/rules/long-paragraph.js.flow +9 -0
  47. package/dist/rules/math-adjacent.d.ts +3 -0
  48. package/dist/rules/math-adjacent.js.flow +9 -0
  49. package/dist/rules/math-align-extra-break.d.ts +3 -0
  50. package/dist/rules/math-align-extra-break.js.flow +9 -0
  51. package/dist/rules/math-align-linebreaks.d.ts +3 -0
  52. package/dist/rules/math-align-linebreaks.js.flow +9 -0
  53. package/dist/rules/math-empty.d.ts +3 -0
  54. package/dist/rules/math-empty.js.flow +9 -0
  55. package/dist/rules/math-font-size.d.ts +3 -0
  56. package/dist/rules/math-font-size.js.flow +9 -0
  57. package/dist/rules/math-frac.d.ts +3 -0
  58. package/dist/rules/math-frac.js.flow +9 -0
  59. package/dist/rules/math-nested.d.ts +3 -0
  60. package/dist/rules/math-nested.js.flow +9 -0
  61. package/dist/rules/math-starts-with-space.d.ts +3 -0
  62. package/dist/rules/math-starts-with-space.js.flow +9 -0
  63. package/dist/rules/math-text-empty.d.ts +3 -0
  64. package/dist/rules/math-text-empty.js.flow +9 -0
  65. package/dist/rules/math-without-dollars.d.ts +3 -0
  66. package/dist/rules/math-without-dollars.js.flow +9 -0
  67. package/dist/rules/nested-lists.d.ts +3 -0
  68. package/dist/rules/nested-lists.js.flow +9 -0
  69. package/dist/rules/profanity.d.ts +3 -0
  70. package/dist/rules/profanity.js.flow +9 -0
  71. package/dist/rules/table-missing-cells.d.ts +3 -0
  72. package/dist/rules/table-missing-cells.js.flow +9 -0
  73. package/dist/rules/unbalanced-code-delimiters.d.ts +3 -0
  74. package/dist/rules/unbalanced-code-delimiters.js.flow +9 -0
  75. package/dist/rules/unescaped-dollar.d.ts +3 -0
  76. package/dist/rules/unescaped-dollar.js.flow +9 -0
  77. package/dist/rules/widget-in-table.d.ts +3 -0
  78. package/dist/rules/widget-in-table.js.flow +9 -0
  79. package/dist/selector.d.ts +108 -0
  80. package/dist/selector.js.flow +31 -0
  81. package/dist/tree-transformer.d.ts +205 -0
  82. package/dist/tree-transformer.js.flow +253 -0
  83. package/dist/types.d.ts +6 -0
  84. package/dist/types.js.flow +12 -0
  85. package/package.json +4 -4
  86. package/src/__tests__/{matcher_test.js → matcher.test.ts} +60 -60
  87. package/src/__tests__/{rule_test.js → rule.test.ts} +13 -5
  88. package/src/__tests__/{rules_test.js → rules.test.ts} +99 -39
  89. package/src/__tests__/{selector-parser_test.js → selector-parser.test.ts} +1 -2
  90. package/src/__tests__/{tree-transformer_test.js → tree-transformer.test.ts} +39 -41
  91. package/src/{index.js → index.ts} +21 -23
  92. package/src/{proptypes.js → proptypes.ts} +4 -14
  93. package/src/{rule.js → rule.ts} +45 -38
  94. package/src/rules/{absolute-url.js → absolute-url.ts} +4 -5
  95. package/src/rules/all-rules.ts +71 -0
  96. package/src/rules/{blockquoted-math.js → blockquoted-math.ts} +3 -4
  97. package/src/rules/{blockquoted-widget.js → blockquoted-widget.ts} +3 -4
  98. package/src/rules/{double-spacing-after-terminal.js → double-spacing-after-terminal.ts} +3 -4
  99. package/src/rules/{extra-content-spacing.js → extra-content-spacing.ts} +3 -4
  100. package/src/rules/{heading-level-1.js → heading-level-1.ts} +3 -4
  101. package/src/rules/{heading-level-skip.js → heading-level-skip.ts} +3 -4
  102. package/src/rules/{heading-sentence-case.js → heading-sentence-case.ts} +3 -4
  103. package/src/rules/{heading-title-case.js → heading-title-case.ts} +11 -6
  104. package/src/rules/{image-alt-text.js → image-alt-text.ts} +3 -4
  105. package/src/rules/{image-in-table.js → image-in-table.ts} +3 -4
  106. package/src/rules/{image-spaces-around-urls.js → image-spaces-around-urls.ts} +3 -4
  107. package/src/rules/{image-widget.js → image-widget.ts} +3 -4
  108. package/src/rules/{link-click-here.js → link-click-here.ts} +3 -4
  109. package/src/rules/{lint-utils.js → lint-utils.ts} +1 -2
  110. package/src/rules/{long-paragraph.js → long-paragraph.ts} +3 -4
  111. package/src/rules/{math-adjacent.js → math-adjacent.ts} +3 -4
  112. package/src/rules/{math-align-extra-break.js → math-align-extra-break.ts} +3 -4
  113. package/src/rules/{math-align-linebreaks.js → math-align-linebreaks.ts} +3 -4
  114. package/src/rules/{math-empty.js → math-empty.ts} +3 -4
  115. package/src/rules/{math-font-size.js → math-font-size.ts} +3 -4
  116. package/src/rules/{math-frac.js → math-frac.ts} +3 -4
  117. package/src/rules/{math-nested.js → math-nested.ts} +3 -4
  118. package/src/rules/{math-starts-with-space.js → math-starts-with-space.ts} +3 -4
  119. package/src/rules/{math-text-empty.js → math-text-empty.ts} +3 -4
  120. package/src/rules/{math-without-dollars.js → math-without-dollars.ts} +3 -4
  121. package/src/rules/{nested-lists.js → nested-lists.ts} +3 -4
  122. package/src/rules/{profanity.js → profanity.ts} +3 -4
  123. package/src/rules/{table-missing-cells.js → table-missing-cells.ts} +3 -4
  124. package/src/rules/{unbalanced-code-delimiters.js → unbalanced-code-delimiters.ts} +3 -4
  125. package/src/rules/{unescaped-dollar.js → unescaped-dollar.ts} +3 -4
  126. package/src/rules/{widget-in-table.js → widget-in-table.ts} +3 -4
  127. package/src/{selector.js → selector.ts} +12 -13
  128. package/src/{tree-transformer.js → tree-transformer.ts} +24 -24
  129. package/src/types.ts +7 -0
  130. package/tsconfig.json +12 -0
  131. package/tsconfig.tsbuildinfo +1 -0
  132. package/src/rules/all-rules.js +0 -72
  133. package/src/types.js +0 -10
@@ -0,0 +1,253 @@
1
+ /**
2
+ * Flowtype definitions for data
3
+ * Generated by Flowgen from a Typescript Definition
4
+ * Flowgen v1.21.0
5
+ * @flow
6
+ */
7
+ /**
8
+ * TreeTransformer is a class for traversing and transforming trees. Create a
9
+ * TreeTransformer by passing the root node of the tree to the
10
+ * constructor. Then traverse that tree by calling the traverse() method. The
11
+ * argument to traverse() is a callback function that will be called once for
12
+ * each node in the tree. This is a post-order depth-first traversal: the
13
+ * callback is not called on the a way down, but on the way back up. That is,
14
+ * the children of a node are traversed before the node itself is.
15
+ *
16
+ * The traversal callback function is passed three arguments, the node being
17
+ * traversed, a TraversalState object, and the concatentated text content of
18
+ * the node and all of its descendants. The TraversalState object is the most
19
+ * most interesting argument: it has methods for querying the ancestors and
20
+ * siblings of the node, and for deleting or replacing the node. These
21
+ * transformation methods are why this class is a tree transformer and not
22
+ * just a tree traverser.
23
+ *
24
+ * A typical tree traversal looks like this:
25
+ *
26
+ * new TreeTransformer(root).traverse((node, state, content) => {
27
+ * let parent = state.parent();
28
+ * let previous = state.previousSibling();
29
+ * // etc.
30
+ * });
31
+ *
32
+ * The traverse() method descends through nodes and arrays of nodes and calls
33
+ * the traverse callback on each node on the way back up to the root of the
34
+ * tree. (Note that it only calls the callback on the nodes themselves, not
35
+ * any arrays that contain nodes.) A node is loosely defined as any object
36
+ * with a string-valued `type` property. Objects that do not have a type
37
+ * property are assumed to not be part of the tree and are not traversed. When
38
+ * traversing an array, all elements of the array are examined, and any that
39
+ * are nodes or arrays are recursively traversed. When traversing a node, all
40
+ * properties of the object are examined and any node or array values are
41
+ * recursively traversed. In typical parse trees, the children of a node are
42
+ * in a `children` or `content` array, but this class is designed to handle
43
+ * more general trees. The Perseus markdown parser, for example, produces
44
+ * nodes of type "table" that have children in the `header` and `cells`
45
+ * properties.
46
+ *
47
+ * CAUTION: the traverse() method does not make any attempt to detect
48
+ * cycles. If you call it on a cyclic graph instead of a tree, it will cause
49
+ * infinite recursion (or, more likely, a stack overflow).
50
+ *
51
+ * TODO(davidflanagan): it probably wouldn't be hard to detect cycles: when
52
+ * pushing a new node onto the containers stack we could just check that it
53
+ * isn't already there.
54
+ *
55
+ * If a node has a text-valued `content` property, it is taken to be the
56
+ * plain-text content of the node. The traverse() method concatenates these
57
+ * content strings and passes them to the traversal callback for each
58
+ * node. This means that the callback has access the full text content of its
59
+ * node and all of the nodes descendants.
60
+ *
61
+ * See the TraversalState class for more information on what information and
62
+ * methods are available to the traversal callback.
63
+ */
64
+ export type TreeNode = {|
65
+ type: string,
66
+ |};
67
+ export type TraversalCallback = (
68
+ node: TreeNode,
69
+ state: TraversalState,
70
+ content: string
71
+ ) => void;
72
+ declare export default class TreeTransformer {
73
+ root: TreeNode;
74
+ constructor(root: TreeNode): this;
75
+ static isNode(n: any): boolean;
76
+ static isTextNode(n: any): boolean;
77
+ traverse(f: TraversalCallback): void;
78
+ _traverse(
79
+ n: TreeNode | Array<TreeNode>,
80
+ state: TraversalState,
81
+ f: TraversalCallback
82
+ ): string;
83
+ }
84
+ /**
85
+ * This class represents the state of a tree traversal. An instance is created
86
+ * by the traverse() method of the TreeTransformer class to maintain the state
87
+ * for that traversal, and the instance is passed to the traversal callback
88
+ * function for each node that is traversed. This class is not intended to be
89
+ * instantiated directly, but is exported so that its type can be used for
90
+ * Flow annotaions.
91
+ */
92
+ declare export class TraversalState {
93
+ root: TreeNode;
94
+ _currentNode: TreeNode | null | void;
95
+ _containers: Stack<TreeNode | Array<TreeNode>>;
96
+ _indexes: Stack<string | number>;
97
+ _ancestors: Stack<TreeNode>;
98
+ constructor(root: TreeNode): this;
99
+
100
+ /**
101
+ * Return the current node in the traversal. Any time the traversal
102
+ * callback is called, this method will return the name value as the
103
+ * first argument to the callback.
104
+ */
105
+ currentNode(): TreeNode;
106
+
107
+ /**
108
+ * Return the parent of the current node, if there is one, or null.
109
+ */
110
+ parent(): TreeNode | null | void;
111
+
112
+ /**
113
+ * Return an array of ancestor nodes. The first element of this array is
114
+ * the same as this.parent() and the last element is the root node. If we
115
+ * are currently at the root node, the the returned array will be empty.
116
+ * This method makes a copy of the internal state, so modifications to the
117
+ * returned array have no effect on the traversal.
118
+ */
119
+ ancestors(): $ReadOnlyArray<TreeNode>;
120
+
121
+ /**
122
+ * Return the next sibling of this node, if it has one, or null otherwise.
123
+ */
124
+ nextSibling(): TreeNode | null | void;
125
+
126
+ /**
127
+ * Return the previous sibling of this node, if it has one, or null
128
+ * otherwise.
129
+ */
130
+ previousSibling(): TreeNode | null | void;
131
+
132
+ /**
133
+ * Remove the next sibling node (if there is one) from the tree. Returns
134
+ * the removed sibling or null. This method makes it easy to traverse a
135
+ * tree and concatenate adjacent text nodes into a single node.
136
+ */
137
+ removeNextSibling(): TreeNode | null | void;
138
+
139
+ /**
140
+ * Replace the current node in the tree with the specified nodes. If no
141
+ * nodes are passed, this is a node deletion. If one node (or array) is
142
+ * passed, this is a 1-for-1 replacement. If more than one node is passed
143
+ * then this is a combination of deletion and insertion. The new node or
144
+ * nodes will not be traversed, so this method can safely be used to
145
+ * reparent the current node node beneath a new parent.
146
+ *
147
+ * This method throws an error if you attempt to replace the root node of
148
+ * the tree.
149
+ */
150
+ replace(...replacements: $ReadOnlyArray<TreeNode>): void;
151
+
152
+ /**
153
+ * Returns true if the current node has a previous sibling and false
154
+ * otherwise. If this method returns false, then previousSibling() will
155
+ * return null, and goToPreviousSibling() will throw an error.
156
+ */
157
+ hasPreviousSibling(): boolean;
158
+
159
+ /**
160
+ * Modify this traversal state object to have the state it would have had
161
+ * when visiting the previous sibling. Note that you may want to use
162
+ * clone() to make a copy before modifying the state object like this.
163
+ * This mutator method is not typically used during ordinary tree
164
+ * traversals, but is used by the Selector class for matching multi-node
165
+ * selectors.
166
+ */
167
+ goToPreviousSibling(): void;
168
+
169
+ /**
170
+ * Returns true if the current node has an ancestor and false otherwise.
171
+ * If this method returns false, then the parent() method will return
172
+ * null and goToParent() will throw an error
173
+ */
174
+ hasParent(): boolean;
175
+
176
+ /**
177
+ * Modify this object to look like it will look when we (later) visit the
178
+ * parent node of this node. You should not modify the instance passed to
179
+ * the tree traversal callback. Instead, make a copy with the clone()
180
+ * method and modify that. This mutator method is not typically used
181
+ * during ordinary tree traversals, but is used by the Selector class for
182
+ * matching multi-node selectors that involve parent and ancestor
183
+ * selectors.
184
+ */
185
+ goToParent(): void;
186
+
187
+ /**
188
+ * Return a new TraversalState object that is a copy of this one.
189
+ * This method is useful in conjunction with the mutating methods
190
+ * goToParent() and goToPreviousSibling().
191
+ */
192
+ clone(): TraversalState;
193
+
194
+ /**
195
+ * Returns true if this TraversalState object is equal to that
196
+ * TraversalState object, or false otherwise. This method exists
197
+ * primarily for use by our unit tests.
198
+ */
199
+ equals(that: TraversalState): boolean;
200
+ }
201
+ /**
202
+ * This class is an internal utility that just treats an array as a stack
203
+ * and gives us a top() method so we don't have to write expressions like
204
+ * `ancestors[ancestors.length-1]`. The values() method automatically
205
+ * copies the internal array so we don't have to worry about client code
206
+ * modifying our internal stacks. The use of this Stack abstraction makes
207
+ * the TraversalState class simpler in a number of places.
208
+ */
209
+ declare class Stack<T> {
210
+ stack: Array<T>;
211
+ constructor(array?: $ReadOnlyArray<T> | null): this;
212
+
213
+ /**
214
+ * Push a value onto the stack.
215
+ */
216
+ push(v: T): void;
217
+
218
+ /**
219
+ * Pop a value off of the stack.
220
+ */
221
+ pop(): T;
222
+
223
+ /**
224
+ * Return the top value of the stack without popping it.
225
+ */
226
+ top(): T;
227
+
228
+ /**
229
+ * Return a copy of the stack as an array
230
+ */
231
+ values(): $ReadOnlyArray<T>;
232
+
233
+ /**
234
+ * Return the number of elements in the stack
235
+ */
236
+ size(): number;
237
+
238
+ /**
239
+ * Return a string representation of the stack
240
+ */
241
+ toString(): string;
242
+
243
+ /**
244
+ * Return a shallow copy of the stack
245
+ */
246
+ clone(): Stack<T>;
247
+
248
+ /**
249
+ * Compare this stack to another and return true if the contents of
250
+ * the two arrays are the same.
251
+ */
252
+ equals(that: Stack<T>): boolean;
253
+ }
@@ -0,0 +1,6 @@
1
+ export type LinterContextProps = {
2
+ contentType: string;
3
+ highlightLint: boolean;
4
+ paths: ReadonlyArray<string>;
5
+ stack: ReadonlyArray<string>;
6
+ };
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Flowtype definitions for data
3
+ * Generated by Flowgen from a Typescript Definition
4
+ * Flowgen v1.21.0
5
+ * @flow
6
+ */
7
+ export type LinterContextProps = {|
8
+ contentType: string,
9
+ highlightLint: boolean,
10
+ paths: $ReadOnlyArray<string>,
11
+ stack: $ReadOnlyArray<string>,
12
+ |};
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Linter engine for Perseus",
4
4
  "author": "Khan Academy",
5
5
  "license": "MIT",
6
- "version": "0.2.4",
6
+ "version": "0.3.0",
7
7
  "publishConfig": {
8
8
  "access": "public"
9
9
  },
@@ -16,15 +16,15 @@
16
16
  },
17
17
  "module": "dist/es/index.js",
18
18
  "main": "dist/index.js",
19
- "source": "src/index.js",
19
+ "source": "src/index.ts",
20
20
  "scripts": {
21
21
  "test": "bash -c 'yarn --silent --cwd \"../..\" test ${@:0} $($([[ ${@: -1} = -* ]] || [[ ${@: -1} = bash ]]) && echo $PWD)'"
22
22
  },
23
23
  "dependencies": {
24
- "@khanacademy/perseus-error": "^0.1.4"
24
+ "@khanacademy/perseus-error": "^0.2.0"
25
25
  },
26
26
  "devDependencies": {
27
- "@khanacademy/pure-markdown": "^0.1.4",
27
+ "@khanacademy/pure-markdown": "^0.2.0",
28
28
  "prop-types": "^15.6.1"
29
29
  },
30
30
  "peerDependencies": {
@@ -1,12 +1,11 @@
1
- // @flow
2
1
  /* These tests exercise the Selector.match() method and also test that we
3
2
  * can integrate ../../perseus-markdown.js with ../tree-transform.js and
4
3
  * ../selector.js
5
4
  */
6
5
  import * as PureMarkdown from "@khanacademy/pure-markdown";
7
6
 
8
- import Selector from "../selector.js";
9
- import TreeTransformer from "../tree-transformer.js";
7
+ import Selector from "../selector";
8
+ import TreeTransformer from "../tree-transformer";
10
9
 
11
10
  describe("PerseusLinter selector matching:", () => {
12
11
  const markdown = `
@@ -33,14 +32,14 @@ C
33
32
  const tt = new TreeTransformer(tree);
34
33
  tt.traverse((n, state, content) => {
35
34
  // The wildcard selector should match at every node
36
- // $FlowFixMe[incompatible-use]
35
+ // @ts-expect-error [FEI-5003] - TS2533 - Object is possibly 'null' or 'undefined'.
37
36
  expect(selector.match(state)[0]).toEqual(n);
38
37
  });
39
38
  });
40
39
 
41
40
  it("type-based matching works", () => {
42
41
  const tree = parseTree();
43
- const selectors = {};
42
+ const selectors: Record<string, any> = {};
44
43
  const tt = new TreeTransformer(tree);
45
44
 
46
45
  // Traverse the tree once and create a selector for every type
@@ -83,14 +82,13 @@ C
83
82
  tt.traverse((n, state, content) => {
84
83
  const match = selector.match(state);
85
84
  const parent = state.parent();
86
- // $FlowFixMe[incompatible-use]
87
- // $FlowFixMe[incompatible-type]
85
+ // @ts-expect-error [FEI-5003] - TS2533 - Object is possibly 'null' or 'undefined'.
88
86
  if (n.type === "text" && parent.type === "paragraph") {
89
87
  expect(Array.isArray(match)).toBeTruthy();
90
88
  expect(match).toHaveLength(2);
91
- // $FlowFixMe[incompatible-use]
89
+ // @ts-expect-error [FEI-5003] - TS2533 - Object is possibly 'null' or 'undefined'.
92
90
  expect(match[0]).toEqual(parent);
93
- // $FlowFixMe[incompatible-use]
91
+ // @ts-expect-error [FEI-5003] - TS2533 - Object is possibly 'null' or 'undefined'.
94
92
  expect(match[1]).toEqual(n);
95
93
  matchedText += content;
96
94
  numMatches++;
@@ -118,16 +116,18 @@ C
118
116
  const grandparent = ancestors.pop();
119
117
  if (
120
118
  n.type === "text" &&
119
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
121
120
  parent.type === "em" &&
121
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
122
122
  grandparent.type === "paragraph"
123
123
  ) {
124
124
  expect(Array.isArray(match)).toBeTruthy();
125
125
  expect(match).toHaveLength(3);
126
- // $FlowFixMe[incompatible-use]
126
+ // @ts-expect-error [FEI-5003] - TS2533 - Object is possibly 'null' or 'undefined'.
127
127
  expect(match[0]).toEqual(grandparent);
128
- // $FlowFixMe[incompatible-use]
128
+ // @ts-expect-error [FEI-5003] - TS2533 - Object is possibly 'null' or 'undefined'.
129
129
  expect(match[1]).toEqual(parent);
130
- // $FlowFixMe[incompatible-use]
130
+ // @ts-expect-error [FEI-5003] - TS2533 - Object is possibly 'null' or 'undefined'.
131
131
  expect(match[2]).toEqual(n);
132
132
  matchedText += content;
133
133
  numMatches++;
@@ -152,11 +152,11 @@ C
152
152
  if (match !== null) {
153
153
  expect(Array.isArray(match)).toBeTruthy();
154
154
  expect(match).toHaveLength(2);
155
- // $FlowFixMe[incompatible-use]
155
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
156
156
  expect(match[0].type).toEqual("paragraph");
157
- // $FlowFixMe[incompatible-use]
157
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
158
158
  expect(match[1].type).toEqual("text");
159
- // $FlowFixMe[incompatible-use]
159
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
160
160
  expect(match[1]).toEqual(n);
161
161
  matchedText += content;
162
162
  numMatches++;
@@ -179,13 +179,13 @@ C
179
179
  if (match !== null) {
180
180
  expect(Array.isArray(match)).toBeTruthy();
181
181
  expect(match).toHaveLength(3);
182
- // $FlowFixMe[incompatible-use]
182
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
183
183
  expect(match[0].type).toEqual("paragraph");
184
- // $FlowFixMe[incompatible-use]
184
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
185
185
  expect(match[1].type).toEqual("em");
186
- // $FlowFixMe[incompatible-use]
186
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
187
187
  expect(match[2].type).toEqual("text");
188
- // $FlowFixMe[incompatible-use]
188
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
189
189
  expect(match[2]).toEqual(n);
190
190
  matchedText += content;
191
191
  numMatches++;
@@ -208,13 +208,13 @@ C
208
208
  if (match !== null) {
209
209
  expect(Array.isArray(match)).toBeTruthy();
210
210
  expect(match).toHaveLength(2);
211
- // $FlowFixMe[incompatible-use]
211
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
212
212
  expect(match[0].type).toEqual("heading");
213
- // $FlowFixMe[incompatible-use]
213
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
214
214
  expect(match[0]).toEqual(state.previousSibling());
215
- // $FlowFixMe[incompatible-use]
215
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
216
216
  expect(match[1].type).toEqual("paragraph");
217
- // $FlowFixMe[incompatible-use]
217
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
218
218
  expect(match[1]).toEqual(n);
219
219
  matchedText += content;
220
220
  numMatches++;
@@ -237,15 +237,15 @@ C
237
237
  if (match !== null) {
238
238
  expect(Array.isArray(match)).toBeTruthy();
239
239
  expect(match).toHaveLength(3);
240
- // $FlowFixMe[incompatible-use]
240
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
241
241
  expect(match[0].type).toEqual("heading");
242
- // $FlowFixMe[incompatible-use]
242
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
243
243
  expect(match[1].type).toEqual("paragraph");
244
- // $FlowFixMe[incompatible-use]
244
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
245
245
  expect(match[1]).toEqual(state.previousSibling());
246
- // $FlowFixMe[incompatible-use]
246
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
247
247
  expect(match[2].type).toEqual("paragraph");
248
- // $FlowFixMe[incompatible-use]
248
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
249
249
  expect(match[2]).toEqual(n);
250
250
  matchedText += content;
251
251
  numMatches++;
@@ -268,11 +268,11 @@ C
268
268
  if (match !== null) {
269
269
  expect(Array.isArray(match)).toBeTruthy();
270
270
  expect(match).toHaveLength(2);
271
- // $FlowFixMe[incompatible-use]
271
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
272
272
  expect(match[0].type).toEqual("heading");
273
- // $FlowFixMe[incompatible-use]
273
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
274
274
  expect(match[1].type).toEqual("paragraph");
275
- // $FlowFixMe[incompatible-use]
275
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
276
276
  expect(match[1]).toEqual(n);
277
277
  matchedText += content;
278
278
  numMatches++;
@@ -295,13 +295,13 @@ C
295
295
  if (match !== null) {
296
296
  expect(Array.isArray(match)).toBeTruthy();
297
297
  expect(match).toHaveLength(3);
298
- // $FlowFixMe[incompatible-use]
298
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
299
299
  expect(match[0].type).toEqual("heading");
300
- // $FlowFixMe[incompatible-use]
300
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
301
301
  expect(match[1].type).toEqual("paragraph");
302
- // $FlowFixMe[incompatible-use]
302
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
303
303
  expect(match[2].type).toEqual("paragraph");
304
- // $FlowFixMe[incompatible-use]
304
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
305
305
  expect(match[2]).toEqual(n);
306
306
  matchedText += content;
307
307
  numMatches++;
@@ -324,15 +324,15 @@ C
324
324
  if (match !== null) {
325
325
  expect(Array.isArray(match)).toBeTruthy();
326
326
  expect(match).toHaveLength(3);
327
- // $FlowFixMe[incompatible-use]
327
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
328
328
  expect(match[0].type).toEqual("list");
329
- // $FlowFixMe[incompatible-use]
329
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
330
330
  expect(match[1].type).toEqual("paragraph");
331
- // $FlowFixMe[incompatible-use]
331
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
332
332
  expect(match[1]).toEqual(state.parent());
333
- // $FlowFixMe[incompatible-use]
333
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
334
334
  expect(match[2].type).toEqual("em");
335
- // $FlowFixMe[incompatible-use]
335
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
336
336
  expect(match[2]).toEqual(n);
337
337
  matchedText += content;
338
338
  numMatches++;
@@ -355,15 +355,15 @@ C
355
355
  if (match !== null) {
356
356
  expect(Array.isArray(match)).toBeTruthy();
357
357
  expect(match).toHaveLength(3);
358
- // $FlowFixMe[incompatible-use]
358
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
359
359
  expect(match[0].type).toEqual("list");
360
- // $FlowFixMe[incompatible-use]
360
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
361
361
  expect(match[1].type).toEqual("paragraph");
362
- // $FlowFixMe[incompatible-use]
362
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
363
363
  expect(match[1]).toEqual(state.parent());
364
- // $FlowFixMe[incompatible-use]
364
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
365
365
  expect(match[2].type).toEqual("em");
366
- // $FlowFixMe[incompatible-use]
366
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
367
367
  expect(match[2]).toEqual(n);
368
368
  matchedText += content;
369
369
  numMatches++;
@@ -386,17 +386,17 @@ C
386
386
  if (match !== null) {
387
387
  expect(Array.isArray(match)).toBeTruthy();
388
388
  expect(match).toHaveLength(3);
389
- // $FlowFixMe[incompatible-use]
389
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
390
390
  expect(match[0].type).toEqual("paragraph");
391
- // $FlowFixMe[incompatible-use]
391
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
392
392
  expect(match[0]).toEqual(state.parent());
393
- // $FlowFixMe[incompatible-use]
393
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
394
394
  expect(match[1].type).toEqual("em");
395
- // $FlowFixMe[incompatible-use]
395
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
396
396
  expect(match[1]).toEqual(state.previousSibling());
397
- // $FlowFixMe[incompatible-use]
397
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
398
398
  expect(match[2].type).toEqual("text");
399
- // $FlowFixMe[incompatible-use]
399
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
400
400
  expect(match[2]).toEqual(n);
401
401
  matchedText += content;
402
402
  numMatches++;
@@ -419,17 +419,17 @@ C
419
419
  if (match !== null) {
420
420
  expect(Array.isArray(match)).toBeTruthy();
421
421
  expect(match).toHaveLength(3);
422
- // $FlowFixMe[incompatible-use]
422
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
423
423
  expect(match[0].type).toEqual("paragraph");
424
- // $FlowFixMe[incompatible-use]
424
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
425
425
  expect(match[0]).toEqual(state.parent());
426
- // $FlowFixMe[incompatible-use]
426
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
427
427
  expect(match[1].type).toEqual("em");
428
- // $FlowFixMe[incompatible-use]
428
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
429
429
  expect(match[1]).toEqual(state.previousSibling());
430
- // $FlowFixMe[incompatible-use]
430
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
431
431
  expect(match[2].type).toEqual("text");
432
- // $FlowFixMe[incompatible-use]
432
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
433
433
  expect(match[2]).toEqual(n);
434
434
  matchedText += content;
435
435
  numMatches++;
@@ -452,7 +452,7 @@ C
452
452
  if (match !== null) {
453
453
  expect(Array.isArray(match)).toBeTruthy();
454
454
  expect(match).toHaveLength(1);
455
- // $FlowFixMe[incompatible-use]
455
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
456
456
  expect(match[0]).toEqual(n);
457
457
  expect(
458
458
  n.type === "paragraph" || n.type === "list",
@@ -479,11 +479,11 @@ C
479
479
  expect(Array.isArray(match)).toBeTruthy();
480
480
  if (n.type === "heading") {
481
481
  expect(match).toHaveLength(1);
482
- // $FlowFixMe[incompatible-use]
482
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
483
483
  expect(match[0]).toEqual(n);
484
484
  } else {
485
485
  expect(match).toHaveLength(2);
486
- // $FlowFixMe[incompatible-use]
486
+ // @ts-expect-error [FEI-5003] - TS2532 - Object is possibly 'undefined'.
487
487
  expect(match[1]).toEqual(n);
488
488
  expect(n.type).toEqual("text");
489
489
  }
@@ -1,8 +1,7 @@
1
- // @flow
2
1
  import * as PureMarkdown from "@khanacademy/pure-markdown";
3
2
 
4
- import Rule from "../rule.js";
5
- import TreeTransformer from "../tree-transformer.js";
3
+ import Rule from "../rule";
4
+ import TreeTransformer from "../tree-transformer";
6
5
 
7
6
  describe("PerseusLinter lint Rules class", () => {
8
7
  const markdown = `
@@ -59,7 +58,7 @@ the previous heading was level ${previousHeading.level}`;
59
58
  },
60
59
  ];
61
60
 
62
- let rules = [];
61
+ let rules: Array<never> | Array<Rule | any> = [];
63
62
 
64
63
  function parseTree() {
65
64
  return PureMarkdown.parse(markdown);
@@ -74,7 +73,16 @@ the previous heading was level ${previousHeading.level}`;
74
73
  it("check() method", () => {
75
74
  const tree = parseTree();
76
75
  const tt = new TreeTransformer(tree);
77
- const warnings = [];
76
+ const warnings: Array<
77
+ | any
78
+ | {
79
+ end: number;
80
+ message: string;
81
+ rule: string;
82
+ severity?: number;
83
+ start: number;
84
+ }
85
+ > = [];
78
86
 
79
87
  tt.traverse((node, state, content) => {
80
88
  rules.forEach((r) => {