@m2c2kit/cli 0.1.9 → 0.1.10

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/.env CHANGED
@@ -1 +1 @@
1
- CLI_VERSION=0.1.9
1
+ CLI_VERSION=0.1.10
package/dist/cli.js CHANGED
@@ -146,6 +146,10 @@ await yarg
146
146
  sourceFilePath: path.join(packageHomeFolderPath, "fonts", "roboto", "Roboto-Regular.ttf"),
147
147
  destinationFilePath: path.join(newFolderPath, "fonts", "roboto", "Roboto-Regular.ttf"),
148
148
  },
149
+ {
150
+ sourceFilePath: path.join(packageHomeFolderPath, "scripts", "post-install.mjs"),
151
+ destinationFilePath: path.join(newFolderPath, "post-install.mjs"),
152
+ },
149
153
  ];
150
154
  let errorCopyingFiles = false;
151
155
  copyFiles.forEach((c) => {
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+ import fs from "fs";
3
+ import { resolve, basename } from "path";
4
+
5
+ const { dependencies } = JSON.parse(fs.readFileSync("./package.json"));
6
+
7
+ /** If this m2c2kit app uses surveys, then copy the required css
8
+ * files from node_modules so they can be bundled */
9
+ if (Object.keys(dependencies).includes("@m2c2kit/survey")) {
10
+ // does ./css folder exist? if not, create
11
+ if (!fs.existsSync("./css")) {
12
+ fs.mkdirSync("./css");
13
+ }
14
+
15
+ const cssDistDir = "./node_modules/@m2c2kit/survey/dist/css/";
16
+ const cssFiles = fs
17
+ .readdirSync(cssDistDir, {
18
+ withFileTypes: true,
19
+ })
20
+ .filter((dirent) => !dirent.isDirectory())
21
+ .map((dirent) => resolve(cssDistDir, dirent.name));
22
+
23
+ cssFiles.forEach((file) => {
24
+ const sourceContents = fs.readFileSync(file);
25
+ fs.writeFileSync(`./css/${basename(file)}`, sourceContents);
26
+ });
27
+ }
@@ -3,12 +3,13 @@
3
3
  "version": "1.0.0",
4
4
  "scripts": {
5
5
  "serve": "rollup -c --watch --configServe",
6
- "build": "rollup -c --configProd"
6
+ "build": "rollup -c --configProd",
7
+ "postinstall": "node ./post-install.mjs"
7
8
  },
8
9
  "private": true,
9
10
  "dependencies": {
10
- "@m2c2kit/core": "0.1.7",
11
- "@m2c2kit/addons": "0.1.7"
11
+ "@m2c2kit/core": "0.1.8",
12
+ "@m2c2kit/addons": "0.1.8"
12
13
  },
13
14
  "devDependencies": {
14
15
  "rollup": "2.63.0",
@@ -58,7 +58,11 @@ export default (commandLineArgs) => {
58
58
  {
59
59
  src: "img/*",
60
60
  dest: `${outputFolder}/img`,
61
- },
61
+ },
62
+ {
63
+ src: "css/*",
64
+ dest: `${outputFolder}/css`,
65
+ },
62
66
  ],
63
67
  copyOnce: false,
64
68
  hook: "writeBundle",
@@ -1,29 +1,31 @@
1
1
  import {
2
- WebColors,
3
- Action,
4
2
  Game,
3
+ Action,
5
4
  Scene,
6
- Sprite,
5
+ Shape,
7
6
  Point,
8
7
  Label,
9
- LabelHorizontalAlignmentMode,
10
- Shape,
8
+ WebColors,
11
9
  Rect,
12
- GameOptions,
10
+ LabelHorizontalAlignmentMode,
13
11
  GameParameters,
12
+ GameOptions,
14
13
  TrialSchema,
15
14
  Session,
16
- GameTrialEvent,
17
- GameLifecycleEvent,
18
15
  SessionLifecycleEvent,
19
- EventBase,
20
- EventType
16
+ ActivityDataEvent,
17
+ ActivityLifecycleEvent,
18
+ Sprite,
21
19
  } from "@m2c2kit/core";
22
20
  import { Button, Instructions } from "@m2c2kit/addons";
23
21
 
24
22
  class {{className}} extends Game {
25
23
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
26
24
  constructor() {
25
+ /**
26
+ * These are configurable game parameters and their defaults.
27
+ * At run time, they can be changed with the setParameters() method.
28
+ */
27
29
  const defaultParameters: GameParameters = {
28
30
  ReadyTime: {
29
31
  value: 1000,
@@ -33,6 +35,12 @@ class {{className}} extends Game {
33
35
  TrialNum: { value: 3, description: "How many trials to run" },
34
36
  };
35
37
 
38
+ /**
39
+ * This describes all the data that will be generated by the assessment.
40
+ * At runtime, when a trial completes, the data will be returned to the
41
+ * session with a callback, along with this schema transformed into
42
+ * JSON Schema Draft-07 format.
43
+ */
36
44
  const demoTrialSchema: TrialSchema = {
37
45
  colorChosen: { type: "string", description: "the color that was picked" },
38
46
  correct: { type: "boolean", description: "was the answer correct?" },
@@ -47,9 +55,9 @@ class {{className}} extends Game {
47
55
  showFps: true,
48
56
  trialSchema: demoTrialSchema,
49
57
  parameters: defaultParameters,
50
- // set this color so we can see the boundaries of the game during development,
51
- // but typically we would not set this
52
- bodyBackgroundColor: WebColors.Wheat,
58
+ // You can set this color so we can see the boundaries of the game during development,
59
+ // but typically we would not set this, so it is commented out
60
+ // bodyBackgroundColor: WebColors.Wheat,
53
61
  // note: using 2:1 aspect ratio, because that is closer to modern phones
54
62
  width: 400,
55
63
  height: 800,
@@ -97,6 +105,7 @@ class {{className}} extends Game {
97
105
  textFontSize: 24,
98
106
  titleFontSize: 30,
99
107
  image: "smiley",
108
+ imageMarginBottom: 24
100
109
  },
101
110
  {
102
111
  title: "{{appName}} Demo",
@@ -301,11 +310,6 @@ class {{className}} extends Game {
301
310
  });
302
311
  startOverButton.isUserInteractionEnabled = true;
303
312
  startOverButton.onTapDown(() => {
304
- // in the setup() for the end scene, we animate the smiley sprite with
305
- // a move action. if the user taps the start over button before the
306
- // animation is completed, we should remove it by calling
307
- // removeAllActions()
308
- smileySprite.removeAllActions();
309
313
  game.initData();
310
314
  game.presentScene(getReadyScene);
311
315
  });
@@ -325,69 +329,14 @@ class {{className}} extends Game {
325
329
  });
326
330
  endScene.addChild(exitButton);
327
331
 
328
- const smileySprite = new Sprite({ imageName: "smiley" });
329
- endScene.addChild(smileySprite);
330
-
331
332
  endScene.setup(() => {
332
333
  doneLabel.text = `You did ${game.trialIndex} trials. You're done!`;
333
-
334
- // example of how to position a sprite and create an action to move it
335
- smileySprite.position = new Point(200, 500);
336
- smileySprite.run(
337
- Action.Move({ point: new Point(200, 100), duration: 3000 })
338
- );
339
334
  });
340
335
 
341
336
  game.entryScene = "instructions-01";
342
337
  }
343
338
  }
344
339
 
345
- // ===========================================================================
346
-
347
- //#region to support m2c2kit in Android WebView
348
- /** When running within an Android WebView, the below defines how the session
349
- * can communicate events back to the Android app. Note: names of this Android
350
- * namespace and its functions must match the corresponding Android code
351
- * in addJavascriptInterface() and @JavascriptInterface */
352
- // eslint-disable-next-line @typescript-eslint/no-namespace
353
- declare namespace Android {
354
- function onGameTrialComplete(gameTrialEventAsString: string): void;
355
- function onGameLifecycleChange(gameLifecycleEventAsString: string): void;
356
- function onSessionLifecycleChange(
357
- sessionLifecycleEventAsString: string
358
- ): void;
359
- /** if the Android native app will control the session execution and be
360
- * able to set custom game paraemters (which is probably what you want),
361
- * be sure that sessionManualStart() in the native code returns true */
362
- function sessionManualStart(): boolean;
363
- }
364
-
365
- function contextIsAndroidWebView(): boolean {
366
- return typeof Android !== "undefined";
367
- }
368
-
369
- function sendEventToAndroid(event: EventBase) {
370
- switch (event.eventType) {
371
- case EventType.sessionLifecycle: {
372
- Android.onSessionLifecycleChange(JSON.stringify(event));
373
- break;
374
- }
375
- case EventType.gameTrial: {
376
- Android.onGameTrialComplete(JSON.stringify(event));
377
- break;
378
- }
379
- case EventType.gameLifecycle: {
380
- Android.onGameLifecycleChange(JSON.stringify(event));
381
- break;
382
- }
383
- default:
384
- throw new Error(
385
- `attempt to send unknown event ${event.eventType} to Android`
386
- );
387
- }
388
- }
389
- //#endregion
390
-
391
340
  const game1 = new {{className}}();
392
341
  // default was 3 trials; this is how we can specify a different value
393
342
  game1.setParameters({ TrialNum: 2 });
@@ -395,68 +344,71 @@ game1.setParameters({ TrialNum: 2 });
395
344
  const session = new Session({
396
345
  activities: [game1],
397
346
  sessionCallbacks: {
398
- // onSessionLifecycleChange() will be called on events such
399
- // as when the session initialization is complete. Once initialized,
400
- // the session will automatically start, unless we're running
401
- // in an Android WebView and a manual start is desired.
402
- onSessionLifecycleChange: (event: SessionLifecycleEvent) => {
403
- if (event.initialized) {
404
- //#region to support m2c2kit in Android WebView
405
- if (contextIsAndroidWebView()) {
406
- sendEventToAndroid(event);
407
- }
408
- if (contextIsAndroidWebView() && Android.sessionManualStart()) {
409
- return;
410
- }
411
- //#endregion
347
+ /**
348
+ * onSessionLifecycleChange() will be called on events such
349
+ * as when the session initialization is complete or when it
350
+ * ends.
351
+ *
352
+ * Once initialized, the session will automatically start,
353
+ * unless we're running in an Android WebView AND a manual start
354
+ * is desired.
355
+ */
356
+ onSessionLifecycleChange: (ev: SessionLifecycleEvent) => {
357
+ if (ev.initialized) {
412
358
  session.start();
413
359
  }
414
- if (event.ended) {
360
+ if (ev.ended) {
415
361
  console.log("session ended");
416
- //#region to support m2c2kit in Android WebView
417
- if (contextIsAndroidWebView()) {
418
- sendEventToAndroid(event);
419
- }
420
- //#endregion
421
362
  }
422
363
  },
423
364
  },
424
- gameCallbacks: {
425
- // onGameTrialComplete() is where you insert code to post data to an API
426
- // or interop with a native function in the host app, if applicable
427
- onGameTrialComplete: (event: GameTrialEvent) => {
428
- console.log(`********** trial (index ${event.trialIndex}) complete`);
429
- console.log("data: " + JSON.stringify(event.gameData));
430
- console.log("trial schema: " + JSON.stringify(event.trialSchema));
431
- console.log("game parameters: " + JSON.stringify(event.gameParameters));
432
-
433
- //#region to support m2c2kit in Android WebView
434
- if (contextIsAndroidWebView()) {
435
- sendEventToAndroid(event);
436
- }
437
- //#endregion
365
+ activityCallbacks: {
366
+ /**
367
+ * onActivityDataCreate() is where you insert code to post data to an API
368
+ * or interop with a native function in the host app.
369
+ *
370
+ * newData is the data that was just generated by the completed trial
371
+ * data is all the data, cumulative of all trials, that have been generated.
372
+ *
373
+ * We separate out newData from data in case you want to alter the execution
374
+ * based on the most recent trial, e.g., maybe you want to stop after
375
+ * a certain user behavior or performance threshold in the just completed
376
+ * trial.
377
+ */
378
+ onActivityDataCreate: (ev: ActivityDataEvent) => {
379
+ console.log(`********** trial complete`);
380
+ console.log("newData: " + JSON.stringify(ev.newData));
381
+ console.log("newData schema: " + JSON.stringify(ev.newDataSchema));
382
+ console.log("data: " + JSON.stringify(ev.data));
383
+ console.log("data schema: " + JSON.stringify(ev.dataSchema));
384
+ console.log(
385
+ "activity parameters: " + JSON.stringify(ev.activityConfiguration)
386
+ );
438
387
  },
439
- onGameLifecycleChange: (event: GameLifecycleEvent) => {
440
- if (event.ended) {
441
- console.log(`ended game ${event.gameName}`);
388
+ /**
389
+ * onActivityLifecycleChange() notifies us when an activity, such
390
+ * as an assessment or a survey, has completed. Usually, however,
391
+ * we want to know when all the activities are done, so we'll
392
+ * look for the session ending via onSessionLifecycleChange
393
+ */
394
+ onActivityLifecycleChange: (ev: ActivityLifecycleEvent) => {
395
+ if (ev.ended) {
396
+ console.log(`ended activity ${ev.name}`);
442
397
  if (session.nextActivity) {
443
398
  session.advanceToNextActivity();
444
399
  } else {
445
400
  session.end();
446
401
  }
447
- //#region to support m2c2kit in Android WebView
448
- if (contextIsAndroidWebView()) {
449
- sendEventToAndroid(event);
450
- }
451
- //#endregion
452
402
  }
453
403
  },
454
404
  },
455
405
  });
456
406
 
457
- /** make session also available on window in case we want to control
407
+ /**
408
+ * Make session also available on window in case we want to control
458
409
  * the session through another means, such as other javascript or
459
- * browser code, or the Android WebView loadUrl() method */
410
+ * browser code, or the Android WebView loadUrl() method
411
+ * */
460
412
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
461
413
  (window as unknown as any).session = session;
462
414
  session.init();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@m2c2kit/cli",
3
- "version": "0.1.9",
3
+ "version": "0.1.10",
4
4
  "description": "m2c2kit command line interface",
5
5
  "module": "dist/cli.js",
6
6
  "files": [
@@ -17,7 +17,7 @@
17
17
  "build": "npm run clean && npm run compile && npm run copy-files && npm run write-dotenv",
18
18
  "compile": "tsc",
19
19
  "clean": "rimraf dist/ && rimraf build/",
20
- "copy-files": "copyfiles -f build/src/cli.js dist && copyfiles templates/* fonts/**/* dist/",
20
+ "copy-files": "copyfiles -f build/src/cli.js dist && copyfiles scripts/* templates/* fonts/**/* dist/",
21
21
  "write-dotenv": "node write-dotenv.js"
22
22
  },
23
23
  "author": "",