@payloadcms/plugin-import-export 4.0.0-internal.d28e9fb → 4.0.0-internal.d7d662c
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/components/CollectionField/index.d.ts +3 -2
- package/dist/components/CollectionField/index.d.ts.map +1 -1
- package/dist/components/CollectionField/index.js.map +1 -1
- package/dist/components/ExportListMenuItem/index.d.ts.map +1 -1
- package/dist/components/ExportListMenuItem/index.js +14 -12
- package/dist/components/ExportListMenuItem/index.js.map +1 -1
- package/dist/components/ExportPreview/index.css +52 -0
- package/dist/components/ExportPreview/index.d.ts +1 -1
- package/dist/components/ExportPreview/index.d.ts.map +1 -1
- package/dist/components/ExportPreview/index.js +12 -2
- package/dist/components/ExportPreview/index.js.map +1 -1
- package/dist/components/FieldsToExport/index.d.ts +3 -2
- package/dist/components/FieldsToExport/index.d.ts.map +1 -1
- package/dist/components/FieldsToExport/index.js +18 -15
- package/dist/components/FieldsToExport/index.js.map +1 -1
- package/dist/components/FieldsToExport/reduceFields.d.ts +6 -0
- package/dist/components/FieldsToExport/reduceFields.d.ts.map +1 -1
- package/dist/components/FieldsToExport/reduceFields.js +4 -0
- package/dist/components/FieldsToExport/reduceFields.js.map +1 -1
- package/dist/components/FormatField/index.d.ts +3 -2
- package/dist/components/FormatField/index.d.ts.map +1 -1
- package/dist/components/FormatField/index.js +6 -3
- package/dist/components/FormatField/index.js.map +1 -1
- package/dist/components/ImportListMenuItem/index.d.ts.map +1 -1
- package/dist/components/ImportListMenuItem/index.js +14 -12
- package/dist/components/ImportListMenuItem/index.js.map +1 -1
- package/dist/components/ImportPreview/index.css +45 -0
- package/dist/components/ImportPreview/index.d.ts +1 -1
- package/dist/components/ImportPreview/index.d.ts.map +1 -1
- package/dist/components/ImportPreview/index.js +44 -11
- package/dist/components/ImportPreview/index.js.map +1 -1
- package/dist/components/LimitField/index.d.ts +3 -2
- package/dist/components/LimitField/index.d.ts.map +1 -1
- package/dist/components/LimitField/index.js.map +1 -1
- package/dist/components/LocaleField/index.d.ts +3 -2
- package/dist/components/LocaleField/index.d.ts.map +1 -1
- package/dist/components/LocaleField/index.js.map +1 -1
- package/dist/components/Page/index.d.ts +4 -3
- package/dist/components/Page/index.d.ts.map +1 -1
- package/dist/components/Page/index.js +1 -1
- package/dist/components/Page/index.js.map +1 -1
- package/dist/components/RelationshipCell/getRelationshipGroupKey.d.ts +7 -0
- package/dist/components/RelationshipCell/getRelationshipGroupKey.d.ts.map +1 -0
- package/dist/components/RelationshipCell/getRelationshipGroupKey.js +3 -0
- package/dist/components/RelationshipCell/getRelationshipGroupKey.js.map +1 -0
- package/dist/components/RelationshipCell/getRelationshipGroups.d.ts +43 -0
- package/dist/components/RelationshipCell/getRelationshipGroups.d.ts.map +1 -0
- package/dist/components/RelationshipCell/getRelationshipGroups.js +109 -0
- package/dist/components/RelationshipCell/getRelationshipGroups.js.map +1 -0
- package/dist/components/RelationshipCell/index.css +30 -0
- package/dist/components/RelationshipCell/index.d.ts +15 -0
- package/dist/components/RelationshipCell/index.d.ts.map +1 -0
- package/dist/components/RelationshipCell/index.js +57 -0
- package/dist/components/RelationshipCell/index.js.map +1 -0
- package/dist/components/SortBy/index.css +9 -0
- package/dist/components/SortBy/index.d.ts +4 -3
- package/dist/components/SortBy/index.d.ts.map +1 -1
- package/dist/components/SortBy/index.js +1 -2
- package/dist/components/SortBy/index.js.map +1 -1
- package/dist/components/SortOrder/index.css +9 -0
- package/dist/components/SortOrder/index.d.ts +4 -3
- package/dist/components/SortOrder/index.d.ts.map +1 -1
- package/dist/components/SortOrder/index.js +1 -2
- package/dist/components/SortOrder/index.js.map +1 -1
- package/dist/export/batchProcessor.d.ts +4 -3
- package/dist/export/batchProcessor.d.ts.map +1 -1
- package/dist/export/batchProcessor.js +6 -2
- package/dist/export/batchProcessor.js.map +1 -1
- package/dist/export/createExport.d.ts +4 -2
- package/dist/export/createExport.d.ts.map +1 -1
- package/dist/export/createExport.js +7 -2
- package/dist/export/createExport.js.map +1 -1
- package/dist/export/getCreateExportCollectionTask.d.ts.map +1 -1
- package/dist/export/getCreateExportCollectionTask.js +11 -0
- package/dist/export/getCreateExportCollectionTask.js.map +1 -1
- package/dist/export/getExportCollection.d.ts.map +1 -1
- package/dist/export/getExportCollection.js +9 -4
- package/dist/export/getExportCollection.js.map +1 -1
- package/dist/export/getFields.js.map +1 -1
- package/dist/export/handleDownload.d.ts.map +1 -1
- package/dist/export/handleDownload.js +7 -3
- package/dist/export/handleDownload.js.map +1 -1
- package/dist/export/handlePreview.d.ts.map +1 -1
- package/dist/export/handlePreview.js +25 -6
- 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 +4 -3
- package/dist/import/batchProcessor.d.ts.map +1 -1
- package/dist/import/batchProcessor.js +15 -8
- package/dist/import/batchProcessor.js.map +1 -1
- package/dist/import/createImport.d.ts +3 -2
- package/dist/import/createImport.d.ts.map +1 -1
- package/dist/import/createImport.js +9 -2
- package/dist/import/createImport.js.map +1 -1
- package/dist/import/getCreateImportCollectionTask.d.ts.map +1 -1
- package/dist/import/getCreateImportCollectionTask.js +5 -2
- package/dist/import/getCreateImportCollectionTask.js.map +1 -1
- package/dist/import/getImportCollection.d.ts.map +1 -1
- package/dist/import/getImportCollection.js +6 -4
- package/dist/import/getImportCollection.js.map +1 -1
- package/dist/import/handlePreview.d.ts.map +1 -1
- package/dist/import/handlePreview.js +5 -1
- package/dist/import/handlePreview.js.map +1 -1
- package/dist/index.d.ts +2 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -8
- package/dist/index.js.map +1 -1
- package/dist/translations/languages/en.d.ts.map +1 -1
- package/dist/types.d.ts +17 -33
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utilities/applyFieldHooks.d.ts +1 -2
- package/dist/utilities/applyFieldHooks.d.ts.map +1 -1
- package/dist/utilities/applyFieldHooks.js +2 -3
- package/dist/utilities/applyFieldHooks.js.map +1 -1
- package/dist/utilities/flattenObject.d.ts.map +1 -1
- package/dist/utilities/flattenObject.js +3 -13
- package/dist/utilities/flattenObject.js.map +1 -1
- package/dist/utilities/flattenedFields.d.ts.map +1 -1
- package/dist/utilities/flattenedFields.js +3 -0
- package/dist/utilities/flattenedFields.js.map +1 -1
- package/dist/utilities/getExportFieldFunctions.js +64 -35
- package/dist/utilities/getExportFieldFunctions.js.map +1 -1
- package/dist/utilities/getFileFromDoc.js +3 -3
- package/dist/utilities/getFileFromDoc.js.map +1 -1
- package/dist/utilities/getImportFieldFunctions.js +0 -8
- package/dist/utilities/getImportFieldFunctions.js.map +1 -1
- package/dist/utilities/getSchemaColumns.d.ts +1 -1
- package/dist/utilities/getSchemaColumns.js +2 -2
- package/dist/utilities/getSchemaColumns.js.map +1 -1
- package/dist/utilities/getSelect.d.ts.map +1 -1
- package/dist/utilities/getSelect.js +11 -3
- package/dist/utilities/getSelect.js.map +1 -1
- package/dist/utilities/getSubmittedFormValues.d.ts +12 -0
- package/dist/utilities/getSubmittedFormValues.d.ts.map +1 -0
- package/dist/utilities/getSubmittedFormValues.js +24 -0
- package/dist/utilities/getSubmittedFormValues.js.map +1 -0
- package/dist/utilities/processRichTextField.d.ts.map +1 -1
- package/dist/utilities/processRichTextField.js +7 -0
- package/dist/utilities/processRichTextField.js.map +1 -1
- package/dist/utilities/setNestedValue.d.ts +2 -1
- package/dist/utilities/setNestedValue.d.ts.map +1 -1
- package/dist/utilities/setNestedValue.js +65 -34
- package/dist/utilities/setNestedValue.js.map +1 -1
- package/dist/utilities/sortHelpers.d.ts +1 -1
- package/dist/utilities/unflattenObject.d.ts.map +1 -1
- package/dist/utilities/unflattenObject.js +29 -18
- package/dist/utilities/unflattenObject.js.map +1 -1
- package/dist/utilities/unflattenPostProcess.d.ts.map +1 -1
- package/dist/utilities/unflattenPostProcess.js +39 -13
- package/dist/utilities/unflattenPostProcess.js.map +1 -1
- package/license.md +1 -1
- package/package.json +25 -28
- package/dist/components/ExportPreview/index.scss +0 -48
- package/dist/components/FieldsToExport/index.scss +0 -0
- package/dist/components/FieldsToExport/reduceFields.spec.js +0 -239
- package/dist/components/FieldsToExport/reduceFields.spec.js.map +0 -1
- package/dist/components/ImportPreview/index.scss +0 -41
- package/dist/components/SortBy/index.scss +0 -3
- package/dist/components/SortOrder/index.scss +0 -3
- package/dist/utilities/applyFieldHooks.spec.js +0 -205
- package/dist/utilities/applyFieldHooks.spec.js.map +0 -1
- package/dist/utilities/buildDisabledFieldRegex.spec.js +0 -64
- package/dist/utilities/buildDisabledFieldRegex.spec.js.map +0 -1
- package/dist/utilities/fieldToRegex.spec.js +0 -151
- package/dist/utilities/fieldToRegex.spec.js.map +0 -1
- package/dist/utilities/filterToSelectedFields.spec.js +0 -204
- package/dist/utilities/filterToSelectedFields.spec.js.map +0 -1
- package/dist/utilities/flattenObject.spec.js +0 -158
- package/dist/utilities/flattenObject.spec.js.map +0 -1
- package/dist/utilities/getExportFieldFunctions.spec.js +0 -50
- package/dist/utilities/getExportFieldFunctions.spec.js.map +0 -1
- package/dist/utilities/getImportFieldFunctions.spec.js +0 -167
- package/dist/utilities/getImportFieldFunctions.spec.js.map +0 -1
- package/dist/utilities/getSchemaColumns.spec.js +0 -157
- package/dist/utilities/getSchemaColumns.spec.js.map +0 -1
- package/dist/utilities/legacyHookDispatch.spec.js +0 -227
- package/dist/utilities/legacyHookDispatch.spec.js.map +0 -1
- package/dist/utilities/parseCSV.spec.js +0 -195
- package/dist/utilities/parseCSV.spec.js.map +0 -1
- package/dist/utilities/siblingDoc.spec.js +0 -278
- package/dist/utilities/siblingDoc.spec.js.map +0 -1
- package/dist/utilities/unflattenObject.spec.js +0 -713
- package/dist/utilities/unflattenObject.spec.js.map +0 -1
- /package/dist/components/Page/{index.scss → index.css} +0 -0
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
import { parseCSV } from './parseCSV.js';
|
|
2
|
-
import { describe, it, expect, vi } from 'vitest';
|
|
3
|
-
describe('parseCSV', ()=>{
|
|
4
|
-
const mockReq = {
|
|
5
|
-
payload: {
|
|
6
|
-
logger: {
|
|
7
|
-
error: vi.fn()
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
};
|
|
11
|
-
describe('cast function behavior', ()=>{
|
|
12
|
-
it('should preserve comma-separated values as strings', async ()=>{
|
|
13
|
-
const csvData = Buffer.from('numbers,ids\n"1,2,3,5,8","id1,id2,id3"');
|
|
14
|
-
const result = await parseCSV({
|
|
15
|
-
data: csvData,
|
|
16
|
-
req: mockReq
|
|
17
|
-
});
|
|
18
|
-
expect(result).toEqual([
|
|
19
|
-
{
|
|
20
|
-
numbers: '1,2,3,5,8',
|
|
21
|
-
ids: 'id1,id2,id3'
|
|
22
|
-
}
|
|
23
|
-
]);
|
|
24
|
-
});
|
|
25
|
-
it('should convert single numbers to numbers', async ()=>{
|
|
26
|
-
const csvData = Buffer.from('single,decimal\n"42","3.14"');
|
|
27
|
-
const result = await parseCSV({
|
|
28
|
-
data: csvData,
|
|
29
|
-
req: mockReq
|
|
30
|
-
});
|
|
31
|
-
expect(result).toEqual([
|
|
32
|
-
{
|
|
33
|
-
single: 42,
|
|
34
|
-
decimal: 3.14
|
|
35
|
-
}
|
|
36
|
-
]);
|
|
37
|
-
});
|
|
38
|
-
it('should handle booleans correctly', async ()=>{
|
|
39
|
-
const csvData = Buffer.from('bool1,bool2,notBool\n"true","false","True"');
|
|
40
|
-
const result = await parseCSV({
|
|
41
|
-
data: csvData,
|
|
42
|
-
req: mockReq
|
|
43
|
-
});
|
|
44
|
-
expect(result).toEqual([
|
|
45
|
-
{
|
|
46
|
-
bool1: true,
|
|
47
|
-
bool2: false,
|
|
48
|
-
notBool: 'True'
|
|
49
|
-
}
|
|
50
|
-
]);
|
|
51
|
-
});
|
|
52
|
-
it('should convert empty strings to undefined', async ()=>{
|
|
53
|
-
const csvData = Buffer.from('field1,field2\n"","value"');
|
|
54
|
-
const result = await parseCSV({
|
|
55
|
-
data: csvData,
|
|
56
|
-
req: mockReq
|
|
57
|
-
});
|
|
58
|
-
expect(result).toEqual([
|
|
59
|
-
{
|
|
60
|
-
// field1 is undefined (not present) - empty cells don't update fields
|
|
61
|
-
field2: 'value'
|
|
62
|
-
}
|
|
63
|
-
]);
|
|
64
|
-
});
|
|
65
|
-
it('should handle null strings', async ()=>{
|
|
66
|
-
const csvData = Buffer.from('field1,field2,field3\n"null","NULL","Null"');
|
|
67
|
-
const result = await parseCSV({
|
|
68
|
-
data: csvData,
|
|
69
|
-
req: mockReq
|
|
70
|
-
});
|
|
71
|
-
expect(result).toEqual([
|
|
72
|
-
{
|
|
73
|
-
field1: null,
|
|
74
|
-
field2: null,
|
|
75
|
-
field3: 'Null'
|
|
76
|
-
}
|
|
77
|
-
]);
|
|
78
|
-
});
|
|
79
|
-
it('should preserve spaces in comma-separated values', async ()=>{
|
|
80
|
-
const csvData = Buffer.from('numbers\n" 10 , 20 , 30 "');
|
|
81
|
-
const result = await parseCSV({
|
|
82
|
-
data: csvData,
|
|
83
|
-
req: mockReq
|
|
84
|
-
});
|
|
85
|
-
expect(result).toEqual([
|
|
86
|
-
{
|
|
87
|
-
numbers: ' 10 , 20 , 30 '
|
|
88
|
-
}
|
|
89
|
-
]);
|
|
90
|
-
});
|
|
91
|
-
it('should handle mixed comma-separated values with empty entries', async ()=>{
|
|
92
|
-
const csvData = Buffer.from('mixed\n"1,,3,,5"');
|
|
93
|
-
const result = await parseCSV({
|
|
94
|
-
data: csvData,
|
|
95
|
-
req: mockReq
|
|
96
|
-
});
|
|
97
|
-
expect(result).toEqual([
|
|
98
|
-
{
|
|
99
|
-
mixed: '1,,3,,5'
|
|
100
|
-
}
|
|
101
|
-
]);
|
|
102
|
-
});
|
|
103
|
-
it('should handle MongoDB ObjectIds as strings', async ()=>{
|
|
104
|
-
const csvData = Buffer.from('id\n"507f1f77bcf86cd799439011"');
|
|
105
|
-
const result = await parseCSV({
|
|
106
|
-
data: csvData,
|
|
107
|
-
req: mockReq
|
|
108
|
-
});
|
|
109
|
-
expect(result).toEqual([
|
|
110
|
-
{
|
|
111
|
-
id: '507f1f77bcf86cd799439011'
|
|
112
|
-
}
|
|
113
|
-
]);
|
|
114
|
-
});
|
|
115
|
-
it('should handle multiple rows with various data types', async ()=>{
|
|
116
|
-
const csvData = Buffer.from('title,count,tags,active\n' + '"Item 1","5","tag1,tag2,tag3","true"\n' + '"Item 2","","","false"\n' + '"Item 3","10","single",""\n');
|
|
117
|
-
const result = await parseCSV({
|
|
118
|
-
data: csvData,
|
|
119
|
-
req: mockReq
|
|
120
|
-
});
|
|
121
|
-
expect(result).toEqual([
|
|
122
|
-
{
|
|
123
|
-
title: 'Item 1',
|
|
124
|
-
count: 5,
|
|
125
|
-
tags: 'tag1,tag2,tag3',
|
|
126
|
-
active: true
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
title: 'Item 2',
|
|
130
|
-
// count is undefined (empty cell - field not updated)
|
|
131
|
-
// tags is undefined (empty cell - field not updated)
|
|
132
|
-
active: false
|
|
133
|
-
},
|
|
134
|
-
{
|
|
135
|
-
title: 'Item 3',
|
|
136
|
-
count: 10,
|
|
137
|
-
tags: 'single'
|
|
138
|
-
}
|
|
139
|
-
]);
|
|
140
|
-
});
|
|
141
|
-
it('should skip empty lines', async ()=>{
|
|
142
|
-
const csvData = Buffer.from('field\n"value1"\n\n"value2"\n\n');
|
|
143
|
-
const result = await parseCSV({
|
|
144
|
-
data: csvData,
|
|
145
|
-
req: mockReq
|
|
146
|
-
});
|
|
147
|
-
expect(result).toEqual([
|
|
148
|
-
{
|
|
149
|
-
field: 'value1'
|
|
150
|
-
},
|
|
151
|
-
{
|
|
152
|
-
field: 'value2'
|
|
153
|
-
}
|
|
154
|
-
]);
|
|
155
|
-
});
|
|
156
|
-
it('should strip UTF-8 BOM from column names', async ()=>{
|
|
157
|
-
// UTF-8 BOM is 0xEF 0xBB 0xBF
|
|
158
|
-
const bomBytes = Buffer.from([
|
|
159
|
-
0xef,
|
|
160
|
-
0xbb,
|
|
161
|
-
0xbf
|
|
162
|
-
]);
|
|
163
|
-
const csvContent = Buffer.from('id,title,createdAt\ntesssst,test,2026-02-11T21:03:39.020Z');
|
|
164
|
-
const csvWithBOM = Buffer.concat([
|
|
165
|
-
bomBytes,
|
|
166
|
-
csvContent
|
|
167
|
-
]);
|
|
168
|
-
const result = await parseCSV({
|
|
169
|
-
data: csvWithBOM,
|
|
170
|
-
req: mockReq
|
|
171
|
-
});
|
|
172
|
-
expect(result).toEqual([
|
|
173
|
-
{
|
|
174
|
-
id: 'tesssst',
|
|
175
|
-
title: 'test',
|
|
176
|
-
createdAt: '2026-02-11T21:03:39.020Z'
|
|
177
|
-
}
|
|
178
|
-
]);
|
|
179
|
-
// Verify the column name is exactly "id" without BOM character
|
|
180
|
-
expect(Object.keys(result[0])[0]).toBe('id');
|
|
181
|
-
});
|
|
182
|
-
});
|
|
183
|
-
describe('error handling', ()=>{
|
|
184
|
-
it('should handle parsing errors', async ()=>{
|
|
185
|
-
const invalidCsv = Buffer.from('field1,field2\n"value1');
|
|
186
|
-
await expect(parseCSV({
|
|
187
|
-
data: invalidCsv,
|
|
188
|
-
req: mockReq
|
|
189
|
-
})).rejects.toThrow();
|
|
190
|
-
expect(mockReq.payload.logger.error).toHaveBeenCalled();
|
|
191
|
-
});
|
|
192
|
-
});
|
|
193
|
-
});
|
|
194
|
-
|
|
195
|
-
//# sourceMappingURL=parseCSV.spec.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utilities/parseCSV.spec.ts"],"sourcesContent":["import { PayloadRequest } from 'payload'\n\nimport { parseCSV } from './parseCSV.js'\nimport { describe, it, expect, vi } from 'vitest'\n\ndescribe('parseCSV', () => {\n const mockReq = {\n payload: {\n logger: {\n error: vi.fn(),\n },\n },\n } as unknown as PayloadRequest\n\n describe('cast function behavior', () => {\n it('should preserve comma-separated values as strings', async () => {\n const csvData = Buffer.from('numbers,ids\\n\"1,2,3,5,8\",\"id1,id2,id3\"')\n const result = await parseCSV({ data: csvData, req: mockReq })\n\n expect(result).toEqual([\n {\n numbers: '1,2,3,5,8',\n ids: 'id1,id2,id3',\n },\n ])\n })\n\n it('should convert single numbers to numbers', async () => {\n const csvData = Buffer.from('single,decimal\\n\"42\",\"3.14\"')\n const result = await parseCSV({ data: csvData, req: mockReq })\n\n expect(result).toEqual([\n {\n single: 42,\n decimal: 3.14,\n },\n ])\n })\n\n it('should handle booleans correctly', async () => {\n const csvData = Buffer.from('bool1,bool2,notBool\\n\"true\",\"false\",\"True\"')\n const result = await parseCSV({ data: csvData, req: mockReq })\n\n expect(result).toEqual([\n {\n bool1: true,\n bool2: false,\n notBool: 'True', // Case-sensitive\n },\n ])\n })\n\n it('should convert empty strings to undefined', async () => {\n const csvData = Buffer.from('field1,field2\\n\"\",\"value\"')\n const result = await parseCSV({ data: csvData, req: mockReq })\n\n expect(result).toEqual([\n {\n // field1 is undefined (not present) - empty cells don't update fields\n field2: 'value',\n },\n ])\n })\n\n it('should handle null strings', async () => {\n const csvData = Buffer.from('field1,field2,field3\\n\"null\",\"NULL\",\"Null\"')\n const result = await parseCSV({ data: csvData, req: mockReq })\n\n expect(result).toEqual([\n {\n field1: null,\n field2: null,\n field3: 'Null', // Case-sensitive for mixed case\n },\n ])\n })\n\n it('should preserve spaces in comma-separated values', async () => {\n const csvData = Buffer.from('numbers\\n\" 10 , 20 , 30 \"')\n const result = await parseCSV({ data: csvData, req: mockReq })\n\n expect(result).toEqual([\n {\n numbers: ' 10 , 20 , 30 ', // CSV parser trims outer quotes but preserves the content\n },\n ])\n })\n\n it('should handle mixed comma-separated values with empty entries', async () => {\n const csvData = Buffer.from('mixed\\n\"1,,3,,5\"')\n const result = await parseCSV({ data: csvData, req: mockReq })\n\n expect(result).toEqual([\n {\n mixed: '1,,3,,5',\n },\n ])\n })\n\n it('should handle MongoDB ObjectIds as strings', async () => {\n const csvData = Buffer.from('id\\n\"507f1f77bcf86cd799439011\"')\n const result = await parseCSV({ data: csvData, req: mockReq })\n\n expect(result).toEqual([\n {\n id: '507f1f77bcf86cd799439011',\n },\n ])\n })\n\n it('should handle multiple rows with various data types', async () => {\n const csvData = Buffer.from(\n 'title,count,tags,active\\n' +\n '\"Item 1\",\"5\",\"tag1,tag2,tag3\",\"true\"\\n' +\n '\"Item 2\",\"\",\"\",\"false\"\\n' +\n '\"Item 3\",\"10\",\"single\",\"\"\\n',\n )\n const result = await parseCSV({ data: csvData, req: mockReq })\n\n expect(result).toEqual([\n {\n title: 'Item 1',\n count: 5,\n tags: 'tag1,tag2,tag3',\n active: true,\n },\n {\n title: 'Item 2',\n // count is undefined (empty cell - field not updated)\n // tags is undefined (empty cell - field not updated)\n active: false,\n },\n {\n title: 'Item 3',\n count: 10,\n tags: 'single',\n // active is undefined (empty cell - field not updated)\n },\n ])\n })\n\n it('should skip empty lines', async () => {\n const csvData = Buffer.from('field\\n\"value1\"\\n\\n\"value2\"\\n\\n')\n const result = await parseCSV({ data: csvData, req: mockReq })\n\n expect(result).toEqual([{ field: 'value1' }, { field: 'value2' }])\n })\n\n it('should strip UTF-8 BOM from column names', async () => {\n // UTF-8 BOM is 0xEF 0xBB 0xBF\n const bomBytes = Buffer.from([0xef, 0xbb, 0xbf])\n const csvContent = Buffer.from('id,title,createdAt\\ntesssst,test,2026-02-11T21:03:39.020Z')\n const csvWithBOM = Buffer.concat([bomBytes, csvContent])\n\n const result = await parseCSV({ data: csvWithBOM, req: mockReq })\n\n expect(result).toEqual([\n {\n id: 'tesssst',\n title: 'test',\n createdAt: '2026-02-11T21:03:39.020Z',\n },\n ])\n\n // Verify the column name is exactly \"id\" without BOM character\n expect(Object.keys(result[0])[0]).toBe('id')\n })\n })\n\n describe('error handling', () => {\n it('should handle parsing errors', async () => {\n const invalidCsv = Buffer.from('field1,field2\\n\"value1')\n\n await expect(parseCSV({ data: invalidCsv, req: mockReq })).rejects.toThrow()\n expect(mockReq.payload.logger.error).toHaveBeenCalled()\n })\n })\n})\n"],"names":["parseCSV","describe","it","expect","vi","mockReq","payload","logger","error","fn","csvData","Buffer","from","result","data","req","toEqual","numbers","ids","single","decimal","bool1","bool2","notBool","field2","field1","field3","mixed","id","title","count","tags","active","field","bomBytes","csvContent","csvWithBOM","concat","createdAt","Object","keys","toBe","invalidCsv","rejects","toThrow","toHaveBeenCalled"],"mappings":"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"}
|
|
@@ -1,278 +0,0 @@
|
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
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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"}
|