@khanacademy/perseus-linter 4.3.9 → 4.4.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 +8 -4
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +8 -4
- package/dist/index.js.map +1 -1
- package/dist/rules/image-markdown.d.ts +10 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -4,8 +4,9 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
4
4
|
|
|
5
5
|
var perseusUtils = require('@khanacademy/perseus-utils');
|
|
6
6
|
var perseusCore = require('@khanacademy/perseus-core');
|
|
7
|
+
var pureMarkdown = require('@khanacademy/pure-markdown');
|
|
7
8
|
|
|
8
|
-
const libName="@khanacademy/perseus-linter";const libVersion="4.
|
|
9
|
+
const libName="@khanacademy/perseus-linter";const libVersion="4.4.0";perseusUtils.addLibraryVersionToPerseusDebug(libName,libVersion);
|
|
9
10
|
|
|
10
11
|
const linterContextDefault={contentType:"",highlightLint:false,paths:[],stack:[]};
|
|
11
12
|
|
|
@@ -52,6 +53,10 @@ This image's alt text is only ${image.alt.length} characters long.`}}});
|
|
|
52
53
|
var ImageInTable = Rule.makeRule({name:"image-in-table",severity:Rule.Severity.BULK_WARNING,selector:"table image",message:`Image in table:
|
|
53
54
|
do not put images inside of tables.`});
|
|
54
55
|
|
|
56
|
+
var ImageMarkdown = Rule.makeRule({name:"image-markdown",severity:Rule.Severity.WARNING,selector:"image",lint:function(state,content,nodes,match,context){if(context?.stack&&context.stack.includes("widget")){return null}const parsedMarkdown=pureMarkdown.parse(context?.content||"",{});let hasInlineImageNode=false;pureMarkdown.traverseContent(parsedMarkdown,node=>{if(node.type==="image"){hasInlineImageNode=true;}});if(hasInlineImageNode){return `[Inline markdown image]:
|
|
57
|
+
Markdown images are not recommended - these are images that use the
|
|
58
|
+
 format. Please use the Image widget instead.`}return null}});
