adapt-migrations 1.2.0 → 1.4.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/api/plugins.js CHANGED
@@ -1,47 +1,47 @@
1
- import { deferOrRunWrap, successStopOrErrorWrap } from '../lib/lifecycle.js'
2
- import { valid } from 'semver'
3
-
4
- export function removePlugin (description, config) {
5
- return deferOrRunWrap(function (context) {
6
- return successStopOrErrorWrap('removePlugin', description, async () => {
7
- if (!description || !config) throw new Error('removePlugin - incorrectly configured')
8
-
9
- context.fromPlugins = context.fromPlugins.filter(plugin => plugin.name !== config.name)
10
-
11
- return true
12
- })
13
- }, { description, type: 'action' })
14
- };
15
-
16
- export function addPlugin (description, config) {
17
- return deferOrRunWrap(function (context) {
18
- return successStopOrErrorWrap('addPlugin', description, async () => {
19
- if (!description || !config) throw new Error('addPlugin - incorrectly configured')
20
- if (!valid(config.version)) throw new Error(`addPlugin - invalid version number ${config.version}`)
21
-
22
- const newPlugin = context.toPlugins.find(plugin => (plugin.name === config.name))
23
- if (!newPlugin) throw new Error(`addPlugin - ${config.name} not found`)
24
- context.fromPlugins.push(newPlugin)
25
-
26
- return true
27
- })
28
- }, { description, type: 'action' })
29
- };
30
-
31
- export function updatePlugin (description, config) {
32
- return deferOrRunWrap(function (context) {
33
- return successStopOrErrorWrap('updatePlugin', description, async () => {
34
- if (!description || !config) throw new Error('updatePlugin - incorrectly configured')
35
- if (!valid(config.version)) throw new Error(`updatePlugin - invalid version number ${config.version}`)
36
-
37
- context.fromPlugins.forEach(plugin => {
38
- if (plugin.name !== config.name) return
39
- plugin.version = config.version
40
- if (!config.framework) return
41
- plugin.framework = config.framework
42
- })
43
-
44
- return true
45
- })
46
- }, { description, type: 'action' })
47
- };
1
+ import { deferOrRunWrap, successStopOrErrorWrap } from '../lib/lifecycle.js'
2
+ import { valid } from 'semver'
3
+
4
+ export function removePlugin (description, config) {
5
+ return deferOrRunWrap(function (context) {
6
+ return successStopOrErrorWrap('removePlugin', description, async () => {
7
+ if (!description || !config) throw new Error('removePlugin - incorrectly configured')
8
+
9
+ context.fromPlugins = context.fromPlugins.filter(plugin => plugin.name !== config.name)
10
+
11
+ return true
12
+ })
13
+ }, { description, type: 'action' })
14
+ };
15
+
16
+ export function addPlugin (description, config) {
17
+ return deferOrRunWrap(function (context) {
18
+ return successStopOrErrorWrap('addPlugin', description, async () => {
19
+ if (!description || !config) throw new Error('addPlugin - incorrectly configured')
20
+ if (!valid(config.version)) throw new Error(`addPlugin - invalid version number ${config.version}`)
21
+
22
+ const newPlugin = context.toPlugins.find(plugin => (plugin.name === config.name))
23
+ if (!newPlugin) throw new Error(`addPlugin - ${config.name} not found`)
24
+ context.fromPlugins.push(newPlugin)
25
+
26
+ return true
27
+ })
28
+ }, { description, type: 'action' })
29
+ };
30
+
31
+ export function updatePlugin (description, config) {
32
+ return deferOrRunWrap(function (context) {
33
+ return successStopOrErrorWrap('updatePlugin', description, async () => {
34
+ if (!description || !config) throw new Error('updatePlugin - incorrectly configured')
35
+ if (!valid(config.version)) throw new Error(`updatePlugin - invalid version number ${config.version}`)
36
+
37
+ context.fromPlugins.forEach(plugin => {
38
+ if (plugin.name !== config.name) return
39
+ plugin.version = config.version
40
+ if (!config.framework) return
41
+ plugin.framework = config.framework
42
+ })
43
+
44
+ return true
45
+ })
46
+ }, { description, type: 'action' })
47
+ };
package/api/tests.js CHANGED
@@ -1,57 +1,56 @@
1
- import TaskTest from '../lib/TaskTest.js'
2
- import { deferOrRunWrap } from '../lib/lifecycle.js'
3
- import Logger from '../lib/Logger.js'
4
-
5
- const logger = Logger.getInstance();
6
-
7
- export function testSuccessWhere (description, {
8
- fromPlugins,
9
- toPlugins,
10
- content
11
- }) {
12
- return deferOrRunWrap(() => {
13
- logger.debug(`Tests -- testSuccessWhere ${description}`)
14
- return new TaskTest({
15
- description,
16
- shouldRun: true,
17
- fromPlugins,
18
- toPlugins,
19
- content
20
- })
21
- }, { type: 'test' })
22
- };
23
-
24
- export function testStopWhere (description, {
25
- fromPlugins,
26
- toPlugins,
27
- content
28
- }) {
29
- return deferOrRunWrap(() => {
30
- logger.debug(`Tests -- testStopWhere ${description}`)
31
- return new TaskTest({
32
- description,
33
- shouldStop: true,
34
- shouldRun: false,
35
- fromPlugins,
36
- toPlugins,
37
- content
38
- })
39
- }, { type: 'test' })
40
- };
41
-
42
- export function testErrorWhere (description, {
43
- fromPlugins,
44
- toPlugins,
45
- content
46
- }) {
47
- return deferOrRunWrap(() => {
48
- logger.debug(`Tests -- testErrorWhere ${description}`)
49
- return new TaskTest({
50
- description,
51
- shouldError: true,
52
- fromPlugins,
53
- toPlugins,
54
- content
55
- })
56
- }, { type: 'test' })
57
- };
1
+ import TaskTest from '../lib/TaskTest.js'
2
+ import { deferOrRunWrap } from '../lib/lifecycle.js'
3
+ import Logger from '../lib/Logger.js'
4
+
5
+ const logger = Logger.getInstance();
6
+
7
+ export function testSuccessWhere (description, {
8
+ fromPlugins,
9
+ toPlugins,
10
+ content
11
+ }) {
12
+ return deferOrRunWrap(() => {
13
+ logger.info(`Test success where -- ${description}`)
14
+ return new TaskTest({
15
+ description,
16
+ shouldRun: true,
17
+ fromPlugins,
18
+ toPlugins,
19
+ content
20
+ })
21
+ }, { type: 'test' })
22
+ };
23
+
24
+ export function testStopWhere (description, {
25
+ fromPlugins,
26
+ toPlugins,
27
+ content
28
+ }) {
29
+ return deferOrRunWrap(() => {
30
+ logger.info(`Test stop where -- ${description}`)
31
+ return new TaskTest({
32
+ description,
33
+ shouldStop: true,
34
+ fromPlugins,
35
+ toPlugins,
36
+ content
37
+ })
38
+ }, { type: 'test' })
39
+ };
40
+
41
+ export function testErrorWhere (description, {
42
+ fromPlugins,
43
+ toPlugins,
44
+ content
45
+ }) {
46
+ return deferOrRunWrap(() => {
47
+ logger.info(`Test error where -- ${description}`)
48
+ return new TaskTest({
49
+ description,
50
+ shouldError: true,
51
+ fromPlugins,
52
+ toPlugins,
53
+ content
54
+ })
55
+ }, { type: 'test' })
56
+ };
package/api/where.js CHANGED
@@ -1,46 +1,46 @@
1
- import semver from 'semver'
2
- import { deferOrRunWrap, successStopOrErrorWrap } from '../lib/lifecycle.js'
3
-
4
- export function whereContent (description, callback) {
5
- return deferOrRunWrap(({ content }) => {
6
- return successStopOrErrorWrap('whereContent', description, async () => {
7
- return callback(content)
8
- })
9
- }, { description, type: 'where' })
10
- };
11
-
12
- export function whereFromPlugin (description, callbackOrConfig) {
13
- return deferOrRunWrap(({ fromPlugins }) => {
14
- return successStopOrErrorWrap('whereFromPlugin', description, async () => {
15
- const isCallback = (typeof callbackOrConfig === 'function')
16
- if (isCallback) {
17
- const callback = callbackOrConfig
18
- return callback(fromPlugins)
19
- }
20
- const config = callbackOrConfig
21
- return fromPlugins.some(plugin => {
22
- if (config.name && plugin.name !== config.name) return false
23
- if (config.version && !semver.satisfies(plugin.version, config.version)) return false
24
- return true
25
- })
26
- })
27
- }, { description, type: 'where' })
28
- };
29
-
30
- export function whereToPlugin (description, callbackOrConfig) {
31
- return deferOrRunWrap(({ toPlugins }) => {
32
- return successStopOrErrorWrap('whereToPlugin', description, async () => {
33
- const isCallback = (typeof callbackOrConfig === 'function')
34
- if (isCallback) {
35
- const callback = callbackOrConfig
36
- return callback(toPlugins)
37
- }
38
- const config = callbackOrConfig
39
- return toPlugins.some(plugin => {
40
- if (config.name && plugin.name !== config.name) return false
41
- if (config.version && !semver.satisfies(plugin.version, config.version)) return false
42
- return true
43
- })
44
- })
45
- }, { description, type: 'where' })
46
- };
1
+ import semver from 'semver'
2
+ import { deferOrRunWrap, successStopOrErrorWrap } from '../lib/lifecycle.js'
3
+
4
+ export function whereContent (description, callback) {
5
+ return deferOrRunWrap(({ content }) => {
6
+ return successStopOrErrorWrap('whereContent', description, async () => {
7
+ return callback(content)
8
+ })
9
+ }, { description, type: 'where' })
10
+ };
11
+
12
+ export function whereFromPlugin (description, callbackOrConfig) {
13
+ return deferOrRunWrap(({ fromPlugins }) => {
14
+ return successStopOrErrorWrap('whereFromPlugin', description, async () => {
15
+ const isCallback = (typeof callbackOrConfig === 'function')
16
+ if (isCallback) {
17
+ const callback = callbackOrConfig
18
+ return callback(fromPlugins)
19
+ }
20
+ const config = callbackOrConfig
21
+ return fromPlugins.some(plugin => {
22
+ if (config.name && plugin.name !== config.name) return false
23
+ if (config.version && !semver.satisfies(plugin.version, config.version)) return false
24
+ return true
25
+ })
26
+ })
27
+ }, { description, type: 'where' })
28
+ };
29
+
30
+ export function whereToPlugin (description, callbackOrConfig) {
31
+ return deferOrRunWrap(({ toPlugins }) => {
32
+ return successStopOrErrorWrap('whereToPlugin', description, async () => {
33
+ const isCallback = (typeof callbackOrConfig === 'function')
34
+ if (isCallback) {
35
+ const callback = callbackOrConfig
36
+ return callback(toPlugins)
37
+ }
38
+ const config = callbackOrConfig
39
+ return toPlugins.some(plugin => {
40
+ if (config.name && plugin.name !== config.name) return false
41
+ if (config.version && !semver.satisfies(plugin.version, config.version)) return false
42
+ return true
43
+ })
44
+ })
45
+ }, { description, type: 'where' })
46
+ };
@@ -1,159 +1,159 @@
1
- module.exports = function(grunt) {
2
-
3
- const Helpers = require('../helpers')(grunt);
4
- const globs = require('globs');
5
- const path = require('path');
6
- const fs = require('fs-extra');
7
- const _ = require('underscore');
8
-
9
- function unix(path) {
10
- return path.replace(/\\/g, '/');
11
- }
12
-
13
- function dressPathIndex(fileItem) {
14
- return {
15
- ...fileItem.item,
16
- __index__: fileItem.index,
17
- __path__: unix(fileItem.file.path)
18
- };
19
- }
20
-
21
- function undressPathIndex(object) {
22
- const clone = { ...object };
23
- delete clone.__index__;
24
- delete clone.__path__;
25
- return clone;
26
- }
27
-
28
- grunt.registerTask('migration', 'Migrate from on verion to another', function(mode) {
29
- const next = this.async();
30
- const buildConfig = Helpers.generateConfigData();
31
- const fileNameIncludes = grunt.option('file');
32
-
33
- (async function() {
34
- const migrations = await import('adapt-migrations');
35
- const logger = migrations.Logger.getInstance();
36
- const cwd = process.cwd();
37
- const outputPath = path.join(cwd, './migrations/');
38
- const cache = new migrations.CacheManager();
39
- const cachePath = await cache.getCachePath({
40
- outputPath: buildConfig.outputdir,
41
- tempPath: outputPath
42
- });
43
-
44
- const framework = Helpers.getFramework();
45
- logger.debug(`Using ${framework.useOutputData ? framework.outputPath : framework.sourcePath} folder for course data...`);
46
-
47
- const plugins = framework.getPlugins().getAllPackageJSONFileItems().map(fileItem => fileItem.item);
48
- const migrationScripts = Array.from(await new Promise(resolve => {
49
- globs([
50
- '*/*/migrations/**/*.js',
51
- 'core/migrations/**/*.js'
52
- ], { cwd: path.join(cwd, './src/'), absolute: true }, (err, files) => resolve(err ? null : files));
53
- })).filter(filePath => {
54
- if (!fileNameIncludes) return true;
55
- return filePath.includes(fileNameIncludes);
56
- });
57
-
58
- await migrations.load({
59
- cachePath,
60
- scripts: migrationScripts,
61
- logger
62
- });
63
-
64
- if (mode === 'capture') {
65
-
66
- if (!fs.existsSync(outputPath)) fs.mkdirSync(outputPath);
67
- const languages = framework.getData().languages.map((language) => language.name);
68
- const languageFile = path.join(outputPath, 'captureLanguages.json');
69
- fs.writeJSONSync(languageFile, languages);
70
- languages.forEach(async (language, index) => {
71
- logger.debug(`Migration -- Capture ${language}`)
72
- const data = framework.getData();
73
- // get all items from config.json file and all language files, append __index__ and __path__ to each item
74
- const content = [
75
- ...data.configFile.fileItems,
76
- ...data.languages[index].getAllFileItems()
77
- ].map(dressPathIndex);
78
- const captured = await migrations.capture({ content, fromPlugins: plugins, logger });
79
- const outputFile = path.join(outputPath, `capture_${language}.json`);
80
- fs.writeJSONSync(outputFile, captured);
81
- });
82
-
83
- logger.output(outputPath, 'capture');
84
- return next();
85
- }
86
-
87
- if (mode === 'migrate') {
88
- try {
89
- const languagesFile = path.join(outputPath, 'captureLanguages.json');
90
- const languages = fs.readJSONSync(languagesFile);
91
-
92
- for (const language of languages) {
93
- logger.debug(`Migration -- Migrate ${language}`)
94
- const Journal = migrations.Journal;
95
- if (!fs.existsSync(outputPath)) fs.mkdirSync(outputPath);
96
- const outputFile = path.join(outputPath, `capture_${language}.json`);
97
- const { content, fromPlugins } = fs.readJSONSync(outputFile);
98
- const originalFromPlugins = JSON.parse(JSON.stringify(fromPlugins));
99
- const journal = new Journal({
100
- logger,
101
- data: {
102
- content,
103
- fromPlugins,
104
- originalFromPlugins,
105
- toPlugins: plugins,
106
- },
107
- supplementEntry: (entry, data) => {
108
- entry._id = data[entry.keys[0]][entry.keys[1]]?._id ?? '';
109
- entry._type = data[entry.keys[0]][entry.keys[1]]?._type ?? '';
110
- if (entry._type && data[entry.keys[0]][entry.keys[1]]?.[`_${entry._type}`]) {
111
- entry[`_${entry._type}`] = data[entry.keys[0]][entry.keys[1]]?.[`_${entry._type}`] ?? '';
112
- }
113
- return entry;
114
- }
115
- });
116
- await migrations.migrate({ journal, logger });
117
-
118
- // Todo - {
119
- // display changes success/failure and request user confirmation before completing
120
- // move saving of content outside of the language loop
121
- // only 1 confirmation per course rather than 1 per language
122
- // output journal entries for revert
123
- // }
124
-
125
- // group all content items by path
126
- const outputFilePathItems = _.groupBy(content, '__path__');
127
- // sort items inside each path
128
- Object.values(outputFilePathItems).forEach(outputFile => outputFile.sort((a, b) => a.__index__ - b.__index__));
129
- // get paths
130
- const outputFilePaths = Object.keys(outputFilePathItems);
131
-
132
- outputFilePaths.forEach(outputPath => {
133
- const outputItems = outputFilePathItems[outputPath];
134
- if (!outputItems?.length) return;
135
- const isSingleObject = (outputItems.length === 1 && outputItems[0].__index__ === null);
136
- const stripped = isSingleObject
137
- ? undressPathIndex(outputItems[0]) // config.json, course.json
138
- : outputItems.map(undressPathIndex); // contentObjects.json, articles.json, blocks.json, components.json
139
- // console.log(journal.entries)
140
- fs.writeJSONSync(outputPath, stripped, { replacer: null, spaces: 2 });
141
- });
142
- }
143
- } catch (error) {
144
- logger.error(error.stack);
145
- }
146
- logger.output(outputPath, 'migrate');
147
- return next();
148
- }
149
-
150
- if (mode === 'test') {
151
- await migrations.test();
152
- return next();
153
- }
154
-
155
- return next();
156
- })();
157
- });
158
-
159
- };
1
+ module.exports = function(grunt) {
2
+
3
+ const Helpers = require('../helpers')(grunt);
4
+ const globs = require('globs');
5
+ const path = require('path');
6
+ const fs = require('fs-extra');
7
+ const _ = require('underscore');
8
+
9
+ function unix(path) {
10
+ return path.replace(/\\/g, '/');
11
+ }
12
+
13
+ function dressPathIndex(fileItem) {
14
+ return {
15
+ ...fileItem.item,
16
+ __index__: fileItem.index,
17
+ __path__: unix(fileItem.file.path)
18
+ };
19
+ }
20
+
21
+ function undressPathIndex(object) {
22
+ const clone = { ...object };
23
+ delete clone.__index__;
24
+ delete clone.__path__;
25
+ return clone;
26
+ }
27
+
28
+ grunt.registerTask('migration', 'Migrate from on verion to another', function(mode) {
29
+ const next = this.async();
30
+ const buildConfig = Helpers.generateConfigData();
31
+ const fileNameIncludes = grunt.option('file');
32
+
33
+ (async function() {
34
+ const migrations = await import('adapt-migrations');
35
+ const logger = migrations.Logger.getInstance();
36
+ const cwd = process.cwd();
37
+ const outputPath = path.join(cwd, './migrations/');
38
+ const cache = new migrations.CacheManager();
39
+ const cachePath = await cache.getCachePath({
40
+ outputPath: buildConfig.outputdir,
41
+ tempPath: outputPath
42
+ });
43
+
44
+ const framework = Helpers.getFramework();
45
+ logger.debug(`Using ${framework.useOutputData ? framework.outputPath : framework.sourcePath} folder for course data...`);
46
+
47
+ const plugins = framework.getPlugins().getAllPackageJSONFileItems().map(fileItem => fileItem.item);
48
+ const migrationScripts = Array.from(await new Promise(resolve => {
49
+ globs([
50
+ '*/*/migrations/**/*.js',
51
+ 'core/migrations/**/*.js'
52
+ ], { cwd: path.join(cwd, './src/'), absolute: true }, (err, files) => resolve(err ? null : files));
53
+ })).filter(filePath => {
54
+ if (!fileNameIncludes) return true;
55
+ return filePath.includes(fileNameIncludes);
56
+ });
57
+
58
+ await migrations.load({
59
+ cachePath,
60
+ scripts: migrationScripts,
61
+ logger
62
+ });
63
+
64
+ if (mode === 'capture') {
65
+
66
+ if (!fs.existsSync(outputPath)) fs.mkdirSync(outputPath);
67
+ const languages = framework.getData().languages.map((language) => language.name);
68
+ const languageFile = path.join(outputPath, 'captureLanguages.json');
69
+ fs.writeJSONSync(languageFile, languages);
70
+ languages.forEach(async (language, index) => {
71
+ logger.debug(`Migration -- Capture ${language}`)
72
+ const data = framework.getData();
73
+ // get all items from config.json file and all language files, append __index__ and __path__ to each item
74
+ const content = [
75
+ ...data.configFile.fileItems,
76
+ ...data.languages[index].getAllFileItems()
77
+ ].map(dressPathIndex);
78
+ const captured = await migrations.capture({ content, fromPlugins: plugins, logger });
79
+ const outputFile = path.join(outputPath, `capture_${language}.json`);
80
+ fs.writeJSONSync(outputFile, captured);
81
+ });
82
+
83
+ logger.output(outputPath, 'capture');
84
+ return next();
85
+ }
86
+
87
+ if (mode === 'migrate') {
88
+ try {
89
+ const languagesFile = path.join(outputPath, 'captureLanguages.json');
90
+ const languages = fs.readJSONSync(languagesFile);
91
+
92
+ for (const language of languages) {
93
+ logger.debug(`Migration -- Migrate ${language}`)
94
+ const Journal = migrations.Journal;
95
+ if (!fs.existsSync(outputPath)) fs.mkdirSync(outputPath);
96
+ const outputFile = path.join(outputPath, `capture_${language}.json`);
97
+ const { content, fromPlugins } = fs.readJSONSync(outputFile);
98
+ const originalFromPlugins = JSON.parse(JSON.stringify(fromPlugins));
99
+ const journal = new Journal({
100
+ logger,
101
+ data: {
102
+ content,
103
+ fromPlugins,
104
+ originalFromPlugins,
105
+ toPlugins: plugins,
106
+ },
107
+ supplementEntry: (entry, data) => {
108
+ entry._id = data[entry.keys[0]][entry.keys[1]]?._id ?? '';
109
+ entry._type = data[entry.keys[0]][entry.keys[1]]?._type ?? '';
110
+ if (entry._type && data[entry.keys[0]][entry.keys[1]]?.[`_${entry._type}`]) {
111
+ entry[`_${entry._type}`] = data[entry.keys[0]][entry.keys[1]]?.[`_${entry._type}`] ?? '';
112
+ }
113
+ return entry;
114
+ }
115
+ });
116
+ await migrations.migrate({ journal, logger });
117
+
118
+ // Todo - {
119
+ // display changes success/failure and request user confirmation before completing
120
+ // move saving of content outside of the language loop
121
+ // only 1 confirmation per course rather than 1 per language
122
+ // output journal entries for revert
123
+ // }
124
+
125
+ // group all content items by path
126
+ const outputFilePathItems = _.groupBy(content, '__path__');
127
+ // sort items inside each path
128
+ Object.values(outputFilePathItems).forEach(outputFile => outputFile.sort((a, b) => a.__index__ - b.__index__));
129
+ // get paths
130
+ const outputFilePaths = Object.keys(outputFilePathItems);
131
+
132
+ outputFilePaths.forEach(outputPath => {
133
+ const outputItems = outputFilePathItems[outputPath];
134
+ if (!outputItems?.length) return;
135
+ const isSingleObject = (outputItems.length === 1 && outputItems[0].__index__ === null);
136
+ const stripped = isSingleObject
137
+ ? undressPathIndex(outputItems[0]) // config.json, course.json
138
+ : outputItems.map(undressPathIndex); // contentObjects.json, articles.json, blocks.json, components.json
139
+ // console.log(journal.entries)
140
+ fs.writeJSONSync(outputPath, stripped, { replacer: null, spaces: 2 });
141
+ });
142
+ }
143
+ } catch (error) {
144
+ logger.error(error.stack);
145
+ }
146
+ logger.output(outputPath, 'migrate');
147
+ return next();
148
+ }
149
+
150
+ if (mode === 'test') {
151
+ await migrations.test();
152
+ return next();
153
+ }
154
+
155
+ return next();
156
+ })();
157
+ });
158
+
159
+ };