@payloadcms/plugin-import-export 3.84.1 → 3.85.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/dist/export/batchProcessor.d.ts +9 -1
- package/dist/export/batchProcessor.d.ts.map +1 -1
- package/dist/export/batchProcessor.js +57 -15
- package/dist/export/batchProcessor.js.map +1 -1
- package/dist/export/createExport.d.ts.map +1 -1
- package/dist/export/createExport.js +98 -20
- package/dist/export/createExport.js.map +1 -1
- package/dist/export/handlePreview.d.ts.map +1 -1
- package/dist/export/handlePreview.js +38 -13
- package/dist/export/handlePreview.js.map +1 -1
- package/dist/exports/types.d.ts +1 -1
- package/dist/exports/types.d.ts.map +1 -1
- package/dist/exports/types.js.map +1 -1
- package/dist/import/batchProcessor.d.ts +14 -2
- package/dist/import/batchProcessor.d.ts.map +1 -1
- package/dist/import/batchProcessor.js +49 -27
- package/dist/import/batchProcessor.js.map +1 -1
- package/dist/import/createImport.d.ts +1 -10
- package/dist/import/createImport.d.ts.map +1 -1
- package/dist/import/createImport.js +33 -52
- package/dist/import/createImport.js.map +1 -1
- package/dist/import/handlePreview.d.ts.map +1 -1
- package/dist/import/handlePreview.js +32 -6
- package/dist/import/handlePreview.js.map +1 -1
- package/dist/index.d.ts +58 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +18 -1
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +218 -39
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utilities/applyFieldHooks.d.ts +23 -0
- package/dist/utilities/applyFieldHooks.d.ts.map +1 -0
- package/dist/utilities/applyFieldHooks.js +118 -0
- package/dist/utilities/applyFieldHooks.js.map +1 -0
- package/dist/utilities/applyFieldHooks.spec.js +205 -0
- package/dist/utilities/applyFieldHooks.spec.js.map +1 -0
- package/dist/utilities/collectDisabledFieldPaths.d.ts.map +1 -1
- package/dist/utilities/collectDisabledFieldPaths.js +1 -1
- package/dist/utilities/collectDisabledFieldPaths.js.map +1 -1
- package/dist/utilities/flattenObject.d.ts +8 -6
- package/dist/utilities/flattenObject.d.ts.map +1 -1
- package/dist/utilities/flattenObject.js +95 -75
- package/dist/utilities/flattenObject.js.map +1 -1
- package/dist/utilities/flattenObject.spec.js +158 -0
- package/dist/utilities/flattenObject.spec.js.map +1 -0
- package/dist/utilities/flattenedFields.d.ts +21 -0
- package/dist/utilities/flattenedFields.d.ts.map +1 -0
- package/dist/utilities/flattenedFields.js +34 -0
- package/dist/utilities/flattenedFields.js.map +1 -0
- package/dist/utilities/getExportFieldFunctions.d.ts +5 -5
- package/dist/utilities/getExportFieldFunctions.d.ts.map +1 -1
- package/dist/utilities/getExportFieldFunctions.js +92 -98
- package/dist/utilities/getExportFieldFunctions.js.map +1 -1
- package/dist/utilities/getExportFieldFunctions.spec.js +50 -0
- package/dist/utilities/getExportFieldFunctions.spec.js.map +1 -0
- package/dist/utilities/getImportFieldFunctions.d.ts +5 -5
- package/dist/utilities/getImportFieldFunctions.d.ts.map +1 -1
- package/dist/utilities/getImportFieldFunctions.js +103 -103
- package/dist/utilities/getImportFieldFunctions.js.map +1 -1
- package/dist/utilities/getImportFieldFunctions.spec.js +167 -0
- package/dist/utilities/getImportFieldFunctions.spec.js.map +1 -0
- package/dist/utilities/isPlainObject.d.ts +2 -0
- package/dist/utilities/isPlainObject.d.ts.map +1 -0
- package/dist/utilities/isPlainObject.js +3 -0
- package/dist/utilities/isPlainObject.js.map +1 -0
- package/dist/utilities/legacyHookDispatch.spec.js +227 -0
- package/dist/utilities/legacyHookDispatch.spec.js.map +1 -0
- package/dist/utilities/polymorphicRel.d.ts +14 -0
- package/dist/utilities/polymorphicRel.d.ts.map +1 -0
- package/dist/utilities/polymorphicRel.js +17 -0
- package/dist/utilities/polymorphicRel.js.map +1 -0
- package/dist/utilities/processRichTextField.js.map +1 -1
- package/dist/utilities/removeDisabledFields.js.map +1 -1
- package/dist/utilities/setNestedValue.d.ts.map +1 -1
- package/dist/utilities/setNestedValue.js +10 -8
- package/dist/utilities/setNestedValue.js.map +1 -1
- package/dist/utilities/siblingDoc.spec.js +278 -0
- package/dist/utilities/siblingDoc.spec.js.map +1 -0
- package/dist/utilities/unflattenObject.d.ts +4 -3
- package/dist/utilities/unflattenObject.d.ts.map +1 -1
- package/dist/utilities/unflattenObject.js +57 -169
- package/dist/utilities/unflattenObject.js.map +1 -1
- package/dist/utilities/unflattenObject.spec.js +33 -0
- package/dist/utilities/unflattenObject.spec.js.map +1 -1
- package/dist/utilities/unflattenPostProcess.d.ts +11 -0
- package/dist/utilities/unflattenPostProcess.d.ts.map +1 -0
- package/dist/utilities/unflattenPostProcess.js +148 -0
- package/dist/utilities/unflattenPostProcess.js.map +1 -0
- package/package.json +7 -7
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { applyFieldHooks } from './applyFieldHooks.js';
|
|
2
|
+
import { flattenObject } from './flattenObject.js';
|
|
3
|
+
import { getExportFieldFunctions } from './getExportFieldFunctions.js';
|
|
4
|
+
import { getImportFieldFunctions } from './getImportFieldFunctions.js';
|
|
5
|
+
import { unflattenObject } from './unflattenObject.js';
|
|
6
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
7
|
+
const mockReq = {
|
|
8
|
+
payload: {
|
|
9
|
+
logger: {
|
|
10
|
+
error: vi.fn()
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
describe('beforeExport / beforeImport siblingDoc arg', ()=>{
|
|
15
|
+
describe('CSV export (flattenObject)', ()=>{
|
|
16
|
+
it('passes the source doc at the current nesting level as siblingDoc', ()=>{
|
|
17
|
+
const received = [];
|
|
18
|
+
const fields = [
|
|
19
|
+
{
|
|
20
|
+
name: 'title',
|
|
21
|
+
type: 'text'
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: 'group',
|
|
25
|
+
type: 'group',
|
|
26
|
+
flattenedFields: [
|
|
27
|
+
{
|
|
28
|
+
name: 'inner',
|
|
29
|
+
type: 'text',
|
|
30
|
+
custom: {
|
|
31
|
+
'plugin-import-export': {
|
|
32
|
+
hooks: {
|
|
33
|
+
beforeExport: ({ columnName, siblingData, siblingDoc, value })=>{
|
|
34
|
+
received.push({
|
|
35
|
+
columnName,
|
|
36
|
+
isSiblingDocSource: siblingDoc && typeof siblingDoc === 'object' && siblingDoc.inner === value,
|
|
37
|
+
isSiblingDocRow: siblingDoc === siblingData
|
|
38
|
+
});
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
];
|
|
48
|
+
const exportFieldHooks = getExportFieldFunctions({
|
|
49
|
+
fields
|
|
50
|
+
});
|
|
51
|
+
flattenObject({
|
|
52
|
+
data: {
|
|
53
|
+
group: {
|
|
54
|
+
inner: 'deep'
|
|
55
|
+
},
|
|
56
|
+
title: 'Top'
|
|
57
|
+
},
|
|
58
|
+
exportFieldHooks,
|
|
59
|
+
format: 'csv',
|
|
60
|
+
req: mockReq
|
|
61
|
+
});
|
|
62
|
+
expect(received).toEqual([
|
|
63
|
+
{
|
|
64
|
+
columnName: 'group_inner',
|
|
65
|
+
isSiblingDocSource: true,
|
|
66
|
+
isSiblingDocRow: false
|
|
67
|
+
}
|
|
68
|
+
]);
|
|
69
|
+
});
|
|
70
|
+
it('lets a hook read another sibling by reading siblingDoc', ()=>{
|
|
71
|
+
const fields = [
|
|
72
|
+
{
|
|
73
|
+
name: 'firstName',
|
|
74
|
+
type: 'text'
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: 'fullName',
|
|
78
|
+
type: 'text',
|
|
79
|
+
custom: {
|
|
80
|
+
'plugin-import-export': {
|
|
81
|
+
hooks: {
|
|
82
|
+
beforeExport: ({ siblingDoc, value })=>{
|
|
83
|
+
const last = siblingDoc.lastName;
|
|
84
|
+
const first = siblingDoc.firstName;
|
|
85
|
+
if (first && last) {
|
|
86
|
+
return `${first} ${last}`;
|
|
87
|
+
}
|
|
88
|
+
return value;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
name: 'lastName',
|
|
96
|
+
type: 'text'
|
|
97
|
+
}
|
|
98
|
+
];
|
|
99
|
+
const exportFieldHooks = getExportFieldFunctions({
|
|
100
|
+
fields
|
|
101
|
+
});
|
|
102
|
+
const result = flattenObject({
|
|
103
|
+
data: {
|
|
104
|
+
firstName: 'Ada',
|
|
105
|
+
fullName: '(computed)',
|
|
106
|
+
lastName: 'Lovelace'
|
|
107
|
+
},
|
|
108
|
+
exportFieldHooks,
|
|
109
|
+
format: 'csv',
|
|
110
|
+
req: mockReq
|
|
111
|
+
});
|
|
112
|
+
expect(result.fullName).toBe('Ada Lovelace');
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
describe('JSON export (applyFieldHooks)', ()=>{
|
|
116
|
+
it('passes the untouched source sibling as siblingDoc and the mutable output as siblingData', ()=>{
|
|
117
|
+
let capturedSiblingDoc = null;
|
|
118
|
+
let capturedSiblingData = null;
|
|
119
|
+
const fields = [
|
|
120
|
+
{
|
|
121
|
+
name: 'outer',
|
|
122
|
+
type: 'group',
|
|
123
|
+
flattenedFields: [
|
|
124
|
+
{
|
|
125
|
+
name: 'tracked',
|
|
126
|
+
type: 'text',
|
|
127
|
+
custom: {
|
|
128
|
+
'plugin-import-export': {
|
|
129
|
+
hooks: {
|
|
130
|
+
beforeExport: ({ siblingData, siblingDoc, value })=>{
|
|
131
|
+
capturedSiblingDoc = siblingDoc;
|
|
132
|
+
capturedSiblingData = siblingData;
|
|
133
|
+
siblingData.injected = 'written-into-output';
|
|
134
|
+
return String(value) + '_changed';
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
]
|
|
141
|
+
}
|
|
142
|
+
];
|
|
143
|
+
const exportFieldHooks = getExportFieldFunctions({
|
|
144
|
+
fields
|
|
145
|
+
});
|
|
146
|
+
const source = {
|
|
147
|
+
outer: {
|
|
148
|
+
tracked: 'original'
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
applyFieldHooks({
|
|
152
|
+
data: source,
|
|
153
|
+
fieldHooks: exportFieldHooks,
|
|
154
|
+
fields,
|
|
155
|
+
format: 'json',
|
|
156
|
+
operation: 'export',
|
|
157
|
+
req: mockReq,
|
|
158
|
+
type: 'beforeExport'
|
|
159
|
+
});
|
|
160
|
+
expect(capturedSiblingDoc).toEqual({
|
|
161
|
+
tracked: 'original'
|
|
162
|
+
});
|
|
163
|
+
// The hook's mutation lives on siblingData, not siblingDoc
|
|
164
|
+
expect(capturedSiblingData?.injected).toBe('written-into-output');
|
|
165
|
+
expect(capturedSiblingDoc?.injected).toBeUndefined();
|
|
166
|
+
// And the source object itself is not mutated
|
|
167
|
+
expect(source).toEqual({
|
|
168
|
+
outer: {
|
|
169
|
+
tracked: 'original'
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
describe('CSV import (unflattenObject)', ()=>{
|
|
175
|
+
it('passes the full flat row as siblingDoc (equal to data)', ()=>{
|
|
176
|
+
const received = [];
|
|
177
|
+
const fields = [
|
|
178
|
+
{
|
|
179
|
+
name: 'title',
|
|
180
|
+
type: 'text'
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
name: 'note',
|
|
184
|
+
type: 'text',
|
|
185
|
+
custom: {
|
|
186
|
+
'plugin-import-export': {
|
|
187
|
+
hooks: {
|
|
188
|
+
beforeImport: ({ data, siblingDoc, value })=>{
|
|
189
|
+
received.push({
|
|
190
|
+
siblingDocIsData: siblingDoc === data
|
|
191
|
+
});
|
|
192
|
+
return value;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
];
|
|
199
|
+
const importFieldHooks = getImportFieldFunctions({
|
|
200
|
+
fields
|
|
201
|
+
});
|
|
202
|
+
unflattenObject({
|
|
203
|
+
data: {
|
|
204
|
+
note: 'hello',
|
|
205
|
+
title: 'Top'
|
|
206
|
+
},
|
|
207
|
+
fields,
|
|
208
|
+
format: 'csv',
|
|
209
|
+
importFieldHooks,
|
|
210
|
+
req: mockReq
|
|
211
|
+
});
|
|
212
|
+
expect(received).toEqual([
|
|
213
|
+
{
|
|
214
|
+
siblingDocIsData: true
|
|
215
|
+
}
|
|
216
|
+
]);
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
describe('JSON import (applyFieldHooks)', ()=>{
|
|
220
|
+
it('passes the untouched source sibling as siblingDoc and the mutable output as siblingData', ()=>{
|
|
221
|
+
let capturedSiblingDoc = null;
|
|
222
|
+
let capturedSiblingData = null;
|
|
223
|
+
const fields = [
|
|
224
|
+
{
|
|
225
|
+
name: 'outer',
|
|
226
|
+
type: 'group',
|
|
227
|
+
flattenedFields: [
|
|
228
|
+
{
|
|
229
|
+
name: 'tracked',
|
|
230
|
+
type: 'text',
|
|
231
|
+
custom: {
|
|
232
|
+
'plugin-import-export': {
|
|
233
|
+
hooks: {
|
|
234
|
+
beforeImport: ({ siblingData, siblingDoc, value })=>{
|
|
235
|
+
capturedSiblingDoc = siblingDoc;
|
|
236
|
+
capturedSiblingData = siblingData;
|
|
237
|
+
siblingData.injected = 'written-into-output';
|
|
238
|
+
return value;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
]
|
|
245
|
+
}
|
|
246
|
+
];
|
|
247
|
+
const importFieldHooks = getImportFieldFunctions({
|
|
248
|
+
fields
|
|
249
|
+
});
|
|
250
|
+
const source = {
|
|
251
|
+
outer: {
|
|
252
|
+
tracked: 'original'
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
applyFieldHooks({
|
|
256
|
+
data: source,
|
|
257
|
+
fieldHooks: importFieldHooks,
|
|
258
|
+
fields,
|
|
259
|
+
format: 'json',
|
|
260
|
+
operation: 'import',
|
|
261
|
+
req: mockReq,
|
|
262
|
+
type: 'beforeImport'
|
|
263
|
+
});
|
|
264
|
+
expect(capturedSiblingDoc).toEqual({
|
|
265
|
+
tracked: 'original'
|
|
266
|
+
});
|
|
267
|
+
expect(capturedSiblingData?.injected).toBe('written-into-output');
|
|
268
|
+
expect(capturedSiblingDoc?.injected).toBeUndefined();
|
|
269
|
+
expect(source).toEqual({
|
|
270
|
+
outer: {
|
|
271
|
+
tracked: 'original'
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
//# sourceMappingURL=siblingDoc.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/siblingDoc.spec.ts"],"sourcesContent":["import { FlattenedField, PayloadRequest } from 'payload'\n\nimport type { FieldBeforeExportHook, FieldBeforeImportHook } from '../types.js'\n\nimport { applyFieldHooks } from './applyFieldHooks.js'\nimport { flattenObject } from './flattenObject.js'\nimport { getExportFieldFunctions } from './getExportFieldFunctions.js'\nimport { getImportFieldFunctions } from './getImportFieldFunctions.js'\nimport { unflattenObject } from './unflattenObject.js'\n\nimport { describe, expect, it, vi } from 'vitest'\n\nconst mockReq = {\n payload: {\n logger: {\n error: vi.fn(),\n },\n },\n} as unknown as PayloadRequest\n\ndescribe('beforeExport / beforeImport siblingDoc arg', () => {\n describe('CSV export (flattenObject)', () => {\n it('passes the source doc at the current nesting level as siblingDoc', () => {\n const received: Array<{\n columnName: string\n isSiblingDocSource: boolean\n isSiblingDocRow: boolean\n }> = []\n\n const fields: FlattenedField[] = [\n { name: 'title', type: 'text' } as FlattenedField,\n {\n name: 'group',\n type: 'group',\n flattenedFields: [\n {\n name: 'inner',\n type: 'text',\n custom: {\n 'plugin-import-export': {\n hooks: {\n beforeExport: (({ columnName, siblingData, siblingDoc, value }) => {\n received.push({\n columnName,\n isSiblingDocSource:\n siblingDoc &&\n typeof siblingDoc === 'object' &&\n siblingDoc.inner === value,\n isSiblingDocRow: siblingDoc === siblingData,\n })\n return value\n }) satisfies FieldBeforeExportHook,\n },\n },\n },\n },\n ],\n } as unknown as FlattenedField,\n ]\n\n const exportFieldHooks = getExportFieldFunctions({ fields })\n\n flattenObject({\n data: { group: { inner: 'deep' }, title: 'Top' },\n exportFieldHooks,\n format: 'csv',\n req: mockReq,\n })\n\n expect(received).toEqual([\n {\n columnName: 'group_inner',\n isSiblingDocSource: true,\n isSiblingDocRow: false,\n },\n ])\n })\n\n it('lets a hook read another sibling by reading siblingDoc', () => {\n const fields: FlattenedField[] = [\n { name: 'firstName', type: 'text' } as FlattenedField,\n {\n name: 'fullName',\n type: 'text',\n custom: {\n 'plugin-import-export': {\n hooks: {\n beforeExport: (({ siblingDoc, value }) => {\n const last = siblingDoc.lastName as string | undefined\n const first = siblingDoc.firstName as string | undefined\n if (first && last) {\n return `${first} ${last}`\n }\n return value\n }) satisfies FieldBeforeExportHook,\n },\n },\n },\n } as FlattenedField,\n { name: 'lastName', type: 'text' } as FlattenedField,\n ]\n\n const exportFieldHooks = getExportFieldFunctions({ fields })\n\n const result = flattenObject({\n data: { firstName: 'Ada', fullName: '(computed)', lastName: 'Lovelace' },\n exportFieldHooks,\n format: 'csv',\n req: mockReq,\n })\n\n expect(result.fullName).toBe('Ada Lovelace')\n })\n })\n\n describe('JSON export (applyFieldHooks)', () => {\n it('passes the untouched source sibling as siblingDoc and the mutable output as siblingData', () => {\n let capturedSiblingDoc: Record<string, unknown> | null = null\n let capturedSiblingData: Record<string, unknown> | null = null\n\n const fields: FlattenedField[] = [\n {\n name: 'outer',\n type: 'group',\n flattenedFields: [\n {\n name: 'tracked',\n type: 'text',\n custom: {\n 'plugin-import-export': {\n hooks: {\n beforeExport: (({ siblingData, siblingDoc, value }) => {\n capturedSiblingDoc = siblingDoc\n capturedSiblingData = siblingData\n siblingData.injected = 'written-into-output'\n return String(value) + '_changed'\n }) satisfies FieldBeforeExportHook,\n },\n },\n },\n },\n ],\n } as unknown as FlattenedField,\n ]\n\n const exportFieldHooks = getExportFieldFunctions({ fields })\n\n const source = { outer: { tracked: 'original' } }\n\n applyFieldHooks({\n data: source,\n fieldHooks: exportFieldHooks,\n fields,\n format: 'json',\n operation: 'export',\n req: mockReq,\n type: 'beforeExport',\n })\n\n expect(capturedSiblingDoc).toEqual({ tracked: 'original' })\n // The hook's mutation lives on siblingData, not siblingDoc\n expect((capturedSiblingData as unknown as Record<string, unknown>)?.injected).toBe(\n 'written-into-output',\n )\n expect((capturedSiblingDoc as unknown as Record<string, unknown>)?.injected).toBeUndefined()\n // And the source object itself is not mutated\n expect(source).toEqual({ outer: { tracked: 'original' } })\n })\n })\n\n describe('CSV import (unflattenObject)', () => {\n it('passes the full flat row as siblingDoc (equal to data)', () => {\n const received: Array<{ siblingDocIsData: boolean }> = []\n\n const fields: FlattenedField[] = [\n { name: 'title', type: 'text' } as FlattenedField,\n {\n name: 'note',\n type: 'text',\n custom: {\n 'plugin-import-export': {\n hooks: {\n beforeImport: (({ data, siblingDoc, value }) => {\n received.push({ siblingDocIsData: siblingDoc === data })\n return value\n }) satisfies FieldBeforeImportHook,\n },\n },\n },\n } as FlattenedField,\n ]\n\n const importFieldHooks = getImportFieldFunctions({ fields })\n\n unflattenObject({\n data: { note: 'hello', title: 'Top' },\n fields,\n format: 'csv',\n importFieldHooks,\n req: mockReq,\n })\n\n expect(received).toEqual([{ siblingDocIsData: true }])\n })\n })\n\n describe('JSON import (applyFieldHooks)', () => {\n it('passes the untouched source sibling as siblingDoc and the mutable output as siblingData', () => {\n let capturedSiblingDoc: Record<string, unknown> | null = null\n let capturedSiblingData: Record<string, unknown> | null = null\n\n const fields: FlattenedField[] = [\n {\n name: 'outer',\n type: 'group',\n flattenedFields: [\n {\n name: 'tracked',\n type: 'text',\n custom: {\n 'plugin-import-export': {\n hooks: {\n beforeImport: (({ siblingData, siblingDoc, value }) => {\n capturedSiblingDoc = siblingDoc\n capturedSiblingData = siblingData\n siblingData.injected = 'written-into-output'\n return value\n }) satisfies FieldBeforeImportHook,\n },\n },\n },\n },\n ],\n } as unknown as FlattenedField,\n ]\n\n const importFieldHooks = getImportFieldFunctions({ fields })\n\n const source = { outer: { tracked: 'original' } }\n\n applyFieldHooks({\n data: source,\n fieldHooks: importFieldHooks,\n fields,\n format: 'json',\n operation: 'import',\n req: mockReq,\n type: 'beforeImport',\n })\n\n expect(capturedSiblingDoc).toEqual({ tracked: 'original' })\n expect((capturedSiblingData as unknown as Record<string, unknown>)?.injected).toBe(\n 'written-into-output',\n )\n expect((capturedSiblingDoc as unknown as Record<string, unknown>)?.injected).toBeUndefined()\n expect(source).toEqual({ outer: { tracked: 'original' } })\n })\n })\n})\n"],"names":["applyFieldHooks","flattenObject","getExportFieldFunctions","getImportFieldFunctions","unflattenObject","describe","expect","it","vi","mockReq","payload","logger","error","fn","received","fields","name","type","flattenedFields","custom","hooks","beforeExport","columnName","siblingData","siblingDoc","value","push","isSiblingDocSource","inner","isSiblingDocRow","exportFieldHooks","data","group","title","format","req","toEqual","last","lastName","first","firstName","result","fullName","toBe","capturedSiblingDoc","capturedSiblingData","injected","String","source","outer","tracked","fieldHooks","operation","toBeUndefined","beforeImport","siblingDocIsData","importFieldHooks","note"],"mappings":"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"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { FlattenedField, PayloadRequest } from 'payload';
|
|
2
|
-
import type {
|
|
2
|
+
import type { ImportFieldHookEntry } from '../types.js';
|
|
3
3
|
type UnflattenArgs = {
|
|
4
4
|
data: Record<string, unknown>;
|
|
5
5
|
fields: FlattenedField[];
|
|
6
|
-
|
|
6
|
+
format?: 'csv' | 'json' | ({} & string);
|
|
7
|
+
importFieldHooks?: Record<string, ImportFieldHookEntry>;
|
|
7
8
|
req: PayloadRequest;
|
|
8
9
|
};
|
|
9
10
|
/**
|
|
@@ -19,6 +20,6 @@ type UnflattenArgs = {
|
|
|
19
20
|
* - Regular nested objects
|
|
20
21
|
* 4. Post-processes to handle localized fields, hasMany conversions, and relationship transforms
|
|
21
22
|
*/
|
|
22
|
-
export declare const unflattenObject: ({ data, fields,
|
|
23
|
+
export declare const unflattenObject: ({ data, fields, format, importFieldHooks, req, }: UnflattenArgs) => Record<string, unknown>;
|
|
23
24
|
export {};
|
|
24
25
|
//# sourceMappingURL=unflattenObject.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unflattenObject.d.ts","sourceRoot":"","sources":["../../src/utilities/unflattenObject.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAE7D,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"unflattenObject.d.ts","sourceRoot":"","sources":["../../src/utilities/unflattenObject.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAE7D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAA;AAKvD,KAAK,aAAa,GAAG;IACnB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC7B,MAAM,EAAE,cAAc,EAAE,CAAA;IACxB,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,CAAC,EAAE,GAAG,MAAM,CAAC,CAAA;IACvC,gBAAgB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAA;IACvD,GAAG,EAAE,cAAc,CAAA;CACpB,CAAA;AAiCD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,eAAe,qDAMzB,aAAa,KAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAkUxC,CAAA"}
|
|
@@ -1,4 +1,30 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getNestedFlattenedFields } from './flattenedFields.js';
|
|
2
|
+
import { postProcessDocument } from './unflattenPostProcess.js';
|
|
3
|
+
const indexSegment = /^\d+$/;
|
|
4
|
+
const collectArrayLikeNames = (fields, into)=>{
|
|
5
|
+
for (const field of fields){
|
|
6
|
+
if (!('name' in field) || !field.name) {
|
|
7
|
+
continue;
|
|
8
|
+
}
|
|
9
|
+
if (field.type === 'array' || field.type === 'blocks') {
|
|
10
|
+
into.add(field.name);
|
|
11
|
+
}
|
|
12
|
+
const nested = getNestedFlattenedFields(field);
|
|
13
|
+
if (nested) {
|
|
14
|
+
collectArrayLikeNames(nested, into);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Drops numeric array-index segments from a flat key so a runtime key like
|
|
20
|
+
* `items_0_note` matches the static, index-free key a user hook is registered
|
|
21
|
+
* under. A digit-only segment is only stripped when the segment immediately
|
|
22
|
+
* before it names an array or blocks field, so a literal field name like
|
|
23
|
+
* `2024` is preserved.
|
|
24
|
+
*/ const toLogicalKey = (flatKey, arrayLikeNames)=>{
|
|
25
|
+
const segments = flatKey.split('_');
|
|
26
|
+
return segments.filter((seg, i)=>!indexSegment.test(seg) || !arrayLikeNames.has(segments[i - 1] ?? '')).join('_');
|
|
27
|
+
};
|
|
2
28
|
/**
|
|
3
29
|
* Converts flattened CSV data back into a nested document structure.
|
|
4
30
|
*
|
|
@@ -11,11 +37,13 @@ import { processRichTextField } from './processRichTextField.js';
|
|
|
11
37
|
* - Polymorphic relationships (_relationTo and _id suffix pairs)
|
|
12
38
|
* - Regular nested objects
|
|
13
39
|
* 4. Post-processes to handle localized fields, hasMany conversions, and relationship transforms
|
|
14
|
-
*/ export const unflattenObject = ({ data, fields,
|
|
40
|
+
*/ export const unflattenObject = ({ data, fields, format = 'csv', importFieldHooks = {}, req })=>{
|
|
15
41
|
if (!data || typeof data !== 'object') {
|
|
16
42
|
return {};
|
|
17
43
|
}
|
|
18
44
|
const result = {};
|
|
45
|
+
const arrayLikeNames = new Set();
|
|
46
|
+
collectArrayLikeNames(fields, arrayLikeNames);
|
|
19
47
|
// Sort keys to ensure array indices are processed in order
|
|
20
48
|
const sortedKeys = Object.keys(data).sort((a, b)=>{
|
|
21
49
|
// Extract array indices from flattened keys (e.g., "field_0_subfield" -> "0")
|
|
@@ -72,13 +100,33 @@ import { processRichTextField } from './processRichTextField.js';
|
|
|
72
100
|
}
|
|
73
101
|
}
|
|
74
102
|
}
|
|
75
|
-
|
|
76
|
-
if (
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
103
|
+
const importHookEntry = importFieldHooks[flatKey] ?? importFieldHooks[toLogicalKey(flatKey, arrayLikeNames)];
|
|
104
|
+
if (importHookEntry) {
|
|
105
|
+
try {
|
|
106
|
+
if (importHookEntry.type === 'beforeImport') {
|
|
107
|
+
value = importHookEntry.fn({
|
|
108
|
+
columnName: flatKey,
|
|
109
|
+
data,
|
|
110
|
+
format,
|
|
111
|
+
siblingData: data,
|
|
112
|
+
siblingDoc: data,
|
|
113
|
+
value
|
|
114
|
+
});
|
|
115
|
+
} else {
|
|
116
|
+
value = importHookEntry.fn({
|
|
117
|
+
columnName: flatKey,
|
|
118
|
+
data,
|
|
119
|
+
value
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
} catch (error) {
|
|
123
|
+
req.payload.logger.error({
|
|
124
|
+
err: error,
|
|
125
|
+
msg: `[plugin-import-export] Field-level beforeImport hook for "${flatKey}" threw — falling back to original value`
|
|
126
|
+
});
|
|
127
|
+
// Keep the original value so the row is not dropped — downstream
|
|
128
|
+
// validation will surface any deeper issue per-row.
|
|
129
|
+
}
|
|
82
130
|
}
|
|
83
131
|
// Example: "blocks_0_content_text" -> ["blocks", "0", "content", "text"]
|
|
84
132
|
const pathSegments = flatKey.split('_');
|
|
@@ -271,165 +319,5 @@ const getParentObject = (obj, segments)=>{
|
|
|
271
319
|
}
|
|
272
320
|
return current;
|
|
273
321
|
};
|
|
274
|
-
/**
|
|
275
|
-
* Post-processes the unflattened document to handle special field types:
|
|
276
|
-
* - Localized fields: transforms field_locale keys to nested { field: { locale: value } }
|
|
277
|
-
* - Number hasMany: converts comma-separated strings or arrays to number arrays
|
|
278
|
-
* - Relationship hasMany: converts comma-separated IDs to arrays
|
|
279
|
-
* - Polymorphic relationships: transforms flat {relationTo, id} to {relationTo, value}
|
|
280
|
-
* - Rich text fields: ensures proper data structure
|
|
281
|
-
*/ const postProcessDocument = (doc, fields)=>{
|
|
282
|
-
const localizedFields = fields.filter((field)=>field.localized);
|
|
283
|
-
const processedLocalizedFields = new Set();
|
|
284
|
-
for (const field of localizedFields){
|
|
285
|
-
if (processedLocalizedFields.has(field.name)) {
|
|
286
|
-
continue;
|
|
287
|
-
}
|
|
288
|
-
// Look for all locale-specific keys for this field
|
|
289
|
-
const localePattern = new RegExp(`^${field.name}_([a-z]{2}(?:_[A-Z]{2})?)$`);
|
|
290
|
-
const localeData = {};
|
|
291
|
-
const keysToDelete = [];
|
|
292
|
-
for (const [key, value] of Object.entries(doc)){
|
|
293
|
-
const match = key.match(localePattern);
|
|
294
|
-
if (match && match[1]) {
|
|
295
|
-
const locale = match[1];
|
|
296
|
-
localeData[locale] = value;
|
|
297
|
-
keysToDelete.push(key);
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
// If we found locale-specific data, restructure it as Payload expects
|
|
301
|
-
if (Object.keys(localeData).length > 0) {
|
|
302
|
-
// Payload stores localized fields as nested objects: { field: { en: 'value', es: 'value' } }
|
|
303
|
-
doc[field.name] = localeData;
|
|
304
|
-
keysToDelete.forEach((key)=>delete doc[key]);
|
|
305
|
-
processedLocalizedFields.add(field.name);
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
// Handle number fields with hasMany - convert string arrays to number arrays
|
|
309
|
-
const numberFields = fields.filter((field)=>field.type === 'number' && field.hasMany);
|
|
310
|
-
for (const field of numberFields){
|
|
311
|
-
const value = doc[field.name];
|
|
312
|
-
// Skip if field doesn't exist in document
|
|
313
|
-
if (!(field.name in doc)) {
|
|
314
|
-
continue;
|
|
315
|
-
}
|
|
316
|
-
// Handle comma-separated string (e.g., "1,2,3,4,5")
|
|
317
|
-
if (typeof value === 'string' && value.includes(',')) {
|
|
318
|
-
doc[field.name] = value.split(',').map((v)=>v.trim()).filter((v)=>v !== '').map((v)=>{
|
|
319
|
-
const num = parseFloat(v);
|
|
320
|
-
return isNaN(num) ? 0 : num;
|
|
321
|
-
});
|
|
322
|
-
} else if (Array.isArray(value)) {
|
|
323
|
-
// Filter out null, undefined, and empty string values, then convert to numbers
|
|
324
|
-
doc[field.name] = value.filter((v)=>v !== null && v !== undefined && v !== '').map((v)=>{
|
|
325
|
-
if (typeof v === 'string') {
|
|
326
|
-
const num = parseFloat(v);
|
|
327
|
-
return isNaN(num) ? 0 : num;
|
|
328
|
-
}
|
|
329
|
-
return v;
|
|
330
|
-
});
|
|
331
|
-
} else if (value !== null && value !== undefined && value !== '') {
|
|
332
|
-
const num = typeof value === 'string' ? parseFloat(value) : value;
|
|
333
|
-
doc[field.name] = isNaN(num) ? [] : [
|
|
334
|
-
num
|
|
335
|
-
];
|
|
336
|
-
} else {
|
|
337
|
-
doc[field.name] = [];
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
// Handle relationship fields with hasMany - convert comma-separated IDs to arrays
|
|
341
|
-
const relationshipFields = fields.filter((field)=>(field.type === 'relationship' || field.type === 'upload') && field.hasMany === true && !Array.isArray(field.relationTo));
|
|
342
|
-
for (const field of relationshipFields){
|
|
343
|
-
const value = doc[field.name];
|
|
344
|
-
// Handle comma-separated string of IDs (e.g., "id1,id2,id3")
|
|
345
|
-
if (typeof value === 'string' && value.includes(',')) {
|
|
346
|
-
doc[field.name] = value.split(',').map((v)=>v.trim()).filter((v)=>v !== '');
|
|
347
|
-
} else if (Array.isArray(value)) {
|
|
348
|
-
doc[field.name] = value.filter((v)=>v !== null && v !== undefined && v !== '');
|
|
349
|
-
} else if (value !== null && value !== undefined && value !== '') {
|
|
350
|
-
doc[field.name] = [
|
|
351
|
-
value
|
|
352
|
-
];
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
// Handle polymorphic relationships - transform from flat structure to proper format
|
|
356
|
-
for (const [key, value] of Object.entries(doc)){
|
|
357
|
-
// Handle arrays of polymorphic relationships
|
|
358
|
-
if (Array.isArray(value)) {
|
|
359
|
-
// Check if this array contains polymorphic relationship objects
|
|
360
|
-
const hasPolymorphicItems = value.some((item)=>typeof item === 'object' && item !== null && 'relationTo' in item);
|
|
361
|
-
if (hasPolymorphicItems) {
|
|
362
|
-
// Filter out null/invalid polymorphic items and transform valid ones
|
|
363
|
-
const processedArray = [];
|
|
364
|
-
for(let i = 0; i < value.length; i++){
|
|
365
|
-
const item = value[i];
|
|
366
|
-
if (typeof item === 'object' && item !== null && 'relationTo' in item) {
|
|
367
|
-
const typedItem = item;
|
|
368
|
-
// Skip if both relationTo and value/id are null/empty
|
|
369
|
-
if (!typedItem.relationTo || !typedItem.id && !typedItem.value) {
|
|
370
|
-
continue;
|
|
371
|
-
}
|
|
372
|
-
// Transform from {relationTo: 'collection', id: '123'} to {relationTo: 'collection', value: '123'}
|
|
373
|
-
if ('id' in typedItem) {
|
|
374
|
-
typedItem.value = typedItem.id;
|
|
375
|
-
delete typedItem.id;
|
|
376
|
-
}
|
|
377
|
-
processedArray.push(typedItem);
|
|
378
|
-
} else if (item !== null && item !== undefined) {
|
|
379
|
-
processedArray.push(item);
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
// Update the array with filtered results
|
|
383
|
-
if (value.length !== processedArray.length) {
|
|
384
|
-
doc[key] = processedArray.length > 0 ? processedArray : [];
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
// For non-polymorphic arrays, preserve null placeholders for sparse arrays
|
|
388
|
-
} else if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
|
|
389
|
-
// Check if this is a single polymorphic relationship
|
|
390
|
-
if ('relationTo' in value && ('id' in value || 'value' in value)) {
|
|
391
|
-
const typedValue = value;
|
|
392
|
-
// If both relationTo and value are null/empty, set the whole field to null
|
|
393
|
-
if (!typedValue.relationTo || !typedValue.id && !typedValue.value) {
|
|
394
|
-
doc[key] = null;
|
|
395
|
-
} else {
|
|
396
|
-
// If it has 'id', transform to 'value'
|
|
397
|
-
if ('id' in typedValue && !('value' in typedValue)) {
|
|
398
|
-
typedValue.value = typedValue.id;
|
|
399
|
-
delete typedValue.id;
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
} else {
|
|
403
|
-
// Recursively process nested objects
|
|
404
|
-
postProcessDocument(value, fields);
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
// Process rich text fields to ensure proper data types
|
|
409
|
-
const richTextFields = fields.filter((field)=>field.type === 'richText');
|
|
410
|
-
for (const field of richTextFields){
|
|
411
|
-
if (field.name in doc && doc[field.name]) {
|
|
412
|
-
doc[field.name] = processRichTextField(doc[field.name]);
|
|
413
|
-
}
|
|
414
|
-
}
|
|
415
|
-
// Also process rich text fields in blocks
|
|
416
|
-
const blockFields = fields.filter((field)=>field.type === 'blocks');
|
|
417
|
-
for (const field of blockFields){
|
|
418
|
-
if (field.name in doc && Array.isArray(doc[field.name])) {
|
|
419
|
-
const blocks = doc[field.name];
|
|
420
|
-
for (const block of blocks){
|
|
421
|
-
if (!block || typeof block !== 'object') {
|
|
422
|
-
continue;
|
|
423
|
-
}
|
|
424
|
-
// Look for richText fields directly in the block
|
|
425
|
-
for (const [key, value] of Object.entries(block)){
|
|
426
|
-
if (key === 'richText' || typeof key === 'string' && key.includes('richText')) {
|
|
427
|
-
block[key] = processRichTextField(value);
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
};
|
|
434
322
|
|
|
435
323
|
//# sourceMappingURL=unflattenObject.js.map
|