@khanacademy/perseus-linter 1.2.18 → 1.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/dist/index.js CHANGED
@@ -525,22 +525,27 @@ class SiblingCombinator extends SelectorCombinator {
525
525
  // This represents the type returned by String.match(). It is an
526
526
  // array of strings, but also has index:number and input:string properties.
527
527
  // TypeScript doesn't handle it well, so we punt and just use any.
528
+
528
529
  // This is the return type of the check() method of a Rule object
530
+
529
531
  // This is the return type of the lint detection function passed as the 4th
530
532
  // argument to the Rule() constructor. It can return null or a string or an
531
533
  // object containing a string and two numbers.
532
534
  // prettier-ignore
533
535
  // (prettier formats this in a way that ka-lint does not like)
536
+
534
537
  // This is the type of the lint detection function that the Rule() constructor
535
538
  // expects as its fourth argument. It is passed the TraversalState object and
536
539
  // content string that were passed to check(), and is also passed the array of
537
540
  // nodes returned by the selector match and the array of strings returned by
538
541
  // the pattern match. It should return null if no lint is detected or an
539
542
  // error message or an object contining an error message.
543
+
540
544
  // An optional check to verify whether or not a particular rule should
541
545
  // be checked by context. For example, some rules only apply in exercises,
542
546
  // and should never be applied to articles. Defaults to true, so if we
543
547
  // omit the applies function in a rule, it'll be tested everywhere.
548
+
544
549
  /**
545
550
  * A Rule object describes a Perseus lint rule. See the comment at the top of
546
551
  * this file for detailed description.
@@ -628,7 +633,6 @@ class Rule {
628
633
  if (!error) {
629
634
  return null; // No lint; we're done
630
635
  }
631
-
632
636
  if (typeof error === "string") {
633
637
  // If the lint function returned a string we assume it
634
638
  // applies to the entire content of the node and return it.
@@ -1010,6 +1014,28 @@ Whitespace in image URLs causes translation difficulties.`;
1010
1014
  }
1011
1015
  });
1012
1016
 
1017
+ var ImageUrlEmpty = Rule.makeRule({
1018
+ name: "image-url-empty",
1019
+ severity: Rule.Severity.ERROR,
1020
+ selector: "image",
1021
+ lint: function (state, content, nodes) {
1022
+ const image = nodes[0];
1023
+ const url = image.target;
1024
+
1025
+ // If no URL is provided, an infinite spinner will be shown in articles
1026
+ // overlaying the page where the image should be. This prevents the page
1027
+ // from fully loading. As a result, we check for URLS with all images.
1028
+ if (!url || !url.trim()) {
1029
+ return "Images should have a URL";
1030
+ }
1031
+
1032
+ // NOTE(TB): Ideally there would be a check to confirm the URL works
1033
+ // and leads to a valid resource, but fetching the URL would require
1034
+ // linting to be able to handle async functions, which it currently
1035
+ // cannot do.
1036
+ }
1037
+ });
1038
+
1013
1039
  // Normally we have one rule per file. But since our selector class
1014
1040
  // can't match specific widget types directly, this rule implements
1015
1041
  // a number of image widget related rules in one place. This should
@@ -1274,7 +1300,7 @@ do not put widgets inside of tables.`
1274
1300
  });
1275
1301
 
1276
1302
  // TODO(davidflanagan):
1277
- var AllRules = [AbsoluteUrl, BlockquotedMath, BlockquotedWidget, DoubleSpacingAfterTerminal, ExpressionWidget, ExtraContentSpacing, HeadingLevel1, HeadingLevelSkip, HeadingSentenceCase, HeadingTitleCase, ImageAltText, ImageInTable, LinkClickHere, LongParagraph, MathAdjacent, MathAlignExtraBreak, MathAlignLinebreaks, MathEmpty, MathFrac, MathNested, MathStartsWithSpace, MathTextEmpty, NestedLists, StaticWidgetInQuestionStem, TableMissingCells, UnescapedDollar, WidgetInTable, MathWithoutDollars, UnbalancedCodeDelimiters, ImageSpacesAroundUrls, ImageWidget];
1303
+ var AllRules = [AbsoluteUrl, BlockquotedMath, BlockquotedWidget, DoubleSpacingAfterTerminal, ImageUrlEmpty, ExpressionWidget, ExtraContentSpacing, HeadingLevel1, HeadingLevelSkip, HeadingSentenceCase, HeadingTitleCase, ImageAltText, ImageInTable, LinkClickHere, LongParagraph, MathAdjacent, MathAlignExtraBreak, MathAlignLinebreaks, MathEmpty, MathFrac, MathNested, MathStartsWithSpace, MathTextEmpty, NestedLists, StaticWidgetInQuestionStem, TableMissingCells, UnescapedDollar, WidgetInTable, MathWithoutDollars, UnbalancedCodeDelimiters, ImageSpacesAroundUrls, ImageWidget];
1278
1304
 
1279
1305
  /**
1280
1306
  * TreeTransformer is a class for traversing and transforming trees. Create a
@@ -1336,9 +1362,11 @@ var AllRules = [AbsoluteUrl, BlockquotedMath, BlockquotedWidget, DoubleSpacingAf
1336
1362
 
1337
1363
  // TreeNode is the type of a node in a parse tree. The only real requirement is
1338
1364
  // that every node has a string-valued `type` property
1365
+
1339
1366
  // TraversalCallback is the type of the callback function passed to the
1340
1367
  // traverse() method. It is invoked with node, state, and content arguments
1341
1368
  // and is expected to return nothing.
1369
+
1342
1370
  // This is the TreeTransformer class described in detail at the
1343
1371
  // top of this file.
1344
1372
  class TreeTransformer {
@@ -1819,10 +1847,51 @@ class Stack {
1819
1847
  }
1820
1848
  }
1821
1849
 
1850
+ /**
1851
+ * Adds the given perseus library version information to the __perseus_debug__
1852
+ * object and ensures that the object is attached to `globalThis` (`window` in
1853
+ * browser environments).
1854
+ *
1855
+ * This allows each library to provide runtime version information to assist in
1856
+ * debugging in production environments.
1857
+ */
1858
+ const addLibraryVersionToPerseusDebug = (libraryName, libraryVersion) => {
1859
+ // If the library version is the default value, then we don't want to
1860
+ // prefix it with a "v" to indicate that it is a version number.
1861
+ let prefix = "v";
1862
+ if (libraryVersion === "__lib_version__") {
1863
+ prefix = "";
1864
+ }
1865
+ const formattedVersion = `${prefix}${libraryVersion}`;
1866
+ if (typeof globalThis !== "undefined") {
1867
+ globalThis.__perseus_debug__ = globalThis.__perseus_debug__ ?? {};
1868
+ const existingVersionEntry = globalThis.__perseus_debug__[libraryName];
1869
+ if (existingVersionEntry) {
1870
+ // If we already have an entry and it doesn't match the registered
1871
+ // version, we morph the entry into an array and log a warning.
1872
+ if (existingVersionEntry !== formattedVersion) {
1873
+ // Existing entry might be an array already (oops, at least 2
1874
+ // versions of the library already loaded!).
1875
+ const allVersions = Array.isArray(existingVersionEntry) ? existingVersionEntry : [existingVersionEntry];
1876
+ allVersions.push(formattedVersion);
1877
+ globalThis.__perseus_debug__[libraryName] = allVersions;
1878
+
1879
+ // eslint-disable-next-line no-console
1880
+ console.warn(`Multiple versions of ${libraryName} loaded on this page: ${allVersions.sort().join(", ")}`);
1881
+ }
1882
+ } else {
1883
+ globalThis.__perseus_debug__[libraryName] = formattedVersion;
1884
+ }
1885
+ } else {
1886
+ // eslint-disable-next-line no-console
1887
+ console.warn(`globalThis not found found (${formattedVersion})`);
1888
+ }
1889
+ };
1890
+
1822
1891
  // This file is processed by a Rollup plugin (replace) to inject the production
1823
1892
  const libName = "@khanacademy/perseus-linter";
1824
- const libVersion = "1.2.18";
1825
- perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
1893
+ const libVersion = "1.3.1";
1894
+ addLibraryVersionToPerseusDebug(libName, libVersion);
1826
1895
 
1827
1896
  // Define the shape of the linter context object that is passed through the
1828
1897
  const linterContextProps = PropTypes__default["default"].shape({