@jungvonmatt/contentful-migrations 5.2.4 → 5.3.2
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/README.md +18 -6
- package/index.d.ts +2 -1
- package/index.js +10 -10
- package/lib/helpers/locale.d.ts +3 -2
- package/lib/helpers/validation.d.ts +17 -5
- package/lib/helpers/validation.js +56 -26
- package/lib/helpers/validation.test.js +171 -0
- package/lib/helpers/validation.utils.js +76 -0
- package/lib/helpers/validation.utils.test.js +45 -0
- package/lib/migration.js +4 -2
- package/package.json +55 -20
package/README.md
CHANGED
|
@@ -184,13 +184,25 @@ module.exports = withHelpers(async (migration, context, helpers) => {
|
|
|
184
184
|
// Get default locale
|
|
185
185
|
await helpers.locale.getDefaultLocale();
|
|
186
186
|
|
|
187
|
-
// Add or remove values from "linkContentType" validations without
|
|
188
|
-
await helpers.validation.addLinkContentTypeValues('contentTypeId', 'fieldId', ['
|
|
189
|
-
await helpers.validation.removeLinkContentTypeValues('contentTypeId', 'fieldId', ['
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
187
|
+
// Add or remove values from "linkContentType" validations without knowing all the other elements in the array
|
|
188
|
+
await helpers.validation.addLinkContentTypeValues('contentTypeId', 'fieldId', ['some-content-type']);
|
|
189
|
+
await helpers.validation.removeLinkContentTypeValues('contentTypeId', 'fieldId', ['some-content-type']);
|
|
190
|
+
await helpers.validation.modifyLinkContentTypeValues('contentTypeId', 'fieldId', (existing) => {
|
|
191
|
+
const result = existing.filter((contentType) => !contentType.startsWith('a-')); // remove some by prefix
|
|
192
|
+
result.push('t-test'); // and add one
|
|
193
|
+
return result; // possible duplicate values are removed afterwards
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
// Add or remove values from "in" validations without knowing all the other elements in the array
|
|
197
|
+
await helpers.validation.addInValues('contentTypeId', 'fieldId', ['value']); // add at the end
|
|
198
|
+
await helpers.validation.addInValues('contentTypeId', 'fieldId', ['value'], { mode: 'sorted'}); // add and sort
|
|
193
199
|
await helpers.validation.removeInValues('contentTypeId', 'fieldId', ['value']);
|
|
200
|
+
await helpers.validation.modifyInValues('contentTypeId', 'fieldId', (existing) => {
|
|
201
|
+
const result = existing.filter((value) => value.startsWith('prefix')); // keep values with prefix
|
|
202
|
+
result.push('other'); // and add one
|
|
203
|
+
return result; // possible duplicate values are removed afterwards
|
|
204
|
+
});
|
|
205
|
+
|
|
194
206
|
});
|
|
195
207
|
```
|
|
196
208
|
|
package/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type Migration
|
|
1
|
+
import type Migration from "contentful-migration";
|
|
2
|
+
import type { MigrationContext, MigrationFunction } from "contentful-migration";
|
|
2
3
|
import type { LocaleHelpers } from "./lib/helpers/locale";
|
|
3
4
|
import type { ValidationHelpers } from "./lib/helpers/validation";
|
|
4
5
|
|
package/index.js
CHANGED
|
@@ -11,16 +11,16 @@
|
|
|
11
11
|
* });
|
|
12
12
|
*
|
|
13
13
|
*/
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
const { getValidationHelpers } = require('./lib/helpers/validation');
|
|
15
|
+
const { getLocaleHelpers } = require('./lib/helpers/locale');
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
// Export wrapper
|
|
18
|
+
module.exports.withHelpers = (cb) => (migration, context) => {
|
|
19
|
+
const locale = getLocaleHelpers(migration, context);
|
|
20
|
+
const validation = getValidationHelpers(migration, context);
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
return cb(migration, context, { locale, validation });
|
|
23
|
+
};
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
module.exports.getValidationHelpers = getValidationHelpers;
|
|
26
|
+
module.exports.getLocaleHelpers = getLocaleHelpers;
|
package/lib/helpers/locale.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import type { Locale } from "contentful-management/dist/typings/export-types";
|
|
2
|
-
import type Migration
|
|
2
|
+
import type Migration from "contentful-migration";
|
|
3
|
+
import type { MigrationContext } from "contentful-migration";
|
|
3
4
|
|
|
4
5
|
export interface LocaleHelpers {
|
|
5
|
-
getLocales(): Promise<[
|
|
6
|
+
getLocales(): Promise<Locale[]>;
|
|
6
7
|
getDefaultLocale(): Promise<Locale>;
|
|
7
8
|
}
|
|
8
9
|
|
|
@@ -1,10 +1,22 @@
|
|
|
1
|
-
import type Migration
|
|
1
|
+
import type Migration from "contentful-migration";
|
|
2
|
+
import type { MigrationContext } from "contentful-migration";
|
|
3
|
+
|
|
4
|
+
export type ValueMappingFunction = (values: string[]) => string[];
|
|
5
|
+
|
|
6
|
+
export type AddValuesOptionMode = 'sorted' | 'start' | 'end' | 'before' | 'after';
|
|
7
|
+
|
|
8
|
+
export interface AddValuesOptions {
|
|
9
|
+
mode?: AddValuesOptionMode;
|
|
10
|
+
ref?: string;
|
|
11
|
+
}
|
|
2
12
|
|
|
3
13
|
export interface ValidationHelpers {
|
|
4
|
-
addLinkContentTypeValues(contentTypeId: string, fieldId: string, values: string | [
|
|
5
|
-
addInValues(contentTypeId: string, fieldId: string, values: string | [
|
|
6
|
-
removeLinkContentTypeValues(contentTypeId: string, fieldId: string, values: string | [
|
|
7
|
-
removeInValues(contentTypeId: string, fieldId: string, values: string | [
|
|
14
|
+
addLinkContentTypeValues(contentTypeId: string, fieldId: string, values: string | string[]): Promise<void>;
|
|
15
|
+
addInValues(contentTypeId: string, fieldId: string, values: string | string[], options?: AddValuesOptions): Promise<void>;
|
|
16
|
+
removeLinkContentTypeValues(contentTypeId: string, fieldId: string, values: string | string[]): Promise<void>;
|
|
17
|
+
removeInValues(contentTypeId: string, fieldId: string, values: string | string[]): Promise<void>;
|
|
18
|
+
modifyLinkContentTypeValues(contentTypeId: string, fieldId: string, valueMappingFunction: ValueMappingFunction): Promise<void>;
|
|
19
|
+
modifyInValues(contentTypeId: string, fieldId: string, valueMappingFunction: ValueMappingFunction): Promise<void>;
|
|
8
20
|
}
|
|
9
21
|
|
|
10
22
|
export function getValidationHelpers(migration: Migration, context: MigrationContext): ValidationHelpers;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const { TYPE_ARRAY } = require('../contentful');
|
|
2
|
+
const { addValues, unique } = require('./validation.utils');
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Adds utils for the migration
|
|
@@ -10,9 +11,9 @@ const { TYPE_LINK, TYPE_ARRAY } = require('../contentful');
|
|
|
10
11
|
* const validationHelper = getValidationHelpers(migration, context);
|
|
11
12
|
* ...
|
|
12
13
|
*
|
|
13
|
-
* await validationHelper.addLinkContentTypeValues('contentTypeId', 'fieldId', ['
|
|
14
|
+
* await validationHelper.addLinkContentTypeValues('contentTypeId', 'fieldId', ['some-content-type']);
|
|
14
15
|
* await validationHelper.addInValues('contentTypeId', 'fieldId', ['value']);
|
|
15
|
-
* await validationHelper.removeLinkContentTypeValues('contentTypeId', 'fieldId', ['
|
|
16
|
+
* await validationHelper.removeLinkContentTypeValues('contentTypeId', 'fieldId', ['some-content-type']);
|
|
16
17
|
* await validationHelper.removeInValues('contentTypeId', 'fieldId', ['value']);
|
|
17
18
|
*
|
|
18
19
|
* };
|
|
@@ -21,24 +22,12 @@ const { TYPE_LINK, TYPE_ARRAY } = require('../contentful');
|
|
|
21
22
|
const getValidationHelpers = (migration, context) => {
|
|
22
23
|
const { makeRequest } = context;
|
|
23
24
|
|
|
24
|
-
const addValidationValues = (
|
|
25
|
-
validations.map((validation) => {
|
|
26
|
-
if (validation?.[key]) {
|
|
27
|
-
if (!Array.isArray(values)) {
|
|
28
|
-
values = [values];
|
|
29
|
-
}
|
|
30
|
-
if (!Array.isArray(validation[key])) {
|
|
31
|
-
throw new Error(
|
|
32
|
-
`addValidationValues can only be used on arrays. validation.${key} is typeof ${typeof validation[key]}`
|
|
33
|
-
);
|
|
34
|
-
}
|
|
35
|
-
validation[key] = [...new Set([...validation[key], ...values])];
|
|
36
|
-
}
|
|
25
|
+
const addValidationValues = (existingValues, newValues = []) => unique([...existingValues, ...newValues]);
|
|
37
26
|
|
|
38
|
-
|
|
39
|
-
|
|
27
|
+
const removeValidationValues = (existingValues, newValues = []) =>
|
|
28
|
+
existingValues.filter((x) => !newValues.includes(x));
|
|
40
29
|
|
|
41
|
-
const
|
|
30
|
+
const modifyValidations = (validations, method, key, values) =>
|
|
42
31
|
validations.map((validation) => {
|
|
43
32
|
if (validation?.[key]) {
|
|
44
33
|
if (!Array.isArray(values)) {
|
|
@@ -46,16 +35,18 @@ const getValidationHelpers = (migration, context) => {
|
|
|
46
35
|
}
|
|
47
36
|
if (!Array.isArray(validation[key])) {
|
|
48
37
|
throw new Error(
|
|
49
|
-
`
|
|
38
|
+
`modifying validation properties is only supported on arrays. validation.${key} is typeof ${typeof validation[
|
|
39
|
+
key
|
|
40
|
+
]}`
|
|
50
41
|
);
|
|
51
42
|
}
|
|
52
|
-
validation[key] = validation[key]
|
|
43
|
+
validation[key] = method(validation[key], values);
|
|
53
44
|
}
|
|
54
45
|
|
|
55
46
|
return validation;
|
|
56
47
|
});
|
|
57
48
|
|
|
58
|
-
const modifyValidationValuesForType = async (validationKey, method, contentTypeId, fieldId,
|
|
49
|
+
const modifyValidationValuesForType = async (validationKey, method, contentTypeId, fieldId, values) => {
|
|
59
50
|
// Fetch content type
|
|
60
51
|
const { fields } = await makeRequest({
|
|
61
52
|
method: 'GET',
|
|
@@ -63,32 +54,71 @@ const getValidationHelpers = (migration, context) => {
|
|
|
63
54
|
});
|
|
64
55
|
|
|
65
56
|
const { type, items = {}, validations = [] } = fields?.find((field) => field.id === fieldId) ?? {};
|
|
57
|
+
if (type === undefined) {
|
|
58
|
+
throw new Error(`Content type ${contentTypeId} has no field ${fieldId}`);
|
|
59
|
+
}
|
|
66
60
|
|
|
67
61
|
if (type === TYPE_ARRAY) {
|
|
68
62
|
const ct = migration.editContentType(contentTypeId);
|
|
69
|
-
ct.editField(fieldId).items({
|
|
63
|
+
ct.editField(fieldId).items({
|
|
64
|
+
...items,
|
|
65
|
+
validations: modifyValidations(items?.validations, method, validationKey, values),
|
|
66
|
+
});
|
|
70
67
|
} else {
|
|
71
68
|
const ct = migration.editContentType(contentTypeId);
|
|
72
|
-
ct.editField(fieldId).validations(
|
|
69
|
+
ct.editField(fieldId).validations(modifyValidations(validations, method, validationKey, values));
|
|
73
70
|
}
|
|
74
71
|
};
|
|
75
72
|
|
|
76
73
|
return {
|
|
74
|
+
/**
|
|
75
|
+
* Add the specified values to the list of allowed content type values
|
|
76
|
+
*/
|
|
77
77
|
async addLinkContentTypeValues(contentTypeId, fieldId, values) {
|
|
78
78
|
await modifyValidationValuesForType('linkContentType', addValidationValues, contentTypeId, fieldId, values);
|
|
79
79
|
},
|
|
80
80
|
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
/**
|
|
82
|
+
* Add the specified values to the list of allowed values
|
|
83
|
+
* @param {string} options.mode The mode how to add the values (sorted, start, end, before, after)
|
|
84
|
+
* @param {string|undefined} options.ref The reference value for mode "before" and "after"
|
|
85
|
+
*/
|
|
86
|
+
async addInValues(contentTypeId, fieldId, values, options = {}) {
|
|
87
|
+
const addValuesWithOptions = (existingValues, newValues = []) => addValues(existingValues, newValues, options);
|
|
88
|
+
await modifyValidationValuesForType('in', addValuesWithOptions, contentTypeId, fieldId, values);
|
|
83
89
|
},
|
|
84
90
|
|
|
91
|
+
/**
|
|
92
|
+
* Remove the specified values from the list of allowed content type values
|
|
93
|
+
*/
|
|
85
94
|
async removeLinkContentTypeValues(contentTypeId, fieldId, values) {
|
|
86
95
|
await modifyValidationValuesForType('linkContentType', removeValidationValues, contentTypeId, fieldId, values);
|
|
87
96
|
},
|
|
88
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Remove the specified values from the list of allowed values
|
|
100
|
+
*/
|
|
89
101
|
async removeInValues(contentTypeId, fieldId, values) {
|
|
90
102
|
await modifyValidationValuesForType('in', removeValidationValues, contentTypeId, fieldId, values);
|
|
91
103
|
},
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Modifies the list of allowed content types by calling the valueMappingFunction with the existing values and
|
|
107
|
+
* setting the result as the new value list.
|
|
108
|
+
*/
|
|
109
|
+
async modifyLinkContentTypeValues(contentTypeId, fieldId, valueMappingFunction) {
|
|
110
|
+
const uniqueMappingFunction = (values) => unique(valueMappingFunction(values));
|
|
111
|
+
await modifyValidationValuesForType('linkContentType', uniqueMappingFunction, contentTypeId, fieldId, []);
|
|
112
|
+
},
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Modifies the list of allowed values by calling the valueMappingFunction with the existing values and setting the
|
|
116
|
+
* result as the new value list.
|
|
117
|
+
*/
|
|
118
|
+
async modifyInValues(contentTypeId, fieldId, valueMappingFunction) {
|
|
119
|
+
const uniqueMappingFunction = (values) => unique(valueMappingFunction(values));
|
|
120
|
+
await modifyValidationValuesForType('in', uniqueMappingFunction, contentTypeId, fieldId, []);
|
|
121
|
+
},
|
|
92
122
|
};
|
|
93
123
|
};
|
|
94
124
|
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
const { getValidationHelpers } = require('./validation');
|
|
2
|
+
|
|
3
|
+
describe('getValidationHelpers', () => {
|
|
4
|
+
const getTestContentType = () => ({
|
|
5
|
+
fields: [
|
|
6
|
+
{
|
|
7
|
+
id: 'selectWithOtherValidationProps',
|
|
8
|
+
type: 'Text',
|
|
9
|
+
items: [],
|
|
10
|
+
validations: [
|
|
11
|
+
{
|
|
12
|
+
foo: 'test',
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
in: ['foo', 'bar', 'baz'],
|
|
16
|
+
message: 'Some message',
|
|
17
|
+
},
|
|
18
|
+
],
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
id: 'select',
|
|
22
|
+
type: 'Text',
|
|
23
|
+
items: [],
|
|
24
|
+
validations: [
|
|
25
|
+
{
|
|
26
|
+
in: ['foo', 'bar', 'baz'],
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
id: 'reference',
|
|
32
|
+
type: 'Text',
|
|
33
|
+
validations: [
|
|
34
|
+
{
|
|
35
|
+
linkContentType: ['foo', 'bar', 'baz'],
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
id: 'string-array',
|
|
41
|
+
type: 'Array',
|
|
42
|
+
items: [],
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const context = {
|
|
48
|
+
makeRequest: () => Promise.resolve(getTestContentType()),
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
let resultValidation;
|
|
52
|
+
|
|
53
|
+
const migration = {
|
|
54
|
+
editContentType: () => ({
|
|
55
|
+
editField: () => ({
|
|
56
|
+
validations: (validationObject) => {
|
|
57
|
+
resultValidation = validationObject;
|
|
58
|
+
},
|
|
59
|
+
}),
|
|
60
|
+
}),
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
beforeEach(() => {
|
|
64
|
+
resultValidation = undefined;
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
describe('addInValues', () => {
|
|
68
|
+
it('should add values at the end', async () => {
|
|
69
|
+
const validations = getValidationHelpers(migration, context);
|
|
70
|
+
await validations.addInValues('some-content-type', 'selectWithOtherValidationProps', 'bat');
|
|
71
|
+
expect(resultValidation).toEqual([
|
|
72
|
+
{
|
|
73
|
+
foo: 'test',
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
in: ['foo', 'bar', 'baz', 'bat'],
|
|
77
|
+
message: 'Some message',
|
|
78
|
+
},
|
|
79
|
+
]);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('should only add new values', async () => {
|
|
83
|
+
const validations = getValidationHelpers(migration, context);
|
|
84
|
+
await validations.addInValues('some-content-type', 'select', ['bat', 'foo', 'test']);
|
|
85
|
+
expect(resultValidation).toEqual([
|
|
86
|
+
{
|
|
87
|
+
in: ['foo', 'bar', 'baz', 'bat', 'test'],
|
|
88
|
+
},
|
|
89
|
+
]);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('should add new values sorted', async () => {
|
|
93
|
+
const validations = getValidationHelpers(migration, context);
|
|
94
|
+
await validations.addInValues('some-content-type', 'select', ['bat', 'foo', 'test'], { mode: 'sorted' });
|
|
95
|
+
expect(resultValidation).toEqual([
|
|
96
|
+
{
|
|
97
|
+
in: ['bar', 'bat', 'baz', 'foo', 'test'],
|
|
98
|
+
},
|
|
99
|
+
]);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe('removeInValues', () => {
|
|
104
|
+
it('should remove values', async () => {
|
|
105
|
+
const validations = getValidationHelpers(migration, context);
|
|
106
|
+
await validations.removeInValues('some-content-type', 'select', ['foo', 'baz']);
|
|
107
|
+
expect(resultValidation).toEqual([
|
|
108
|
+
{
|
|
109
|
+
in: ['bar'],
|
|
110
|
+
},
|
|
111
|
+
]);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
describe('modifyInValues', () => {
|
|
116
|
+
it('should modify values with custom function', async () => {
|
|
117
|
+
const validations = getValidationHelpers(migration, context);
|
|
118
|
+
await validations.modifyInValues('some-content-type', 'select', (values) => {
|
|
119
|
+
const result = values.slice(0, values.length - 1); // remove bar
|
|
120
|
+
result.push('test');
|
|
121
|
+
return result;
|
|
122
|
+
});
|
|
123
|
+
expect(resultValidation).toEqual([
|
|
124
|
+
{
|
|
125
|
+
in: ['foo', 'bar', 'test'],
|
|
126
|
+
},
|
|
127
|
+
]);
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
describe('addLinkContentTypeValues', () => {
|
|
132
|
+
it('should add values at the end', async () => {
|
|
133
|
+
const validations = getValidationHelpers(migration, context);
|
|
134
|
+
await validations.addLinkContentTypeValues('some-content-type', 'reference', 'bat');
|
|
135
|
+
expect(resultValidation).toEqual([
|
|
136
|
+
{
|
|
137
|
+
linkContentType: ['foo', 'bar', 'baz', 'bat'],
|
|
138
|
+
},
|
|
139
|
+
]);
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
describe('removeLinkContentTypeValues', () => {
|
|
144
|
+
it('should remove values', async () => {
|
|
145
|
+
const validations = getValidationHelpers(migration, context);
|
|
146
|
+
await validations.removeLinkContentTypeValues('some-content-type', 'reference', ['foo', 'baz']);
|
|
147
|
+
expect(resultValidation).toEqual([
|
|
148
|
+
{
|
|
149
|
+
linkContentType: ['bar'],
|
|
150
|
+
},
|
|
151
|
+
]);
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
describe('modifyLinkContentTypeValues', () => {
|
|
156
|
+
it('should modify unique values with custom function', async () => {
|
|
157
|
+
const validations = getValidationHelpers(migration, context);
|
|
158
|
+
await validations.modifyLinkContentTypeValues('some-content-type', 'reference', (values) => {
|
|
159
|
+
const result = values.slice(0, values.length - 1); // remove bar
|
|
160
|
+
result.push('test');
|
|
161
|
+
result.push('foo'); // should be removed since it exists
|
|
162
|
+
return result;
|
|
163
|
+
});
|
|
164
|
+
expect(resultValidation).toEqual([
|
|
165
|
+
{
|
|
166
|
+
linkContentType: ['foo', 'bar', 'test'],
|
|
167
|
+
},
|
|
168
|
+
]);
|
|
169
|
+
});
|
|
170
|
+
});
|
|
171
|
+
});
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns a new array containing only the unique values of the given array.
|
|
3
|
+
* The given order of the elements is kept.
|
|
4
|
+
* If duplicates exist the first occurrence is kept and the others are removed.
|
|
5
|
+
*/
|
|
6
|
+
const unique = (array) => [...new Set(array)];
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Returns an array with the unique items of both arrays sorted by natural ordering.
|
|
10
|
+
* @param {Array} array1
|
|
11
|
+
* @param {Array} array2
|
|
12
|
+
*/
|
|
13
|
+
const addOrdered = (array1, array2) => {
|
|
14
|
+
const result = [...new Set([...array1, ...array2])];
|
|
15
|
+
result.sort();
|
|
16
|
+
return result;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const ADD_MODE_SORTED = 'sorted';
|
|
20
|
+
const ADD_MODE_START = 'start';
|
|
21
|
+
const ADD_MODE_END = 'end';
|
|
22
|
+
const ADD_MODE_BEFORE = 'before';
|
|
23
|
+
const ADD_MODE_AFTER = 'after'; // default
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Get the insert position depending on the options.
|
|
27
|
+
* @param {string[]} array The array where values should be added.
|
|
28
|
+
* @param {string} options.mode The mode how to add the values (sorted, start, end, before, after)
|
|
29
|
+
* @param {string|undefined} options.ref The reference value for mode "before" and "after"
|
|
30
|
+
* @returns {number}
|
|
31
|
+
*/
|
|
32
|
+
const getInsertPosition = (array, options = {}) => {
|
|
33
|
+
if (options.mode === ADD_MODE_START) {
|
|
34
|
+
return 0;
|
|
35
|
+
}
|
|
36
|
+
if (options.mode === ADD_MODE_END) {
|
|
37
|
+
return array.length;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
let refIndex = array.indexOf(options.ref);
|
|
41
|
+
if (refIndex >= 0) {
|
|
42
|
+
if (options.mode === ADD_MODE_BEFORE) {
|
|
43
|
+
return refIndex;
|
|
44
|
+
}
|
|
45
|
+
if (options.mode === ADD_MODE_AFTER) {
|
|
46
|
+
return refIndex + 1;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// default at the end
|
|
51
|
+
return array.length;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Adds values to a string array depending on the specified mode.
|
|
56
|
+
* The result list always contains unique values by calling the unique function.
|
|
57
|
+
* @param {string[]} array The array where values should be added.
|
|
58
|
+
* @param {string[]} toAdd The list of values to add.
|
|
59
|
+
* @param {string} options.mode The mode how to add the values (sorted, start, end, before, after)
|
|
60
|
+
* @param {string|undefined} options.ref The reference value for mode "before" and "after"
|
|
61
|
+
* @returns {string[]}
|
|
62
|
+
*/
|
|
63
|
+
const addValues = (array, toAdd, options = {}) => {
|
|
64
|
+
if (options.mode === ADD_MODE_SORTED) {
|
|
65
|
+
return addOrdered(array, toAdd);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
let position = getInsertPosition(array, options);
|
|
69
|
+
return unique([...array.slice(0, position), ...toAdd, ...array.slice(position)]);
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
module.exports = {
|
|
73
|
+
addOrdered,
|
|
74
|
+
addValues,
|
|
75
|
+
unique,
|
|
76
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
const { addOrdered, addValues, unique } = require('./validation.utils');
|
|
2
|
+
|
|
3
|
+
describe('unique', () => {
|
|
4
|
+
it('should remove duplicates', async () => {
|
|
5
|
+
expect(unique(['foo', 'bar', 'foo', 'baz', 'bar'])).toEqual(['foo', 'bar', 'baz']);
|
|
6
|
+
});
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
describe('addOrdered', () => {
|
|
10
|
+
const a1 = ['foo', 'bar'];
|
|
11
|
+
const a2 = ['baz', 'bar', 'bat'];
|
|
12
|
+
|
|
13
|
+
it('should add unique values and order the list', async () => {
|
|
14
|
+
expect(addOrdered(a1, a2)).toEqual(['bar', 'bat', 'baz', 'foo']);
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe('addValues', () => {
|
|
19
|
+
const a1 = ['foo', 'bar', 'test'];
|
|
20
|
+
const a2 = ['baz', 'bar', 'bat'];
|
|
21
|
+
|
|
22
|
+
it('should add values sorted', async () => {
|
|
23
|
+
expect(addValues(a1, a2, { mode: 'sorted' })).toEqual(['bar', 'bat', 'baz', 'foo', 'test']);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should add values at start', async () => {
|
|
27
|
+
expect(addValues(a1, a2, { mode: 'start' })).toEqual(['baz', 'bar', 'bat', 'foo', 'test']);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('should add values at end', async () => {
|
|
31
|
+
expect(addValues(a1, a2, { mode: 'end' })).toEqual(['foo', 'bar', 'test', 'baz', 'bat']);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should add values before', async () => {
|
|
35
|
+
expect(addValues(a1, a2, { mode: 'before', ref: 'bar' })).toEqual(['foo', 'baz', 'bar', 'bat', 'test']);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should add values before fallback', async () => {
|
|
39
|
+
expect(addValues(a1, a2, { mode: 'before', ref: 'unknown' })).toEqual(['foo', 'bar', 'test', 'baz', 'bat']);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should add values after', async () => {
|
|
43
|
+
expect(addValues(a1, a2, { mode: 'after', ref: 'bar' })).toEqual(['foo', 'bar', 'baz', 'bat', 'test']);
|
|
44
|
+
});
|
|
45
|
+
});
|
package/lib/migration.js
CHANGED
|
@@ -93,10 +93,12 @@ const fetchMigration = async (config) => {
|
|
|
93
93
|
.toString()
|
|
94
94
|
// Add call to utils.getDefaultLocale() to the top
|
|
95
95
|
.replace(
|
|
96
|
-
'module.exports = function (migration) {'
|
|
96
|
+
'module.exports = function (migration) {',
|
|
97
|
+
`
|
|
97
98
|
${migrationHeader}
|
|
98
99
|
const defaultLocale = helpers.locale.getDefaultLocale();
|
|
99
|
-
`
|
|
100
|
+
`
|
|
101
|
+
)
|
|
100
102
|
// Replace the default locale with defaultLocale.code so that the migration
|
|
101
103
|
// still works as expected when the locale is changed in contentful
|
|
102
104
|
.replace(testDefaultValueRegex, '$1[defaultLocale.code]$2')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jungvonmatt/contentful-migrations",
|
|
3
|
-
"version": "5.2
|
|
3
|
+
"version": "5.3.2",
|
|
4
4
|
"description": "Helper to handle migrations in contentful",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"files": [
|
|
@@ -15,8 +15,9 @@
|
|
|
15
15
|
"migrations": "cli.js"
|
|
16
16
|
},
|
|
17
17
|
"scripts": {
|
|
18
|
-
"test": "npm run lint",
|
|
19
|
-
"lint": "eslint . --ext .js,.ts,.tsx --ignore-path .gitignore"
|
|
18
|
+
"test": "jest --coverage && npm run lint",
|
|
19
|
+
"lint": "eslint . --ext .js,.ts,.tsx --ignore-path .gitignore",
|
|
20
|
+
"fix-lint": "npm run lint -- --fix"
|
|
20
21
|
},
|
|
21
22
|
"repository": {
|
|
22
23
|
"type": "git",
|
|
@@ -33,39 +34,41 @@
|
|
|
33
34
|
"content-type"
|
|
34
35
|
],
|
|
35
36
|
"dependencies": {
|
|
36
|
-
"@contentful/rich-text-plain-text-renderer": "^15.
|
|
37
|
-
"array.prototype.flatmap": "^1.
|
|
37
|
+
"@contentful/rich-text-plain-text-renderer": "^15.12.1",
|
|
38
|
+
"array.prototype.flatmap": "^1.3.0",
|
|
38
39
|
"ascii-tree": "^0.3.0",
|
|
39
40
|
"chalk": "^4.1.2",
|
|
40
|
-
"cli-progress": "^3.
|
|
41
|
+
"cli-progress": "^3.11.2",
|
|
41
42
|
"commander": "^8.3.0",
|
|
42
43
|
"common-tags": "^1.8.2",
|
|
43
|
-
"contentful-cli": "^1.
|
|
44
|
-
"contentful-import": "^8.2
|
|
44
|
+
"contentful-cli": "^1.14.21",
|
|
45
|
+
"contentful-import": "^8.3.2",
|
|
45
46
|
"contentful-management": "^7.45.2",
|
|
46
|
-
"contentful-migration": "^4.
|
|
47
|
+
"contentful-migration": "^4.9.2",
|
|
47
48
|
"cosmiconfig": "^7.0.1",
|
|
48
49
|
"deep-diff": "^1.0.2",
|
|
49
|
-
"diff": "^5.
|
|
50
|
+
"diff": "^5.1.0",
|
|
50
51
|
"dotenv": "^10.0.0",
|
|
51
|
-
"fs-extra": "^10.
|
|
52
|
+
"fs-extra": "^10.1.0",
|
|
52
53
|
"globby": "^12.0.2",
|
|
53
54
|
"inquirer": "^8.2.0",
|
|
54
|
-
"markdown-table": "^3.0.
|
|
55
|
+
"markdown-table": "^3.0.2",
|
|
55
56
|
"merge-options": "^3.0.4",
|
|
56
57
|
"mustache": "^4.2.0",
|
|
57
|
-
"node-fetch": "^3.
|
|
58
|
+
"node-fetch": "^3.2.8",
|
|
58
59
|
"node-object-hash": "^2.3.10",
|
|
59
60
|
"pkg-up": "^4.0.0",
|
|
60
|
-
"prettier": "^2.
|
|
61
|
-
"read-pkg-up": "^9.
|
|
61
|
+
"prettier": "^2.7.1",
|
|
62
|
+
"read-pkg-up": "^9.1.0"
|
|
62
63
|
},
|
|
63
64
|
"devDependencies": {
|
|
64
|
-
"babel-
|
|
65
|
-
"eslint": "^8.
|
|
66
|
-
"eslint-config-prettier": "^8.
|
|
67
|
-
"eslint-plugin-prettier": "^4.
|
|
65
|
+
"@babel/eslint-parser": "^7.18.2",
|
|
66
|
+
"eslint": "^8.20.0",
|
|
67
|
+
"eslint-config-prettier": "^8.5.0",
|
|
68
|
+
"eslint-plugin-prettier": "^4.2.1",
|
|
68
69
|
"husky": "^7.0.4",
|
|
70
|
+
"jest": "^27.5.1",
|
|
71
|
+
"jest-sonar-reporter": "^2.0.0",
|
|
69
72
|
"lint-staged": "^12.1.2"
|
|
70
73
|
},
|
|
71
74
|
"publishConfig": {
|
|
@@ -76,6 +79,9 @@
|
|
|
76
79
|
"printWidth": 120
|
|
77
80
|
},
|
|
78
81
|
"eslintConfig": {
|
|
82
|
+
"ignorePatterns": [
|
|
83
|
+
"**/*.d.ts"
|
|
84
|
+
],
|
|
79
85
|
"plugins": [
|
|
80
86
|
"prettier"
|
|
81
87
|
],
|
|
@@ -85,8 +91,9 @@
|
|
|
85
91
|
"extends": [
|
|
86
92
|
"prettier"
|
|
87
93
|
],
|
|
88
|
-
"parser": "babel-
|
|
94
|
+
"parser": "@babel/eslint-parser",
|
|
89
95
|
"parserOptions": {
|
|
96
|
+
"requireConfigFile": false,
|
|
90
97
|
"allowImportExportEverywhere": true,
|
|
91
98
|
"ecmaFeatures": {
|
|
92
99
|
"ecmaVersion": 2017,
|
|
@@ -106,6 +113,29 @@
|
|
|
106
113
|
"prettier --write"
|
|
107
114
|
]
|
|
108
115
|
},
|
|
116
|
+
"jest": {
|
|
117
|
+
"testResultsProcessor": "jest-sonar-reporter",
|
|
118
|
+
"coverageDirectory": "<rootDir>/__coverage__/",
|
|
119
|
+
"collectCoverageFrom": [
|
|
120
|
+
"<rootDir>/lib/*/**"
|
|
121
|
+
],
|
|
122
|
+
"roots": [
|
|
123
|
+
"<rootDir>/lib/"
|
|
124
|
+
],
|
|
125
|
+
"moduleFileExtensions": [
|
|
126
|
+
"js"
|
|
127
|
+
],
|
|
128
|
+
"testRegex": "/lib/.*\\.test.js$",
|
|
129
|
+
"moduleDirectories": [
|
|
130
|
+
"node_modules"
|
|
131
|
+
],
|
|
132
|
+
"globals": {
|
|
133
|
+
"DEVELOPMENT": false
|
|
134
|
+
},
|
|
135
|
+
"reporters": [
|
|
136
|
+
"default"
|
|
137
|
+
]
|
|
138
|
+
},
|
|
109
139
|
"husky": {
|
|
110
140
|
"hooks": {
|
|
111
141
|
"pre-commit": "lint-staged"
|
|
@@ -115,5 +145,10 @@
|
|
|
115
145
|
"storage": "content",
|
|
116
146
|
"migrationContentTypeId": "contentful-migrations",
|
|
117
147
|
"directory": "migrations"
|
|
148
|
+
},
|
|
149
|
+
"jestSonar": {
|
|
150
|
+
"reportPath": "__coverage__",
|
|
151
|
+
"reportFile": "test-report.xml",
|
|
152
|
+
"indent": 2
|
|
118
153
|
}
|
|
119
154
|
}
|