diff --git a/Config.js b/Config.js index 88643764..175ad6de 100644 --- a/Config.js +++ b/Config.js @@ -1,5 +1,4 @@ const path = require("path"); -const {BuildEnvs} = require("./Enums.js"); const Lab = { descriptor_name: "lab-descriptor", diff --git a/.eslintrc.js b/exp_build/.eslintrc.js similarity index 95% rename from .eslintrc.js rename to exp_build/.eslintrc.js index cb25a11e..7444e52f 100644 --- a/.eslintrc.js +++ b/exp_build/.eslintrc.js @@ -1,14 +1,14 @@ -module.exports = { - "env": { - "browser": true, - "es2021": true - }, - "extends": "eslint:recommended", - "parserOptions": { - "ecmaVersion": "latest", - "sourceType": "module" - }, - "rules": { - }, - "plugins": ["only-warn"] -} +module.exports = { + "env": { + "browser": true, + "es2021": true + }, + "extends": "eslint:recommended", + "parserOptions": { + "ecmaVersion": "latest", + "sourceType": "module" + }, + "rules": { + }, + "plugins": ["only-warn"] +} diff --git a/Aim.js b/exp_build/aim.js similarity index 79% rename from Aim.js rename to exp_build/aim.js index c9217d0b..26338af7 100644 --- a/Aim.js +++ b/exp_build/aim.js @@ -1,26 +1,26 @@ -const { Task } = require("./Task.js"); -const { - UnitTypes, - ContentTypes, - validType, - validContentType, -} = require("./Enums.js"); - -class Aim extends Task { - constructor(basedir, lu_label, exp_path) { - super( - UnitTypes.AIM, - "Aim", - ContentTypes.TEXT, - exp_path, - basedir, - "aim.md", - "index.html", - [], - [], - lu_label - ); - } -} - -module.exports = { Aim }; +const { Task } = require("./task.js"); +const { + UnitTypes, + ContentTypes, + validType, + validContentType, +} = require("../enums.js"); + +class Aim extends Task { + constructor(basedir, lu_label, exp_path) { + super( + UnitTypes.AIM, + "Aim", + ContentTypes.TEXT, + exp_path, + basedir, + "aim.md", + "index.html", + [], + [], + lu_label + ); + } +} + +module.exports = { Aim }; diff --git a/expGen.js b/exp_build/exp_gen.js similarity index 87% rename from expGen.js rename to exp_build/exp_gen.js index 58f23a5c..62d4cb66 100644 --- a/expGen.js +++ b/exp_build/exp_gen.js @@ -2,10 +2,10 @@ const path = require("path"); const Handlebars = require("handlebars"); const shell = require("shelljs"); -const { Experiment } = require("./Experiment.js"); -const Config = require("./Config.js"); -const { BuildEnvs, validBuildEnv } = require("./Enums.js"); -const log = require("./Logger.js"); +const { Experiment } = require("./experiment.js"); +const Config = require("../config.js"); +const { BuildEnvs, validBuildEnv } = require("../enums.js"); +const log = require("../logger.js"); function run(src, lab_data, build_options) { log.debug(`Running build process at ${src}`); diff --git a/Experiment.js b/exp_build/experiment.js similarity index 89% rename from Experiment.js rename to exp_build/experiment.js index 207d4a95..ddbee1b9 100644 --- a/Experiment.js +++ b/exp_build/experiment.js @@ -1,245 +1,247 @@ -const path = require("path"); -const fs = require("fs"); -const { renderMarkdown } = require("./renderer.js"); -const process = require("process"); -const shell = require("shelljs"); - -const Config = require("./Config.js"); -const { LearningUnit } = require("./LearningUnit.js"); -const { Task } = require("./Task.js"); -const { - UnitTypes, - ContentTypes, - BuildEnvs, - PluginScope, -} = require("./Enums.js"); -const { Plugin } = require("./plugin"); -const log = require("./Logger"); - -function getAssessmentPath(src, units) { - let assessmentPath = []; - units.forEach((unit) => { - if (unit["unit-type"] === "lu") { - const nextSrc = path.resolve(src, unit.basedir); - let paths = getAssessmentPath(nextSrc, unit.units); - assessmentPath.push(...paths); - } - if (unit["content-type"] === "assesment" || unit["content-type"] === "assessment") { - const quiz = path.resolve(src, unit.source); - assessmentPath.push(quiz); - } - }); - return assessmentPath; -} - -class Experiment { - constructor(src) { - this.src = src; - this.descriptor = require(Experiment.descriptorPath(src)); - } - - static ui_template_path = path.resolve( - __dirname, - Config.Experiment.ui_template_name - ); - - static static_content_path = path.resolve( - __dirname, - Config.Experiment.static_content_dir - ); - - static descriptorPath(src) { - return path.resolve(src, Config.Experiment.descriptor_name); - } - - static contributorsPath(src) { - return path.resolve(`${src}/experiment`, "contributors.md"); - } - - static registerPartials(hb) { - Config.Experiment.partials.forEach(([name, file]) => { - const partial_content = fs.readFileSync( - path.resolve( - Experiment.ui_template_path, - "partials", - `${file}.handlebars` - ) - ); - hb.registerPartial(name, partial_content.toString()); - }); - } - - init(hb) { - try { - log.debug("Initializing experiment"); - const bp = Config.build_path(this.src); - shell.mkdir(path.resolve(this.src, Config.Experiment.build_dir)); - shell.cp("-R", path.resolve(this.src, Config.Experiment.exp_dir), bp); - shell.cp("-R", path.resolve(Experiment.ui_template_path, "assets"), bp); - - // Copy the Katex CSS and fonts to the build directory in assets/katex_assets - log.debug("Moving Katex assets"); - shell.mkdir(path.resolve(bp, "assets", "katex_assets")); - const katex_assets_path = path.resolve(__dirname, "node_modules", "katex", "dist"); - shell.cp( - "-R", - path.resolve(katex_assets_path, "katex.min.css"), - path.resolve(bp, "assets", "katex_assets") - ); - shell.cp( - "-R", - path.resolve(katex_assets_path, "fonts"), - path.resolve(bp, "assets", "katex_assets") - ); - - log.debug("Moving feedback file"); - shell.cp( - "-R", - path.resolve(Experiment.static_content_path, "feedback.md"), - bp - ); - - log.debug("Linking with Handlebars"); - Experiment.registerPartials(hb); - } catch (e) { - log.error("Error initializing experiment", e); - log.error("Exiting Build Process"); - process.exit(); - } - } - - validate(build_options) { - log.debug("Validating experiment"); - const buildPath = Config.build_path(this.src); - const expPath = path.resolve(this.src, Config.Experiment.exp_dir); - if (build_options.isESLINT) { - try { - log.debug("Validating with eslint"); - shell.exec(`npx eslint -c ${__dirname}/.eslintrc.js ${expPath} > ${buildPath}/eslint.log`); - } catch (e) { - log.error("Error validating with eslint", e); - } - } - if (build_options.isExpDesc) { - const descriptorPath = Experiment.descriptorPath(this.src); - const descriptor = require(descriptorPath); - try { - log.debug("Validating experiment descriptor"); - shell.exec(`node ${__dirname}/validation/validate.js -f ${descriptorPath} >> ${buildPath}/validate.log`); - } catch (e) { - log.error("Error validating experiment descriptor", e); - } - // loop through the units and validate the content - try { - log.debug("Validating Assessment files"); - const assessmentPath = getAssessmentPath(expPath, descriptor.units); - assessmentPath.forEach((file) => { - if (fs.existsSync(file)) { - // trim ep from file - const fileName = file.replace(expPath, ""); - shell.exec(`echo =${fileName} >> ${buildPath}/assesment.log`); - shell.exec( - `node ${__dirname}/validation/validate.js -f ${file} -c assessment >> ${buildPath}/assesment.log` - ); - } else { - log.error(`Assessment file ${path} does not exist`); - } - }); - } catch (e) { - log.error("Error validating Assessment files", e); - } - } - } - name() { - const name_file = fs.readFileSync( - path.resolve(Config.build_path(this.src), "experiment-name.md") - ); - return renderMarkdown(name_file.toString()); - } - - build(hb, lab_data, options) { - /* - here we are assuming that the descriptor contains a simgle object - that represents the learning unit corresponding to the experiment. - */ - log.debug(`Building experiment`); - const explu = LearningUnit.fromRecord(this.descriptor, this.src); - const exp_info = { - name: this.name(), - menu: explu.units, - src: this.src, - bp: Config.build_path(this.src) + "/", - }; - - if (options.plugins) { - exp_info.plugins = Plugin.processExpScopePlugins( - exp_info, - hb, - lab_data, - options - ); - } - explu.build(exp_info, lab_data, options); - // post build - if (options.plugins) { - Plugin.processPostBuildPlugins(exp_info, options); - } - /* - This "tmp" directory is needed because when you have a sub-directory - with the same name, it can cause issue. So, we assume that there should - not be any sub-directory with "tmp" name, and first move the contents to tmp - before moving the contents to the top level directory. - */ - const tmp_dir = path.resolve(this.src, Config.Experiment.build_dir, "tmp"); - shell.mv(path.resolve(Config.build_path(this.src)), tmp_dir); - shell.mv( - path.resolve(tmp_dir, "*"), - path.resolve(this.src, Config.Experiment.build_dir) - ); - shell.rm("-rf", tmp_dir); - } - - includeFeedback() { - const feedbackLU = { - "unit-type": "task", - label: "Feedback", - "content-type": "text", - source: "feedback.md", - target: "feedback.html", - }; - - this.descriptor.units.push(feedbackLU); - } - - includeContributors() { - const contributors = { - "unit-type": "task", - label: "Contributors", - "content-type": "text", - source: "contributors.md", - target: "contributors.html", - }; - this.descriptor.units.push(contributors); - } -} - -module.exports = { Experiment }; - -// need to handle optional menu items - -/* - -TODO - -Removing this becaiuse it is optional and we have not yet handled -the case. - - { - "target": "posttest.html", - "source": "posttest.js", - "label": "Posttest", - "unit-type": "task", - "content-type": "assesment" - }, - -*/ +const path = require("path"); +const fs = require("fs"); +const { renderMarkdown } = require("./renderer.js"); +const process = require("process"); +const shell = require("shelljs"); + +const Config = require("../config.js"); +const { LearningUnit } = require("./learning_unit.js"); +const { Task } = require("./task.js"); +const { + UnitTypes, + ContentTypes, + BuildEnvs, + PluginScope, +} = require("../enums.js"); +const { Plugin } = require("./plugin.js"); +const log = require("../logger.js"); + +function getAssessmentPath(src, units) { + let assessmentPath = []; + units.forEach((unit) => { + if (unit["unit-type"] === "lu") { + const nextSrc = path.resolve(src, unit.basedir); + let paths = getAssessmentPath(nextSrc, unit.units); + assessmentPath.push(...paths); + } + if (unit["content-type"] === "assesment" || unit["content-type"] === "assessment") { + const quiz = path.resolve(src, unit.source); + assessmentPath.push(quiz); + } + }); + return assessmentPath; +} + +class Experiment { + constructor(src) { + this.src = src; + this.descriptor = require(Experiment.descriptorPath(src)); + } + + static ui_template_path = path.resolve( + __dirname, + Config.Experiment.ui_template_name + ); + + static static_content_path = path.resolve( + __dirname, + Config.Experiment.static_content_dir + ); + + static descriptorPath(src) { + return path.resolve(src, Config.Experiment.descriptor_name); + } + + static contributorsPath(src) { + return path.resolve(`${src}/experiment`, "contributors.md"); + } + + static registerPartials(hb) { + Config.Experiment.partials.forEach(([name, file]) => { + const partial_content = fs.readFileSync( + path.resolve( + Experiment.ui_template_path, + "partials", + `${file}.handlebars` + ) + ); + hb.registerPartial(name, partial_content.toString()); + }); + } + + init(hb) { + try { + log.debug("Initializing experiment"); + const bp = Config.build_path(this.src); + shell.mkdir(path.resolve(this.src, Config.Experiment.build_dir)); + shell.cp("-R", path.resolve(this.src, Config.Experiment.exp_dir), bp); + shell.cp("-R", path.resolve(Experiment.ui_template_path, "assets"), bp); + + // Copy the Katex CSS and fonts to the build directory in assets/katex_assets + log.debug("Moving Katex assets"); + shell.mkdir(path.resolve(bp, "assets", "katex_assets")); + const pathtoKatex = require.resolve("katex") + const katex_assets_path = path.dirname(pathtoKatex); + shell.cp( + "-R", + path.resolve(katex_assets_path, "katex.min.css"), + path.resolve(bp, "assets", "katex_assets") + ); + shell.cp( + "-R", + path.resolve(katex_assets_path, "fonts"), + path.resolve(bp, "assets", "katex_assets") + ); + + log.debug("Moving feedback file"); + shell.cp( + "-R", + path.resolve(Experiment.static_content_path, "feedback.md"), + bp + ); + + log.debug("Linking with Handlebars"); + Experiment.registerPartials(hb); + } catch (e) { + log.error("Error initializing experiment", e); + log.error("Exiting Build Process"); + process.exit(); + } + } + + validate(build_options) { + log.debug("Validating experiment"); + const buildPath = Config.build_path(this.src); + const expPath = path.resolve(this.src, Config.Experiment.exp_dir); + if (build_options.isESLINT) { + try { + log.debug("Validating with eslint"); + shell.exec(`npx eslint -c ${__dirname}/.eslintrc.js ${expPath} > ${buildPath}/eslint.log`); + } catch (e) { + log.error("Error validating with eslint", e); + } + } + if (build_options.isExpDesc) { + const descriptorPath = Experiment.descriptorPath(this.src); + const descriptor = require(descriptorPath); + const pathToValidator = path.resolve(__dirname, "../validation/validate.js"); + try { + log.debug("Validating experiment descriptor"); + shell.exec(`node ${pathToValidator} -f ${descriptorPath} >> ${buildPath}/validate.log`); + } catch (e) { + log.error("Error validating experiment descriptor", e); + } + // loop through the units and validate the content + try { + log.debug("Validating Assessment files"); + const assessmentPath = getAssessmentPath(expPath, descriptor.units); + assessmentPath.forEach((file) => { + if (fs.existsSync(file)) { + // trim ep from file + const fileName = file.replace(expPath, ""); + shell.exec(`echo =${fileName} >> ${buildPath}/assesment.log`); + shell.exec( + `node ${pathToValidator} -f ${file} -c assessment >> ${buildPath}/assesment.log` + ); + } else { + log.error(`Assessment file ${path} does not exist`); + } + }); + } catch (e) { + log.error("Error validating Assessment files", e); + } + } + } + name() { + const name_file = fs.readFileSync( + path.resolve(Config.build_path(this.src), "experiment-name.md") + ); + return renderMarkdown(name_file.toString()); + } + + build(hb, lab_data, options) { + /* + here we are assuming that the descriptor contains a simgle object + that represents the learning unit corresponding to the experiment. + */ + log.debug(`Building experiment`); + const explu = LearningUnit.fromRecord(this.descriptor, this.src); + const exp_info = { + name: this.name(), + menu: explu.units, + src: this.src, + bp: Config.build_path(this.src) + "/", + }; + + if (options.plugins) { + exp_info.plugins = Plugin.processExpScopePlugins( + exp_info, + hb, + lab_data, + options + ); + } + explu.build(exp_info, lab_data, options); + // post build + if (options.plugins) { + Plugin.processPostBuildPlugins(exp_info, options); + } + /* + This "tmp" directory is needed because when you have a sub-directory + with the same name, it can cause issue. So, we assume that there should + not be any sub-directory with "tmp" name, and first move the contents to tmp + before moving the contents to the top level directory. + */ + const tmp_dir = path.resolve(this.src, Config.Experiment.build_dir, "tmp"); + shell.mv(path.resolve(Config.build_path(this.src)), tmp_dir); + shell.mv( + path.resolve(tmp_dir, "*"), + path.resolve(this.src, Config.Experiment.build_dir) + ); + shell.rm("-rf", tmp_dir); + } + + includeFeedback() { + const feedbackLU = { + "unit-type": "task", + label: "Feedback", + "content-type": "text", + source: "feedback.md", + target: "feedback.html", + }; + + this.descriptor.units.push(feedbackLU); + } + + includeContributors() { + const contributors = { + "unit-type": "task", + label: "Contributors", + "content-type": "text", + source: "contributors.md", + target: "contributors.html", + }; + this.descriptor.units.push(contributors); + } +} + +module.exports = { Experiment }; + +// need to handle optional menu items + +/* + +TODO + +Removing this becaiuse it is optional and we have not yet handled +the case. + + { + "target": "posttest.html", + "source": "posttest.js", + "label": "Posttest", + "unit-type": "task", + "content-type": "assesment" + }, + +*/ diff --git a/LearningUnit.js b/exp_build/learning_unit.js similarity index 87% rename from LearningUnit.js rename to exp_build/learning_unit.js index 2d126000..7bb56179 100644 --- a/LearningUnit.js +++ b/exp_build/learning_unit.js @@ -1,85 +1,85 @@ -const path = require("path"); -const fs = require("fs"); -const marked = require("marked"); -const process = require("process"); -const Handlebars = require("handlebars"); -const shell = require("shelljs"); - -const {Unit} = require("./Unit.js"); -const {Task} = require("./Task.js"); -const {Aim} = require("./Aim.js"); - -const {UnitTypes, ContentTypes, validType, validContentType} = require("./Enums.js"); -const log = require("./Logger"); - -class LearningUnit extends Unit { - constructor( - unit_type, - label, - exp_path, - basedir, - units - ) { - super(unit_type, label, exp_path, basedir); - if (units) { - this.units = Array.from(units).map( - (u) => { - switch(u["unit-type"]){ - case UnitTypes.LU: - return LearningUnit.fromRecord(u, exp_path); - break; - case UnitTypes.TASK: - u.basedir = basedir; - return Task.fromRecord(u, label, exp_path); - break; - case UnitTypes.AIM: - return (new Aim(this.basedir, label, exp_path)); - break; - } - }); - } - else { - units = []; - } - } - - static unit_type = UnitTypes.LU; - - static fromRecord(lu, exp_path) { - const u = new LearningUnit( - lu["unit-type"], - lu["label"], - exp_path, - lu["basedir"], - lu["units"] - ); - return u; - } - - - menuItemInfo(host_path) { - return { - label: this.label, - unit_type: this.unit_type, - id: this.label.toLowerCase().replace(/ /g, '-'), - units: this.units?this.units.map(t => { - let info = t.menuItemInfo(host_path); - //console.log(info); - return info; - }):[] - }; - } - - - build(exp_info, lab_data, options) { - log.debug(`Building LU ${this.label}`); - if (this.units.length > 0) { - this.units.forEach(u => { - u.build(exp_info, lab_data, options); - }); - } - log.debug(`Finished building LU ${this.label}`); - } -} - -module.exports = {LearningUnit}; +const path = require("path"); +const fs = require("fs"); +const marked = require("marked"); +const process = require("process"); +const Handlebars = require("handlebars"); +const shell = require("shelljs"); + +const {Unit} = require("./unit.js"); +const {Task} = require("./task.js"); +const {Aim} = require("./aim.js"); + +const {UnitTypes, ContentTypes, validType, validContentType} = require("../enums.js"); +const log = require("../logger.js"); + +class LearningUnit extends Unit { + constructor( + unit_type, + label, + exp_path, + basedir, + units + ) { + super(unit_type, label, exp_path, basedir); + if (units) { + this.units = Array.from(units).map( + (u) => { + switch(u["unit-type"]){ + case UnitTypes.LU: + return LearningUnit.fromRecord(u, exp_path); + break; + case UnitTypes.TASK: + u.basedir = basedir; + return Task.fromRecord(u, label, exp_path); + break; + case UnitTypes.AIM: + return (new Aim(this.basedir, label, exp_path)); + break; + } + }); + } + else { + units = []; + } + } + + static unit_type = UnitTypes.LU; + + static fromRecord(lu, exp_path) { + const u = new LearningUnit( + lu["unit-type"], + lu["label"], + exp_path, + lu["basedir"], + lu["units"] + ); + return u; + } + + + menuItemInfo(host_path) { + return { + label: this.label, + unit_type: this.unit_type, + id: this.label.toLowerCase().replace(/ /g, '-'), + units: this.units?this.units.map(t => { + let info = t.menuItemInfo(host_path); + //console.log(info); + return info; + }):[] + }; + } + + + build(exp_info, lab_data, options) { + log.debug(`Building LU ${this.label}`); + if (this.units.length > 0) { + this.units.forEach(u => { + u.build(exp_info, lab_data, options); + }); + } + log.debug(`Finished building LU ${this.label}`); + } +} + +module.exports = {LearningUnit}; diff --git a/exp_build/plugin-config.production.js b/exp_build/plugin-config.production.js new file mode 100644 index 00000000..bffc3087 --- /dev/null +++ b/exp_build/plugin-config.production.js @@ -0,0 +1,6 @@ +const { PluginScope } = require("../enums.js"); + +const config = [ +]; + +module.exports = config; diff --git a/plugin-config.testing.js b/exp_build/plugin-config.testing.js similarity index 86% rename from plugin-config.testing.js rename to exp_build/plugin-config.testing.js index 0bd3de5d..204253db 100644 --- a/plugin-config.testing.js +++ b/exp_build/plugin-config.testing.js @@ -1,45 +1,45 @@ -const { PluginScope } = require("./Enums.js"); -const issues = require("./assets_plugins/json/bug-report-questions.js"); - -const config = [ - { - id: "plugin-bug-report", - scope: PluginScope.PAGE, - js_modules: [ - "https://virtual-labs.github.io/svc-bug-report/client/src/bug-report.js", - ], - attributes: { - issues: JSON.stringify(issues), - }, - }, - { - id: "plugin-rating", - scope: PluginScope.PAGE, - }, - { - id: "tool-performance", - scope: PluginScope.EXPERIMENT, - repo: "https://github.com/virtual-labs/tool-performance", - template: "handlebars/performance-report.handlebars", - target: "performance-report.html", - label: "Performance Tool", - }, - { - id: "tool-validation", - scope: PluginScope.EXPERIMENT, - repo: "https://github.com/virtual-labs/tool-validation", - tag: "v1.0.0", - template: "handlebars/validator-report.handlebars", - target: "validator-report.html", - label: "Validation Tool", - }, - { - id: "tool-validation", - scope: PluginScope.POSTBUILD, - repo: "https://github.com/virtual-labs/tool-validation", - tag: "v1.0.0", - command: "npm i && node js/link_validation.js", - } -]; - -module.exports = config; +const { PluginScope } = require("../enums.js"); +const issues = require("../assets_plugins/json/bug-report-questions.js"); + +const config = [ + { + id: "plugin-bug-report", + scope: PluginScope.PAGE, + js_modules: [ + "https://virtual-labs.github.io/svc-bug-report/client/src/bug-report.js", + ], + attributes: { + issues: JSON.stringify(issues), + }, + }, + { + id: "plugin-rating", + scope: PluginScope.PAGE, + }, + { + id: "tool-performance", + scope: PluginScope.EXPERIMENT, + repo: "https://github.com/virtual-labs/tool-performance", + template: "handlebars/performance-report.handlebars", + target: "performance-report.html", + label: "Performance Tool", + }, + { + id: "tool-validation", + scope: PluginScope.EXPERIMENT, + repo: "https://github.com/virtual-labs/tool-validation", + tag: "v1.0.0", + template: "handlebars/validator-report.handlebars", + target: "validator-report.html", + label: "Validation Tool", + }, + { + id: "tool-validation", + scope: PluginScope.POSTBUILD, + repo: "https://github.com/virtual-labs/tool-validation", + tag: "v1.0.0", + command: "npm i && node js/link_validation.js", + } +]; + +module.exports = config; diff --git a/plugin.js b/exp_build/plugin.js similarity index 94% rename from plugin.js rename to exp_build/plugin.js index 7be051c9..cf789922 100644 --- a/plugin.js +++ b/exp_build/plugin.js @@ -1,231 +1,231 @@ -const path = require("path"); -const fs = require("fs"); -const shell = require("shelljs"); -const { JSDOM } = require("jsdom"); - -const Config = require("./Config.js"); -const { PluginConfig, PluginScope } = require("./Enums.js"); -const log = require("./Logger"); - -function setCurr(component, targetPath, subTaskFlag = false) { - let obj = { ...component }, - isCurrentItem = false; - - if (obj.unit_type === "aim") { - subTaskFlag = true; - isCurrentItem = true; - } - - if (!subTaskFlag) { - obj = component.menuItemInfo(targetPath); - } - - if (obj.unit_type === "lu") { - obj.units = [ - ...obj.units.map((subComponent) => - setCurr(subComponent, targetPath, true) - ), - ]; - } - - return { ...obj, isCurrentItem: isCurrentItem }; -} - -function prepareRepo(repoInfo) { - log.debug(`Preparing repo ${repoInfo.id}`); - if (!fs.existsSync(repoInfo.id)) { - if (repoInfo.tag) - { - shell.exec(`git clone --depth=1 ${repoInfo.repo} --branch ${repoInfo.tag}`,{ silent: true }); - } - else - { - shell.exec(`git clone --depth=1 ${repoInfo.repo}`,{ silent: true }); - } - } else { - shell.cd(`${repoInfo.id}`); - shell.exec(`git pull`,{ silent: true }); - shell.cd(".."); - } -} - -class Plugin { - static getConfigFileName(options_env) { - const env = options_env || BuildEnvs.TESTING; - const pluginConfigFile = `./plugin-config.${env}.js`; - return pluginConfigFile; - } - - static processExpScopePlugins(exp_info, hb, lab_data, options) { - log.debug("Processing experiment scope plugins"); - let pluginConfig = require(Plugin.getConfigFileName(options.env)); - - if(!options.isValidate) - { - pluginConfig = pluginConfig.filter((p) => p.id !== "tool-validation"); - } - - const expScopePlugins = pluginConfig.filter( - (p) => p.scope === PluginScope.EXPERIMENT - ); - - let plugins = []; - if (!fs.existsSync("plugins")) { - shell.exec("mkdir plugins"); - } - - expScopePlugins.forEach((plugin) => { - try { - shell.cd("plugins"); - prepareRepo(plugin); - shell.cd(".."); - const pluginPath = path.resolve("plugins", plugin.id); - const page_template = fs.readFileSync( - path.resolve(pluginPath, plugin.template) - ); - - let assets_path = path.relative( - path.dirname( - path.join(Config.build_path(exp_info.src), plugin.target) - ), - Config.build_path(exp_info.src) - ); - assets_path = assets_path ? assets_path : "."; - const cssModule = plugin.cssModule || PluginConfig.Default.CSS_MODULE; - const jsModule = plugin.jsModule || PluginConfig.Default.JS_MODULE; - - const page_data = { - experiment_name: exp_info.name, - assets_path: assets_path, - units: exp_info.menu.map((component) => - setCurr( - component, - path.join(Config.build_path(exp_info.src), plugin.target) - ) - ), - cssModule: path.join("plugins", plugin.id, cssModule), - jsModule: path.join("plugins", plugin.id, jsModule), - }; - - fs.writeFileSync( - path.join(Config.build_path(exp_info.src), plugin.target), - hb.compile(page_template.toString())(page_data) - ); - - plugins.push({ target: plugin.target, label: plugin.label }); - log.debug(`Plugin ${plugin.id} processed`); - } catch (e) { - log.error(`Error while processing plugin ${plugin.id}`); - log.error(e); - } - }); - - // shell.exec( - // `rsync -av "${path.resolve("./plugins")}" "${Config.build_path( - // exp_info.src - // )}" --exclude=.git` - // ); - // remove .git folder from all folders in plugins - shell.rm("-rf", path.resolve("./plugins", "**", ".git/")); - shell.cp("-r", path.resolve("./plugins"), Config.build_path(exp_info.src)); - return plugins; - } - - static preProcessPageScopePlugins(options) { - const pluginConfigFile = Plugin.getConfigFileName(options.env); - const pluginConfig = require(pluginConfigFile); - const plugins = {}; - pluginConfig - .filter((p) => p.scope === PluginScope.PAGE) - .forEach((element) => { - plugins[element.id] = element; - }); - - // console.log(plugins["plugin-bug-report"].attributes.bug_options); - return plugins; - } - static processPageScopePlugins(page, options) { - log.debug(`Processing page scope plugins`); - const pluginConfigFile = Plugin.getConfigFileName(options.env); - const pluginConfig = require(pluginConfigFile); - - const pageScopePlugins = pluginConfig.filter( - (p) => p.scope === PluginScope.PAGE - ); - - const html = fs.readFileSync(path.resolve(page.targetPath())); - const dom = new JSDOM(html); - const { document } = dom.window; - - pageScopePlugins.forEach((plugin) => { - // Render the Plugin UI component inside the parent - const pluginParent = document.getElementById(plugin.id); - log.debug(`Processing plugin ${plugin.id}`); - if (pluginParent) { - // Write code to process a template file and add to the parent - } - - // add the css-modules in the head - plugin.css_modules && - plugin.css_modules.forEach((css) => { - const cssNode = document.createElement("link"); - cssNode.rel = "stylesheet"; - cssNode.href = css; - - document.head.appendChild(cssNode); - }); - - // add the js-modules at the bottom of the body - plugin.js_modules && - plugin.js_modules.forEach((mjs) => { - const scriptNode = document.createElement("script"); - scriptNode.type = "module"; - scriptNode.src = mjs; - - document.body.appendChild(scriptNode); - }); - log.debug(`Plugin ${plugin.id} processed`); - }); - fs.writeFileSync(page.targetPath(), dom.serialize()); - } - - static processPostBuildPlugins(exp_info, options) { - log.debug("Processing post build plugins"); - let pluginConfig = require(Plugin.getConfigFileName(options.env)); - - if(!options.isValidate) - { - pluginConfig = pluginConfig.filter((p) => p.id !== "tool-validation"); - } - - const postBuildScopePlugins = pluginConfig.filter( - (p) => p.scope === PluginScope.POSTBUILD - ); - if (!fs.existsSync("plugins")) { - shell.exec("mkdir plugins"); - } - - postBuildScopePlugins.forEach((plugin) => { - try { - log.debug(`Processing plugin ${plugin.id}`); - shell.cd("plugins"); - prepareRepo(plugin); - shell.cd(`${plugin.id}`); - try{ - shell.exec(`${plugin.command} ${exp_info.bp}`,{ silent: true }); - } catch(e) { - log.error(`Error while executing command ${plugin.command}`); - log.error(e); - } - shell.cd(".."); - shell.cd(".."); - log.debug(`Plugin ${plugin.id} processed`); - } catch (e) { - log.error(`Error while processing plugin ${plugin.id}`); - log.error(e); - } - }); - } -} - -module.exports = { Plugin }; +const path = require("path"); +const fs = require("fs"); +const shell = require("shelljs"); +const { JSDOM } = require("jsdom"); + +const Config = require("../config.js"); +const { PluginConfig, PluginScope } = require("../enums.js"); +const log = require("../logger.js"); + +function setCurr(component, targetPath, subTaskFlag = false) { + let obj = { ...component }, + isCurrentItem = false; + + if (obj.unit_type === "aim") { + subTaskFlag = true; + isCurrentItem = true; + } + + if (!subTaskFlag) { + obj = component.menuItemInfo(targetPath); + } + + if (obj.unit_type === "lu") { + obj.units = [ + ...obj.units.map((subComponent) => + setCurr(subComponent, targetPath, true) + ), + ]; + } + + return { ...obj, isCurrentItem: isCurrentItem }; +} + +function prepareRepo(repoInfo) { + log.debug(`Preparing repo ${repoInfo.id}`); + if (!fs.existsSync(repoInfo.id)) { + if (repoInfo.tag) + { + shell.exec(`git clone --depth=1 ${repoInfo.repo} --branch ${repoInfo.tag}`,{ silent: true }); + } + else + { + shell.exec(`git clone --depth=1 ${repoInfo.repo}`,{ silent: true }); + } + } else { + shell.cd(`${repoInfo.id}`); + shell.exec(`git pull`,{ silent: true }); + shell.cd(".."); + } +} + +class Plugin { + static getConfigFileName(options_env) { + const env = options_env || BuildEnvs.TESTING; + const pluginConfigFile = `./plugin-config.${env}.js`; + return pluginConfigFile; + } + + static processExpScopePlugins(exp_info, hb, lab_data, options) { + log.debug("Processing experiment scope plugins"); + let pluginConfig = require(Plugin.getConfigFileName(options.env)); + + if(!options.isValidate) + { + pluginConfig = pluginConfig.filter((p) => p.id !== "tool-validation"); + } + + const expScopePlugins = pluginConfig.filter( + (p) => p.scope === PluginScope.EXPERIMENT + ); + + let plugins = []; + if (!fs.existsSync("plugins")) { + shell.exec("mkdir plugins"); + } + + expScopePlugins.forEach((plugin) => { + try { + shell.cd("plugins"); + prepareRepo(plugin); + shell.cd(".."); + const pluginPath = path.resolve("plugins", plugin.id); + const page_template = fs.readFileSync( + path.resolve(pluginPath, plugin.template) + ); + + let assets_path = path.relative( + path.dirname( + path.join(Config.build_path(exp_info.src), plugin.target) + ), + Config.build_path(exp_info.src) + ); + assets_path = assets_path ? assets_path : "."; + const cssModule = plugin.cssModule || PluginConfig.Default.CSS_MODULE; + const jsModule = plugin.jsModule || PluginConfig.Default.JS_MODULE; + + const page_data = { + experiment_name: exp_info.name, + assets_path: assets_path, + units: exp_info.menu.map((component) => + setCurr( + component, + path.join(Config.build_path(exp_info.src), plugin.target) + ) + ), + cssModule: path.join("plugins", plugin.id, cssModule), + jsModule: path.join("plugins", plugin.id, jsModule), + }; + + fs.writeFileSync( + path.join(Config.build_path(exp_info.src), plugin.target), + hb.compile(page_template.toString())(page_data) + ); + + plugins.push({ target: plugin.target, label: plugin.label }); + log.debug(`Plugin ${plugin.id} processed`); + } catch (e) { + log.error(`Error while processing plugin ${plugin.id}`); + log.error(e); + } + }); + + // shell.exec( + // `rsync -av "${path.resolve("./plugins")}" "${Config.build_path( + // exp_info.src + // )}" --exclude=.git` + // ); + // remove .git folder from all folders in plugins + shell.rm("-rf", path.resolve("./plugins", "**", ".git/")); + shell.cp("-r", path.resolve("./plugins"), Config.build_path(exp_info.src)); + return plugins; + } + + static preProcessPageScopePlugins(options) { + const pluginConfigFile = Plugin.getConfigFileName(options.env); + const pluginConfig = require(pluginConfigFile); + const plugins = {}; + pluginConfig + .filter((p) => p.scope === PluginScope.PAGE) + .forEach((element) => { + plugins[element.id] = element; + }); + + // console.log(plugins["plugin-bug-report"].attributes.bug_options); + return plugins; + } + static processPageScopePlugins(page, options) { + log.debug(`Processing page scope plugins`); + const pluginConfigFile = Plugin.getConfigFileName(options.env); + const pluginConfig = require(pluginConfigFile); + + const pageScopePlugins = pluginConfig.filter( + (p) => p.scope === PluginScope.PAGE + ); + + const html = fs.readFileSync(path.resolve(page.targetPath())); + const dom = new JSDOM(html); + const { document } = dom.window; + + pageScopePlugins.forEach((plugin) => { + // Render the Plugin UI component inside the parent + const pluginParent = document.getElementById(plugin.id); + log.debug(`Processing plugin ${plugin.id}`); + if (pluginParent) { + // Write code to process a template file and add to the parent + } + + // add the css-modules in the head + plugin.css_modules && + plugin.css_modules.forEach((css) => { + const cssNode = document.createElement("link"); + cssNode.rel = "stylesheet"; + cssNode.href = css; + + document.head.appendChild(cssNode); + }); + + // add the js-modules at the bottom of the body + plugin.js_modules && + plugin.js_modules.forEach((mjs) => { + const scriptNode = document.createElement("script"); + scriptNode.type = "module"; + scriptNode.src = mjs; + + document.body.appendChild(scriptNode); + }); + log.debug(`Plugin ${plugin.id} processed`); + }); + fs.writeFileSync(page.targetPath(), dom.serialize()); + } + + static processPostBuildPlugins(exp_info, options) { + log.debug("Processing post build plugins"); + let pluginConfig = require(Plugin.getConfigFileName(options.env)); + + if(!options.isValidate) + { + pluginConfig = pluginConfig.filter((p) => p.id !== "tool-validation"); + } + + const postBuildScopePlugins = pluginConfig.filter( + (p) => p.scope === PluginScope.POSTBUILD + ); + if (!fs.existsSync("plugins")) { + shell.exec("mkdir plugins"); + } + + postBuildScopePlugins.forEach((plugin) => { + try { + log.debug(`Processing plugin ${plugin.id}`); + shell.cd("plugins"); + prepareRepo(plugin); + shell.cd(`${plugin.id}`); + try{ + shell.exec(`${plugin.command} ${exp_info.bp}`,{ silent: true }); + } catch(e) { + log.error(`Error while executing command ${plugin.command}`); + log.error(e); + } + shell.cd(".."); + shell.cd(".."); + log.debug(`Plugin ${plugin.id} processed`); + } catch (e) { + log.error(`Error while processing plugin ${plugin.id}`); + log.error(e); + } + }); + } +} + +module.exports = { Plugin }; diff --git a/renderer.js b/exp_build/renderer.js similarity index 98% rename from renderer.js rename to exp_build/renderer.js index b0950332..04bd8c92 100644 --- a/renderer.js +++ b/exp_build/renderer.js @@ -1,10 +1,10 @@ const marked = require("marked"); const katex = require("katex"); -const Config = require("./Config.js"); +const Config = require("../config.js"); const path = require("path"); const shell = require("shelljs"); const args = require("minimist")(process.argv.slice(2)); -const log = require("./Logger"); +const log = require("../logger.js"); let src = "../"; diff --git a/static_content/feedback.md b/exp_build/static_content/feedback.md similarity index 98% rename from static_content/feedback.md rename to exp_build/static_content/feedback.md index d70257c2..33fd1349 100644 --- a/static_content/feedback.md +++ b/exp_build/static_content/feedback.md @@ -1,12 +1,12 @@ -
Dear User,
- -Thanks for using Virtual Labs. Your opinion is valuable to us. To help us improve, we'd like to ask you a few questions about your experience. It will only take 3 minutes and your answers will help us make Virtual Labs better for you and other users. -
Thanks for your time !
- The Virtual Labs Team
+
Dear User,
+ +Thanks for using Virtual Labs. Your opinion is valuable to us. To help us improve, we'd like to ask you a few questions about your experience. It will only take 3 minutes and your answers will help us make Virtual Labs better for you and other users. +
Thanks for your time !
+ The Virtual Labs Team