@khanacademy/perseus 0.2.7 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +29 -0
- package/README.md +5 -0
- package/dist/es/index.css +1 -436
- package/dist/es/index.js +3172 -5450
- package/dist/es/index.js.map +1 -1
- package/dist/index.css +1 -436
- package/dist/index.js +13520 -15805
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
- package/src/__tests__/perseus-markdown_test.jsx +6 -6
- package/src/__tests__/renderer_test.jsx +9 -9
- package/src/article-renderer.jsx +4 -5
- package/src/components/input-with-examples.jsx +4 -5
- package/src/components/lint.jsx +2 -1
- package/src/components/sortable.jsx +6 -7
- package/src/hint-renderer.jsx +3 -4
- package/src/hints-renderer.jsx +3 -4
- package/src/index.js +1 -0
- package/src/item-renderer.jsx +4 -5
- package/src/jquery.mobile.vmouse.js +2 -1
- package/src/perseus-markdown.jsx +3 -3
- package/src/renderer.jsx +31 -33
- package/src/styles/perseus-renderer.less +1 -1
- package/src/{not-gorgon.js → translation-linter.js} +10 -14
- package/src/types.js +3 -1
- package/src/widget-container.jsx +1 -1
- package/src/widgets/__tests__/__snapshots__/definition_test.js.snap +30 -12
- package/src/widgets/__tests__/definition_test.js +18 -33
- package/src/widgets/__tests__/grapher.cypress.jsx +2 -2
- package/src/widgets/__tests__/interactive-graph.cypress.jsx +2 -2
- package/src/widgets/categorizer.jsx +1 -1
- package/src/widgets/definition.jsx +36 -71
- package/src/widgets/explanation.jsx +1 -1
- package/src/widgets/expression.jsx +1 -1
- package/src/widgets/graded-group-set.jsx +1 -1
- package/src/widgets/graded-group.jsx +1 -1
- package/src/widgets/group.jsx +1 -1
- package/src/widgets/image.jsx +1 -1
- package/src/widgets/input-number.jsx +1 -1
- package/src/widgets/matcher.jsx +4 -1
- package/src/widgets/matrix.jsx +1 -1
- package/src/widgets/numeric-input.jsx +1 -1
- package/src/widgets/orderer.jsx +4 -1
- package/src/widgets/passage-ref-target.jsx +4 -1
- package/src/widgets/passage.jsx +1 -1
- package/src/widgets/radio/widget.jsx +1 -1
- package/src/widgets/sequence.jsx +4 -1
- package/src/widgets/sorter.jsx +4 -1
- package/src/widgets/table.jsx +4 -1
- package/src/README.md +0 -35
- package/src/__tests__/__snapshots__/pure-markdown_test.js.snap +0 -113
- package/src/__tests__/pure-markdown_test.js +0 -552
- package/src/gorgon/README +0 -40
- package/src/gorgon/__tests__/matcher_test.js +0 -497
- package/src/gorgon/__tests__/rule_test.js +0 -101
- package/src/gorgon/__tests__/rules_test.js +0 -487
- package/src/gorgon/__tests__/selector-parser_test.js +0 -52
- package/src/gorgon/__tests__/tree-transformer_test.js +0 -446
- package/src/gorgon/gorgon.js +0 -290
- package/src/gorgon/proptypes.js +0 -29
- package/src/gorgon/rule.js +0 -413
- package/src/gorgon/rules/absolute-url.js +0 -24
- package/src/gorgon/rules/all-rules.js +0 -72
- package/src/gorgon/rules/blockquoted-math.js +0 -10
- package/src/gorgon/rules/blockquoted-widget.js +0 -10
- package/src/gorgon/rules/double-spacing-after-terminal.js +0 -12
- package/src/gorgon/rules/extra-content-spacing.js +0 -12
- package/src/gorgon/rules/heading-level-1.js +0 -14
- package/src/gorgon/rules/heading-level-skip.js +0 -20
- package/src/gorgon/rules/heading-sentence-case.js +0 -11
- package/src/gorgon/rules/heading-title-case.js +0 -63
- package/src/gorgon/rules/image-alt-text.js +0 -21
- package/src/gorgon/rules/image-in-table.js +0 -10
- package/src/gorgon/rules/image-spaces-around-urls.js +0 -35
- package/src/gorgon/rules/image-widget.js +0 -50
- package/src/gorgon/rules/link-click-here.js +0 -11
- package/src/gorgon/rules/lint-utils.js +0 -48
- package/src/gorgon/rules/long-paragraph.js +0 -14
- package/src/gorgon/rules/math-adjacent.js +0 -10
- package/src/gorgon/rules/math-align-extra-break.js +0 -11
- package/src/gorgon/rules/math-align-linebreaks.js +0 -43
- package/src/gorgon/rules/math-empty.js +0 -10
- package/src/gorgon/rules/math-font-size.js +0 -12
- package/src/gorgon/rules/math-frac.js +0 -10
- package/src/gorgon/rules/math-nested.js +0 -11
- package/src/gorgon/rules/math-starts-with-space.js +0 -12
- package/src/gorgon/rules/math-text-empty.js +0 -10
- package/src/gorgon/rules/math-without-dollars.js +0 -14
- package/src/gorgon/rules/nested-lists.js +0 -11
- package/src/gorgon/rules/profanity.js +0 -10
- package/src/gorgon/rules/table-missing-cells.js +0 -20
- package/src/gorgon/rules/unbalanced-code-delimiters.js +0 -14
- package/src/gorgon/rules/unescaped-dollar.js +0 -10
- package/src/gorgon/rules/widget-in-table.js +0 -10
- package/src/gorgon/selector.js +0 -506
- package/src/gorgon/tree-transformer.js +0 -588
- package/src/pure-markdown.js +0 -347
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "Core Perseus API (includes renderers and widgets)",
|
|
4
4
|
"author": "Khan Academy",
|
|
5
5
|
"license": "MIT",
|
|
6
|
-
"version": "0.
|
|
6
|
+
"version": "0.3.1",
|
|
7
7
|
"publishConfig": {
|
|
8
8
|
"access": "public"
|
|
9
9
|
},
|
|
@@ -22,8 +22,10 @@
|
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@khanacademy/kmath": "^0.0.5",
|
|
25
|
-
"@khanacademy/math-input": "^0.5.2",
|
|
26
25
|
"@khanacademy/kas": "^0.2.4",
|
|
26
|
+
"@khanacademy/math-input": "^0.5.2",
|
|
27
|
+
"@khanacademy/perseus-linter": "^0.2.0",
|
|
28
|
+
"@khanacademy/pure-markdown": "^0.1.0",
|
|
27
29
|
"@khanacademy/simple-markdown": "^0.8.3",
|
|
28
30
|
"mathquill": "git+https://git@github.com/Khan/mathquill.git#a9ae54e057c5c1acc8244a5627acbff29901d992"
|
|
29
31
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @flow
|
|
2
|
-
import
|
|
3
|
-
|
|
2
|
+
import * as PerseusLinter from "@khanacademy/perseus-linter";
|
|
3
|
+
|
|
4
4
|
import PerseusMarkdown from "../perseus-markdown.jsx";
|
|
5
5
|
|
|
6
6
|
const {parse, basicOutput, characterCount} = PerseusMarkdown;
|
|
@@ -565,14 +565,14 @@ describe("perseus markdown", () => {
|
|
|
565
565
|
"data 4 | $data 5 | data 6\n" +
|
|
566
566
|
"data 7 | data 8 | data 9";
|
|
567
567
|
const context = {
|
|
568
|
-
...linterContextDefault,
|
|
568
|
+
...PerseusLinter.linterContextDefault,
|
|
569
569
|
content,
|
|
570
570
|
widgets: {},
|
|
571
571
|
};
|
|
572
572
|
|
|
573
573
|
// Act
|
|
574
574
|
const parsedWithLint = parse(content);
|
|
575
|
-
|
|
575
|
+
PerseusLinter.runLinter(parsedWithLint, context, true);
|
|
576
576
|
|
|
577
577
|
// Assert
|
|
578
578
|
expect(parsedWithLint).toMatchSnapshot();
|
|
@@ -650,14 +650,14 @@ describe("perseus markdown", () => {
|
|
|
650
650
|
"data 4 | $data 5 | data 6\n" +
|
|
651
651
|
"data 7 | data 8 | data 9";
|
|
652
652
|
const context = {
|
|
653
|
-
...linterContextDefault,
|
|
653
|
+
...PerseusLinter.linterContextDefault,
|
|
654
654
|
content,
|
|
655
655
|
widgets: {},
|
|
656
656
|
};
|
|
657
657
|
|
|
658
658
|
// Act
|
|
659
659
|
const parsedWithLint = parse(content);
|
|
660
|
-
|
|
660
|
+
PerseusLinter.runLinter(parsedWithLint, context, true);
|
|
661
661
|
|
|
662
662
|
const output = PerseusMarkdown.basicOutput(parsedWithLint);
|
|
663
663
|
|
|
@@ -31,15 +31,15 @@ import type {
|
|
|
31
31
|
PerseusInputNumberWidgetOptions,
|
|
32
32
|
} from "../perseus-types.js";
|
|
33
33
|
|
|
34
|
-
// NOTE(jeremy): We can't use an automatic mock for
|
|
35
|
-
// it's "instance" methods is created using `debounce` and Jest
|
|
36
|
-
// a mocked instance method for it (I suspect that Jest doesn't
|
|
37
|
-
// symbol as an instance method).
|
|
34
|
+
// NOTE(jeremy): We can't use an automatic mock for the translation linter,
|
|
35
|
+
// because one of it's "instance" methods is created using `debounce` and Jest
|
|
36
|
+
// doesn't provide a mocked instance method for it (I suspect that Jest doesn't
|
|
37
|
+
// see that symbol as an instance method).
|
|
38
38
|
const mockRunLinter = jest.fn();
|
|
39
39
|
const mockApplyLintErrors = jest.fn();
|
|
40
|
-
jest.mock("../
|
|
41
|
-
// We mock the
|
|
42
|
-
// spy/verify calls to instances of
|
|
40
|
+
jest.mock("../translation-linter.js", () => {
|
|
41
|
+
// We mock the TranslationLinter constructor here setting things up so we
|
|
42
|
+
// can spy/verify calls to instances of TranslationLinter
|
|
43
43
|
return function () {
|
|
44
44
|
return {
|
|
45
45
|
runLinter: mockRunLinter,
|
|
@@ -106,7 +106,7 @@ describe("renderer", () => {
|
|
|
106
106
|
});
|
|
107
107
|
});
|
|
108
108
|
|
|
109
|
-
describe("linting (
|
|
109
|
+
describe("linting (TranslationLinter)", () => {
|
|
110
110
|
const extraProps = {
|
|
111
111
|
linterContext: {
|
|
112
112
|
contentType: "exercise",
|
|
@@ -165,7 +165,7 @@ describe("renderer", () => {
|
|
|
165
165
|
|
|
166
166
|
// Assert
|
|
167
167
|
expect(renderer.state.jiptContent).toBeNull();
|
|
168
|
-
expect(renderer.state.
|
|
168
|
+
expect(renderer.state.translationLintErrors).toHaveLength(0);
|
|
169
169
|
expect(renderer.state.lastUsedWidgetId).toBeNull();
|
|
170
170
|
|
|
171
171
|
expect(renderer.state.widgetInfo).toStrictEqual(question1.widgets);
|
package/src/article-renderer.jsx
CHANGED
|
@@ -5,12 +5,11 @@
|
|
|
5
5
|
* composed of multiple (Renderer) sections concatenated together.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import * as PerseusLinter from "@khanacademy/perseus-linter";
|
|
8
9
|
import classNames from "classnames";
|
|
9
10
|
import PropTypes from "prop-types";
|
|
10
11
|
import * as React from "react";
|
|
11
12
|
|
|
12
|
-
import Gorgon from "./gorgon/gorgon.js";
|
|
13
|
-
import {linterContextProps, linterContextDefault} from "./gorgon/proptypes.js";
|
|
14
13
|
import ProvideKeypad from "./mixins/provide-keypad.jsx";
|
|
15
14
|
import {ClassNames as ApiClassNames, ApiOptions} from "./perseus-api.jsx";
|
|
16
15
|
import Renderer from "./renderer.jsx";
|
|
@@ -38,14 +37,14 @@ class ArticleRenderer extends React.Component<$FlowFixMe, $FlowFixMe> {
|
|
|
38
37
|
|
|
39
38
|
// Whether to use the new Bibliotron styles for articles
|
|
40
39
|
useNewStyles: PropTypes.bool,
|
|
41
|
-
linterContext: linterContextProps,
|
|
40
|
+
linterContext: PerseusLinter.linterContextProps,
|
|
42
41
|
legacyPerseusLint: PropTypes.arrayOf(PropTypes.string),
|
|
43
42
|
};
|
|
44
43
|
|
|
45
44
|
static defaultProps: $FlowFixMe = {
|
|
46
45
|
apiOptions: {},
|
|
47
46
|
useNewStyles: false,
|
|
48
|
-
linterContext: linterContextDefault,
|
|
47
|
+
linterContext: PerseusLinter.linterContextDefault,
|
|
49
48
|
};
|
|
50
49
|
|
|
51
50
|
constructor(props: $FlowFixMe) {
|
|
@@ -198,7 +197,7 @@ class ArticleRenderer extends React.Component<$FlowFixMe, $FlowFixMe> {
|
|
|
198
197
|
);
|
|
199
198
|
},
|
|
200
199
|
}}
|
|
201
|
-
linterContext={
|
|
200
|
+
linterContext={PerseusLinter.pushContextStack(
|
|
202
201
|
this.props.linterContext,
|
|
203
202
|
"article",
|
|
204
203
|
)}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
/* eslint-disable react/sort-comp */
|
|
2
2
|
// @flow
|
|
3
|
+
import * as PerseusLinter from "@khanacademy/perseus-linter";
|
|
3
4
|
import PropTypes from "prop-types";
|
|
4
5
|
import * as React from "react";
|
|
5
6
|
import _ from "underscore";
|
|
6
7
|
|
|
7
|
-
import Gorgon from "../gorgon/gorgon.js";
|
|
8
|
-
import {linterContextProps, linterContextDefault} from "../gorgon/proptypes.js";
|
|
9
8
|
import {ClassNames as ApiClassNames} from "../perseus-api.jsx";
|
|
10
9
|
import Renderer from "../renderer.jsx";
|
|
11
10
|
import Util from "../util.js";
|
|
@@ -38,7 +37,7 @@ class InputWithExamples extends React.Component<$FlowFixMe, $FlowFixMe> {
|
|
|
38
37
|
|
|
39
38
|
// A unique string identifying this InputWithExamples
|
|
40
39
|
id: PropTypes.string.isRequired,
|
|
41
|
-
linterContext: linterContextProps,
|
|
40
|
+
linterContext: PerseusLinter.linterContextProps,
|
|
42
41
|
};
|
|
43
42
|
|
|
44
43
|
static defaultProps: $FlowFixMe = {
|
|
@@ -47,7 +46,7 @@ class InputWithExamples extends React.Component<$FlowFixMe, $FlowFixMe> {
|
|
|
47
46
|
onFocus: function () {},
|
|
48
47
|
onBlur: function () {},
|
|
49
48
|
disabled: false,
|
|
50
|
-
linterContext: linterContextDefault,
|
|
49
|
+
linterContext: PerseusLinter.linterContextDefault,
|
|
51
50
|
};
|
|
52
51
|
|
|
53
52
|
state: $FlowFixMe = {
|
|
@@ -179,7 +178,7 @@ class InputWithExamples extends React.Component<$FlowFixMe, $FlowFixMe> {
|
|
|
179
178
|
<div id={this._getUniqueId()}>
|
|
180
179
|
<Renderer
|
|
181
180
|
content={examplesContent}
|
|
182
|
-
linterContext={
|
|
181
|
+
linterContext={PerseusLinter.pushContextStack(
|
|
183
182
|
this.props.linterContext,
|
|
184
183
|
"input-with-examples",
|
|
185
184
|
)}
|
package/src/components/lint.jsx
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
// @flow
|
|
2
2
|
/**
|
|
3
3
|
* This component renders "lint" nodes in a markdown parse tree. Lint nodes
|
|
4
|
-
* are inserted into the tree by the
|
|
4
|
+
* are inserted into the tree by the Perseus linter (see
|
|
5
|
+
* perseus-linter/src/index).
|
|
5
6
|
*
|
|
6
7
|
* This component serves multiple purposes
|
|
7
8
|
*
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* eslint-disable @babel/no-invalid-this, react/forbid-prop-types, react/no-unsafe, react/sort-comp */
|
|
2
2
|
// @flow
|
|
3
|
+
import * as PerseusLinter from "@khanacademy/perseus-linter";
|
|
3
4
|
import {CircularSpinner} from "@khanacademy/wonder-blocks-progress-spinner";
|
|
4
5
|
import {StyleSheet, css} from "aphrodite";
|
|
5
6
|
import $ from "jquery";
|
|
@@ -9,8 +10,6 @@ import ReactDOM from "react-dom";
|
|
|
9
10
|
import _ from "underscore";
|
|
10
11
|
|
|
11
12
|
import {getDependencies} from "../dependencies.js";
|
|
12
|
-
import Gorgon from "../gorgon/gorgon.js";
|
|
13
|
-
import {linterContextProps, linterContextDefault} from "../gorgon/proptypes.js";
|
|
14
13
|
import {ClassNames as ApiClassNames} from "../perseus-api.jsx";
|
|
15
14
|
import Renderer from "../renderer.jsx";
|
|
16
15
|
import Util from "../util.js";
|
|
@@ -96,13 +95,13 @@ class Draggable extends React.Component<DraggableProps, DraggableState> {
|
|
|
96
95
|
onMouseUp: PropTypes.func.isRequired,
|
|
97
96
|
onRender: PropTypes.func.isRequired,
|
|
98
97
|
type: PropTypes.oneOf([STATIC, DRAGGING, ANIMATING, DISABLED]),
|
|
99
|
-
linterContext: linterContextProps,
|
|
98
|
+
linterContext: PerseusLinter.linterContextProps,
|
|
100
99
|
};
|
|
101
100
|
|
|
102
101
|
static defaultProps = {
|
|
103
102
|
includePadding: true,
|
|
104
103
|
type: STATIC,
|
|
105
|
-
linterContext: linterContextDefault,
|
|
104
|
+
linterContext: PerseusLinter.linterContextDefault,
|
|
106
105
|
};
|
|
107
106
|
|
|
108
107
|
state: DraggableState = {
|
|
@@ -215,7 +214,7 @@ class Draggable extends React.Component<DraggableProps, DraggableState> {
|
|
|
215
214
|
>
|
|
216
215
|
<Renderer
|
|
217
216
|
content={this.props.content}
|
|
218
|
-
linterContext={
|
|
217
|
+
linterContext={PerseusLinter.pushContextStack(
|
|
219
218
|
this.props.linterContext,
|
|
220
219
|
"draggable",
|
|
221
220
|
)}
|
|
@@ -423,7 +422,7 @@ class Sortable extends React.Component<SortableProps, SortableState> {
|
|
|
423
422
|
onMeasure: function () {},
|
|
424
423
|
margin: 5,
|
|
425
424
|
onChange: function () {},
|
|
426
|
-
linterContext: linterContextDefault,
|
|
425
|
+
linterContext: PerseusLinter.linterContextDefault,
|
|
427
426
|
waitForKatexLoad: true,
|
|
428
427
|
};
|
|
429
428
|
|
|
@@ -619,7 +618,7 @@ class Sortable extends React.Component<SortableProps, SortableState> {
|
|
|
619
618
|
includePadding={this.props.padding}
|
|
620
619
|
margin={isLast && isStatic ? 0 : margin}
|
|
621
620
|
endPosition={item.endPosition}
|
|
622
|
-
linterContext={
|
|
621
|
+
linterContext={PerseusLinter.pushContextStack(
|
|
623
622
|
this.props.linterContext,
|
|
624
623
|
"sortable",
|
|
625
624
|
)}
|
package/src/hint-renderer.jsx
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
// @flow
|
|
2
|
+
import * as PerseusLinter from "@khanacademy/perseus-linter";
|
|
2
3
|
import * as i18n from "@khanacademy/wonder-blocks-i18n";
|
|
3
4
|
import {StyleSheet, css} from "aphrodite";
|
|
4
5
|
import classnames from "classnames";
|
|
5
6
|
import * as React from "react";
|
|
6
7
|
|
|
7
|
-
import Gorgon from "./gorgon/gorgon.js";
|
|
8
|
-
import {linterContextDefault} from "./gorgon/proptypes.js";
|
|
9
8
|
import Renderer from "./renderer.jsx";
|
|
10
9
|
import {
|
|
11
10
|
baseUnitPx,
|
|
@@ -36,7 +35,7 @@ type DefaultProps = {|
|
|
|
36
35
|
/* Renders just a hint preview */
|
|
37
36
|
class HintRenderer extends React.Component<Props> {
|
|
38
37
|
static defaultProps: DefaultProps = {
|
|
39
|
-
linterContext: linterContextDefault,
|
|
38
|
+
linterContext: PerseusLinter.linterContextDefault,
|
|
40
39
|
};
|
|
41
40
|
|
|
42
41
|
getSerializedState: () => void = () => {
|
|
@@ -116,7 +115,7 @@ class HintRenderer extends React.Component<Props> {
|
|
|
116
115
|
images={hint.images}
|
|
117
116
|
apiOptions={rendererApiOptions}
|
|
118
117
|
findExternalWidgets={this.props.findExternalWidgets}
|
|
119
|
-
linterContext={
|
|
118
|
+
linterContext={PerseusLinter.pushContextStack(
|
|
120
119
|
this.props.linterContext,
|
|
121
120
|
"hint",
|
|
122
121
|
)}
|
package/src/hints-renderer.jsx
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// @flow
|
|
2
|
+
import * as PerseusLinter from "@khanacademy/perseus-linter";
|
|
2
3
|
import * as i18n from "@khanacademy/wonder-blocks-i18n";
|
|
3
4
|
import {StyleSheet, css} from "aphrodite";
|
|
4
5
|
import classnames from "classnames";
|
|
@@ -6,8 +7,6 @@ import * as React from "react";
|
|
|
6
7
|
import ReactDOM from "react-dom";
|
|
7
8
|
import _ from "underscore";
|
|
8
9
|
|
|
9
|
-
import Gorgon from "./gorgon/gorgon.js";
|
|
10
|
-
import {linterContextDefault} from "./gorgon/proptypes.js";
|
|
11
10
|
import HintRenderer from "./hint-renderer.jsx";
|
|
12
11
|
import {ApiOptions} from "./perseus-api.jsx";
|
|
13
12
|
import typeof Renderer from "./renderer.jsx";
|
|
@@ -43,7 +42,7 @@ type State = {|
|
|
|
43
42
|
// eslint-disable-next-line react/no-unsafe
|
|
44
43
|
class HintsRenderer extends React.Component<Props, State> {
|
|
45
44
|
static defaultProps: DefaultProps = {
|
|
46
|
-
linterContext: linterContextDefault,
|
|
45
|
+
linterContext: PerseusLinter.linterContextDefault,
|
|
47
46
|
};
|
|
48
47
|
|
|
49
48
|
// The isFinalHelpPage property determines if the user has requested help
|
|
@@ -181,7 +180,7 @@ class HintsRenderer extends React.Component<Props, State> {
|
|
|
181
180
|
key={"hintRenderer" + i}
|
|
182
181
|
apiOptions={apiOptions}
|
|
183
182
|
findExternalWidgets={this.props.findExternalWidgets}
|
|
184
|
-
linterContext={
|
|
183
|
+
linterContext={PerseusLinter.pushContextStack(
|
|
185
184
|
this.props.linterContext,
|
|
186
185
|
"hints[" + i + "]",
|
|
187
186
|
)}
|
package/src/index.js
CHANGED
package/src/item-renderer.jsx
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
/* eslint-disable react/no-unsafe */
|
|
2
2
|
// @flow
|
|
3
|
+
import * as PerseusLinter from "@khanacademy/perseus-linter";
|
|
3
4
|
import $ from "jquery";
|
|
4
5
|
import * as React from "react";
|
|
5
6
|
import * as ReactDOM from "react-dom";
|
|
6
7
|
import _ from "underscore";
|
|
7
8
|
|
|
8
|
-
import Gorgon from "./gorgon/gorgon.js";
|
|
9
|
-
import {linterContextDefault} from "./gorgon/proptypes.js";
|
|
10
9
|
import HintsRenderer from "./hints-renderer.jsx";
|
|
11
10
|
import Objective from "./interactive2/objective_.js";
|
|
12
11
|
import ProvideKeypad from "./mixins/provide-keypad.jsx";
|
|
@@ -88,7 +87,7 @@ class ItemRenderer extends React.Component<Props, State> {
|
|
|
88
87
|
initialHintsVisible: 0,
|
|
89
88
|
workAreaSelector: "#workarea",
|
|
90
89
|
reviewMode: false,
|
|
91
|
-
linterContext: linterContextDefault,
|
|
90
|
+
linterContext: PerseusLinter.linterContextDefault,
|
|
92
91
|
};
|
|
93
92
|
|
|
94
93
|
constructor(props: Props) {
|
|
@@ -209,7 +208,7 @@ class ItemRenderer extends React.Component<Props, State> {
|
|
|
209
208
|
questionCompleted={this.state.questionCompleted}
|
|
210
209
|
reviewMode={this.props.reviewMode}
|
|
211
210
|
savedState={this.props.savedState}
|
|
212
|
-
linterContext={
|
|
211
|
+
linterContext={PerseusLinter.pushContextStack(
|
|
213
212
|
this.props.linterContext,
|
|
214
213
|
"question",
|
|
215
214
|
)}
|
|
@@ -227,7 +226,7 @@ class ItemRenderer extends React.Component<Props, State> {
|
|
|
227
226
|
hints={this.props.item.hints}
|
|
228
227
|
hintsVisible={this.state.hintsVisible}
|
|
229
228
|
apiOptions={apiOptions}
|
|
230
|
-
linterContext={
|
|
229
|
+
linterContext={PerseusLinter.pushContextStack(
|
|
231
230
|
this.props.linterContext,
|
|
232
231
|
"hints",
|
|
233
232
|
)}
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
//
|
|
22
22
|
// The current version exposes the following virtual events to jQuery bind methods:
|
|
23
23
|
// "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel"
|
|
24
|
+
import $ from "jquery";
|
|
24
25
|
|
|
25
26
|
(function ($, window, document, undefined) {
|
|
26
27
|
if (typeof $ === "undefined") {
|
|
@@ -542,4 +543,4 @@
|
|
|
542
543
|
true,
|
|
543
544
|
);
|
|
544
545
|
}
|
|
545
|
-
})(
|
|
546
|
+
})($, window, document);
|
package/src/perseus-markdown.jsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* eslint-disable no-useless-escape, no-prototype-builtins */
|
|
2
2
|
// @flow
|
|
3
|
-
|
|
3
|
+
import {pureMarkdownRules} from "@khanacademy/pure-markdown";
|
|
4
4
|
import SimpleMarkdown from "@khanacademy/simple-markdown";
|
|
5
5
|
import * as i18n from "@khanacademy/wonder-blocks-i18n";
|
|
6
6
|
import * as React from "react";
|
|
@@ -8,7 +8,6 @@ import _ from "underscore";
|
|
|
8
8
|
|
|
9
9
|
import Lint from "./components/lint.jsx";
|
|
10
10
|
import {getDependencies} from "./dependencies.js";
|
|
11
|
-
import {pureMarkdownRules} from "./pure-markdown.js";
|
|
12
11
|
|
|
13
12
|
const rules = {
|
|
14
13
|
...pureMarkdownRules,
|
|
@@ -111,7 +110,8 @@ const rules = {
|
|
|
111
110
|
} else if (node.table.type === "lint") {
|
|
112
111
|
// The `table` in this node is actually a `lint` node,
|
|
113
112
|
// not the expected `table` node. This is due to the linter
|
|
114
|
-
// implementation "reparenting" the `table` node, see
|
|
113
|
+
// implementation "reparenting" the `table` node, see
|
|
114
|
+
// perseus-linter/src/index.js
|
|
115
115
|
if (node.table.content?.type === "table") {
|
|
116
116
|
// And the `content` of this lint node is the `table` node
|
|
117
117
|
// which we actually want to render. Thus, we perform
|
package/src/renderer.jsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/* eslint-disable react/no-unsafe */
|
|
2
2
|
// @flow
|
|
3
|
+
import * as PerseusLinter from "@khanacademy/perseus-linter";
|
|
3
4
|
import classNames from "classnames";
|
|
4
5
|
import $ from "jquery";
|
|
5
6
|
import * as React from "react";
|
|
@@ -13,17 +14,15 @@ import ZoomableTeX from "./components/zoomable-tex.jsx";
|
|
|
13
14
|
import Zoomable from "./components/zoomable.jsx";
|
|
14
15
|
import {getDependencies} from "./dependencies.js";
|
|
15
16
|
import ErrorBoundary from "./error-boundary.jsx";
|
|
16
|
-
import Gorgon from "./gorgon/gorgon.js"; // The linter engine
|
|
17
|
-
import {linterContextDefault} from "./gorgon/proptypes.js";
|
|
18
17
|
import InteractionTracker from "./interaction-tracker.js";
|
|
19
18
|
import Objective from "./interactive2/objective_.js";
|
|
20
19
|
import JiptParagraphs from "./jipt-paragraphs.js";
|
|
21
20
|
import {Errors, Log} from "./logging/log.js";
|
|
22
|
-
import NotGorgon from "./not-gorgon.js"; // The i18n linter
|
|
23
21
|
import {ClassNames as ApiClassNames, ApiOptions} from "./perseus-api.jsx";
|
|
24
22
|
import {PerseusError} from "./perseus-error.js";
|
|
25
23
|
import PerseusMarkdown from "./perseus-markdown.jsx";
|
|
26
24
|
import QuestionParagraph from "./question-paragraph.jsx";
|
|
25
|
+
import TranslationLinter from "./translation-linter.js";
|
|
27
26
|
import Util from "./util.js";
|
|
28
27
|
import preprocessTex from "./util/katex-preprocess.js";
|
|
29
28
|
import WidgetContainer from "./widget-container.jsx";
|
|
@@ -171,7 +170,7 @@ type Props = {|
|
|
|
171
170
|
|};
|
|
172
171
|
|
|
173
172
|
type State = {|
|
|
174
|
-
|
|
173
|
+
translationLintErrors: $ReadOnlyArray<string>,
|
|
175
174
|
widgetInfo: $ReadOnly<{|[id: string]: ?WidgetInfo|}>,
|
|
176
175
|
widgetProps: $ReadOnly<{|[id: string]: ?$FlowFixMe|}>,
|
|
177
176
|
jiptContent: any,
|
|
@@ -210,7 +209,7 @@ class Renderer extends React.Component<Props, State> {
|
|
|
210
209
|
_isTwoColumn: boolean;
|
|
211
210
|
|
|
212
211
|
// The i18n linter.
|
|
213
|
-
|
|
212
|
+
_translationLinter: TranslationLinter;
|
|
214
213
|
|
|
215
214
|
lastRenderedMarkdown: React.Element<PerseusDependencies["KatexProvider"]>;
|
|
216
215
|
reuseMarkdown: boolean;
|
|
@@ -234,20 +233,20 @@ class Renderer extends React.Component<Props, State> {
|
|
|
234
233
|
reviewMode: false,
|
|
235
234
|
serializedState: null,
|
|
236
235
|
onSerializedStateUpdated: () => {},
|
|
237
|
-
linterContext: linterContextDefault,
|
|
236
|
+
linterContext: PerseusLinter.linterContextDefault,
|
|
238
237
|
};
|
|
239
238
|
|
|
240
239
|
constructor(props: Props, context: Context) {
|
|
241
240
|
super(props, context);
|
|
242
|
-
this.
|
|
241
|
+
this._translationLinter = new TranslationLinter();
|
|
243
242
|
|
|
244
243
|
this.state = {
|
|
245
244
|
jiptContent: null,
|
|
246
245
|
|
|
247
|
-
//
|
|
248
|
-
// This is a list of error strings
|
|
249
|
-
// run.
|
|
250
|
-
|
|
246
|
+
// TranslationLinter is async and currently does not contain a
|
|
247
|
+
// location. This is a list of error strings TranslationLinter
|
|
248
|
+
// detected on its last run.
|
|
249
|
+
translationLintErrors: [],
|
|
251
250
|
|
|
252
251
|
// The ID of the last widget the user interacted with. We'll
|
|
253
252
|
// use this to set the `isLastUsedWidget` flag on the
|
|
@@ -276,9 +275,9 @@ class Renderer extends React.Component<Props, State> {
|
|
|
276
275
|
if (this.props.linterContext.highlightLint) {
|
|
277
276
|
// Get i18n lint errors asynchronously. If there are lint errors,
|
|
278
277
|
// this component will be rerendered.
|
|
279
|
-
this.
|
|
278
|
+
this._translationLinter.runLinter(
|
|
280
279
|
this.props.content,
|
|
281
|
-
this.
|
|
280
|
+
this.handletranslationLintErrors,
|
|
282
281
|
);
|
|
283
282
|
}
|
|
284
283
|
}
|
|
@@ -344,8 +343,8 @@ class Renderer extends React.Component<Props, State> {
|
|
|
344
343
|
!newJipt &&
|
|
345
344
|
oldContent === newContent &&
|
|
346
345
|
_.isEqual(
|
|
347
|
-
this.state.
|
|
348
|
-
nextState.
|
|
346
|
+
this.state.translationLintErrors,
|
|
347
|
+
nextState.translationLintErrors,
|
|
349
348
|
) &&
|
|
350
349
|
// If we are running the linter then we need to know when
|
|
351
350
|
// widgets have changed because we need for force the linter to
|
|
@@ -392,9 +391,9 @@ class Renderer extends React.Component<Props, State> {
|
|
|
392
391
|
if (this.props.linterContext.highlightLint) {
|
|
393
392
|
// Get i18n lint errors asynchronously. If lint errors have changed
|
|
394
393
|
// since the last run, this component will be rerendered.
|
|
395
|
-
this.
|
|
394
|
+
this._translationLinter.runLinter(
|
|
396
395
|
this.props.content,
|
|
397
|
-
this.
|
|
396
|
+
this.handletranslationLintErrors,
|
|
398
397
|
);
|
|
399
398
|
}
|
|
400
399
|
}
|
|
@@ -538,7 +537,7 @@ class Renderer extends React.Component<Props, State> {
|
|
|
538
537
|
type={type}
|
|
539
538
|
initialProps={this.getWidgetProps(id)}
|
|
540
539
|
shouldHighlight={shouldHighlight}
|
|
541
|
-
linterContext={
|
|
540
|
+
linterContext={PerseusLinter.pushContextStack(
|
|
542
541
|
this.props.linterContext,
|
|
543
542
|
"widget",
|
|
544
543
|
)}
|
|
@@ -1781,18 +1780,17 @@ class Renderer extends React.Component<Props, State> {
|
|
|
1781
1780
|
return examples[0];
|
|
1782
1781
|
};
|
|
1783
1782
|
|
|
1784
|
-
//
|
|
1785
|
-
|
|
1786
|
-
lintErrors: $ReadOnlyArray<string
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
}
|
|
1783
|
+
// TranslationLinter callback
|
|
1784
|
+
handletranslationLintErrors: (lintErrors: $ReadOnlyArray<string>) => void =
|
|
1785
|
+
(lintErrors: $ReadOnlyArray<string>) => {
|
|
1786
|
+
if (!this._isMounted) {
|
|
1787
|
+
return;
|
|
1788
|
+
}
|
|
1791
1789
|
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1790
|
+
this.setState({
|
|
1791
|
+
translationLintErrors: lintErrors,
|
|
1792
|
+
});
|
|
1793
|
+
};
|
|
1796
1794
|
|
|
1797
1795
|
render(): React.Node {
|
|
1798
1796
|
const apiOptions = this.getApiOptions();
|
|
@@ -1886,12 +1884,12 @@ class Renderer extends React.Component<Props, State> {
|
|
|
1886
1884
|
...this.props.linterContext,
|
|
1887
1885
|
};
|
|
1888
1886
|
|
|
1889
|
-
|
|
1887
|
+
PerseusLinter.runLinter(parsedMarkdown, context, true);
|
|
1890
1888
|
|
|
1891
|
-
// Apply the lint errors from the last
|
|
1889
|
+
// Apply the lint errors from the last TranslationLinter run.
|
|
1892
1890
|
// TODO(joshuan): Support overlapping dots.
|
|
1893
|
-
this.
|
|
1894
|
-
...this.state.
|
|
1891
|
+
this._translationLinter.applyLintErrors(parsedMarkdown, [
|
|
1892
|
+
...this.state.translationLintErrors,
|
|
1895
1893
|
...(this.props.legacyPerseusLint || []),
|
|
1896
1894
|
]);
|
|
1897
1895
|
}
|
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
// @flow
|
|
2
|
+
import {Rule} from "@khanacademy/perseus-linter";
|
|
2
3
|
import {debounce} from "underscore";
|
|
3
4
|
|
|
4
|
-
import Rule from "./gorgon/rule.js";
|
|
5
|
-
|
|
6
5
|
/**
|
|
7
|
-
*
|
|
6
|
+
* TranslationLinter asynchronously calls Khan Academy's poentry linter.
|
|
8
7
|
*
|
|
9
8
|
* The poentry linter checks for issues that prevent content from being
|
|
10
|
-
* translated. This linter is KA-specific and so
|
|
11
|
-
* in non-KA environments.
|
|
12
|
-
*
|
|
13
|
-
* NotGorgon is named as such because it is not Gorgon, Perseus' built-in
|
|
14
|
-
* linter.
|
|
9
|
+
* translated. This linter is KA-specific and so TranslationLinter does not do
|
|
10
|
+
* anything in non-KA environments.
|
|
15
11
|
*/
|
|
16
12
|
|
|
17
13
|
// A LintCB is called once the linter has been run.
|
|
@@ -21,7 +17,7 @@ type LintCB = (errors: $ReadOnlyArray<string>) => void;
|
|
|
21
17
|
// last call. The timer is reset if the lint is called during the wait.
|
|
22
18
|
const DEBOUNCE_TIMEOUT = 1000;
|
|
23
19
|
|
|
24
|
-
export default class
|
|
20
|
+
export default class TranslationLinter {
|
|
25
21
|
// To avoid linting when nothing has changed.
|
|
26
22
|
previousContent: ?string = null;
|
|
27
23
|
|
|
@@ -102,17 +98,17 @@ export default class NotGorgon {
|
|
|
102
98
|
|
|
103
99
|
/**
|
|
104
100
|
* Applies an array of errors generated by linters without position
|
|
105
|
-
* information (
|
|
106
|
-
* of a Perseus tree.
|
|
101
|
+
* information (TranslationLinter and the legacy getSaveWarnings()) to the
|
|
102
|
+
* top of a Perseus tree.
|
|
107
103
|
*/
|
|
108
104
|
applyLintErrors(
|
|
109
105
|
parsedMarkdown: any,
|
|
110
|
-
|
|
106
|
+
translationLintErrors: $ReadOnlyArray<string>,
|
|
111
107
|
) {
|
|
112
108
|
// These lint errors do not have position data associated with
|
|
113
109
|
// them, so we just plop them at the top.
|
|
114
|
-
if (
|
|
115
|
-
const errorText =
|
|
110
|
+
if (translationLintErrors.length) {
|
|
111
|
+
const errorText = translationLintErrors.join("\n\n");
|
|
116
112
|
parsedMarkdown.unshift({
|
|
117
113
|
content: {
|
|
118
114
|
type: "text",
|
package/src/types.js
CHANGED
|
@@ -359,6 +359,8 @@ type InitialRequestUrlInterface = {|
|
|
|
359
359
|
protocol: string,
|
|
360
360
|
|};
|
|
361
361
|
|
|
362
|
+
export type VideoKind = "YOUTUBE_ID" | "READABLE_ID";
|
|
363
|
+
|
|
362
364
|
// An object for dependency injection, to allow different clients
|
|
363
365
|
// to provide different methods for logging, translation, network
|
|
364
366
|
// requests, etc.
|
|
@@ -392,7 +394,7 @@ export type PerseusDependencies = {|
|
|
|
392
394
|
// framework.
|
|
393
395
|
useVideo(
|
|
394
396
|
id: string,
|
|
395
|
-
kind:
|
|
397
|
+
kind: VideoKind,
|
|
396
398
|
): Result<{|
|
|
397
399
|
video: ?VideoData,
|
|
398
400
|
|}>,
|
package/src/widget-container.jsx
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/* eslint-disable react/no-unsafe, react/sort-comp */
|
|
2
2
|
// @flow
|
|
3
|
+
import {linterContextDefault} from "@khanacademy/perseus-linter";
|
|
3
4
|
import classNames from "classnames";
|
|
4
5
|
import * as React from "react";
|
|
5
6
|
import ReactDOM from "react-dom";
|
|
6
7
|
|
|
7
|
-
import {linterContextDefault} from "./gorgon/proptypes.js";
|
|
8
8
|
import {zIndexInteractiveComponent} from "./styles/constants.js";
|
|
9
9
|
import {containerSizeClass, getClassFromWidth} from "./util/sizing-utils.js";
|
|
10
10
|
import * as Widgets from "./widgets.js";
|