adapt-authoring-adaptframework 3.1.3 → 3.1.4

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.
@@ -3,7 +3,7 @@ import { App, Hook, ensureDir, writeJson } from 'adapt-authoring-core'
3
3
  import { parseObjectId } from 'adapt-authoring-mongodb'
4
4
  import { createWriteStream } from 'node:fs'
5
5
  import AdaptCli from 'adapt-cli'
6
- import { log, logDir, logMemory, copyFrameworkSource, generateLanguageManifest, applyBuildReplacements, computeVarsHash } from './utils.js'
6
+ import { log, logDir, logMemory, copyFrameworkSource, generateLanguageManifest, applyBuildReplacements, computeVarsHash, getBundledPlugins } from './utils.js'
7
7
  import BuildCache from './BuildCache.js'
8
8
  import fs from 'node:fs/promises'
9
9
  import path from 'upath'
@@ -232,16 +232,7 @@ class AdaptFrameworkBuild {
232
232
 
233
233
  const tasks = [this.copyAssets()]
234
234
  if (!contentOnly) {
235
- // preview cache is shared across courses, so include all installed plugins
236
- // — except disabled themes/menus, since only one of each can be active per
237
- // build and the framework's less:dev task globs every theme/menu in src/,
238
- // which OOMs when more than one is present (see adapt_framework#3802).
239
- const pluginsToInclude = this.isPreview
240
- ? [
241
- ...this.enabledPlugins,
242
- ...this.disabledPlugins.filter(p => p.type !== 'theme' && p.type !== 'menu')
243
- ]
244
- : this.enabledPlugins
235
+ const pluginsToInclude = getBundledPlugins(this.isPreview, this.enabledPlugins, this.disabledPlugins)
245
236
  tasks.push(copyFrameworkSource({
246
237
  destDir: this.dir,
247
238
  enabledPlugins: pluginsToInclude.map(p => p.name),
@@ -526,6 +517,8 @@ class AdaptFrameworkBuild {
526
517
  courseSchema.compiledWithDefaults(this.courseData.course.data)
527
518
  configSchema.compiledWithDefaults(this.courseData.config.data)
528
519
 
520
+ if (this.isPreview) await this.applyBundledGlobalsDefaults()
521
+
529
522
  for (const type of ['contentObject', 'article', 'block']) {
530
523
  const schemaName = type === 'contentObject' ? 'contentobject' : type
531
524
  const schema = await getSchema(schemaName)
@@ -544,6 +537,26 @@ class AdaptFrameworkBuild {
544
537
  }
545
538
  }
546
539
 
540
+ /**
541
+ * Defaults _globals for every bundled plugin. A preview bundles all installed
542
+ * plugins, so a disabled plugin's app:dataReady handler can read _globals that
543
+ * the enabled-only defaults pass leaves undefined and throw, aborting the whole
544
+ * dispatch. Only _globals is copied back (authored values preserved), matching
545
+ * grunt's schema-defaults task so a cache-hit preview equals a cache-miss build.
546
+ * @return {Promise}
547
+ */
548
+ async applyBundledGlobalsDefaults () {
549
+ const [jsonschema, contentplugin] = await App.instance.waitForModule('jsonschema', 'contentplugin')
550
+ const bundledPlugins = getBundledPlugins(this.isPreview, this.enabledPlugins, this.disabledPlugins)
551
+ const bundledSchemas = bundledPlugins
552
+ .reduce((m, p) => [...m, ...contentplugin.getPluginSchemas(p.name)], [])
553
+ const extensionFilter = s => contentplugin.isPluginSchema(s) ? bundledSchemas.includes(s) : true
554
+ const courseSchema = await jsonschema.getSchema('course', { useCache: false, extensionFilter })
555
+ const clone = structuredClone(this.courseData.course.data)
556
+ courseSchema.compiledWithDefaults(clone)
557
+ this.courseData.course.data._globals = clone._globals
558
+ }
559
+
547
560
  /**
548
561
  * Writes the language_data_manifest.js for each language dir.
549
562
  * Only needed on cache-hit builds where grunt is skipped.
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Returns the plugins bundled into a build. A preview's cache is shared across
3
+ * courses, so it bundles all installed plugins — except disabled themes/menus,
4
+ * since only one of each can be active per build and the framework's less:dev
5
+ * task globs every theme/menu in src/, which OOMs when more than one is present
6
+ * (see adapt_framework#3802). Non-preview builds bundle only enabled plugins.
7
+ * @param {Boolean} isPreview Whether this is a preview build
8
+ * @param {Array<Object>} enabledPlugins Plugins used by the course
9
+ * @param {Array<Object>} disabledPlugins Plugins installed but not used by the course
10
+ * @return {Array<Object>} The plugins to bundle
11
+ */
12
+ export function getBundledPlugins (isPreview, enabledPlugins, disabledPlugins) {
13
+ if (!isPreview) return enabledPlugins
14
+ return [
15
+ ...enabledPlugins,
16
+ ...disabledPlugins.filter(p => p.type !== 'theme' && p.type !== 'menu')
17
+ ]
18
+ }
package/lib/utils.js CHANGED
@@ -17,3 +17,4 @@ export { prebuildCache } from './utils/prebuildCache.js'
17
17
  export { generateLanguageManifest } from './utils/generateLanguageManifest.js'
18
18
  export { applyBuildReplacements } from './utils/applyBuildReplacements.js'
19
19
  export { computeVarsHash } from './utils/computeVarsHash.js'
20
+ export { getBundledPlugins } from './utils/getBundledPlugins.js'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "adapt-authoring-adaptframework",
3
- "version": "3.1.3",
3
+ "version": "3.1.4",
4
4
  "description": "Adapt framework integration for the Adapt authoring tool",
5
5
  "homepage": "https://github.com/adapt-security/adapt-authoring-adaptframework",
6
6
  "license": "GPL-3.0",
@@ -0,0 +1,61 @@
1
+ import { describe, it } from 'node:test'
2
+ import assert from 'node:assert/strict'
3
+
4
+ import { getBundledPlugins } from '../lib/utils/getBundledPlugins.js'
5
+
6
+ describe('getBundledPlugins()', () => {
7
+ const enabled = [
8
+ { name: 'adapt-contrib-text', type: 'component' },
9
+ { name: 'adapt-contrib-vanilla', type: 'theme' }
10
+ ]
11
+ const disabled = [
12
+ { name: 'adapt-contrib-pageLevelProgress', type: 'extension' },
13
+ { name: 'adapt-contrib-media', type: 'component' },
14
+ { name: 'adapt-contrib-spoor', type: 'extension' },
15
+ { name: 'some-other-theme', type: 'theme' },
16
+ { name: 'some-other-menu', type: 'menu' }
17
+ ]
18
+
19
+ it('should return only enabled plugins for a non-preview build', () => {
20
+ assert.deepEqual(getBundledPlugins(false, enabled, disabled), enabled)
21
+ })
22
+
23
+ it('should not mutate the enabled array for a non-preview build', () => {
24
+ const result = getBundledPlugins(false, enabled, disabled)
25
+ assert.equal(result, enabled)
26
+ })
27
+
28
+ it('should bundle enabled plus disabled non-theme/menu plugins for a preview', () => {
29
+ const result = getBundledPlugins(true, enabled, disabled)
30
+ assert.deepEqual(result.map(p => p.name), [
31
+ 'adapt-contrib-text',
32
+ 'adapt-contrib-vanilla',
33
+ 'adapt-contrib-pageLevelProgress',
34
+ 'adapt-contrib-media',
35
+ 'adapt-contrib-spoor'
36
+ ])
37
+ })
38
+
39
+ it('should exclude disabled themes from a preview', () => {
40
+ const result = getBundledPlugins(true, enabled, disabled)
41
+ assert.ok(!result.some(p => p.name === 'some-other-theme'))
42
+ })
43
+
44
+ it('should exclude disabled menus from a preview', () => {
45
+ const result = getBundledPlugins(true, enabled, disabled)
46
+ assert.ok(!result.some(p => p.name === 'some-other-menu'))
47
+ })
48
+
49
+ it('should keep enabled themes/menus in a preview (only disabled ones are excluded)', () => {
50
+ const result = getBundledPlugins(true, enabled, disabled)
51
+ assert.ok(result.some(p => p.name === 'adapt-contrib-vanilla' && p.type === 'theme'))
52
+ })
53
+
54
+ it('should return only enabled plugins when no plugins are disabled', () => {
55
+ assert.deepEqual(getBundledPlugins(true, enabled, []), enabled)
56
+ })
57
+
58
+ it('should return an empty array when nothing is enabled or disabled', () => {
59
+ assert.deepEqual(getBundledPlugins(true, [], []), [])
60
+ })
61
+ })