@khanacademy/perseus-linter 1.0.0 → 1.2.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.
- package/dist/es/index.js +85 -5
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +83 -5
- package/dist/index.js.map +1 -1
- package/dist/rule.d.ts +24 -8
- package/dist/rules/expression-widget.d.ts +9 -0
- package/dist/rules/static-widget-in-question-stem.d.ts +3 -0
- package/dist/tree-transformer.d.ts +2 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -791,12 +791,61 @@ var DoubleSpacingAfterTerminal = Rule.makeRule({
|
|
|
791
791
|
any other kind of terminal punctuation.`
|
|
792
792
|
});
|
|
793
793
|
|
|
794
|
+
function buttonNotInButtonSet(name, set) {
|
|
795
|
+
return `Answer requires a button not found in the button sets: ${name} (in ${set})`;
|
|
796
|
+
}
|
|
797
|
+
const stringToButtonSet = {
|
|
798
|
+
"\\sqrt": "prealgebra",
|
|
799
|
+
"\\sin": "trig",
|
|
800
|
+
"\\cos": "trig",
|
|
801
|
+
"\\tan": "trig",
|
|
802
|
+
"\\log": "logarithms",
|
|
803
|
+
"\\ln": "logarithms"
|
|
804
|
+
};
|
|
805
|
+
|
|
806
|
+
/**
|
|
807
|
+
* Rule to make sure that Expression questions that require
|
|
808
|
+
* a specific math symbol to answer have that math symbol
|
|
809
|
+
* available in the keypad (desktop learners can use a keyboard,
|
|
810
|
+
* but mobile learners must use the MathInput keypad)
|
|
811
|
+
*/
|
|
812
|
+
var ExpressionWidget = Rule.makeRule({
|
|
813
|
+
name: "expression-widget",
|
|
814
|
+
severity: Rule.Severity.WARNING,
|
|
815
|
+
selector: "widget",
|
|
816
|
+
lint: function (state, content, nodes, match, context) {
|
|
817
|
+
// This rule only looks at image widgets
|
|
818
|
+
if (state.currentNode().widgetType !== "expression") {
|
|
819
|
+
return;
|
|
820
|
+
}
|
|
821
|
+
const nodeId = state.currentNode().id;
|
|
822
|
+
if (!nodeId) {
|
|
823
|
+
return;
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
// If it can't find a definition for the widget it does nothing
|
|
827
|
+
const widget = context?.widgets?.[nodeId];
|
|
828
|
+
if (!widget) {
|
|
829
|
+
return;
|
|
830
|
+
}
|
|
831
|
+
const answers = widget.options.answerForms;
|
|
832
|
+
const buttons = widget.options.buttonSets;
|
|
833
|
+
for (const answer of answers) {
|
|
834
|
+
for (const [str, set] of Object.entries(stringToButtonSet)) {
|
|
835
|
+
if (answer.value.includes(str) && !buttons.includes(set)) {
|
|
836
|
+
return buttonNotInButtonSet(str, set);
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
});
|
|
842
|
+
|
|
794
843
|
var ExtraContentSpacing = Rule.makeRule({
|
|
795
844
|
name: "extra-content-spacing",
|
|
796
845
|
selector: "paragraph",
|
|
797
846
|
pattern: /\s+$/,
|
|
798
847
|
applies: function (context) {
|
|
799
|
-
return context
|
|
848
|
+
return context?.contentType === "article";
|
|
800
849
|
},
|
|
801
850
|
message: `No extra whitespace at the end of content blocks.`
|
|
802
851
|
});
|
|
@@ -976,9 +1025,13 @@ var ImageWidget = Rule.makeRule({
|
|
|
976
1025
|
if (state.currentNode().widgetType !== "image") {
|
|
977
1026
|
return;
|
|
978
1027
|
}
|
|
1028
|
+
const nodeId = state.currentNode().id;
|
|
1029
|
+
if (!nodeId) {
|
|
1030
|
+
return;
|
|
1031
|
+
}
|
|
979
1032
|
|
|
980
1033
|
// If it can't find a definition for the widget it does nothing
|
|
981
|
-
const widget = context && context.widgets && context.widgets[
|
|
1034
|
+
const widget = context && context.widgets && context.widgets[nodeId];
|
|
982
1035
|
if (!widget) {
|
|
983
1036
|
return;
|
|
984
1037
|
}
|
|
@@ -1062,7 +1115,7 @@ var MathAlignLinebreaks = Rule.makeRule({
|
|
|
1062
1115
|
const index = text.indexOf("\\\\");
|
|
1063
1116
|
if (index === -1) {
|
|
1064
1117
|
// No more backslash pairs, so we found no lint
|
|
1065
|
-
return
|
|
1118
|
+
return;
|
|
1066
1119
|
}
|
|
1067
1120
|
text = text.substring(index + 2);
|
|
1068
1121
|
|
|
@@ -1158,6 +1211,31 @@ nested lists are hard to read on mobile devices;
|
|
|
1158
1211
|
do not use additional indentation.`
|
|
1159
1212
|
});
|
|
1160
1213
|
|
|
1214
|
+
var StaticWidgetInQuestionStem = Rule.makeRule({
|
|
1215
|
+
name: "static-widget-in-question-stem",
|
|
1216
|
+
severity: Rule.Severity.WARNING,
|
|
1217
|
+
selector: "widget",
|
|
1218
|
+
lint: (state, content, nodes, match, context) => {
|
|
1219
|
+
if (context?.contentType !== "exercise") {
|
|
1220
|
+
return;
|
|
1221
|
+
}
|
|
1222
|
+
if (context.stack.includes("hint")) {
|
|
1223
|
+
return;
|
|
1224
|
+
}
|
|
1225
|
+
const nodeId = state.currentNode().id;
|
|
1226
|
+
if (!nodeId) {
|
|
1227
|
+
return;
|
|
1228
|
+
}
|
|
1229
|
+
const widget = context?.widgets?.[nodeId];
|
|
1230
|
+
if (!widget) {
|
|
1231
|
+
return;
|
|
1232
|
+
}
|
|
1233
|
+
if (widget.static) {
|
|
1234
|
+
return `Widget in question stem is static (non-interactive).`;
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
});
|
|
1238
|
+
|
|
1161
1239
|
var TableMissingCells = Rule.makeRule({
|
|
1162
1240
|
name: "table-missing-cells",
|
|
1163
1241
|
severity: Rule.Severity.WARNING,
|
|
@@ -1205,7 +1283,7 @@ do not put widgets inside of tables.`
|
|
|
1205
1283
|
});
|
|
1206
1284
|
|
|
1207
1285
|
// TODO(davidflanagan):
|
|
1208
|
-
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, MathWithoutDollars, UnbalancedCodeDelimiters, ImageSpacesAroundUrls, ImageWidget];
|
|
1286
|
+
var AllRules = [AbsoluteUrl, BlockquotedMath, BlockquotedWidget, DoubleSpacingAfterTerminal, ExpressionWidget, ExtraContentSpacing, HeadingLevel1, HeadingLevelSkip, HeadingSentenceCase, HeadingTitleCase, ImageAltText, ImageInTable, LinkClickHere, LongParagraph, MathAdjacent, MathAlignExtraBreak, MathAlignLinebreaks, MathEmpty, MathFontSize, MathFrac, MathNested, MathStartsWithSpace, MathTextEmpty, NestedLists, StaticWidgetInQuestionStem, TableMissingCells, UnescapedDollar, WidgetInTable, MathWithoutDollars, UnbalancedCodeDelimiters, ImageSpacesAroundUrls, ImageWidget];
|
|
1209
1287
|
|
|
1210
1288
|
/**
|
|
1211
1289
|
* TreeTransformer is a class for traversing and transforming trees. Create a
|
|
@@ -1752,7 +1830,7 @@ class Stack {
|
|
|
1752
1830
|
|
|
1753
1831
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
1754
1832
|
const libName = "@khanacademy/perseus-linter";
|
|
1755
|
-
const libVersion = "1.
|
|
1833
|
+
const libVersion = "1.2.0";
|
|
1756
1834
|
perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
1757
1835
|
|
|
1758
1836
|
// Define the shape of the linter context object that is passed through the
|