@citolab/tspci-tao 2.0.10 → 2.3.0-alpha.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/package.json CHANGED
@@ -1,14 +1,16 @@
1
1
  {
2
2
  "name": "@citolab/tspci-tao",
3
- "version": "2.0.10",
3
+ "version": "2.3.0-alpha.0",
4
4
  "description": "create a zip file that can be imported into TAO",
5
5
  "author": "patrick <patrick.deklein@cito.nl>, Marcel Hoekstra <marcel.hoekstra@cito.nl>",
6
6
  "repository": "",
7
7
  "type": "module",
8
8
  "types": "types/index.d.ts",
9
- "dependencies": {
10
- "archiver": "^5.3.0"
9
+ "devDependencies": {
10
+ "archiver": "^5.3.0",
11
+ "chalk": "5.2.0",
12
+ "inquirer": "9.2.0"
11
13
  },
12
14
  "scripts": {},
13
- "gitHead": "1fbf4b0fd1cc33ad267e67adc79d9c073885e7c7"
15
+ "gitHead": "872d3b8628f1e7e9b2568563b8aae5ffa1a818d6"
14
16
  }
@@ -12,8 +12,6 @@ export const bundle = () => {
12
12
  // AND icon WHICH CAN BE REFERENCED TO A SVG TO OVERRIDE THE 'LIKE' ICON.
13
13
  const propertiesToReplace = {
14
14
  typeIdentifier: "emptytypeIdentifier",
15
- version: "1.0.0",
16
- description: "my interaction description",
17
15
  label: "label",
18
16
  short: "short",
19
17
  score: ["NONE"],
@@ -26,29 +24,50 @@ export const bundle = () => {
26
24
  }
27
25
  const rawConfigData = fs.readFileSync(config);
28
26
  const packageData = JSON.parse(rawConfigData);
29
-
27
+ let migrated = false;
30
28
  // show warning if not specified
31
29
  for (const propertyName in propertiesToReplace) {
30
+ if (!packageData.config) {
31
+ migrated = true;
32
+ packageData.config = {};
33
+ }
34
+ if (!packageData.config.tspci) {
35
+ migrated = true;
36
+ packageData.config.tspci = {};
37
+ }
38
+ if (!packageData.config.tspci[propertyName] && packageData[propertyName]) {
39
+ packageData.config.tspci[propertyName] = packageData[propertyName];
40
+ delete packageData[propertyName];
41
+ migrated = true;
42
+ }
32
43
  if (propertyName === "typeIdentifier") {
33
- if (!packageData[propertyName]) {
44
+ if (!packageData.config.tspci[propertyName]) {
34
45
  console.error(
35
46
  "'typeIdentifier' should be added as an option in package.json and should match the typeIdentifier of the PCI code file."
36
47
  );
37
48
  return;
38
- } else if (!/^[A-Za-z0-9]*$/.test(packageData[propertyName])) {
49
+ } else if (!/^[A-Za-z0-9]*$/.test(packageData.config.tspci[propertyName])) {
39
50
  console.error(
40
51
  "'typeIdentifier' can only contain (alpha)numeric characters. The pci does not work in TAO if typeindentifier contains a hyphen therefor we restrict all non (alpha)numeric characters. Make sure typeIdentifier of the PCI code file matches the typeidentier in package.json."
41
52
  );
42
53
  return;
43
54
  }
44
55
  } else {
45
- if (!packageData[propertyName])
56
+ if (!packageData.config.tspci[propertyName])
46
57
  console.warn(
47
- `${propertyName} not specified in ${packageData.name} in package.json using ${propertiesToReplace[propertyName]}`
58
+ `${propertyName} not specified in ${packageData.name} in package.json using { config: tspci: {${propertiesToReplace[propertyName]}}`
48
59
  );
49
60
  }
50
61
  }
51
62
 
63
+ propertiesToReplace.description = packageData.description;
64
+ propertiesToReplace.version = packageData.version;
65
+
66
+ if (migrated) {
67
+ console.warn('package.json has been migrated to use "{ config: { tspci: { typeIdentifier: ..., xx" properties.');
68
+ fs.writeFileSync(config, JSON.stringify(packageData, null, 2));
69
+ }
70
+
52
71
  const outputDirectory = path.join(PACKAGE_ROOT_PATH, "dist");
53
72
  const outputDirectoryTemp = path.join(outputDirectory, "tmp");
54
73
 
@@ -71,7 +90,6 @@ export const bundle = () => {
71
90
  // to override these files for a specific PCI: add them in the same structure in the tao_pci folder
72
91
  // of the pci.
73
92
 
74
-
75
93
  copyDirectoryRecursiveSync(path.join(PACKAGER_PATH, "toa_pci_default"), outputDirectoryTemp, false);
76
94
 
77
95
  // ---------------------------------------------------------------------
@@ -115,8 +133,13 @@ export const bundle = () => {
115
133
 
116
134
  // loop through properties with values that should be replaced
117
135
  // if the value is not in the config, the default value will be used
136
+ const defaultPackageJsonProperties = ["version", "description"];
118
137
  for (const propertyName in propertiesToReplace) {
119
- propertiesToReplace[propertyName] = packageData[propertyName];
138
+ if (defaultPackageJsonProperties.includes(propertyName)) {
139
+ propertiesToReplace[propertyName] = packageData[propertyName];
140
+ } else {
141
+ propertiesToReplace[propertyName] = packageData.config.tspci[propertyName];
142
+ }
120
143
  }
121
144
 
122
145
  const creatorFile = path.join(outputDirectoryTemp, "imsPciCreator.js");
@@ -245,6 +268,7 @@ export const bundle = () => {
245
268
  console.log(`created tao pci zip: ${zipName}`)
246
269
  );
247
270
  };
271
+
248
272
  function replace_string_in_file(filename, to_replace, replace_with) {
249
273
  var data = fs.readFileSync(filename, "utf8");
250
274
 
package/src/init.mjs ADDED
@@ -0,0 +1,112 @@
1
+ import fs, { cp, mkdirSync } from "fs";
2
+ import path from "path";
3
+ import readline from "readline";
4
+ import chalk from "chalk";
5
+ import inquirer from "inquirer";
6
+ function askOption(prompt) {
7
+ const rl = readline.createInterface({
8
+ input: process.stdin,
9
+ output: process.stdout,
10
+ });
11
+ return new Promise((resolve) => {
12
+ rl.question(prompt, (option) => {
13
+ rl.close();
14
+ resolve(option);
15
+ });
16
+ });
17
+ }
18
+
19
+ function selectOptions(prompt, options) {
20
+ return inquirer.prompt([
21
+ {
22
+ type: "checkbox",
23
+ message: prompt,
24
+ name: "values",
25
+ choices: options.map((o) => ({ name: o, checked: true })),
26
+ },
27
+ ]);
28
+ }
29
+
30
+ export const init = async () => {
31
+ console.log("adding TAO support to PCI");
32
+ const PACKAGE_ROOT_PATH = process.cwd();
33
+ const packageData = JSON.parse(fs.readFileSync(path.join(PACKAGE_ROOT_PATH, "package.json"), "utf8"));
34
+ const typeIdentifer = packageData.config?.tspci?.typeIdentifier;
35
+ if (!typeIdentifer) {
36
+ console.error(
37
+ "No typeIdentifier found in package.json (config { tspci: { typeIdentifier: 'my-pci' }}). Add it and make sure it matches the PCI typeIdentifier property"
38
+ );
39
+ return;
40
+ }
41
+ // get first 5 chars of identifier
42
+ const defaultShort = typeIdentifer.length > 5 ? typeIdentifer.substring(0, 5) : typeIdentifer;
43
+ const short = (await askOption(
44
+ `Enter a short name for the PCI: (default: ${defaultShort})`
45
+ )) || defaultShort;
46
+
47
+ const defaultLabel = typeIdentifer.length > 5 ? typeIdentifer.substring(0, 5) : typeIdentifer;
48
+ const label = (await askOption(
49
+ `Enter the label of the PCI: (default: ${defaultLabel})`
50
+ )) || defaultLabel;
51
+ const scoringsMethods = await selectOptions("Which scoring methods do you want to support?", [
52
+ "MATCH_CORRECT", "NONE"
53
+ ]);
54
+ const scoreMethodArray = scoringsMethods.values
55
+
56
+ // adding short, label and typeIdentifer to packageData
57
+ packageData.config.tspci.short = short;
58
+ packageData.config.tspci.label = label;
59
+ packageData.config.tspci.typeIdentifier = typeIdentifer;
60
+ packageData.config.tspci.score = scoreMethodArray;
61
+
62
+ packageData.scripts = packageData.scripts || {};
63
+ packageData.scripts["package:tao"] = "tspci --target tao";
64
+ // store packageData
65
+ fs.writeFileSync(path.join(PACKAGE_ROOT_PATH, "package.json"), JSON.stringify(packageData, null, 2), "utf8");
66
+
67
+ console.log("Adding TAO interface to PCI");
68
+ if (!packageData.source) {
69
+ console.error("Failed implementing TAO interface; No source property found in package.json.");
70
+ }
71
+
72
+ const sourceFile = fs.readFileSync(path.join(PACKAGE_ROOT_PATH, packageData.source), "utf8");
73
+ if (sourceFile.indexOf("implements IMSpci<PropTypes>, TAOpci") === -1) {
74
+ console.log("TAO interface not implemented yet; Implementing...");
75
+ if (sourceFile.indexOf("implements IMSpci<PropTypes> {") === -1) {
76
+ console.error("Cannot implement TAOpci interface automatically. Please implement it manually.");
77
+ } else {
78
+ let newSourceFile = sourceFile.replace(
79
+ "implements IMSpci<PropTypes> {",
80
+ "implements IMSpci<PropTypes>, TAOpci {"
81
+ );
82
+ // add import { TAOpci } from "@citolab/tspci-tao"; to the top of the file
83
+ newSourceFile = `import { TAOpci } from "@citolab/tspci-tao";\r\n${newSourceFile}`;
84
+ if (newSourceFile.indexOf(" QtiVariableJSON ") === -1) {
85
+ newSourceFile = `import { QtiVariableJSON } from "@citolab/tspci";\r\n${newSourceFile}`;
86
+ }
87
+ const defaultImplementation = `
88
+ off = () => {}; // called when setting correct response in tao
89
+ on = (val) => {};
90
+ trigger = (event: string, value: any) => {
91
+ this.config.properties[event] = value;
92
+ this.render();
93
+ };
94
+ resetResponse = () => {
95
+ // used in tao to reset the response. clean-up and re-render the PCI would be best.
96
+ // this.render();
97
+ };
98
+ setResponse = (response: QtiVariableJSON) => {
99
+ // used to set the response in tao. E.g. when the item author has set a correct response. And you refresh TAO it will call this method to set the response in the PCI in the score-editor.
100
+ };
101
+ `
102
+ const lastBracket = newSourceFile.lastIndexOf("}");
103
+ newSourceFile = newSourceFile.substring(0, lastBracket) + defaultImplementation + newSourceFile.substring(lastBracket);
104
+
105
+ fs.writeFileSync(path.join(PACKAGE_ROOT_PATH, packageData.source), newSourceFile, "utf8");
106
+ console.log("TAO interface implemented");
107
+ }
108
+ } else {
109
+ console.log("TAO interface already implemented");
110
+ }
111
+ };
112
+