@sybelblue/prairielearn-navigator 0.3.0 → 0.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/README.md +13 -1
- package/dist/cli.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -18,7 +18,19 @@ it. Quote globs so the shell passes them through unexpanded:
|
|
|
18
18
|
npx -y @sybelblue/prairielearn-navigator check "courseInstances/Fa26/**"
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
+
Every file it verifies is listed first: each `infoAssessment.json`, followed by
|
|
22
|
+
the `info.json` of each question it references (red if that question has an
|
|
23
|
+
error). With `--format github` this list is a collapsible log group.
|
|
24
|
+
|
|
21
25
|
```
|
|
26
|
+
courseInstances/Fa26/assessments/hw1/infoAssessment.json
|
|
27
|
+
questions/good/info.json
|
|
28
|
+
questions/topic/nested/info.json
|
|
29
|
+
questions/inlineText/info.json
|
|
30
|
+
questions/noHtml/info.json
|
|
31
|
+
questions/noInfo/info.json
|
|
32
|
+
questions/doesNotExist/info.json
|
|
33
|
+
|
|
22
34
|
courseInstances/Fa26/assessments/hw1/infoAssessment.json:13:18 error: incomplete question: missing required html file
|
|
23
35
|
|
|
|
24
36
|
11 | { "id": "topic/nested", "points": 1 },
|
|
@@ -26,7 +38,7 @@ courseInstances/Fa26/assessments/hw1/infoAssessment.json:13:18 error: incomplete
|
|
|
26
38
|
13 | { "id": "noHtml", "points": 1 },
|
|
27
39
|
| ^^^^^^ incomplete question: missing required html file
|
|
28
40
|
|
|
29
|
-
3 errors, 2 warnings in 1 file (1 file checked)
|
|
41
|
+
3 errors, 2 warnings in 1 file (1 file, 6 questions checked)
|
|
30
42
|
```
|
|
31
43
|
|
|
32
44
|
## GitHub Actions
|
package/dist/cli.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
(()=>{"use strict";var e={61(e,t,n){var o,r=this&&this.__createBinding||(Object.create?function(e,t,n,o){void 0===o&&(o=n);var r=Object.getOwnPropertyDescriptor(t,n);r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,o,r)}:function(e,t,n,o){void 0===o&&(o=n),e[o]=t[n]}),s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),i=this&&this.__importStar||(o=function(e){return o=Object.getOwnPropertyNames||function(e){var t=[];for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[t.length]=n);return t},o(e)},function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n=o(e),i=0;i<n.length;i++)"default"!==n[i]&&r(t,e,n[i]);return s(t,e),t});Object.defineProperty(t,"__esModule",{value:!0}),t.run=async function(e){if(e.includes("--help")||e.includes("-h"))return console.log(j),0;let t="pretty";const n=[];for(let o=0;o<e.length;o++){const r=e[o];let s;if("--format"===r)s=e[++o];else{if(!r.startsWith("--format=")){if(r.startsWith("-"))return console.error((0,a.styleText)("red",`Unknown option: ${r}`)),console.error(j),1;n.push(r);continue}s=r.slice(9)}if("pretty"!==s&&"github"!==s)return console.error((0,a.styleText)("red",`Invalid --format: ${s??"(missing)"}`)),1;t=s}0===n.length&&n.push(".");const o=function(e){const t=new Set,n=process.cwd();for(const o of e){if(b(o)){for(const e of O(o,n))t.add(e);continue}const e=l.resolve(n,o);if(c.existsSync(e))if(c.statSync(e).isDirectory())for(const n of c.globSync(`**/${v}`,{cwd:e}))t.add(l.resolve(e,n));else t.add(e)}return[...t].filter(e=>!y.some(t=>e.includes(t))).sort()}(n);if(0===o.length){console.error((0,a.styleText)("yellow","No infoAssessment.json files found in:"));for(const e of n)console.error((0,a.styleText)("yellow",` ${e}`));return 1}let r=0,s=0,i=0;const u=[],f=process.cwd();for(const e of o){const n=l.relative(f,e)||e,o=p(e,n),d=o.filter(e=>"error"===e.severity).length;if(o.length>0)if(i++,r+=d,s+=o.length-d,"github"===t)u.push(...o.map(m));else{const t=c.readFileSync(e,"utf-8");u.push(...o.map(e=>h(e,t)+"\n"))}"pretty"===t&&console.log(o.length>0?(0,a.styleText)(d>0?"red":"yellow",n):(0,a.styleText)("dim",n))}if(u.length>0){"pretty"===t&&console.log();for(const e of u)console.log(e)}return console.log(function(e,t,n,o=0){const r=1===n?"file":"files";if(0===e&&0===o)return(0,a.styleText)("green",`No errors found (${n} ${r} checked)`);const s=[];if(e>0){const t=1===e?"error":"errors";s.push((0,a.styleText)("red",`${e} ${t}`))}if(o>0){const e=1===o?"warning":"warnings";s.push((0,a.styleText)("yellow",`${o} ${e}`))}const i=1===t?"file":"files";return`${s.join(", ")} in ${t} ${i} (${n} ${r} checked)`}(r,i,o.length,s)),r>0?1:0};const c=i(n(24)),l=i(n(760)),a=n(975),u=n(633),f=n(157),d=n(195);function p(e,t){const n=c.readFileSync(e,"utf-8"),o=(0,f.findCourseRoot)(e);return null===o?[{file:t,line:1,column:1,endLine:1,endColumn:1,message:"not inside a course (no infoCourse.json found in any parent directory); skipped",severity:"warning"}]:(0,u.checkAssessment)(n,o).map(e=>{const o=(0,d.offsetToPosition)(n,e.startOffset),r=(0,d.offsetToPosition)(n,e.endOffset);return{file:t,line:o.line,column:o.column,endLine:r.line,endColumn:r.column,message:e.message,severity:e.severity}})}function h(e,t){const n=t.split("\n"),o=e.line-1,r="warning"===e.severity?"yellow":"red",s=(0,a.styleText)("bold",`${e.file}:${e.line}:${e.column}`)+" "+(0,a.styleText)(r,e.severity)+": "+e.message,i=Math.max(0,o-2),c=Math.min(n.length-1,e.endLine-1),l=String(c+1).length,u=e=>String(e).padStart(l),f=[s];f.push((0,a.styleText)("dim"," ".repeat(l)+" |"));for(let e=i;e<=c;e++)f.push((0,a.styleText)("dim",`${u(e+1)} |`)+" "+n[e]);const d=n[e.endLine-1]||"",[p,h]=e.line===e.endLine?[e.column-1,e.endColumn-1]:[0,d.length],g=" ".repeat(p)+"^".repeat(Math.max(1,h-p))+" "+e.message;return f.push((0,a.styleText)("dim"," ".repeat(l)+" |")+" "+(0,a.styleText)(r,g)),f.join("\n")}function g(e){return e.replace(/%/g,"%25").replace(/\r/g,"%0D").replace(/\n/g,"%0A")}function m(e){const t=[`file=${n=e.file,g(n).replace(/:/g,"%3A").replace(/,/g,"%2C")}`,`line=${e.line}`,`col=${e.column}`,`endLine=${e.endLine}`,`endColumn=${e.endColumn}`,"title=prairielearn-navigator"].join(",");var n;return`::${e.severity} ${t}::${g(e.message)}`}const y=[`${l.sep}node_modules${l.sep}`,`${l.sep}.git${l.sep}`],v="infoAssessment.json";function b(e){return/[*?[\]{}]/.test(e)}function O(e,t){return c.globSync([e,`${e.replace(/\/+$/,"")}/**/${v}`],{cwd:t}).filter(e=>l.basename(e)===v).map(e=>l.resolve(t,e))}const j='Usage: prairielearn-navigator check [options] [paths...]\n\nCheck infoAssessment.json files for missing, incomplete, and duplicate questions.\n\nArguments:\n paths Course directories to search, infoAssessment.json files, or glob\n patterns matching either (default: .). Quote globs so the shell\n does not expand them.\n\nOptions:\n --format <pretty|github> Output format (default: pretty). "github" emits\n GitHub Actions annotations.\n --help Show this help message\n\nExit status is 1 if any errors are found; warnings do not affect it.\n\nExamples:\n prairielearn-navigator check\n prairielearn-navigator check path/to/course\n prairielearn-navigator check "courseInstances/Fa26/**"\n prairielearn-navigator check "**/assessments/hw*/infoAssessment.json"\n prairielearn-navigator check --format github'},633(e,t,n){var o,r=this&&this.__createBinding||(Object.create?function(e,t,n,o){void 0===o&&(o=n);var r=Object.getOwnPropertyDescriptor(t,n);r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,o,r)}:function(e,t,n,o){void 0===o&&(o=n),e[o]=t[n]}),s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),i=this&&this.__importStar||(o=function(e){return o=Object.getOwnPropertyNames||function(e){var t=[];for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[t.length]=n);return t},o(e)},function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n=o(e),i=0;i<n.length;i++)"default"!==n[i]&&r(t,e,n[i]);return s(t,e),t});Object.defineProperty(t,"__esModule",{value:!0}),t.incompleteQuestionDiagnosticCode=void 0,t.checkDuplicateQuestionIds=u,t.checkIncompleteQuestions=f,t.checkAssessment=function(e,t){return[...u(e),...f(e,t)].sort((e,t)=>e.startOffset-t.startOffset)};const c=i(n(24)),l=n(634);t.incompleteQuestionDiagnosticCode="prairielearn-navigator-incomplete";const a=/"id"\s*:\s*"([^"]+)"/g;function u(e){const t=new Map;for(const n of e.matchAll(a)){const e=n[1],o=n.index+n[0].indexOf(e),r=t.get(e)??[];r.push(o),t.set(e,r)}const n=[];for(const[e,o]of t)if(!(o.length<=1))for(const t of o)n.push({startOffset:t,endOffset:t+e.length,message:`Duplicate question ID: "${e}" appears ${o.length} times`,severity:"warning"});return n}function f(e,n){const o=[];for(const r of e.matchAll(a)){const e=r[1],s=(0,l.questionFilePathsFromId)({courseId:n,localId:e}),i=r.index+r[0].length,a={startOffset:i-(e.length+1),endOffset:i-1},u=s.strict();if(!u.dir){o.push({...a,message:`missing question: expected question directory ${s.dir}`,severity:"error",code:t.incompleteQuestionDiagnosticCode,related:[{path:s.infoJson,message:"Expected location of info.json"}]});continue}u.infoJson||o.push({...a,message:"incomplete question: missing required JSON file",severity:"error",code:t.incompleteQuestionDiagnosticCode,related:[{path:s.infoJson,message:"Expected location of info.json"}]});let f=!1;if(u.infoJson)try{const e=JSON.parse(c.readFileSync(u.infoJson,"utf8"));f="string"==typeof e.options?.text}catch(e){console.error(`prairielearn -- error reading question info.json: ${e}`)}u.questionHtml||f||o.push({...a,message:"incomplete question: missing required html file",severity:"error",code:t.incompleteQuestionDiagnosticCode,related:[{path:s.questionHtml,message:"Expected location of question.html"}]})}return o}},157(e,t,n){var o,r=this&&this.__createBinding||(Object.create?function(e,t,n,o){void 0===o&&(o=n);var r=Object.getOwnPropertyDescriptor(t,n);r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,o,r)}:function(e,t,n,o){void 0===o&&(o=n),e[o]=t[n]}),s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),i=this&&this.__importStar||(o=function(e){return o=Object.getOwnPropertyNames||function(e){var t=[];for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[t.length]=n);return t},o(e)},function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n=o(e),i=0;i<n.length;i++)"default"!==n[i]&&r(t,e,n[i]);return s(t,e),t});Object.defineProperty(t,"__esModule",{value:!0}),t.findCourseRoot=function(e){let t=l.dirname(l.resolve(e));for(;;){if(c.existsSync(l.join(t,"infoCourse.json")))return t;const e=l.dirname(t);if(e===t)return null;t=e}};const c=i(n(24)),l=i(n(760))},195(e,t){t.offsetToPosition=function(e,t){let n=1,o=0;for(let r=0;r<t&&r<e.length;r++)"\n"===e[r]&&(n++,o=r+1);return{line:n,column:t-o+1}}},634(e,t,n){var o,r=this&&this.__createBinding||(Object.create?function(e,t,n,o){void 0===o&&(o=n);var r=Object.getOwnPropertyDescriptor(t,n);r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,o,r)}:function(e,t,n,o){void 0===o&&(o=n),e[o]=t[n]}),s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),i=this&&this.__importStar||(o=function(e){return o=Object.getOwnPropertyNames||function(e){var t=[];for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[t.length]=n);return t},o(e)},function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n=o(e),i=0;i<n.length;i++)"default"!==n[i]&&r(t,e,n[i]);return s(t,e),t});Object.defineProperty(t,"__esModule",{value:!0}),t.questionFilePathsFromId=function(e){const t=l.join(e.courseId,"questions",e.localId),n=l.join(t,"info.json"),o=l.join(t,"question.html"),r=l.join(t,"server.py");return{dir:t,infoJson:n,questionHtml:o,serverPy:r,strict(){const e={};return c.existsSync(t)&&(e.dir=t),c.existsSync(n)&&(e.infoJson=n),c.existsSync(o)&&(e.questionHtml=o),c.existsSync(r)&&(e.serverPy=r),e}}};const c=i(n(24)),l=i(n(760))},24(e){e.exports=require("node:fs")},760(e){e.exports=require("node:path")},975(e){e.exports=require("node:util")}};const t={};function n(o){const r=t[o];if(void 0!==r)return r.exports;const s=t[o]={exports:{}};return e[o].call(s.exports,s,s.exports,n),s.exports}let o={};(()=>{let e=o;Object.defineProperty(e,"__esModule",{value:!0});const t=n(975),r=n(61);!async function(){const e=process.argv.slice(2),n=e[0];switch(n){case"check":process.exit(await(0,r.run)(e.slice(1)));break;case"--help":case"-h":case void 0:console.log("Usage: prairielearn-navigator <command> [options]\n\nCommands:\n check Check infoAssessment.json files for missing and duplicate questions\n\nRun 'prairielearn-navigator <command> --help' for command-specific help."),process.exit(n?0:1);break;default:console.error((0,t.styleText)("red",`Unknown command: ${n}`)),console.error('Run "prairielearn-navigator --help" for usage.'),process.exit(1)}}()})(),module.exports=o})();
|
|
2
|
+
(()=>{"use strict";var e={61(e,t,n){var o,r=this&&this.__createBinding||(Object.create?function(e,t,n,o){void 0===o&&(o=n);var r=Object.getOwnPropertyDescriptor(t,n);r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,o,r)}:function(e,t,n,o){void 0===o&&(o=n),e[o]=t[n]}),s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),i=this&&this.__importStar||(o=function(e){return o=Object.getOwnPropertyNames||function(e){var t=[];for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[t.length]=n);return t},o(e)},function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n=o(e),i=0;i<n.length;i++)"default"!==n[i]&&r(t,e,n[i]);return s(t,e),t});Object.defineProperty(t,"__esModule",{value:!0}),t.run=async function(e){if(e.includes("--help")||e.includes("-h"))return console.log(_),0;let t="pretty";const n=[];for(let o=0;o<e.length;o++){const r=e[o];let s;if("--format"===r)s=e[++o];else{if(!r.startsWith("--format=")){if(r.startsWith("-"))return console.error((0,a.styleText)("red",`Unknown option: ${r}`)),console.error(_),1;n.push(r);continue}s=r.slice(9)}if("pretty"!==s&&"github"!==s)return console.error((0,a.styleText)("red",`Invalid --format: ${s??"(missing)"}`)),1;t=s}0===n.length&&n.push(".");const o=function(e){const t=new Set,n=process.cwd();for(const o of e){if(O(o)){for(const e of j(o,n))t.add(e);continue}const e=l.resolve(n,o);if(c.existsSync(e))if(c.statSync(e).isDirectory())for(const n of c.globSync(`**/${b}`,{cwd:e}))t.add(l.resolve(e,n));else t.add(e)}return[...t].filter(e=>!v.some(t=>e.includes(t))).sort()}(n);if(0===o.length){console.error((0,a.styleText)("yellow","No infoAssessment.json files found in:"));for(const e of n)console.error((0,a.styleText)("yellow",` ${e}`));return 1}let r=0,s=0,i=0;const u=new Set,f=[],d=[],p=process.cwd();for(const e of o){const n=l.relative(p,e)||e,{errors:o,questions:m}=h(e,n),v=o.filter(e=>"error"===e.severity).length;if(o.length>0)if(i++,r+=v,s+=o.length-v,"github"===t)d.push(...o.map(y));else{const t=c.readFileSync(e,"utf-8");d.push(...o.map(e=>g(e,t)+"\n"))}f.push(o.length>0?(0,a.styleText)(v>0?"red":"yellow",n):(0,a.styleText)("dim",n));for(const e of m){u.add(e.infoJson);const t=" "+(l.relative(p,e.infoJson)||e.infoJson);f.push((0,a.styleText)(e.hasError?"red":"dim",t))}}if("github"===t?(console.log("::group::Checked files"),f.forEach(e=>console.log(e)),console.log("::endgroup::")):f.forEach(e=>console.log(e)),d.length>0){"pretty"===t&&console.log();for(const e of d)console.log(e)}return console.log(function(e,t,n,o,r=0){const s=`${n} ${1===n?"file":"files"}, ${o} ${1===o?"question":"questions"} checked`;if(0===e&&0===r)return(0,a.styleText)("green",`No errors found (${s})`);const i=[];if(e>0){const t=1===e?"error":"errors";i.push((0,a.styleText)("red",`${e} ${t}`))}if(r>0){const e=1===r?"warning":"warnings";i.push((0,a.styleText)("yellow",`${r} ${e}`))}const c=1===t?"file":"files";return`${i.join(", ")} in ${t} ${c} (${s})`}(r,i,o.length,u.size,s)),r>0?1:0};const c=i(n(24)),l=i(n(760)),a=n(975),u=n(633),f=n(157),d=n(195),p=n(634);function h(e,t){const n=c.readFileSync(e,"utf-8"),o=(0,f.findCourseRoot)(e);if(null===o)return{errors:[{file:t,line:1,column:1,endLine:1,endColumn:1,message:"not inside a course (no infoCourse.json found in any parent directory); skipped",severity:"warning"}],questions:[]};const r=(0,u.checkAssessment)(n,o),s=new Set(r.filter(e=>"error"===e.severity).map(e=>n.slice(e.startOffset,e.endOffset))),i=(0,u.referencedQuestionIds)(n).map(e=>({infoJson:(0,p.questionFilePathsFromId)({courseId:o,localId:e}).infoJson,hasError:s.has(e)}));return{errors:r.map(e=>{const o=(0,d.offsetToPosition)(n,e.startOffset),r=(0,d.offsetToPosition)(n,e.endOffset);return{file:t,line:o.line,column:o.column,endLine:r.line,endColumn:r.column,message:e.message,severity:e.severity}}),questions:i}}function g(e,t){const n=t.split("\n"),o=e.line-1,r="warning"===e.severity?"yellow":"red",s=(0,a.styleText)("bold",`${e.file}:${e.line}:${e.column}`)+" "+(0,a.styleText)(r,e.severity)+": "+e.message,i=Math.max(0,o-2),c=Math.min(n.length-1,e.endLine-1),l=String(c+1).length,u=e=>String(e).padStart(l),f=[s];f.push((0,a.styleText)("dim"," ".repeat(l)+" |"));for(let e=i;e<=c;e++)f.push((0,a.styleText)("dim",`${u(e+1)} |`)+" "+n[e]);const d=n[e.endLine-1]||"",[p,h]=e.line===e.endLine?[e.column-1,e.endColumn-1]:[0,d.length],g=" ".repeat(p)+"^".repeat(Math.max(1,h-p))+" "+e.message;return f.push((0,a.styleText)("dim"," ".repeat(l)+" |")+" "+(0,a.styleText)(r,g)),f.join("\n")}function m(e){return e.replace(/%/g,"%25").replace(/\r/g,"%0D").replace(/\n/g,"%0A")}function y(e){const t=[`file=${n=e.file,m(n).replace(/:/g,"%3A").replace(/,/g,"%2C")}`,`line=${e.line}`,`col=${e.column}`,`endLine=${e.endLine}`,`endColumn=${e.endColumn}`,"title=prairielearn-navigator"].join(",");var n;return`::${e.severity} ${t}::${m(e.message)}`}const v=[`${l.sep}node_modules${l.sep}`,`${l.sep}.git${l.sep}`],b="infoAssessment.json";function O(e){return/[*?[\]{}]/.test(e)}function j(e,t){return c.globSync([e,`${e.replace(/\/+$/,"")}/**/${b}`],{cwd:t}).filter(e=>l.basename(e)===b).map(e=>l.resolve(t,e))}const _='Usage: prairielearn-navigator check [options] [paths...]\n\nCheck infoAssessment.json files for missing, incomplete, and duplicate questions.\n\nArguments:\n paths Course directories to search, infoAssessment.json files, or glob\n patterns matching either (default: .). Quote globs so the shell\n does not expand them.\n\nOptions:\n --format <pretty|github> Output format (default: pretty). "github" emits\n GitHub Actions annotations.\n --help Show this help message\n\nExit status is 1 if any errors are found; warnings do not affect it.\n\nExamples:\n prairielearn-navigator check\n prairielearn-navigator check path/to/course\n prairielearn-navigator check "courseInstances/Fa26/**"\n prairielearn-navigator check "**/assessments/hw*/infoAssessment.json"\n prairielearn-navigator check --format github'},633(e,t,n){var o,r=this&&this.__createBinding||(Object.create?function(e,t,n,o){void 0===o&&(o=n);var r=Object.getOwnPropertyDescriptor(t,n);r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,o,r)}:function(e,t,n,o){void 0===o&&(o=n),e[o]=t[n]}),s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),i=this&&this.__importStar||(o=function(e){return o=Object.getOwnPropertyNames||function(e){var t=[];for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[t.length]=n);return t},o(e)},function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n=o(e),i=0;i<n.length;i++)"default"!==n[i]&&r(t,e,n[i]);return s(t,e),t});Object.defineProperty(t,"__esModule",{value:!0}),t.incompleteQuestionDiagnosticCode=void 0,t.referencedQuestionIds=function(e){return[...new Set(Array.from(e.matchAll(a),e=>e[1]))]},t.checkDuplicateQuestionIds=u,t.checkIncompleteQuestions=f,t.checkAssessment=function(e,t){return[...u(e),...f(e,t)].sort((e,t)=>e.startOffset-t.startOffset)};const c=i(n(24)),l=n(634);t.incompleteQuestionDiagnosticCode="prairielearn-navigator-incomplete";const a=/"id"\s*:\s*"([^"]+)"/g;function u(e){const t=new Map;for(const n of e.matchAll(a)){const e=n[1],o=n.index+n[0].indexOf(e),r=t.get(e)??[];r.push(o),t.set(e,r)}const n=[];for(const[e,o]of t)if(!(o.length<=1))for(const t of o)n.push({startOffset:t,endOffset:t+e.length,message:`Duplicate question ID: "${e}" appears ${o.length} times`,severity:"warning"});return n}function f(e,n){const o=[];for(const r of e.matchAll(a)){const e=r[1],s=(0,l.questionFilePathsFromId)({courseId:n,localId:e}),i=r.index+r[0].length,a={startOffset:i-(e.length+1),endOffset:i-1},u=s.strict();if(!u.dir){o.push({...a,message:`missing question: expected question directory ${s.dir}`,severity:"error",code:t.incompleteQuestionDiagnosticCode,related:[{path:s.infoJson,message:"Expected location of info.json"}]});continue}u.infoJson||o.push({...a,message:"incomplete question: missing required JSON file",severity:"error",code:t.incompleteQuestionDiagnosticCode,related:[{path:s.infoJson,message:"Expected location of info.json"}]});let f=!1;if(u.infoJson)try{const e=JSON.parse(c.readFileSync(u.infoJson,"utf8"));f="string"==typeof e.options?.text}catch(e){console.error(`prairielearn -- error reading question info.json: ${e}`)}u.questionHtml||f||o.push({...a,message:"incomplete question: missing required html file",severity:"error",code:t.incompleteQuestionDiagnosticCode,related:[{path:s.questionHtml,message:"Expected location of question.html"}]})}return o}},157(e,t,n){var o,r=this&&this.__createBinding||(Object.create?function(e,t,n,o){void 0===o&&(o=n);var r=Object.getOwnPropertyDescriptor(t,n);r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,o,r)}:function(e,t,n,o){void 0===o&&(o=n),e[o]=t[n]}),s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),i=this&&this.__importStar||(o=function(e){return o=Object.getOwnPropertyNames||function(e){var t=[];for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[t.length]=n);return t},o(e)},function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n=o(e),i=0;i<n.length;i++)"default"!==n[i]&&r(t,e,n[i]);return s(t,e),t});Object.defineProperty(t,"__esModule",{value:!0}),t.findCourseRoot=function(e){let t=l.dirname(l.resolve(e));for(;;){if(c.existsSync(l.join(t,"infoCourse.json")))return t;const e=l.dirname(t);if(e===t)return null;t=e}};const c=i(n(24)),l=i(n(760))},195(e,t){t.offsetToPosition=function(e,t){let n=1,o=0;for(let r=0;r<t&&r<e.length;r++)"\n"===e[r]&&(n++,o=r+1);return{line:n,column:t-o+1}}},634(e,t,n){var o,r=this&&this.__createBinding||(Object.create?function(e,t,n,o){void 0===o&&(o=n);var r=Object.getOwnPropertyDescriptor(t,n);r&&!("get"in r?!t.__esModule:r.writable||r.configurable)||(r={enumerable:!0,get:function(){return t[n]}}),Object.defineProperty(e,o,r)}:function(e,t,n,o){void 0===o&&(o=n),e[o]=t[n]}),s=this&&this.__setModuleDefault||(Object.create?function(e,t){Object.defineProperty(e,"default",{enumerable:!0,value:t})}:function(e,t){e.default=t}),i=this&&this.__importStar||(o=function(e){return o=Object.getOwnPropertyNames||function(e){var t=[];for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[t.length]=n);return t},o(e)},function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n=o(e),i=0;i<n.length;i++)"default"!==n[i]&&r(t,e,n[i]);return s(t,e),t});Object.defineProperty(t,"__esModule",{value:!0}),t.questionFilePathsFromId=function(e){const t=l.join(e.courseId,"questions",e.localId),n=l.join(t,"info.json"),o=l.join(t,"question.html"),r=l.join(t,"server.py");return{dir:t,infoJson:n,questionHtml:o,serverPy:r,strict(){const e={};return c.existsSync(t)&&(e.dir=t),c.existsSync(n)&&(e.infoJson=n),c.existsSync(o)&&(e.questionHtml=o),c.existsSync(r)&&(e.serverPy=r),e}}};const c=i(n(24)),l=i(n(760))},24(e){e.exports=require("node:fs")},760(e){e.exports=require("node:path")},975(e){e.exports=require("node:util")}};const t={};function n(o){const r=t[o];if(void 0!==r)return r.exports;const s=t[o]={exports:{}};return e[o].call(s.exports,s,s.exports,n),s.exports}let o={};(()=>{let e=o;Object.defineProperty(e,"__esModule",{value:!0});const t=n(975),r=n(61);!async function(){const e=process.argv.slice(2),n=e[0];switch(n){case"check":process.exit(await(0,r.run)(e.slice(1)));break;case"--help":case"-h":case void 0:console.log("Usage: prairielearn-navigator <command> [options]\n\nCommands:\n check Check infoAssessment.json files for missing and duplicate questions\n\nRun 'prairielearn-navigator <command> --help' for command-specific help."),process.exit(n?0:1);break;default:console.error((0,t.styleText)("red",`Unknown command: ${n}`)),console.error('Run "prairielearn-navigator --help" for usage.'),process.exit(1)}}()})(),module.exports=o})();
|