@khanacademy/perseus-linter 5.2.1 → 5.3.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 +4 -2
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/rules/sorter-widget-warning.d.ts +6 -0
- package/package.json +3 -3
package/dist/es/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import * as KAS from '@khanacademy/kas';
|
|
|
4
4
|
import { parse, traverseContent } from '@khanacademy/pure-markdown';
|
|
5
5
|
import { vector } from '@khanacademy/kmath';
|
|
6
6
|
|
|
7
|
-
const libName="@khanacademy/perseus-linter";const libVersion="5.
|
|
7
|
+
const libName="@khanacademy/perseus-linter";const libVersion="5.3.0";addLibraryVersionToPerseusDebug(libName,libVersion);
|
|
8
8
|
|
|
9
9
|
const linterContextDefault={contentType:"",highlightLint:false,stack:[]};
|
|
10
10
|
|
|
@@ -141,6 +141,8 @@ var RadioWidgetError = Rule.makeRule({name:"radio-widget-error",severity:Rule.Se
|
|
|
141
141
|
|
|
142
142
|
const minCards=2;var SorterWidgetError = Rule.makeRule({name:"sorter-widget-error",severity:Rule.Severity.ERROR,selector:"widget",lint:function(state,content,nodes,match,context){if(state.currentNode().widgetType!=="sorter"){return}const nodeId=state.currentNode().id;if(!nodeId){return}const widget=context?.widgets?.[nodeId];if(!widget){return}const warnings=[];const correct=widget.options.correct??[];if(correct.length<minCards){warnings.push(`Sorter requires at least ${minCards} cards.`);}if(correct.some(card=>card.trim()==="")){warnings.push("Sorter cards cannot be blank.");}return warnings.join("\n\n")}});
|
|
143
143
|
|
|
144
|
+
const sorterMaxCards=10;const sorterMaxIdealCards=5;const sorterMaxHorizontalCards=5;var SorterWidgetWarning = Rule.makeRule({name:"sorter-widget-warning",severity:Rule.Severity.WARNING,selector:"widget",lint:function(state,content,nodes,match,context){if(state.currentNode().widgetType!=="sorter"){return}const nodeId=state.currentNode().id;if(!nodeId){return}const widget=context?.widgets?.[nodeId];if(!widget){return}const warnings=[];const options=widget.options;const{layout,correct=[]}=options;if(correct.length>sorterMaxCards){warnings.push(`Sorter cannot have more than ${sorterMaxCards} cards.`);}if(layout==="horizontal"&&correct.length>sorterMaxHorizontalCards){warnings.push(`Sorter cannot have more than ${sorterMaxHorizontalCards} cards in horizontal layout.`);}if(correct.length>sorterMaxIdealCards){warnings.push(`Having more than ${sorterMaxIdealCards} cards in Sorter is discouraged.`);}return warnings.join("\n\n")}});
|
|
145
|
+
|
|
144
146
|
var StaticWidgetInQuestionStem = Rule.makeRule({name:"static-widget-in-question-stem",severity:Rule.Severity.WARNING,selector:"widget",lint:(state,content,nodes,match,context)=>{if(context?.contentType!=="exercise"){return}if(context.stack.includes("hint")){return}const nodeId=state.currentNode().id;if(!nodeId){return}const widget=context?.widgets?.[nodeId];if(!widget){return}if(widget.static){return `Widget in question stem is static (non-interactive).`}}});
|
|
145
147
|
|
|
146
148
|
var TableMissingCells = Rule.makeRule({name:"table-missing-cells",severity:Rule.Severity.WARNING,selector:"table",lint:function(state,content,nodes,match){const table=nodes[0];const headerLength=table.header.length;const rowLengths=table.cells.map(r=>r.length);for(let r=0;r<rowLengths.length;r++){if(rowLengths[r]!==headerLength){return `Table rows don't match header:
|
|
@@ -156,7 +158,7 @@ Dollar signs must appear in pairs or be escaped as \\$`});
|
|
|
156
158
|
var WidgetInTable = Rule.makeRule({name:"widget-in-table",severity:Rule.Severity.BULK_WARNING,selector:"table widget",message:`Widget in table:
|
|
157
159
|
do not put widgets inside of tables.`});
|
|
158
160
|
|
|
159
|
-
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,ImageWidgetAltText,ImageWidgetEmptySize,LegacyGifUrl,InaccessibleWidget,RadioWidgetError,ExpressionWidgetError,FreeResponseWidgetError,MatcherWidgetError,NumericInputMissingLabel,NumericInputWidgetError,PhetSimulationWidgetError,PythonProgramWidgetError,LabelImageWidgetError,InteractiveGraphWidgetError,SorterWidgetError];
|
|
161
|
+
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,ImageWidgetAltText,ImageWidgetEmptySize,LegacyGifUrl,InaccessibleWidget,RadioWidgetError,ExpressionWidgetError,FreeResponseWidgetError,MatcherWidgetError,NumericInputMissingLabel,NumericInputWidgetError,PhetSimulationWidgetError,PythonProgramWidgetError,LabelImageWidgetError,InteractiveGraphWidgetError,SorterWidgetError,SorterWidgetWarning];
|
|
160
162
|
|
|
161
163
|
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 PerseusError("Can't replace the root of the tree",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 PerseusError("goToPreviousSibling(): node has no previous sibling",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 PerseusError("goToParent(): node has no ancestor",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):[];}}
|
|
162
164
|
|