@khanacademy/perseus-linter 1.1.0 → 1.2.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/dist/es/index.js CHANGED
@@ -2,18 +2,13 @@ import { PerseusError, Errors, addLibraryVersionToPerseusDebug } from '@khanacad
2
2
  import PropTypes from 'prop-types';
3
3
 
4
4
  function _extends() {
5
- _extends = Object.assign ? Object.assign.bind() : function (target) {
6
- for (var i = 1; i < arguments.length; i++) {
7
- var source = arguments[i];
8
- for (var key in source) {
9
- if (Object.prototype.hasOwnProperty.call(source, key)) {
10
- target[key] = source[key];
11
- }
12
- }
5
+ return _extends = Object.assign ? Object.assign.bind() : function (n) {
6
+ for (var e = 1; e < arguments.length; e++) {
7
+ var t = arguments[e];
8
+ for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]);
13
9
  }
14
- return target;
15
- };
16
- return _extends.apply(this, arguments);
10
+ return n;
11
+ }, _extends.apply(null, arguments);
17
12
  }
18
13
 
19
14
  /* eslint-disable no-useless-escape */
@@ -804,12 +799,62 @@ var DoubleSpacingAfterTerminal = Rule.makeRule({
804
799
  any other kind of terminal punctuation.`
805
800
  });
806
801
 
802
+ function buttonNotInButtonSet(name, set) {
803
+ return `Answer requires a button not found in the button sets: ${name} (in ${set})`;
804
+ }
805
+ const stringToButtonSet = {
806
+ "\\sqrt": "prealgebra",
807
+ "\\sin": "trig",
808
+ "\\cos": "trig",
809
+ "\\tan": "trig",
810
+ "\\log": "logarithms",
811
+ "\\ln": "logarithms"
812
+ };
813
+
814
+ /**
815
+ * Rule to make sure that Expression questions that require
816
+ * a specific math symbol to answer have that math symbol
817
+ * available in the keypad (desktop learners can use a keyboard,
818
+ * but mobile learners must use the MathInput keypad)
819
+ */
820
+ var ExpressionWidget = Rule.makeRule({
821
+ name: "expression-widget",
822
+ severity: Rule.Severity.WARNING,
823
+ selector: "widget",
824
+ lint: function (state, content, nodes, match, context) {
825
+ var _context$widgets;
826
+ // This rule only looks at image widgets
827
+ if (state.currentNode().widgetType !== "expression") {
828
+ return;
829
+ }
830
+ const nodeId = state.currentNode().id;
831
+ if (!nodeId) {
832
+ return;
833
+ }
834
+
835
+ // If it can't find a definition for the widget it does nothing
836
+ const widget = context == null || (_context$widgets = context.widgets) == null ? void 0 : _context$widgets[nodeId];
837
+ if (!widget) {
838
+ return;
839
+ }
840
+ const answers = widget.options.answerForms;
841
+ const buttons = widget.options.buttonSets;
842
+ for (const answer of answers) {
843
+ for (const [str, set] of Object.entries(stringToButtonSet)) {
844
+ if (answer.value.includes(str) && !buttons.includes(set)) {
845
+ return buttonNotInButtonSet(str, set);
846
+ }
847
+ }
848
+ }
849
+ }
850
+ });
851
+
807
852
  var ExtraContentSpacing = Rule.makeRule({
808
853
  name: "extra-content-spacing",
809
854
  selector: "paragraph",
810
855
  pattern: /\s+$/,
811
856
  applies: function (context) {
812
- return context.contentType === "article";
857
+ return (context == null ? void 0 : context.contentType) === "article";
813
858
  },
814
859
  message: `No extra whitespace at the end of content blocks.`
815
860
  });
@@ -989,9 +1034,13 @@ var ImageWidget = Rule.makeRule({
989
1034
  if (state.currentNode().widgetType !== "image") {
990
1035
  return;
991
1036
  }
1037
+ const nodeId = state.currentNode().id;
1038
+ if (!nodeId) {
1039
+ return;
1040
+ }
992
1041
 
993
1042
  // If it can't find a definition for the widget it does nothing
994
- const widget = context && context.widgets && context.widgets[state.currentNode().id];
1043
+ const widget = context && context.widgets && context.widgets[nodeId];
995
1044
  if (!widget) {
996
1045
  return;
997
1046
  }
@@ -1075,7 +1124,7 @@ var MathAlignLinebreaks = Rule.makeRule({
1075
1124
  const index = text.indexOf("\\\\");
1076
1125
  if (index === -1) {
1077
1126
  // No more backslash pairs, so we found no lint
1078
- return null;
1127
+ return;
1079
1128
  }
1080
1129
  text = text.substring(index + 2);
1081
1130
 
@@ -1177,13 +1226,17 @@ var StaticWidgetInQuestionStem = Rule.makeRule({
1177
1226
  selector: "widget",
1178
1227
  lint: (state, content, nodes, match, context) => {
1179
1228
  var _context$widgets;
1180
- if (context.contentType !== "exercise") {
1229
+ if ((context == null ? void 0 : context.contentType) !== "exercise") {
1181
1230
  return;
1182
1231
  }
1183
1232
  if (context.stack.includes("hint")) {
1184
1233
  return;
1185
1234
  }
1186
- const widget = context == null || (_context$widgets = context.widgets) == null ? void 0 : _context$widgets[state.currentNode().id];
1235
+ const nodeId = state.currentNode().id;
1236
+ if (!nodeId) {
1237
+ return;
1238
+ }
1239
+ const widget = context == null || (_context$widgets = context.widgets) == null ? void 0 : _context$widgets[nodeId];
1187
1240
  if (!widget) {
1188
1241
  return;
1189
1242
  }
@@ -1240,7 +1293,7 @@ do not put widgets inside of tables.`
1240
1293
  });
1241
1294
 
1242
1295
  // TODO(davidflanagan):
1243
- 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, StaticWidgetInQuestionStem, TableMissingCells, UnescapedDollar, WidgetInTable, MathWithoutDollars, UnbalancedCodeDelimiters, ImageSpacesAroundUrls, ImageWidget];
1296
+ 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];
1244
1297
 
1245
1298
  /**
1246
1299
  * TreeTransformer is a class for traversing and transforming trees. Create a
@@ -1781,7 +1834,7 @@ class Stack {
1781
1834
 
1782
1835
  // This file is processed by a Rollup plugin (replace) to inject the production
1783
1836
  const libName = "@khanacademy/perseus-linter";
1784
- const libVersion = "1.1.0";
1837
+ const libVersion = "1.2.1";
1785
1838
  addLibraryVersionToPerseusDebug(libName, libVersion);
1786
1839
 
1787
1840
  // Define the shape of the linter context object that is passed through the