@payloadcms/plugin-import-export 3.77.0-internal.8cf758f → 3.77.0-internal.fd50432
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 +2 -2
- package/dist/components/CollectionField/index.d.ts.map +1 -1
- package/dist/components/CollectionField/index.js +5 -28
- package/dist/components/CollectionField/index.js.map +1 -1
- package/dist/components/CollectionSelectField/index.d.ts +13 -0
- package/dist/components/CollectionSelectField/index.d.ts.map +1 -0
- package/dist/components/CollectionSelectField/index.js +159 -0
- package/dist/components/CollectionSelectField/index.js.map +1 -0
- package/dist/components/ExportListMenuItem/index.d.ts.map +1 -1
- package/dist/components/ExportListMenuItem/index.js +5 -1
- package/dist/components/ExportListMenuItem/index.js.map +1 -1
- package/dist/components/ExportPreview/index.d.ts.map +1 -1
- package/dist/components/ExportPreview/index.js.map +1 -1
- package/dist/components/FieldsToExport/index.js +1 -1
- package/dist/components/FieldsToExport/index.js.map +1 -1
- package/dist/components/ImportPreview/index.d.ts.map +1 -1
- package/dist/components/ImportPreview/index.js +50 -30
- package/dist/components/ImportPreview/index.js.map +1 -1
- package/dist/export/createExport.d.ts +1 -2
- package/dist/export/createExport.d.ts.map +1 -1
- package/dist/export/createExport.js +4 -10
- package/dist/export/createExport.js.map +1 -1
- package/dist/export/getCreateExportCollectionTask.d.ts.map +1 -1
- package/dist/export/getCreateExportCollectionTask.js +12 -1
- package/dist/export/getCreateExportCollectionTask.js.map +1 -1
- package/dist/export/getExportCollection.d.ts +5 -1
- package/dist/export/getExportCollection.d.ts.map +1 -1
- package/dist/export/getExportCollection.js +20 -5
- package/dist/export/getExportCollection.js.map +1 -1
- package/dist/export/getFields.d.ts +7 -1
- package/dist/export/getFields.d.ts.map +1 -1
- package/dist/export/getFields.js +15 -3
- package/dist/export/getFields.js.map +1 -1
- package/dist/export/handlePreview.d.ts.map +1 -1
- package/dist/export/handlePreview.js +34 -17
- package/dist/export/handlePreview.js.map +1 -1
- package/dist/exports/rsc.d.ts +0 -1
- package/dist/exports/rsc.d.ts.map +1 -1
- package/dist/exports/rsc.js +0 -1
- package/dist/exports/rsc.js.map +1 -1
- package/dist/import/batchProcessor.d.ts.map +1 -1
- package/dist/import/batchProcessor.js +9 -3
- package/dist/import/batchProcessor.js.map +1 -1
- package/dist/import/getFields.d.ts +7 -3
- package/dist/import/getFields.d.ts.map +1 -1
- package/dist/import/getFields.js +12 -7
- package/dist/import/getFields.js.map +1 -1
- package/dist/import/getImportCollection.d.ts +6 -3
- package/dist/import/getImportCollection.d.ts.map +1 -1
- package/dist/import/getImportCollection.js +7 -4
- package/dist/import/getImportCollection.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/utilities/filterToSelectedFields.spec.js +204 -0
- package/dist/utilities/filterToSelectedFields.spec.js.map +1 -0
- package/dist/utilities/flattenObject.d.ts +1 -7
- package/dist/utilities/flattenObject.d.ts.map +1 -1
- package/dist/utilities/flattenObject.js +14 -25
- package/dist/utilities/flattenObject.js.map +1 -1
- package/dist/utilities/getFilename.d.ts +1 -1
- package/dist/utilities/getFilename.js +3 -3
- package/dist/utilities/getFilename.js.map +1 -1
- package/dist/utilities/getPluginCollections.d.ts.map +1 -1
- package/dist/utilities/getPluginCollections.js +106 -34
- package/dist/utilities/getPluginCollections.js.map +1 -1
- package/dist/utilities/getSchemaColumns.d.ts +11 -7
- package/dist/utilities/getSchemaColumns.d.ts.map +1 -1
- package/dist/utilities/getSchemaColumns.js +35 -77
- package/dist/utilities/getSchemaColumns.js.map +1 -1
- package/dist/utilities/getSchemaColumns.spec.js +157 -0
- package/dist/utilities/getSchemaColumns.spec.js.map +1 -0
- package/dist/utilities/parseCSV.d.ts.map +1 -1
- package/dist/utilities/parseCSV.js +1 -0
- package/dist/utilities/parseCSV.js.map +1 -1
- package/dist/utilities/parseCSV.spec.js +26 -0
- package/dist/utilities/parseCSV.spec.js.map +1 -1
- package/package.json +7 -7
- package/dist/components/ImportCollectionField/index.d.ts +0 -3
- package/dist/components/ImportCollectionField/index.d.ts.map +0 -1
- package/dist/components/ImportCollectionField/index.js +0 -17
- package/dist/components/ImportCollectionField/index.js.map +0 -1
- package/dist/utilities/collectTimezoneCompanionFields.d.ts +0 -24
- package/dist/utilities/collectTimezoneCompanionFields.d.ts.map +0 -1
- package/dist/utilities/collectTimezoneCompanionFields.js +0 -89
- package/dist/utilities/collectTimezoneCompanionFields.js.map +0 -1
- package/dist/utilities/collectTimezoneCompanionFields.spec.js +0 -319
- package/dist/utilities/collectTimezoneCompanionFields.spec.js.map +0 -1
|
@@ -10,37 +10,28 @@ import { getFlattenedFieldKeys } from './getFlattenedFieldKeys.js';
|
|
|
10
10
|
* - Provides consistent base columns
|
|
11
11
|
* - Works for empty exports
|
|
12
12
|
* - Ensures proper column ordering
|
|
13
|
-
*/ export const getSchemaColumns = ({ collectionConfig, disabledFields = [], fields: selectedFields, locale, localeCodes
|
|
14
|
-
const hasVersions = Boolean(collectionConfig.versions);
|
|
15
|
-
// Determine if we need locale expansion
|
|
13
|
+
*/ export const getSchemaColumns = ({ collectionConfig, disabledFields = [], fields: selectedFields, locale, localeCodes })=>{
|
|
16
14
|
const expandLocales = locale === 'all' && localeCodes && localeCodes.length > 0;
|
|
17
|
-
// Get all possible columns from schema (excludes system fields like id, createdAt, updatedAt)
|
|
18
15
|
let schemaColumns = getFlattenedFieldKeys(collectionConfig.flattenedFields, '', expandLocales ? {
|
|
19
16
|
localeCodes
|
|
20
17
|
} : {});
|
|
21
|
-
// Add
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
...schemaColumns
|
|
30
|
-
];
|
|
31
|
-
// Filter to user-selected fields if specified
|
|
18
|
+
// Add id if not present in schema
|
|
19
|
+
const hasIdField = schemaColumns.includes('id');
|
|
20
|
+
if (!hasIdField) {
|
|
21
|
+
schemaColumns = [
|
|
22
|
+
'id',
|
|
23
|
+
...schemaColumns
|
|
24
|
+
];
|
|
25
|
+
}
|
|
32
26
|
if (selectedFields && selectedFields.length > 0) {
|
|
33
|
-
schemaColumns = filterToSelectedFields(schemaColumns, selectedFields
|
|
27
|
+
schemaColumns = filterToSelectedFields(schemaColumns, selectedFields);
|
|
34
28
|
}
|
|
35
|
-
// Remove disabled fields
|
|
36
29
|
if (disabledFields.length > 0) {
|
|
37
30
|
const disabledSet = new Set();
|
|
38
31
|
for (const path of disabledFields){
|
|
39
|
-
// Convert dot notation to underscore and add to set
|
|
40
32
|
disabledSet.add(path.replace(/\./g, '_'));
|
|
41
33
|
}
|
|
42
34
|
schemaColumns = schemaColumns.filter((col)=>{
|
|
43
|
-
// Check if column matches any disabled path
|
|
44
35
|
for (const disabled of disabledSet){
|
|
45
36
|
if (col === disabled || col.startsWith(`${disabled}_`)) {
|
|
46
37
|
return false;
|
|
@@ -49,41 +40,7 @@ import { getFlattenedFieldKeys } from './getFlattenedFieldKeys.js';
|
|
|
49
40
|
return true;
|
|
50
41
|
});
|
|
51
42
|
}
|
|
52
|
-
|
|
53
|
-
// filterToSelectedFields() already returns columns in user's specified order
|
|
54
|
-
if (selectedFields && selectedFields.length > 0) {
|
|
55
|
-
return schemaColumns;
|
|
56
|
-
}
|
|
57
|
-
// No fields selected - apply default ordering (id first, timestamps last)
|
|
58
|
-
const orderedColumns = [];
|
|
59
|
-
// 1. ID always first
|
|
60
|
-
if (schemaColumns.includes('id')) {
|
|
61
|
-
orderedColumns.push('id');
|
|
62
|
-
}
|
|
63
|
-
// 2. Status field for versioned collections
|
|
64
|
-
if (hasVersions) {
|
|
65
|
-
orderedColumns.push('_status');
|
|
66
|
-
}
|
|
67
|
-
// 3. All other fields (excluding id, timestamps, status)
|
|
68
|
-
const excludeFromMiddle = new Set([
|
|
69
|
-
'_status',
|
|
70
|
-
'createdAt',
|
|
71
|
-
'id',
|
|
72
|
-
'updatedAt'
|
|
73
|
-
]);
|
|
74
|
-
for (const col of schemaColumns){
|
|
75
|
-
if (!excludeFromMiddle.has(col)) {
|
|
76
|
-
orderedColumns.push(col);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
// 4. Timestamps at the end
|
|
80
|
-
if (schemaColumns.includes('createdAt')) {
|
|
81
|
-
orderedColumns.push('createdAt');
|
|
82
|
-
}
|
|
83
|
-
if (schemaColumns.includes('updatedAt')) {
|
|
84
|
-
orderedColumns.push('updatedAt');
|
|
85
|
-
}
|
|
86
|
-
return orderedColumns;
|
|
43
|
+
return schemaColumns;
|
|
87
44
|
};
|
|
88
45
|
/**
|
|
89
46
|
* Merges schema-derived columns with data-discovered columns.
|
|
@@ -95,12 +52,9 @@ import { getFlattenedFieldKeys } from './getFlattenedFieldKeys.js';
|
|
|
95
52
|
];
|
|
96
53
|
const schemaSet = new Set(schemaColumns);
|
|
97
54
|
const insertedDerived = new Map();
|
|
98
|
-
// Add any data columns not in schema (preserves schema ordering, appends new ones)
|
|
99
55
|
for (const col of dataColumns){
|
|
100
56
|
if (!schemaSet.has(col)) {
|
|
101
57
|
let inserted = false;
|
|
102
|
-
// Check if this is a derived column from a schema column (e.g., field_id, field_email)
|
|
103
|
-
// Pattern: schemaCol_suffix where suffix is NOT a number (array indices are handled separately)
|
|
104
58
|
for (const schemaCol of schemaColumns){
|
|
105
59
|
if (col.startsWith(`${schemaCol}_`)) {
|
|
106
60
|
const suffix = col.slice(schemaCol.length + 1);
|
|
@@ -137,7 +91,6 @@ import { getFlattenedFieldKeys } from './getFlattenedFieldKeys.js';
|
|
|
137
91
|
}
|
|
138
92
|
}
|
|
139
93
|
}
|
|
140
|
-
// Otherwise append at the end (before timestamps)
|
|
141
94
|
const createdAtIdx = result.indexOf('createdAt');
|
|
142
95
|
if (createdAtIdx !== -1) {
|
|
143
96
|
result.splice(createdAtIdx, 0, col);
|
|
@@ -148,13 +101,26 @@ import { getFlattenedFieldKeys } from './getFlattenedFieldKeys.js';
|
|
|
148
101
|
}
|
|
149
102
|
}
|
|
150
103
|
}
|
|
104
|
+
// Remove schema columns that were fully replaced by toCSV-derived columns (e.g. "user" → "user_id", "user_email")
|
|
105
|
+
for (const [schemaCol, derivedCols] of insertedDerived){
|
|
106
|
+
if (!dataColumns.includes(schemaCol) && derivedCols.length > 0) {
|
|
107
|
+
const idx = result.indexOf(schemaCol);
|
|
108
|
+
if (idx !== -1) {
|
|
109
|
+
result.splice(idx, 1);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
151
113
|
return result;
|
|
152
114
|
};
|
|
153
115
|
/**
|
|
154
116
|
* Filters schema columns to only include those matching user-selected fields.
|
|
155
117
|
* Preserves the order specified by the user in selectedFields.
|
|
156
|
-
*
|
|
157
|
-
|
|
118
|
+
*
|
|
119
|
+
* Container fields (groups, arrays, blocks) don't produce their own column, so we prefix-expand
|
|
120
|
+
* to find their children (e.g., 'group' → 'group_name', 'group_age').
|
|
121
|
+
* Leaf fields (date, text, select) produce an exact column, so we only match exactly to avoid
|
|
122
|
+
* including siblings with similar prefixes (e.g., 'dateWithTimezone' won't pull 'dateWithTimezone_tz').
|
|
123
|
+
*/ export function filterToSelectedFields(columns, selectedFields) {
|
|
158
124
|
const result = [];
|
|
159
125
|
const columnsSet = new Set(columns);
|
|
160
126
|
// Convert selected fields to underscore notation patterns
|
|
@@ -166,27 +132,19 @@ import { getFlattenedFieldKeys } from './getFlattenedFieldKeys.js';
|
|
|
166
132
|
prefix: `${underscored}_`
|
|
167
133
|
};
|
|
168
134
|
});
|
|
169
|
-
// Track which timezone companion fields were explicitly selected
|
|
170
|
-
const explicitlySelectedTzFields = new Set(selectedFields.filter((f)=>{
|
|
171
|
-
const underscored = f.replace(/\./g, '_');
|
|
172
|
-
return timezoneCompanionFields?.has(underscored);
|
|
173
|
-
}).map((f)=>f.replace(/\./g, '_')));
|
|
174
135
|
// Iterate through user-specified fields in order to preserve their ordering
|
|
175
136
|
for (const pattern of patterns){
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
if (columnsSet.has(pattern.exact) && !result.includes(pattern.exact)) {
|
|
137
|
+
const hasExactColumn = columnsSet.has(pattern.exact);
|
|
138
|
+
if (hasExactColumn && !result.includes(pattern.exact)) {
|
|
179
139
|
result.push(pattern.exact);
|
|
180
140
|
}
|
|
181
|
-
//
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
if (!result.includes(column)) {
|
|
189
|
-
result.push(column);
|
|
141
|
+
// Only prefix-expand if no exact column match exists (containers need expansion, leaves don't)
|
|
142
|
+
if (!hasExactColumn) {
|
|
143
|
+
for (const column of columns){
|
|
144
|
+
if (column.startsWith(pattern.prefix)) {
|
|
145
|
+
if (!result.includes(column)) {
|
|
146
|
+
result.push(column);
|
|
147
|
+
}
|
|
190
148
|
}
|
|
191
149
|
}
|
|
192
150
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utilities/getSchemaColumns.ts"],"sourcesContent":["import type { SanitizedCollectionConfig } from 'payload'\n\nimport { getFlattenedFieldKeys } from './getFlattenedFieldKeys.js'\n\nexport type GetSchemaColumnsArgs = {\n /**\n * The collection configuration to derive columns from\n */\n collectionConfig: SanitizedCollectionConfig\n /**\n * Array of disabled field paths from plugin config\n */\n disabledFields?: string[]\n /**\n * User-selected fields to export. If provided, only these fields (and their nested fields) will be included.\n */\n fields?: string[]\n /**\n * The locale to export. When 'all', localized fields are expanded to include all locale suffixes.\n */\n locale?: null | string\n /**\n * Available locale codes from config. Required when locale='all'.\n */\n localeCodes?: string[]\n /**\n * Set of auto-generated timezone companion field names (from collectTimezoneCompanionFields).\n * These fields are excluded unless explicitly selected.\n * If not provided, no timezone filtering is applied.\n */\n timezoneCompanionFields?: Set<string>\n}\n\n/**\n * Derives CSV column names from the collection schema.\n * This provides a base set of columns from field definitions.\n *\n * Note: For arrays/blocks with multiple items, the schema only generates index 0.\n * Additional indices from actual data should be merged with these columns.\n *\n * Benefits:\n * - Provides consistent base columns\n * - Works for empty exports\n * - Ensures proper column ordering\n */\nexport const getSchemaColumns = ({\n collectionConfig,\n disabledFields = [],\n fields: selectedFields,\n locale,\n localeCodes,\n timezoneCompanionFields,\n}: GetSchemaColumnsArgs): string[] => {\n const hasVersions = Boolean(collectionConfig.versions)\n\n // Determine if we need locale expansion\n const expandLocales = locale === 'all' && localeCodes && localeCodes.length > 0\n\n // Get all possible columns from schema (excludes system fields like id, createdAt, updatedAt)\n let schemaColumns = getFlattenedFieldKeys(\n collectionConfig.flattenedFields,\n '',\n expandLocales ? { localeCodes } : {},\n )\n\n // Add system fields that aren't in flattenedFields\n const systemFields = ['id', 'createdAt', 'updatedAt']\n schemaColumns = [...systemFields, ...schemaColumns]\n\n // Filter to user-selected fields if specified\n if (selectedFields && selectedFields.length > 0) {\n schemaColumns = filterToSelectedFields(schemaColumns, selectedFields, timezoneCompanionFields)\n }\n\n // Remove disabled fields\n if (disabledFields.length > 0) {\n const disabledSet = new Set<string>()\n for (const path of disabledFields) {\n // Convert dot notation to underscore and add to set\n disabledSet.add(path.replace(/\\./g, '_'))\n }\n schemaColumns = schemaColumns.filter((col) => {\n // Check if column matches any disabled path\n for (const disabled of disabledSet) {\n if (col === disabled || col.startsWith(`${disabled}_`)) {\n return false\n }\n }\n return true\n })\n }\n\n // When user has selected specific fields, preserve their ordering\n // filterToSelectedFields() already returns columns in user's specified order\n if (selectedFields && selectedFields.length > 0) {\n return schemaColumns\n }\n\n // No fields selected - apply default ordering (id first, timestamps last)\n const orderedColumns: string[] = []\n\n // 1. ID always first\n if (schemaColumns.includes('id')) {\n orderedColumns.push('id')\n }\n\n // 2. Status field for versioned collections\n if (hasVersions) {\n orderedColumns.push('_status')\n }\n\n // 3. All other fields (excluding id, timestamps, status)\n const excludeFromMiddle = new Set(['_status', 'createdAt', 'id', 'updatedAt'])\n for (const col of schemaColumns) {\n if (!excludeFromMiddle.has(col)) {\n orderedColumns.push(col)\n }\n }\n\n // 4. Timestamps at the end\n if (schemaColumns.includes('createdAt')) {\n orderedColumns.push('createdAt')\n }\n if (schemaColumns.includes('updatedAt')) {\n orderedColumns.push('updatedAt')\n }\n\n return orderedColumns\n}\n\n/**\n * Merges schema-derived columns with data-discovered columns.\n * Schema columns provide the base ordering, data columns add any additional\n * columns (e.g., array indices beyond 0, dynamic fields, derived columns from toCSV).\n */\nexport const mergeColumns = (schemaColumns: string[], dataColumns: string[]): string[] => {\n const result = [...schemaColumns]\n const schemaSet = new Set(schemaColumns)\n const insertedDerived = new Map<string, string[]>()\n\n // Add any data columns not in schema (preserves schema ordering, appends new ones)\n for (const col of dataColumns) {\n if (!schemaSet.has(col)) {\n let inserted = false\n\n // Check if this is a derived column from a schema column (e.g., field_id, field_email)\n // Pattern: schemaCol_suffix where suffix is NOT a number (array indices are handled separately)\n for (const schemaCol of schemaColumns) {\n if (col.startsWith(`${schemaCol}_`)) {\n const suffix = col.slice(schemaCol.length + 1)\n // Skip if suffix starts with a digit (array index pattern like field_0_*)\n if (!/^\\d/.test(suffix)) {\n const baseIdx = result.indexOf(schemaCol)\n if (baseIdx !== -1) {\n const derivedList = insertedDerived.get(schemaCol) || []\n const insertIdx = baseIdx + 1 + derivedList.length\n result.splice(insertIdx, 0, col)\n derivedList.push(col)\n insertedDerived.set(schemaCol, derivedList)\n schemaSet.add(col)\n inserted = true\n break\n }\n }\n }\n }\n\n if (!inserted) {\n // Check for array indices (e.g., field_1_*), insert after field_0_*\n const match = col.match(/^(.+?)_(\\d+)(_.*)?$/)\n if (match) {\n const [, basePath, index, suffix] = match\n if (basePath && index) {\n const prevIndex = parseInt(index, 10) - 1\n const prevCol = `${basePath}_${prevIndex}${suffix ?? ''}`\n const prevIdx = result.indexOf(prevCol)\n if (prevIdx !== -1) {\n // Insert after the previous index column\n result.splice(prevIdx + 1, 0, col)\n schemaSet.add(col)\n continue\n }\n }\n }\n\n // Otherwise append at the end (before timestamps)\n const createdAtIdx = result.indexOf('createdAt')\n if (createdAtIdx !== -1) {\n result.splice(createdAtIdx, 0, col)\n } else {\n result.push(col)\n }\n schemaSet.add(col)\n }\n }\n }\n\n return result\n}\n\n/**\n * Filters schema columns to only include those matching user-selected fields.\n * Preserves the order specified by the user in selectedFields.\n * Handles nested field selection (e.g., 'group.value' includes 'group_value' and 'group_value_*')\n */\nfunction filterToSelectedFields(\n columns: string[],\n selectedFields: string[],\n timezoneCompanionFields?: Set<string>,\n): string[] {\n const result: string[] = []\n const columnsSet = new Set(columns)\n\n // Convert selected fields to underscore notation patterns\n const patterns = selectedFields.map((field) => {\n const underscored = field.replace(/\\./g, '_')\n return {\n exact: underscored,\n original: field,\n prefix: `${underscored}_`,\n }\n })\n\n // Track which timezone companion fields were explicitly selected\n const explicitlySelectedTzFields = new Set(\n selectedFields\n .filter((f) => {\n const underscored = f.replace(/\\./g, '_')\n return timezoneCompanionFields?.has(underscored)\n })\n .map((f) => f.replace(/\\./g, '_')),\n )\n\n // Iterate through user-specified fields in order to preserve their ordering\n for (const pattern of patterns) {\n // First add the exact match if it exists and not already added\n // (it may have been added as a nested field of a previous pattern)\n if (columnsSet.has(pattern.exact) && !result.includes(pattern.exact)) {\n result.push(pattern.exact)\n }\n\n // Then add any columns with the prefix (nested fields)\n for (const column of columns) {\n if (column !== pattern.exact && column.startsWith(pattern.prefix)) {\n // Skip auto-generated timezone companion fields unless explicitly selected\n if (timezoneCompanionFields?.has(column) && !explicitlySelectedTzFields.has(column)) {\n continue\n }\n if (!result.includes(column)) {\n result.push(column)\n }\n }\n }\n }\n\n return result\n}\n"],"names":["getFlattenedFieldKeys","getSchemaColumns","collectionConfig","disabledFields","fields","selectedFields","locale","localeCodes","timezoneCompanionFields","hasVersions","Boolean","versions","expandLocales","length","schemaColumns","flattenedFields","systemFields","filterToSelectedFields","disabledSet","Set","path","add","replace","filter","col","disabled","startsWith","orderedColumns","includes","push","excludeFromMiddle","has","mergeColumns","dataColumns","result","schemaSet","insertedDerived","Map","inserted","schemaCol","suffix","slice","test","baseIdx","indexOf","derivedList","get","insertIdx","splice","set","match","basePath","index","prevIndex","parseInt","prevCol","prevIdx","createdAtIdx","columns","columnsSet","patterns","map","field","underscored","exact","original","prefix","explicitlySelectedTzFields","f","pattern","column"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/getSchemaColumns.ts"],"sourcesContent":["import type { SanitizedCollectionConfig } from 'payload'\n\nimport { getFlattenedFieldKeys } from './getFlattenedFieldKeys.js'\n\nexport type GetSchemaColumnsArgs = {\n /**\n * The collection configuration to derive columns from\n */\n collectionConfig: SanitizedCollectionConfig\n /**\n * Array of disabled field paths from plugin config\n */\n disabledFields?: string[]\n /**\n * User-selected fields to export. If provided, only these fields (and their nested fields) will be included.\n */\n fields?: string[]\n /**\n * The locale to export. When 'all', localized fields are expanded to include all locale suffixes.\n */\n locale?: null | string\n /**\n * Available locale codes from config. Required when locale='all'.\n */\n localeCodes?: string[]\n}\n\n/**\n * Derives CSV column names from the collection schema.\n * This provides a base set of columns from field definitions.\n *\n * Note: For arrays/blocks with multiple items, the schema only generates index 0.\n * Additional indices from actual data should be merged with these columns.\n *\n * Benefits:\n * - Provides consistent base columns\n * - Works for empty exports\n * - Ensures proper column ordering\n */\nexport const getSchemaColumns = ({\n collectionConfig,\n disabledFields = [],\n fields: selectedFields,\n locale,\n localeCodes,\n}: GetSchemaColumnsArgs): string[] => {\n const expandLocales = locale === 'all' && localeCodes && localeCodes.length > 0\n\n let schemaColumns = getFlattenedFieldKeys(\n collectionConfig.flattenedFields,\n '',\n expandLocales ? { localeCodes } : {},\n )\n\n // Add id if not present in schema\n const hasIdField = schemaColumns.includes('id')\n if (!hasIdField) {\n schemaColumns = ['id', ...schemaColumns]\n }\n\n if (selectedFields && selectedFields.length > 0) {\n schemaColumns = filterToSelectedFields(schemaColumns, selectedFields)\n }\n\n if (disabledFields.length > 0) {\n const disabledSet = new Set<string>()\n for (const path of disabledFields) {\n disabledSet.add(path.replace(/\\./g, '_'))\n }\n schemaColumns = schemaColumns.filter((col) => {\n for (const disabled of disabledSet) {\n if (col === disabled || col.startsWith(`${disabled}_`)) {\n return false\n }\n }\n return true\n })\n }\n\n return schemaColumns\n}\n\n/**\n * Merges schema-derived columns with data-discovered columns.\n * Schema columns provide the base ordering, data columns add any additional\n * columns (e.g., array indices beyond 0, dynamic fields, derived columns from toCSV).\n */\nexport const mergeColumns = (schemaColumns: string[], dataColumns: string[]): string[] => {\n const result = [...schemaColumns]\n const schemaSet = new Set(schemaColumns)\n const insertedDerived = new Map<string, string[]>()\n\n for (const col of dataColumns) {\n if (!schemaSet.has(col)) {\n let inserted = false\n\n for (const schemaCol of schemaColumns) {\n if (col.startsWith(`${schemaCol}_`)) {\n const suffix = col.slice(schemaCol.length + 1)\n // Skip if suffix starts with a digit (array index pattern like field_0_*)\n if (!/^\\d/.test(suffix)) {\n const baseIdx = result.indexOf(schemaCol)\n if (baseIdx !== -1) {\n const derivedList = insertedDerived.get(schemaCol) || []\n const insertIdx = baseIdx + 1 + derivedList.length\n result.splice(insertIdx, 0, col)\n derivedList.push(col)\n insertedDerived.set(schemaCol, derivedList)\n schemaSet.add(col)\n inserted = true\n break\n }\n }\n }\n }\n\n if (!inserted) {\n // Check for array indices (e.g., field_1_*), insert after field_0_*\n const match = col.match(/^(.+?)_(\\d+)(_.*)?$/)\n if (match) {\n const [, basePath, index, suffix] = match\n if (basePath && index) {\n const prevIndex = parseInt(index, 10) - 1\n const prevCol = `${basePath}_${prevIndex}${suffix ?? ''}`\n const prevIdx = result.indexOf(prevCol)\n if (prevIdx !== -1) {\n // Insert after the previous index column\n result.splice(prevIdx + 1, 0, col)\n schemaSet.add(col)\n continue\n }\n }\n }\n\n const createdAtIdx = result.indexOf('createdAt')\n if (createdAtIdx !== -1) {\n result.splice(createdAtIdx, 0, col)\n } else {\n result.push(col)\n }\n schemaSet.add(col)\n }\n }\n }\n\n // Remove schema columns that were fully replaced by toCSV-derived columns (e.g. \"user\" → \"user_id\", \"user_email\")\n for (const [schemaCol, derivedCols] of insertedDerived) {\n if (!dataColumns.includes(schemaCol) && derivedCols.length > 0) {\n const idx = result.indexOf(schemaCol)\n if (idx !== -1) {\n result.splice(idx, 1)\n }\n }\n }\n\n return result\n}\n\n/**\n * Filters schema columns to only include those matching user-selected fields.\n * Preserves the order specified by the user in selectedFields.\n *\n * Container fields (groups, arrays, blocks) don't produce their own column, so we prefix-expand\n * to find their children (e.g., 'group' → 'group_name', 'group_age').\n * Leaf fields (date, text, select) produce an exact column, so we only match exactly to avoid\n * including siblings with similar prefixes (e.g., 'dateWithTimezone' won't pull 'dateWithTimezone_tz').\n */\nexport function filterToSelectedFields(columns: string[], selectedFields: string[]): string[] {\n const result: string[] = []\n const columnsSet = new Set(columns)\n\n // Convert selected fields to underscore notation patterns\n const patterns = selectedFields.map((field) => {\n const underscored = field.replace(/\\./g, '_')\n return {\n exact: underscored,\n original: field,\n prefix: `${underscored}_`,\n }\n })\n\n // Iterate through user-specified fields in order to preserve their ordering\n for (const pattern of patterns) {\n const hasExactColumn = columnsSet.has(pattern.exact)\n\n if (hasExactColumn && !result.includes(pattern.exact)) {\n result.push(pattern.exact)\n }\n\n // Only prefix-expand if no exact column match exists (containers need expansion, leaves don't)\n if (!hasExactColumn) {\n for (const column of columns) {\n if (column.startsWith(pattern.prefix)) {\n if (!result.includes(column)) {\n result.push(column)\n }\n }\n }\n }\n }\n\n return result\n}\n"],"names":["getFlattenedFieldKeys","getSchemaColumns","collectionConfig","disabledFields","fields","selectedFields","locale","localeCodes","expandLocales","length","schemaColumns","flattenedFields","hasIdField","includes","filterToSelectedFields","disabledSet","Set","path","add","replace","filter","col","disabled","startsWith","mergeColumns","dataColumns","result","schemaSet","insertedDerived","Map","has","inserted","schemaCol","suffix","slice","test","baseIdx","indexOf","derivedList","get","insertIdx","splice","push","set","match","basePath","index","prevIndex","parseInt","prevCol","prevIdx","createdAtIdx","derivedCols","idx","columns","columnsSet","patterns","map","field","underscored","exact","original","prefix","pattern","hasExactColumn","column"],"mappings":"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"}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { getSchemaColumns } from './getSchemaColumns.js';
|
|
3
|
+
function createCollectionConfig(flattenedFields, options) {
|
|
4
|
+
return {
|
|
5
|
+
flattenedFields,
|
|
6
|
+
timestamps: options?.timestamps ?? true,
|
|
7
|
+
trash: options?.trash ?? false,
|
|
8
|
+
versions: options?.versions
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
describe('getSchemaColumns', ()=>{
|
|
12
|
+
describe('fields from flattenedFields', ()=>{
|
|
13
|
+
it('should include all fields present in flattenedFields in their natural order', ()=>{
|
|
14
|
+
const flattenedFields = [
|
|
15
|
+
{
|
|
16
|
+
name: 'id',
|
|
17
|
+
type: 'number'
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: 'title',
|
|
21
|
+
type: 'text'
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: 'createdAt',
|
|
25
|
+
type: 'date'
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
name: 'updatedAt',
|
|
29
|
+
type: 'date'
|
|
30
|
+
}
|
|
31
|
+
];
|
|
32
|
+
const collectionConfig = createCollectionConfig(flattenedFields);
|
|
33
|
+
const result = getSchemaColumns({
|
|
34
|
+
collectionConfig
|
|
35
|
+
});
|
|
36
|
+
expect(result).toEqual([
|
|
37
|
+
'id',
|
|
38
|
+
'title',
|
|
39
|
+
'createdAt',
|
|
40
|
+
'updatedAt'
|
|
41
|
+
]);
|
|
42
|
+
});
|
|
43
|
+
it('should include custom id field when defined in flattenedFields', ()=>{
|
|
44
|
+
const flattenedFields = [
|
|
45
|
+
{
|
|
46
|
+
name: 'id',
|
|
47
|
+
type: 'text'
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
name: 'title',
|
|
51
|
+
type: 'text'
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: 'createdAt',
|
|
55
|
+
type: 'date'
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: 'updatedAt',
|
|
59
|
+
type: 'date'
|
|
60
|
+
}
|
|
61
|
+
];
|
|
62
|
+
const collectionConfig = createCollectionConfig(flattenedFields);
|
|
63
|
+
const result = getSchemaColumns({
|
|
64
|
+
collectionConfig
|
|
65
|
+
});
|
|
66
|
+
expect(result).toContain('id');
|
|
67
|
+
});
|
|
68
|
+
it('should not include createdAt or updatedAt when timestamps disabled (not in flattenedFields)', ()=>{
|
|
69
|
+
const flattenedFields = [
|
|
70
|
+
{
|
|
71
|
+
name: 'id',
|
|
72
|
+
type: 'number'
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: 'title',
|
|
76
|
+
type: 'text'
|
|
77
|
+
}
|
|
78
|
+
];
|
|
79
|
+
const collectionConfig = createCollectionConfig(flattenedFields, {
|
|
80
|
+
timestamps: false
|
|
81
|
+
});
|
|
82
|
+
const result = getSchemaColumns({
|
|
83
|
+
collectionConfig
|
|
84
|
+
});
|
|
85
|
+
expect(result).toContain('id');
|
|
86
|
+
expect(result).toContain('title');
|
|
87
|
+
expect(result).not.toContain('createdAt');
|
|
88
|
+
expect(result).not.toContain('updatedAt');
|
|
89
|
+
});
|
|
90
|
+
it('should include deletedAt when present in flattenedFields (trash enabled)', ()=>{
|
|
91
|
+
const flattenedFields = [
|
|
92
|
+
{
|
|
93
|
+
name: 'id',
|
|
94
|
+
type: 'number'
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
name: 'title',
|
|
98
|
+
type: 'text'
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
name: 'createdAt',
|
|
102
|
+
type: 'date'
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
name: 'updatedAt',
|
|
106
|
+
type: 'date'
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
name: 'deletedAt',
|
|
110
|
+
type: 'date'
|
|
111
|
+
}
|
|
112
|
+
];
|
|
113
|
+
const collectionConfig = createCollectionConfig(flattenedFields);
|
|
114
|
+
const result = getSchemaColumns({
|
|
115
|
+
collectionConfig
|
|
116
|
+
});
|
|
117
|
+
expect(result).toContain('deletedAt');
|
|
118
|
+
});
|
|
119
|
+
it('should add id when missing from flattenedFields (Payload core limitation)', ()=>{
|
|
120
|
+
const flattenedFields = [
|
|
121
|
+
{
|
|
122
|
+
name: 'title',
|
|
123
|
+
type: 'text'
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
name: 'excerpt',
|
|
127
|
+
type: 'textarea'
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
name: 'createdAt',
|
|
131
|
+
type: 'date'
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
name: 'updatedAt',
|
|
135
|
+
type: 'date'
|
|
136
|
+
}
|
|
137
|
+
];
|
|
138
|
+
const collectionConfig = createCollectionConfig(flattenedFields);
|
|
139
|
+
const result = getSchemaColumns({
|
|
140
|
+
collectionConfig
|
|
141
|
+
});
|
|
142
|
+
// id is added because Payload core doesn't add it to flattenedFields
|
|
143
|
+
// but it exists on every document
|
|
144
|
+
expect(result).toContain('id');
|
|
145
|
+
expect(result[0]).toBe('id');
|
|
146
|
+
expect(result).toEqual([
|
|
147
|
+
'id',
|
|
148
|
+
'title',
|
|
149
|
+
'excerpt',
|
|
150
|
+
'createdAt',
|
|
151
|
+
'updatedAt'
|
|
152
|
+
]);
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
//# sourceMappingURL=getSchemaColumns.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/getSchemaColumns.spec.ts"],"sourcesContent":["import type { FlattenedField, SanitizedCollectionConfig } from 'payload'\n\nimport { describe, expect, it } from 'vitest'\n\nimport { getSchemaColumns } from './getSchemaColumns.js'\n\nfunction createCollectionConfig(\n flattenedFields: FlattenedField[],\n options?: { timestamps?: boolean; trash?: boolean; versions?: unknown },\n): SanitizedCollectionConfig {\n return {\n flattenedFields,\n timestamps: options?.timestamps ?? true,\n trash: options?.trash ?? false,\n versions: options?.versions,\n } as SanitizedCollectionConfig\n}\n\ndescribe('getSchemaColumns', () => {\n describe('fields from flattenedFields', () => {\n it('should include all fields present in flattenedFields in their natural order', () => {\n const flattenedFields: FlattenedField[] = [\n { name: 'id', type: 'number' },\n { name: 'title', type: 'text' },\n { name: 'createdAt', type: 'date' },\n { name: 'updatedAt', type: 'date' },\n ]\n\n const collectionConfig = createCollectionConfig(flattenedFields)\n const result = getSchemaColumns({ collectionConfig })\n\n expect(result).toEqual(['id', 'title', 'createdAt', 'updatedAt'])\n })\n\n it('should include custom id field when defined in flattenedFields', () => {\n const flattenedFields: FlattenedField[] = [\n { name: 'id', type: 'text' },\n { name: 'title', type: 'text' },\n { name: 'createdAt', type: 'date' },\n { name: 'updatedAt', type: 'date' },\n ]\n\n const collectionConfig = createCollectionConfig(flattenedFields)\n const result = getSchemaColumns({ collectionConfig })\n\n expect(result).toContain('id')\n })\n\n it('should not include createdAt or updatedAt when timestamps disabled (not in flattenedFields)', () => {\n const flattenedFields: FlattenedField[] = [\n { name: 'id', type: 'number' },\n { name: 'title', type: 'text' },\n ]\n\n const collectionConfig = createCollectionConfig(flattenedFields, { timestamps: false })\n const result = getSchemaColumns({ collectionConfig })\n\n expect(result).toContain('id')\n expect(result).toContain('title')\n expect(result).not.toContain('createdAt')\n expect(result).not.toContain('updatedAt')\n })\n\n it('should include deletedAt when present in flattenedFields (trash enabled)', () => {\n const flattenedFields: FlattenedField[] = [\n { name: 'id', type: 'number' },\n { name: 'title', type: 'text' },\n { name: 'createdAt', type: 'date' },\n { name: 'updatedAt', type: 'date' },\n { name: 'deletedAt', type: 'date' },\n ]\n\n const collectionConfig = createCollectionConfig(flattenedFields)\n const result = getSchemaColumns({ collectionConfig })\n\n expect(result).toContain('deletedAt')\n })\n\n it('should add id when missing from flattenedFields (Payload core limitation)', () => {\n const flattenedFields: FlattenedField[] = [\n { name: 'title', type: 'text' },\n { name: 'excerpt', type: 'textarea' },\n { name: 'createdAt', type: 'date' },\n { name: 'updatedAt', type: 'date' },\n ]\n\n const collectionConfig = createCollectionConfig(flattenedFields)\n const result = getSchemaColumns({ collectionConfig })\n\n // id is added because Payload core doesn't add it to flattenedFields\n // but it exists on every document\n expect(result).toContain('id')\n expect(result[0]).toBe('id')\n expect(result).toEqual(['id', 'title', 'excerpt', 'createdAt', 'updatedAt'])\n })\n })\n})\n"],"names":["describe","expect","it","getSchemaColumns","createCollectionConfig","flattenedFields","options","timestamps","trash","versions","name","type","collectionConfig","result","toEqual","toContain","not","toBe"],"mappings":"AAEA,SAASA,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ,SAAQ;AAE7C,SAASC,gBAAgB,QAAQ,wBAAuB;AAExD,SAASC,uBACPC,eAAiC,EACjCC,OAAuE;IAEvE,OAAO;QACLD;QACAE,YAAYD,SAASC,cAAc;QACnCC,OAAOF,SAASE,SAAS;QACzBC,UAAUH,SAASG;IACrB;AACF;AAEAT,SAAS,oBAAoB;IAC3BA,SAAS,+BAA+B;QACtCE,GAAG,+EAA+E;YAChF,MAAMG,kBAAoC;gBACxC;oBAAEK,MAAM;oBAAMC,MAAM;gBAAS;gBAC7B;oBAAED,MAAM;oBAASC,MAAM;gBAAO;gBAC9B;oBAAED,MAAM;oBAAaC,MAAM;gBAAO;gBAClC;oBAAED,MAAM;oBAAaC,MAAM;gBAAO;aACnC;YAED,MAAMC,mBAAmBR,uBAAuBC;YAChD,MAAMQ,SAASV,iBAAiB;gBAAES;YAAiB;YAEnDX,OAAOY,QAAQC,OAAO,CAAC;gBAAC;gBAAM;gBAAS;gBAAa;aAAY;QAClE;QAEAZ,GAAG,kEAAkE;YACnE,MAAMG,kBAAoC;gBACxC;oBAAEK,MAAM;oBAAMC,MAAM;gBAAO;gBAC3B;oBAAED,MAAM;oBAASC,MAAM;gBAAO;gBAC9B;oBAAED,MAAM;oBAAaC,MAAM;gBAAO;gBAClC;oBAAED,MAAM;oBAAaC,MAAM;gBAAO;aACnC;YAED,MAAMC,mBAAmBR,uBAAuBC;YAChD,MAAMQ,SAASV,iBAAiB;gBAAES;YAAiB;YAEnDX,OAAOY,QAAQE,SAAS,CAAC;QAC3B;QAEAb,GAAG,+FAA+F;YAChG,MAAMG,kBAAoC;gBACxC;oBAAEK,MAAM;oBAAMC,MAAM;gBAAS;gBAC7B;oBAAED,MAAM;oBAASC,MAAM;gBAAO;aAC/B;YAED,MAAMC,mBAAmBR,uBAAuBC,iBAAiB;gBAAEE,YAAY;YAAM;YACrF,MAAMM,SAASV,iBAAiB;gBAAES;YAAiB;YAEnDX,OAAOY,QAAQE,SAAS,CAAC;YACzBd,OAAOY,QAAQE,SAAS,CAAC;YACzBd,OAAOY,QAAQG,GAAG,CAACD,SAAS,CAAC;YAC7Bd,OAAOY,QAAQG,GAAG,CAACD,SAAS,CAAC;QAC/B;QAEAb,GAAG,4EAA4E;YAC7E,MAAMG,kBAAoC;gBACxC;oBAAEK,MAAM;oBAAMC,MAAM;gBAAS;gBAC7B;oBAAED,MAAM;oBAASC,MAAM;gBAAO;gBAC9B;oBAAED,MAAM;oBAAaC,MAAM;gBAAO;gBAClC;oBAAED,MAAM;oBAAaC,MAAM;gBAAO;gBAClC;oBAAED,MAAM;oBAAaC,MAAM;gBAAO;aACnC;YAED,MAAMC,mBAAmBR,uBAAuBC;YAChD,MAAMQ,SAASV,iBAAiB;gBAAES;YAAiB;YAEnDX,OAAOY,QAAQE,SAAS,CAAC;QAC3B;QAEAb,GAAG,6EAA6E;YAC9E,MAAMG,kBAAoC;gBACxC;oBAAEK,MAAM;oBAASC,MAAM;gBAAO;gBAC9B;oBAAED,MAAM;oBAAWC,MAAM;gBAAW;gBACpC;oBAAED,MAAM;oBAAaC,MAAM;gBAAO;gBAClC;oBAAED,MAAM;oBAAaC,MAAM;gBAAO;aACnC;YAED,MAAMC,mBAAmBR,uBAAuBC;YAChD,MAAMQ,SAASV,iBAAiB;gBAAES;YAAiB;YAEnD,qEAAqE;YACrE,kCAAkC;YAClCX,OAAOY,QAAQE,SAAS,CAAC;YACzBd,OAAOY,MAAM,CAAC,EAAE,EAAEI,IAAI,CAAC;YACvBhB,OAAOY,QAAQC,OAAO,CAAC;gBAAC;gBAAM;gBAAS;gBAAW;gBAAa;aAAY;QAC7E;IACF;AACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parseCSV.d.ts","sourceRoot":"","sources":["../../src/utilities/parseCSV.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAI7C,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;IACrB,GAAG,EAAE,cAAc,CAAA;CACpB,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,QAAQ,kBAAyB,YAAY,KAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,
|
|
1
|
+
{"version":3,"file":"parseCSV.d.ts","sourceRoot":"","sources":["../../src/utilities/parseCSV.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAI7C,MAAM,MAAM,YAAY,GAAG;IACzB,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;IACrB,GAAG,EAAE,cAAc,CAAA;CACpB,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,QAAQ,kBAAyB,YAAY,KAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,CA8D7F,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utilities/parseCSV.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\nimport { parse } from 'csv-parse'\n\nexport type ParseCSVArgs = {\n data: Buffer | string\n req: PayloadRequest\n}\n\n/**\n * Parses CSV data into an array of record objects.\n * Handles type coercion for booleans, numbers, and null values.\n */\nexport const parseCSV = async ({ data, req }: ParseCSVArgs): Promise<Record<string, unknown>[]> => {\n return new Promise((resolve, reject) => {\n const records: Record<string, unknown>[] = []\n\n const parser = parse({\n cast: (value, _context) => {\n // Empty strings become undefined to preserve existing data during updates\n if (value === '') {\n return undefined\n }\n\n if (value === 'true') {\n return true\n }\n if (value === 'false') {\n return false\n }\n\n // Explicit null requires typing \"null\" or \"NULL\"\n if (value === 'null' || value === 'NULL') {\n return null\n }\n\n // Keep comma-separated values as strings for hasMany fields\n if (value.includes(',')) {\n return value\n }\n\n if (!isNaN(Number(value)) && value !== '') {\n const num = Number(value)\n if (String(num) === value || value.includes('.')) {\n return num\n }\n }\n\n return value\n },\n columns: true,\n skip_empty_lines: true,\n trim: true,\n })\n\n parser.on('readable', () => {\n let record\n while ((record = parser.read()) !== null) {\n records.push(record)\n }\n })\n\n parser.on('error', (err) => {\n req.payload.logger.error({ err, msg: 'Error parsing CSV' })\n reject(err)\n })\n\n parser.on('end', () => {\n resolve(records)\n })\n\n parser.write(data)\n parser.end()\n })\n}\n"],"names":["parse","parseCSV","data","req","Promise","resolve","reject","records","parser","cast","value","_context","undefined","includes","isNaN","Number","num","String","columns","skip_empty_lines","trim","on","record","read","push","err","payload","logger","error","msg","write","end"],"mappings":"AAEA,SAASA,KAAK,QAAQ,YAAW;AAOjC;;;CAGC,GACD,OAAO,MAAMC,WAAW,OAAO,EAAEC,IAAI,EAAEC,GAAG,EAAgB;IACxD,OAAO,IAAIC,QAAQ,CAACC,SAASC;QAC3B,MAAMC,UAAqC,EAAE;QAE7C,MAAMC,SAASR,MAAM;YACnBS,MAAM,CAACC,OAAOC;gBACZ,0EAA0E;gBAC1E,IAAID,UAAU,IAAI;oBAChB,OAAOE;gBACT;gBAEA,IAAIF,UAAU,QAAQ;oBACpB,OAAO;gBACT;gBACA,IAAIA,UAAU,SAAS;oBACrB,OAAO;gBACT;gBAEA,iDAAiD;gBACjD,IAAIA,UAAU,UAAUA,UAAU,QAAQ;oBACxC,OAAO;gBACT;gBAEA,4DAA4D;gBAC5D,IAAIA,MAAMG,QAAQ,CAAC,MAAM;oBACvB,OAAOH;gBACT;gBAEA,IAAI,CAACI,MAAMC,OAAOL,WAAWA,UAAU,IAAI;oBACzC,MAAMM,MAAMD,OAAOL;oBACnB,IAAIO,OAAOD,SAASN,SAASA,MAAMG,QAAQ,CAAC,MAAM;wBAChD,OAAOG;oBACT;gBACF;gBAEA,OAAON;YACT;YACAQ,SAAS;YACTC,kBAAkB;YAClBC,MAAM;QACR;
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/parseCSV.ts"],"sourcesContent":["import type { PayloadRequest } from 'payload'\n\nimport { parse } from 'csv-parse'\n\nexport type ParseCSVArgs = {\n data: Buffer | string\n req: PayloadRequest\n}\n\n/**\n * Parses CSV data into an array of record objects.\n * Handles type coercion for booleans, numbers, and null values.\n */\nexport const parseCSV = async ({ data, req }: ParseCSVArgs): Promise<Record<string, unknown>[]> => {\n return new Promise((resolve, reject) => {\n const records: Record<string, unknown>[] = []\n\n const parser = parse({\n bom: true,\n cast: (value, _context) => {\n // Empty strings become undefined to preserve existing data during updates\n if (value === '') {\n return undefined\n }\n\n if (value === 'true') {\n return true\n }\n if (value === 'false') {\n return false\n }\n\n // Explicit null requires typing \"null\" or \"NULL\"\n if (value === 'null' || value === 'NULL') {\n return null\n }\n\n // Keep comma-separated values as strings for hasMany fields\n if (value.includes(',')) {\n return value\n }\n\n if (!isNaN(Number(value)) && value !== '') {\n const num = Number(value)\n if (String(num) === value || value.includes('.')) {\n return num\n }\n }\n\n return value\n },\n columns: true,\n skip_empty_lines: true,\n trim: true,\n })\n\n parser.on('readable', () => {\n let record\n while ((record = parser.read()) !== null) {\n records.push(record)\n }\n })\n\n parser.on('error', (err) => {\n req.payload.logger.error({ err, msg: 'Error parsing CSV' })\n reject(err)\n })\n\n parser.on('end', () => {\n resolve(records)\n })\n\n parser.write(data)\n parser.end()\n })\n}\n"],"names":["parse","parseCSV","data","req","Promise","resolve","reject","records","parser","bom","cast","value","_context","undefined","includes","isNaN","Number","num","String","columns","skip_empty_lines","trim","on","record","read","push","err","payload","logger","error","msg","write","end"],"mappings":"AAEA,SAASA,KAAK,QAAQ,YAAW;AAOjC;;;CAGC,GACD,OAAO,MAAMC,WAAW,OAAO,EAAEC,IAAI,EAAEC,GAAG,EAAgB;IACxD,OAAO,IAAIC,QAAQ,CAACC,SAASC;QAC3B,MAAMC,UAAqC,EAAE;QAE7C,MAAMC,SAASR,MAAM;YACnBS,KAAK;YACLC,MAAM,CAACC,OAAOC;gBACZ,0EAA0E;gBAC1E,IAAID,UAAU,IAAI;oBAChB,OAAOE;gBACT;gBAEA,IAAIF,UAAU,QAAQ;oBACpB,OAAO;gBACT;gBACA,IAAIA,UAAU,SAAS;oBACrB,OAAO;gBACT;gBAEA,iDAAiD;gBACjD,IAAIA,UAAU,UAAUA,UAAU,QAAQ;oBACxC,OAAO;gBACT;gBAEA,4DAA4D;gBAC5D,IAAIA,MAAMG,QAAQ,CAAC,MAAM;oBACvB,OAAOH;gBACT;gBAEA,IAAI,CAACI,MAAMC,OAAOL,WAAWA,UAAU,IAAI;oBACzC,MAAMM,MAAMD,OAAOL;oBACnB,IAAIO,OAAOD,SAASN,SAASA,MAAMG,QAAQ,CAAC,MAAM;wBAChD,OAAOG;oBACT;gBACF;gBAEA,OAAON;YACT;YACAQ,SAAS;YACTC,kBAAkB;YAClBC,MAAM;QACR;QAEAb,OAAOc,EAAE,CAAC,YAAY;YACpB,IAAIC;YACJ,MAAO,AAACA,CAAAA,SAASf,OAAOgB,IAAI,EAAC,MAAO,KAAM;gBACxCjB,QAAQkB,IAAI,CAACF;YACf;QACF;QAEAf,OAAOc,EAAE,CAAC,SAAS,CAACI;YAClBvB,IAAIwB,OAAO,CAACC,MAAM,CAACC,KAAK,CAAC;gBAAEH;gBAAKI,KAAK;YAAoB;YACzDxB,OAAOoB;QACT;QAEAlB,OAAOc,EAAE,CAAC,OAAO;YACfjB,QAAQE;QACV;QAEAC,OAAOuB,KAAK,CAAC7B;QACbM,OAAOwB,GAAG;IACZ;AACF,EAAC"}
|
|
@@ -153,6 +153,32 @@ describe('parseCSV', ()=>{
|
|
|
153
153
|
}
|
|
154
154
|
]);
|
|
155
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
|
+
});
|
|
156
182
|
});
|
|
157
183
|
describe('error handling', ()=>{
|
|
158
184
|
it('should handle parsing errors', async ()=>{
|
|
@@ -1 +1 @@
|
|
|
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\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","invalidCsv","rejects","toThrow","toHaveBeenCalled"],"mappings":"AAEA,SAASA,QAAQ,QAAQ,gBAAe;AACxC,SAASC,QAAQ,EAAEC,EAAE,EAAEC,MAAM,EAAEC,EAAE,QAAQ,SAAQ;AAEjDH,SAAS,YAAY;IACnB,MAAMI,UAAU;QACdC,SAAS;YACPC,QAAQ;gBACNC,OAAOJ,GAAGK,EAAE;YACd;QACF;IACF;IAEAR,SAAS,0BAA0B;QACjCC,GAAG,qDAAqD;YACtD,MAAMQ,UAAUC,OAAOC,IAAI,CAAC;YAC5B,MAAMC,SAAS,MAAMb,SAAS;gBAAEc,MAAMJ;gBAASK,KAAKV;YAAQ;YAE5DF,OAAOU,QAAQG,OAAO,CAAC;gBACrB;oBACEC,SAAS;oBACTC,KAAK;gBACP;aACD;QACH;QAEAhB,GAAG,4CAA4C;YAC7C,MAAMQ,UAAUC,OAAOC,IAAI,CAAC;YAC5B,MAAMC,SAAS,MAAMb,SAAS;gBAAEc,MAAMJ;gBAASK,KAAKV;YAAQ;YAE5DF,OAAOU,QAAQG,OAAO,CAAC;gBACrB;oBACEG,QAAQ;oBACRC,SAAS;gBACX;aACD;QACH;QAEAlB,GAAG,oCAAoC;YACrC,MAAMQ,UAAUC,OAAOC,IAAI,CAAC;YAC5B,MAAMC,SAAS,MAAMb,SAAS;gBAAEc,MAAMJ;gBAASK,KAAKV;YAAQ;YAE5DF,OAAOU,QAAQG,OAAO,CAAC;gBACrB;oBACEK,OAAO;oBACPC,OAAO;oBACPC,SAAS;gBACX;aACD;QACH;QAEArB,GAAG,6CAA6C;YAC9C,MAAMQ,UAAUC,OAAOC,IAAI,CAAC;YAC5B,MAAMC,SAAS,MAAMb,SAAS;gBAAEc,MAAMJ;gBAASK,KAAKV;YAAQ;YAE5DF,OAAOU,QAAQG,OAAO,CAAC;gBACrB;oBACE,sEAAsE;oBACtEQ,QAAQ;gBACV;aACD;QACH;QAEAtB,GAAG,8BAA8B;YAC/B,MAAMQ,UAAUC,OAAOC,IAAI,CAAC;YAC5B,MAAMC,SAAS,MAAMb,SAAS;gBAAEc,MAAMJ;gBAASK,KAAKV;YAAQ;YAE5DF,OAAOU,QAAQG,OAAO,CAAC;gBACrB;oBACES,QAAQ;oBACRD,QAAQ;oBACRE,QAAQ;gBACV;aACD;QACH;QAEAxB,GAAG,oDAAoD;YACrD,MAAMQ,UAAUC,OAAOC,IAAI,CAAC;YAC5B,MAAMC,SAAS,MAAMb,SAAS;gBAAEc,MAAMJ;gBAASK,KAAKV;YAAQ;YAE5DF,OAAOU,QAAQG,OAAO,CAAC;gBACrB;oBACEC,SAAS;gBACX;aACD;QACH;QAEAf,GAAG,iEAAiE;YAClE,MAAMQ,UAAUC,OAAOC,IAAI,CAAC;YAC5B,MAAMC,SAAS,MAAMb,SAAS;gBAAEc,MAAMJ;gBAASK,KAAKV;YAAQ;YAE5DF,OAAOU,QAAQG,OAAO,CAAC;gBACrB;oBACEW,OAAO;gBACT;aACD;QACH;QAEAzB,GAAG,8CAA8C;YAC/C,MAAMQ,UAAUC,OAAOC,IAAI,CAAC;YAC5B,MAAMC,SAAS,MAAMb,SAAS;gBAAEc,MAAMJ;gBAASK,KAAKV;YAAQ;YAE5DF,OAAOU,QAAQG,OAAO,CAAC;gBACrB;oBACEY,IAAI;gBACN;aACD;QACH;QAEA1B,GAAG,uDAAuD;YACxD,MAAMQ,UAAUC,OAAOC,IAAI,CACzB,8BACE,2CACA,6BACA;YAEJ,MAAMC,SAAS,MAAMb,SAAS;gBAAEc,MAAMJ;gBAASK,KAAKV;YAAQ;YAE5DF,OAAOU,QAAQG,OAAO,CAAC;gBACrB;oBACEa,OAAO;oBACPC,OAAO;oBACPC,MAAM;oBACNC,QAAQ;gBACV;gBACA;oBACEH,OAAO;oBACP,sDAAsD;oBACtD,qDAAqD;oBACrDG,QAAQ;gBACV;gBACA;oBACEH,OAAO;oBACPC,OAAO;oBACPC,MAAM;gBAER;aACD;QACH;QAEA7B,GAAG,2BAA2B;YAC5B,MAAMQ,UAAUC,OAAOC,IAAI,CAAC;YAC5B,MAAMC,SAAS,MAAMb,SAAS;gBAAEc,MAAMJ;gBAASK,KAAKV;YAAQ;YAE5DF,OAAOU,QAAQG,OAAO,CAAC;gBAAC;oBAAEiB,OAAO;gBAAS;gBAAG;oBAAEA,OAAO;gBAAS;aAAE;QACnE;IACF;
|
|
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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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@payloadcms/plugin-import-export",
|
|
3
|
-
"version": "3.77.0-internal.
|
|
3
|
+
"version": "3.77.0-internal.fd50432",
|
|
4
4
|
"description": "Import-Export plugin for Payload",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"payload",
|
|
@@ -64,17 +64,17 @@
|
|
|
64
64
|
"csv-parse": "5.6.0",
|
|
65
65
|
"csv-stringify": "6.5.2",
|
|
66
66
|
"qs-esm": "7.0.2",
|
|
67
|
-
"@payloadcms/translations": "3.77.0-internal.
|
|
68
|
-
"@payloadcms/ui": "3.77.0-internal.
|
|
67
|
+
"@payloadcms/translations": "3.77.0-internal.fd50432",
|
|
68
|
+
"@payloadcms/ui": "3.77.0-internal.fd50432"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@payloadcms/eslint-config": "3.28.0",
|
|
72
|
-
"
|
|
73
|
-
"
|
|
72
|
+
"@payloadcms/ui": "3.77.0-internal.fd50432",
|
|
73
|
+
"payload": "3.77.0-internal.fd50432"
|
|
74
74
|
},
|
|
75
75
|
"peerDependencies": {
|
|
76
|
-
"@payloadcms/ui": "3.77.0-internal.
|
|
77
|
-
"payload": "3.77.0-internal.
|
|
76
|
+
"@payloadcms/ui": "3.77.0-internal.fd50432",
|
|
77
|
+
"payload": "3.77.0-internal.fd50432"
|
|
78
78
|
},
|
|
79
79
|
"homepage:": "https://payloadcms.com",
|
|
80
80
|
"scripts": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/ImportCollectionField/index.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAA;AAIzD,eAAO,MAAM,qBAAqB,EAAE,0BAWnC,CAAA"}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
-
import { SelectField, useDocumentInfo } from '@payloadcms/ui';
|
|
4
|
-
export const ImportCollectionField = (props)=>{
|
|
5
|
-
const { id, initialData } = useDocumentInfo();
|
|
6
|
-
// If creating (no id) and have initialData with collectionSlug (e.g., from drawer),
|
|
7
|
-
// hide the field to prevent user selection.
|
|
8
|
-
if (!id && initialData?.collectionSlug) {
|
|
9
|
-
return null;
|
|
10
|
-
}
|
|
11
|
-
// Otherwise render the normal select field
|
|
12
|
-
return /*#__PURE__*/ _jsx(SelectField, {
|
|
13
|
-
...props
|
|
14
|
-
});
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
//# sourceMappingURL=index.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/ImportCollectionField/index.tsx"],"sourcesContent":["'use client'\nimport type { SelectFieldClientComponent } from 'payload'\n\nimport { SelectField, useDocumentInfo } from '@payloadcms/ui'\n\nexport const ImportCollectionField: SelectFieldClientComponent = (props) => {\n const { id, initialData } = useDocumentInfo()\n\n // If creating (no id) and have initialData with collectionSlug (e.g., from drawer),\n // hide the field to prevent user selection.\n if (!id && initialData?.collectionSlug) {\n return null\n }\n\n // Otherwise render the normal select field\n return <SelectField {...props} />\n}\n"],"names":["SelectField","useDocumentInfo","ImportCollectionField","props","id","initialData","collectionSlug"],"mappings":"AAAA;;AAGA,SAASA,WAAW,EAAEC,eAAe,QAAQ,iBAAgB;AAE7D,OAAO,MAAMC,wBAAoD,CAACC;IAChE,MAAM,EAAEC,EAAE,EAAEC,WAAW,EAAE,GAAGJ;IAE5B,oFAAoF;IACpF,4CAA4C;IAC5C,IAAI,CAACG,MAAMC,aAAaC,gBAAgB;QACtC,OAAO;IACT;IAEA,2CAA2C;IAC3C,qBAAO,KAACN;QAAa,GAAGG,KAAK;;AAC/B,EAAC"}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import type { FlattenedField } from 'payload';
|
|
2
|
-
type FieldWithPresentational = {
|
|
3
|
-
fields?: FlattenedField[];
|
|
4
|
-
name?: string;
|
|
5
|
-
tabs?: {
|
|
6
|
-
fields: FlattenedField[];
|
|
7
|
-
name?: string;
|
|
8
|
-
}[];
|
|
9
|
-
type: 'collapsible' | 'row' | 'tabs';
|
|
10
|
-
} | FlattenedField;
|
|
11
|
-
/**
|
|
12
|
-
* Collects the names of auto-generated timezone companion fields from the schema.
|
|
13
|
-
*
|
|
14
|
-
* When a date field has `timezone: true`, Payload automatically generates a companion
|
|
15
|
-
* select field and inserts it immediately after the date field in the fields array.
|
|
16
|
-
* This function identifies those auto-generated fields by looking at the field sequence
|
|
17
|
-
* rather than assuming a specific naming convention (since the name can be overridden).
|
|
18
|
-
*
|
|
19
|
-
* This is used to filter out timezone companions unless explicitly selected,
|
|
20
|
-
* without incorrectly filtering user-defined fields that happen to end with `_tz`.
|
|
21
|
-
*/
|
|
22
|
-
export declare const collectTimezoneCompanionFields: (fields: FieldWithPresentational[], prefix?: string) => Set<string>;
|
|
23
|
-
export {};
|
|
24
|
-
//# sourceMappingURL=collectTimezoneCompanionFields.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"collectTimezoneCompanionFields.d.ts","sourceRoot":"","sources":["../../src/utilities/collectTimezoneCompanionFields.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAA;AAE7C,KAAK,uBAAuB,GACxB;IACE,MAAM,CAAC,EAAE,cAAc,EAAE,CAAA;IACzB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE;QACL,MAAM,EAAE,cAAc,EAAE,CAAA;QACxB,IAAI,CAAC,EAAE,MAAM,CAAA;KACd,EAAE,CAAA;IACH,IAAI,EAAE,aAAa,GAAG,KAAK,GAAG,MAAM,CAAA;CACrC,GACD,cAAc,CAAA;AAElB;;;;;;;;;;GAUG;AACH,eAAO,MAAM,8BAA8B,WACjC,uBAAuB,EAAE,sBAEhC,GAAG,CAAC,MAAM,CAmFZ,CAAA"}
|