|
|
59
|
+
|
|
55
60
|
var ImageSpacesAroundUrls = Rule.makeRule({name:"image-spaces-around-urls",severity:Rule.Severity.ERROR,selector:"image",lint:function(state,content,nodes,match,context){const image=nodes[0];const url=image.target;if(context&&context.content){const index=context.content.indexOf(url);if(index===-1){return}if(context.content[index-1]!=="("||context.content[index+url.length]!==")"){return `Whitespace before or after image url:
|
|
56
61
|
For images, don't include any space or newlines after '(' or before ')'.
|
|
57
62
|
Whitespace in image URLs causes translation difficulties.`}}}});
|
|
@@ -62,8 +67,7 @@ var ImageWidget = Rule.makeRule({name:"image-widget",severity:Rule.Severity.WARN
|
|
|
62
67
|
for accessibility, all images should have a text description.
|
|
63
68
|
Add a description in the "Alt Text" box of the image widget.`}if(alt.trim().length<8){return `Images should have alt text:
|
|
64
69
|
for accessibility, all images should have descriptive alt text.
|
|
65
|
-
This image's alt text is only ${alt.trim().length} characters long.`}
|
|
66
|
-
Don't include math expressions in image captions.`}}});
|
|
70
|
+
This image's alt text is only ${alt.trim().length} characters long.`}}});
|
|
67
71
|
|
|
68
72
|
var InaccessibleWidget = Rule.makeRule({name:"inaccessible-widget",severity:Rule.Severity.WARNING,selector:"widget",lint:function(state,content,nodes,match,context){const node=state.currentNode();const widgetType=node.widgetType;const widgetId=node.id;if(!widgetType||!widgetId){return}const widgetInfo=context?.widgets?.[widgetId];if(!widgetInfo){return}const accessible=perseusCore.CoreWidgetRegistry.isAccessible(widgetType,widgetInfo.options);if(!accessible){return {message:`The "${widgetType}" widget is not accessible.`,start:0,end:content.length,metadata:{widgetType:widgetType,widgetId:widgetId}}}}});
|
|
69
73
|
|
|
@@ -117,7 +121,7 @@ Dollar signs must appear in pairs or be escaped as \\$`});
|
|
|
117
121
|
var WidgetInTable = Rule.makeRule({name:"widget-in-table",severity:Rule.Severity.BULK_WARNING,selector:"table widget",message:`Widget in table:
|
|
118
122
|
do not put widgets inside of tables.`});
|
|
119
123
|
|
|
120
|
-
var AllRules = [AbsoluteUrl,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,InaccessibleWidget];
|
|
124
|
+
var AllRules = [AbsoluteUrl,DoubleSpacingAfterTerminal,ImageUrlEmpty,ExpressionWidget,ExtraContentSpacing,HeadingLevel1,HeadingLevelSkip,HeadingSentenceCase,HeadingTitleCase,ImageAltText,ImageMarkdown,ImageInTable,LinkClickHere,LongParagraph,MathAdjacent,MathAlignExtraBreak,MathAlignLinebreaks,MathEmpty,MathFrac,MathNested,MathStartsWithSpace,MathTextEmpty,NestedLists,StaticWidgetInQuestionStem,TableMissingCells,UnescapedDollar,WidgetInTable,MathWithoutDollars,UnbalancedCodeDelimiters,ImageSpacesAroundUrls,ImageWidget,InaccessibleWidget];
|
|
121
125
|
|
|
122
126
|
class TreeTransformer{static isNode(n){return n&&typeof n==="object"&&typeof n.type==="string"}static isTextNode(n){return TreeTransformer.isNode(n)&&n.type==="text"&&typeof n.content==="string"}traverse(f){this._traverse(this.root,new TraversalState(this.root),f);}_traverse(n,state,f){let content="";if(TreeTransformer.isNode(n)){const node=n;state._containers.push(node);state._ancestors.push(node);if(typeof node.content==="string"){content=node.content;}const keys=Object.keys(node);keys.forEach(key=>{if(key==="type"){return}const value=node[key];if(value&&typeof value==="object"){state._indexes.push(key);content+=this._traverse(value,state,f);state._indexes.pop();}});state._currentNode=state._ancestors.pop();state._containers.pop();f(node,state,content);}else if(Array.isArray(n)){const nodes=n;state._containers.push(nodes);let index=0;while(index<nodes.length){state._indexes.push(index);content+=this._traverse(nodes[index],state,f);index=state._indexes.pop()+1;}state._containers.pop();}return content}constructor(root){this.root=root;}}class TraversalState{currentNode(){return this._currentNode||this.root}parent(){return this._ancestors.top()}ancestors(){return this._ancestors.values()}nextSibling(){const siblings=this._containers.top();if(!siblings||!Array.isArray(siblings)){return null}const index=this._indexes.top();if(siblings.length>index+1){return siblings[index+1]}return null}previousSibling(){const siblings=this._containers.top();if(!siblings||!Array.isArray(siblings)){return null}const index=this._indexes.top();if(index>0){return siblings[index-1]}return null}removeNextSibling(){const siblings=this._containers.top();if(siblings&&Array.isArray(siblings)){const index=this._indexes.top();if(siblings.length>index+1){return siblings.splice(index+1,1)[0]}}return null}replace(...replacements){const parent=this._containers.top();if(!parent){throw new perseusCore.PerseusError("Can't replace the root of the tree",perseusCore.Errors.Internal)}if(Array.isArray(parent)){const index=this._indexes.top();parent.splice(index,1,...replacements);this._indexes.pop();this._indexes.push(index+replacements.length-1);}else {const property=this._indexes.top();if(replacements.length===0){delete parent[property];}else if(replacements.length===1){parent[property]=replacements[0];}else {parent[property]=replacements;}}}hasPreviousSibling(){return Array.isArray(this._containers.top())&&this._indexes.top()>0}goToPreviousSibling(){if(!this.hasPreviousSibling()){throw new perseusCore.PerseusError("goToPreviousSibling(): node has no previous sibling",perseusCore.Errors.Internal)}this._currentNode=this.previousSibling();const index=this._indexes.pop();this._indexes.push(index-1);}hasParent(){return this._ancestors.size()!==0}goToParent(){if(!this.hasParent()){throw new perseusCore.PerseusError("goToParent(): node has no ancestor",perseusCore.Errors.NotAllowed)}this._currentNode=this._ancestors.pop();while(this._containers.size()&&this._containers.top()[this._indexes.top()]!==this._currentNode){this._containers.pop();this._indexes.pop();}}clone(){const clone=new TraversalState(this.root);clone._currentNode=this._currentNode;clone._containers=this._containers.clone();clone._indexes=this._indexes.clone();clone._ancestors=this._ancestors.clone();return clone}equals(that){return this.root===that.root&&this._currentNode===that._currentNode&&this._containers.equals(that._containers)&&this._indexes.equals(that._indexes)&&this._ancestors.equals(that._ancestors)}constructor(root){this.root=root;this._currentNode=null;this._containers=new Stack;this._indexes=new Stack;this._ancestors=new Stack;}}class Stack{push(v){this.stack.push(v);}pop(){return this.stack.pop()}top(){return this.stack[this.stack.length-1]}values(){return this.stack.slice(0)}size(){return this.stack.length}toString(){return this.stack.toString()}clone(){return new Stack(this.stack)}equals(that){if(!that||!that.stack||that.stack.length!==this.stack.length){return false}for(let i=0;i<this.stack.length;i++){if(this.stack[i]!==that.stack[i]){return false}}return true}constructor(array){this.stack=array?array.slice(0):[];}}
|
|
123
127
|
|