@payloadcms/plugin-import-export 4.0.0-canary.26 → 4.0.0-canary.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/export/handlePreview.js +1 -1
- package/dist/export/handlePreview.js.map +1 -1
- package/dist/utilities/fieldPath.d.ts +2 -0
- package/dist/utilities/fieldPath.d.ts.map +1 -0
- package/dist/utilities/fieldPath.js +8 -0
- package/dist/utilities/fieldPath.js.map +1 -0
- package/dist/utilities/getSelect.d.ts.map +1 -1
- package/dist/utilities/getSelect.js +9 -3
- package/dist/utilities/getSelect.js.map +1 -1
- package/dist/utilities/getSelect.spec.js +70 -0
- package/dist/utilities/getSelect.spec.js.map +1 -0
- package/dist/utilities/setNestedValue.d.ts +2 -1
- package/dist/utilities/setNestedValue.d.ts.map +1 -1
- package/dist/utilities/setNestedValue.js +51 -34
- package/dist/utilities/setNestedValue.js.map +1 -1
- package/dist/utilities/setNestedValue.spec.js +164 -0
- package/dist/utilities/setNestedValue.spec.js.map +1 -0
- package/package.json +7 -7
|
@@ -199,7 +199,7 @@ export const handlePreview = async (req)=>{
|
|
|
199
199
|
const trimmed = {};
|
|
200
200
|
for (const key of fields){
|
|
201
201
|
const value = getObjectDotNotation(output, key);
|
|
202
|
-
setNestedValue(trimmed, key, value ?? null);
|
|
202
|
+
setNestedValue(trimmed, key, value ?? null, output);
|
|
203
203
|
}
|
|
204
204
|
output = trimmed;
|
|
205
205
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/export/handlePreview.ts"],"sourcesContent":["import type { PayloadRequest, Sort, Where } from 'payload'\n\nimport { addDataAndFileToRequest } from 'payload'\nimport { getObjectDotNotation } from 'payload/shared'\n\nimport type { ExportBeforeHook, ExportPreviewResponse } from '../types.js'\n\nimport {\n DEFAULT_PREVIEW_LIMIT,\n MAX_PREVIEW_LIMIT,\n MIN_PREVIEW_LIMIT,\n MIN_PREVIEW_PAGE,\n} from '../constants.js'\nimport { applyFieldHooks } from '../utilities/applyFieldHooks.js'\nimport { flattenObject } from '../utilities/flattenObject.js'\nimport { getExportFieldFunctions } from '../utilities/getExportFieldFunctions.js'\nimport { getFlattenedFieldKeys } from '../utilities/getFlattenedFieldKeys.js'\nimport { getSchemaColumns, mergeColumns } from '../utilities/getSchemaColumns.js'\nimport { getSelect } from '../utilities/getSelect.js'\nimport { removeDisabledFields } from '../utilities/removeDisabledFields.js'\nimport { resolveLimit } from '../utilities/resolveLimit.js'\nimport { setNestedValue } from '../utilities/setNestedValue.js'\n\nconst applyExportBeforeHook = async (\n hook: ExportBeforeHook | undefined,\n data: Record<string, unknown>[],\n originalDocs: unknown[],\n format: 'csv' | 'json' | ({} & string),\n req: PayloadRequest,\n): Promise<Record<string, unknown>[]> => {\n if (!hook || data.length === 0) {\n return data\n }\n return hook({\n batchNumber: 1,\n data,\n format,\n originalData: originalDocs as Record<string, unknown>[],\n req,\n totalBatches: 1,\n })\n}\n\nexport const handlePreview = async (req: PayloadRequest): Promise<Response> => {\n await addDataAndFileToRequest(req)\n\n const {\n collectionSlug,\n draft: draftFromReq,\n fields,\n limit: exportLimit,\n locale,\n previewLimit: rawPreviewLimit = DEFAULT_PREVIEW_LIMIT,\n previewPage: rawPreviewPage = 1,\n sort,\n where: whereFromReq = {},\n } = req.data as {\n collectionSlug: string\n draft?: 'no' | 'yes'\n fields?: string[]\n format?: 'csv' | 'json'\n limit?: number\n locale?: string\n previewLimit?: number\n previewPage?: number\n sort?: Sort\n where?: Where\n }\n\n // Validate and clamp pagination values to safe bounds\n const previewLimit = Math.max(MIN_PREVIEW_LIMIT, Math.min(rawPreviewLimit, MAX_PREVIEW_LIMIT))\n const previewPage = Math.max(MIN_PREVIEW_PAGE, rawPreviewPage)\n\n const targetCollection = req.payload.collections[collectionSlug]\n if (!targetCollection) {\n return Response.json(\n { error: `Collection with slug ${collectionSlug} not found` },\n { status: 400 },\n )\n }\n\n const pluginConfig = targetCollection.config.custom?.['plugin-import-export']\n const maxLimit = await resolveLimit({\n limit: pluginConfig?.exportLimit,\n req,\n })\n\n const select = Array.isArray(fields) && fields.length > 0 ? getSelect(fields) : undefined\n const draft = draftFromReq === 'yes'\n const collectionHasVersions = Boolean(targetCollection.config.versions)\n\n // Only filter by _status for versioned collections\n const publishedWhere: Where = collectionHasVersions ? { _status: { equals: 'published' } } : {}\n\n const where: Where = {\n and: [whereFromReq, draft ? {} : publishedWhere],\n }\n\n // Count total docs matching export criteria\n const countResult = await req.payload.count({\n collection: collectionSlug,\n overrideAccess: false,\n req,\n where,\n })\n\n const totalMatchingDocs = countResult.totalDocs\n\n // Calculate actual export count (respecting both export limit and max limit)\n let effectiveLimit = totalMatchingDocs\n\n // Apply user's export limit if provided\n if (exportLimit && exportLimit > 0) {\n effectiveLimit = Math.min(effectiveLimit, exportLimit)\n }\n\n // Apply max limit if configured\n if (typeof maxLimit === 'number' && maxLimit > 0) {\n effectiveLimit = Math.min(effectiveLimit, maxLimit)\n }\n\n const exportTotalDocs = effectiveLimit\n\n // Calculate preview pagination that respects export limit\n // Preview should only show docs that will actually be exported\n const previewStartIndex = (previewPage - 1) * previewLimit\n\n // Calculate pagination info based on export limit (not raw DB results)\n const previewTotalPages = exportTotalDocs === 0 ? 0 : Math.ceil(exportTotalDocs / previewLimit)\n\n const isCSV = req?.data?.format === 'csv'\n\n // Get locale codes for locale expansion when locale='all'\n const localeCodes =\n locale === 'all' && req.payload.config.localization\n ? req.payload.config.localization.localeCodes\n : undefined\n\n // Get disabled fields configuration\n const disabledFields =\n targetCollection.config.admin?.custom?.['plugin-import-export']?.disabledFields ?? []\n\n // Compute schema-based columns for CSV (provides base ordering and handles empty exports)\n const schemaColumns = isCSV\n ? getSchemaColumns({\n collectionConfig: targetCollection.config,\n disabledFields,\n fields,\n locale: locale ?? undefined,\n localeCodes,\n })\n : undefined\n\n // columns will be finalized after data is available (merged with data-discovered columns)\n let columns = schemaColumns\n\n // If we're beyond the effective limit (considering both user limit and maxLimit), return empty docs\n if (exportTotalDocs > 0 && previewStartIndex >= exportTotalDocs) {\n const response: ExportPreviewResponse = {\n columns,\n docs: [],\n exportTotalDocs,\n hasNextPage: false,\n hasPrevPage: previewPage > 1,\n limit: previewLimit,\n maxLimit,\n page: previewPage,\n totalDocs: exportTotalDocs,\n totalPages: previewTotalPages,\n }\n return Response.json(response)\n }\n\n // Fetch preview page with full previewLimit to maintain consistent pagination offsets\n // We'll trim the results afterwards if needed to respect export limit\n const result = await req.payload.find({\n collection: collectionSlug,\n depth: 1,\n draft,\n limit: previewLimit,\n locale,\n overrideAccess: false,\n page: previewPage,\n req,\n select,\n sort,\n where,\n })\n\n // Trim docs to respect effective limit boundary (user limit clamped by maxLimit)\n let docs = result.docs\n if (exportTotalDocs > 0) {\n const remainingInExport = exportTotalDocs - previewStartIndex\n if (remainingInExport < docs.length) {\n docs = docs.slice(0, remainingInExport)\n }\n }\n\n // Transform docs based on format\n let transformed: Record<string, unknown>[]\n\n const exportFieldHooks = getExportFieldFunctions({\n fields: targetCollection.config.flattenedFields,\n })\n\n const exportHooks = targetCollection.config.custom?.['plugin-import-export']?.exportHooks\n\n if (isCSV) {\n const possibleKeys = getFlattenedFieldKeys(targetCollection.config.flattenedFields, '', {\n localeCodes,\n })\n\n // Flatten docs without padding yet. This preserves the exact keys produced by beforeExport hooks,\n // allowing mergeColumns to detect which schema columns were replaced with derived ones.\n transformed = docs.map((doc) =>\n flattenObject({\n data: doc,\n exportFieldHooks,\n fields,\n format: 'csv',\n req,\n }),\n )\n\n transformed = await applyExportBeforeHook(exportHooks?.before, transformed, docs, 'csv', req)\n\n if (schemaColumns && transformed.length > 0) {\n const dataColumns: string[] = []\n const seenCols = new Set<string>()\n for (const row of transformed) {\n for (const key of Object.keys(row)) {\n if (!seenCols.has(key)) {\n seenCols.add(key)\n dataColumns.push(key)\n }\n }\n }\n const mergedColumns = mergeColumns(schemaColumns, dataColumns)\n columns =\n Boolean(exportHooks?.before) && transformed.length > 0\n ? mergedColumns.filter((col) => dataColumns.includes(col))\n : mergedColumns\n }\n\n // Pad rows with null for missing columns (uses merged columns, not raw schema)\n if (!fields || fields.length === 0) {\n const paddingKeys = columns ?? possibleKeys\n for (const row of transformed) {\n for (const key of paddingKeys) {\n if (!(key in row)) {\n row[key] = null\n }\n }\n }\n }\n } else {\n transformed = docs.map((doc) => {\n // Apply field-level export hooks for JSON format\n let output: Record<string, unknown> = applyFieldHooks({\n type: 'beforeExport',\n data: doc as Record<string, unknown>,\n fieldHooks: exportFieldHooks,\n fields: targetCollection.config.flattenedFields,\n format: 'json',\n operation: 'export',\n req,\n })\n\n // Remove disabled fields\n output = removeDisabledFields(output, disabledFields)\n\n // Then trim to selected fields only (if fields are provided)\n if (Array.isArray(fields) && fields.length > 0) {\n const trimmed: Record<string, unknown> = {}\n\n for (const key of fields) {\n const value = getObjectDotNotation(output, key)\n setNestedValue(trimmed, key, value ?? null)\n }\n\n output = trimmed\n }\n\n return output\n })\n\n transformed = await applyExportBeforeHook(exportHooks?.before, transformed, docs, 'json', req)\n }\n\n const hasNextPage = previewPage < previewTotalPages\n const hasPrevPage = previewPage > 1\n\n const response: ExportPreviewResponse = {\n columns,\n docs: transformed,\n exportTotalDocs,\n hasNextPage,\n hasPrevPage,\n limit: previewLimit,\n maxLimit,\n page: previewPage,\n totalDocs: exportTotalDocs,\n totalPages: previewTotalPages,\n }\n\n return Response.json(response)\n}\n"],"names":["addDataAndFileToRequest","getObjectDotNotation","DEFAULT_PREVIEW_LIMIT","MAX_PREVIEW_LIMIT","MIN_PREVIEW_LIMIT","MIN_PREVIEW_PAGE","applyFieldHooks","flattenObject","getExportFieldFunctions","getFlattenedFieldKeys","getSchemaColumns","mergeColumns","getSelect","removeDisabledFields","resolveLimit","setNestedValue","applyExportBeforeHook","hook","data","originalDocs","format","req","length","batchNumber","originalData","totalBatches","handlePreview","collectionSlug","draft","draftFromReq","fields","limit","exportLimit","locale","previewLimit","rawPreviewLimit","previewPage","rawPreviewPage","sort","where","whereFromReq","Math","max","min","targetCollection","payload","collections","Response","json","error","status","pluginConfig","config","custom","maxLimit","select","Array","isArray","undefined","collectionHasVersions","Boolean","versions","publishedWhere","_status","equals","and","countResult","count","collection","overrideAccess","totalMatchingDocs","totalDocs","effectiveLimit","exportTotalDocs","previewStartIndex","previewTotalPages","ceil","isCSV","localeCodes","localization","disabledFields","admin","schemaColumns","collectionConfig","columns","response","docs","hasNextPage","hasPrevPage","page","totalPages","result","find","depth","remainingInExport","slice","transformed","exportFieldHooks","flattenedFields","exportHooks","possibleKeys","map","doc","before","dataColumns","seenCols","Set","row","key","Object","keys","has","add","push","mergedColumns","filter","col","includes","paddingKeys","output","type","fieldHooks","operation","trimmed","value"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/export/handlePreview.ts"],"sourcesContent":["import type { PayloadRequest, Sort, Where } from 'payload'\n\nimport { addDataAndFileToRequest } from 'payload'\nimport { getObjectDotNotation } from 'payload/shared'\n\nimport type { ExportBeforeHook, ExportPreviewResponse } from '../types.js'\n\nimport {\n DEFAULT_PREVIEW_LIMIT,\n MAX_PREVIEW_LIMIT,\n MIN_PREVIEW_LIMIT,\n MIN_PREVIEW_PAGE,\n} from '../constants.js'\nimport { applyFieldHooks } from '../utilities/applyFieldHooks.js'\nimport { flattenObject } from '../utilities/flattenObject.js'\nimport { getExportFieldFunctions } from '../utilities/getExportFieldFunctions.js'\nimport { getFlattenedFieldKeys } from '../utilities/getFlattenedFieldKeys.js'\nimport { getSchemaColumns, mergeColumns } from '../utilities/getSchemaColumns.js'\nimport { getSelect } from '../utilities/getSelect.js'\nimport { removeDisabledFields } from '../utilities/removeDisabledFields.js'\nimport { resolveLimit } from '../utilities/resolveLimit.js'\nimport { setNestedValue } from '../utilities/setNestedValue.js'\n\nconst applyExportBeforeHook = async (\n hook: ExportBeforeHook | undefined,\n data: Record<string, unknown>[],\n originalDocs: unknown[],\n format: 'csv' | 'json' | ({} & string),\n req: PayloadRequest,\n): Promise<Record<string, unknown>[]> => {\n if (!hook || data.length === 0) {\n return data\n }\n return hook({\n batchNumber: 1,\n data,\n format,\n originalData: originalDocs as Record<string, unknown>[],\n req,\n totalBatches: 1,\n })\n}\n\nexport const handlePreview = async (req: PayloadRequest): Promise<Response> => {\n await addDataAndFileToRequest(req)\n\n const {\n collectionSlug,\n draft: draftFromReq,\n fields,\n limit: exportLimit,\n locale,\n previewLimit: rawPreviewLimit = DEFAULT_PREVIEW_LIMIT,\n previewPage: rawPreviewPage = 1,\n sort,\n where: whereFromReq = {},\n } = req.data as {\n collectionSlug: string\n draft?: 'no' | 'yes'\n fields?: string[]\n format?: 'csv' | 'json'\n limit?: number\n locale?: string\n previewLimit?: number\n previewPage?: number\n sort?: Sort\n where?: Where\n }\n\n // Validate and clamp pagination values to safe bounds\n const previewLimit = Math.max(MIN_PREVIEW_LIMIT, Math.min(rawPreviewLimit, MAX_PREVIEW_LIMIT))\n const previewPage = Math.max(MIN_PREVIEW_PAGE, rawPreviewPage)\n\n const targetCollection = req.payload.collections[collectionSlug]\n if (!targetCollection) {\n return Response.json(\n { error: `Collection with slug ${collectionSlug} not found` },\n { status: 400 },\n )\n }\n\n const pluginConfig = targetCollection.config.custom?.['plugin-import-export']\n const maxLimit = await resolveLimit({\n limit: pluginConfig?.exportLimit,\n req,\n })\n\n const select = Array.isArray(fields) && fields.length > 0 ? getSelect(fields) : undefined\n const draft = draftFromReq === 'yes'\n const collectionHasVersions = Boolean(targetCollection.config.versions)\n\n // Only filter by _status for versioned collections\n const publishedWhere: Where = collectionHasVersions ? { _status: { equals: 'published' } } : {}\n\n const where: Where = {\n and: [whereFromReq, draft ? {} : publishedWhere],\n }\n\n // Count total docs matching export criteria\n const countResult = await req.payload.count({\n collection: collectionSlug,\n overrideAccess: false,\n req,\n where,\n })\n\n const totalMatchingDocs = countResult.totalDocs\n\n // Calculate actual export count (respecting both export limit and max limit)\n let effectiveLimit = totalMatchingDocs\n\n // Apply user's export limit if provided\n if (exportLimit && exportLimit > 0) {\n effectiveLimit = Math.min(effectiveLimit, exportLimit)\n }\n\n // Apply max limit if configured\n if (typeof maxLimit === 'number' && maxLimit > 0) {\n effectiveLimit = Math.min(effectiveLimit, maxLimit)\n }\n\n const exportTotalDocs = effectiveLimit\n\n // Calculate preview pagination that respects export limit\n // Preview should only show docs that will actually be exported\n const previewStartIndex = (previewPage - 1) * previewLimit\n\n // Calculate pagination info based on export limit (not raw DB results)\n const previewTotalPages = exportTotalDocs === 0 ? 0 : Math.ceil(exportTotalDocs / previewLimit)\n\n const isCSV = req?.data?.format === 'csv'\n\n // Get locale codes for locale expansion when locale='all'\n const localeCodes =\n locale === 'all' && req.payload.config.localization\n ? req.payload.config.localization.localeCodes\n : undefined\n\n // Get disabled fields configuration\n const disabledFields =\n targetCollection.config.admin?.custom?.['plugin-import-export']?.disabledFields ?? []\n\n // Compute schema-based columns for CSV (provides base ordering and handles empty exports)\n const schemaColumns = isCSV\n ? getSchemaColumns({\n collectionConfig: targetCollection.config,\n disabledFields,\n fields,\n locale: locale ?? undefined,\n localeCodes,\n })\n : undefined\n\n // columns will be finalized after data is available (merged with data-discovered columns)\n let columns = schemaColumns\n\n // If we're beyond the effective limit (considering both user limit and maxLimit), return empty docs\n if (exportTotalDocs > 0 && previewStartIndex >= exportTotalDocs) {\n const response: ExportPreviewResponse = {\n columns,\n docs: [],\n exportTotalDocs,\n hasNextPage: false,\n hasPrevPage: previewPage > 1,\n limit: previewLimit,\n maxLimit,\n page: previewPage,\n totalDocs: exportTotalDocs,\n totalPages: previewTotalPages,\n }\n return Response.json(response)\n }\n\n // Fetch preview page with full previewLimit to maintain consistent pagination offsets\n // We'll trim the results afterwards if needed to respect export limit\n const result = await req.payload.find({\n collection: collectionSlug,\n depth: 1,\n draft,\n limit: previewLimit,\n locale,\n overrideAccess: false,\n page: previewPage,\n req,\n select,\n sort,\n where,\n })\n\n // Trim docs to respect effective limit boundary (user limit clamped by maxLimit)\n let docs = result.docs\n if (exportTotalDocs > 0) {\n const remainingInExport = exportTotalDocs - previewStartIndex\n if (remainingInExport < docs.length) {\n docs = docs.slice(0, remainingInExport)\n }\n }\n\n // Transform docs based on format\n let transformed: Record<string, unknown>[]\n\n const exportFieldHooks = getExportFieldFunctions({\n fields: targetCollection.config.flattenedFields,\n })\n\n const exportHooks = targetCollection.config.custom?.['plugin-import-export']?.exportHooks\n\n if (isCSV) {\n const possibleKeys = getFlattenedFieldKeys(targetCollection.config.flattenedFields, '', {\n localeCodes,\n })\n\n // Flatten docs without padding yet. This preserves the exact keys produced by beforeExport hooks,\n // allowing mergeColumns to detect which schema columns were replaced with derived ones.\n transformed = docs.map((doc) =>\n flattenObject({\n data: doc,\n exportFieldHooks,\n fields,\n format: 'csv',\n req,\n }),\n )\n\n transformed = await applyExportBeforeHook(exportHooks?.before, transformed, docs, 'csv', req)\n\n if (schemaColumns && transformed.length > 0) {\n const dataColumns: string[] = []\n const seenCols = new Set<string>()\n for (const row of transformed) {\n for (const key of Object.keys(row)) {\n if (!seenCols.has(key)) {\n seenCols.add(key)\n dataColumns.push(key)\n }\n }\n }\n const mergedColumns = mergeColumns(schemaColumns, dataColumns)\n columns =\n Boolean(exportHooks?.before) && transformed.length > 0\n ? mergedColumns.filter((col) => dataColumns.includes(col))\n : mergedColumns\n }\n\n // Pad rows with null for missing columns (uses merged columns, not raw schema)\n if (!fields || fields.length === 0) {\n const paddingKeys = columns ?? possibleKeys\n for (const row of transformed) {\n for (const key of paddingKeys) {\n if (!(key in row)) {\n row[key] = null\n }\n }\n }\n }\n } else {\n transformed = docs.map((doc) => {\n // Apply field-level export hooks for JSON format\n let output: Record<string, unknown> = applyFieldHooks({\n type: 'beforeExport',\n data: doc as Record<string, unknown>,\n fieldHooks: exportFieldHooks,\n fields: targetCollection.config.flattenedFields,\n format: 'json',\n operation: 'export',\n req,\n })\n\n // Remove disabled fields\n output = removeDisabledFields(output, disabledFields)\n\n // Then trim to selected fields only (if fields are provided)\n if (Array.isArray(fields) && fields.length > 0) {\n const trimmed: Record<string, unknown> = {}\n\n for (const key of fields) {\n const value = getObjectDotNotation(output, key)\n setNestedValue(trimmed, key, value ?? null, output)\n }\n\n output = trimmed\n }\n\n return output\n })\n\n transformed = await applyExportBeforeHook(exportHooks?.before, transformed, docs, 'json', req)\n }\n\n const hasNextPage = previewPage < previewTotalPages\n const hasPrevPage = previewPage > 1\n\n const response: ExportPreviewResponse = {\n columns,\n docs: transformed,\n exportTotalDocs,\n hasNextPage,\n hasPrevPage,\n limit: previewLimit,\n maxLimit,\n page: previewPage,\n totalDocs: exportTotalDocs,\n totalPages: previewTotalPages,\n }\n\n return Response.json(response)\n}\n"],"names":["addDataAndFileToRequest","getObjectDotNotation","DEFAULT_PREVIEW_LIMIT","MAX_PREVIEW_LIMIT","MIN_PREVIEW_LIMIT","MIN_PREVIEW_PAGE","applyFieldHooks","flattenObject","getExportFieldFunctions","getFlattenedFieldKeys","getSchemaColumns","mergeColumns","getSelect","removeDisabledFields","resolveLimit","setNestedValue","applyExportBeforeHook","hook","data","originalDocs","format","req","length","batchNumber","originalData","totalBatches","handlePreview","collectionSlug","draft","draftFromReq","fields","limit","exportLimit","locale","previewLimit","rawPreviewLimit","previewPage","rawPreviewPage","sort","where","whereFromReq","Math","max","min","targetCollection","payload","collections","Response","json","error","status","pluginConfig","config","custom","maxLimit","select","Array","isArray","undefined","collectionHasVersions","Boolean","versions","publishedWhere","_status","equals","and","countResult","count","collection","overrideAccess","totalMatchingDocs","totalDocs","effectiveLimit","exportTotalDocs","previewStartIndex","previewTotalPages","ceil","isCSV","localeCodes","localization","disabledFields","admin","schemaColumns","collectionConfig","columns","response","docs","hasNextPage","hasPrevPage","page","totalPages","result","find","depth","remainingInExport","slice","transformed","exportFieldHooks","flattenedFields","exportHooks","possibleKeys","map","doc","before","dataColumns","seenCols","Set","row","key","Object","keys","has","add","push","mergedColumns","filter","col","includes","paddingKeys","output","type","fieldHooks","operation","trimmed","value"],"mappings":"AAEA,SAASA,uBAAuB,QAAQ,UAAS;AACjD,SAASC,oBAAoB,QAAQ,iBAAgB;AAIrD,SACEC,qBAAqB,EACrBC,iBAAiB,EACjBC,iBAAiB,EACjBC,gBAAgB,QACX,kBAAiB;AACxB,SAASC,eAAe,QAAQ,kCAAiC;AACjE,SAASC,aAAa,QAAQ,gCAA+B;AAC7D,SAASC,uBAAuB,QAAQ,0CAAyC;AACjF,SAASC,qBAAqB,QAAQ,wCAAuC;AAC7E,SAASC,gBAAgB,EAAEC,YAAY,QAAQ,mCAAkC;AACjF,SAASC,SAAS,QAAQ,4BAA2B;AACrD,SAASC,oBAAoB,QAAQ,uCAAsC;AAC3E,SAASC,YAAY,QAAQ,+BAA8B;AAC3D,SAASC,cAAc,QAAQ,iCAAgC;AAE/D,MAAMC,wBAAwB,OAC5BC,MACAC,MACAC,cACAC,QACAC;IAEA,IAAI,CAACJ,QAAQC,KAAKI,MAAM,KAAK,GAAG;QAC9B,OAAOJ;IACT;IACA,OAAOD,KAAK;QACVM,aAAa;QACbL;QACAE;QACAI,cAAcL;QACdE;QACAI,cAAc;IAChB;AACF;AAEA,OAAO,MAAMC,gBAAgB,OAAOL;IAClC,MAAMrB,wBAAwBqB;IAE9B,MAAM,EACJM,cAAc,EACdC,OAAOC,YAAY,EACnBC,MAAM,EACNC,OAAOC,WAAW,EAClBC,MAAM,EACNC,cAAcC,kBAAkBjC,qBAAqB,EACrDkC,aAAaC,iBAAiB,CAAC,EAC/BC,IAAI,EACJC,OAAOC,eAAe,CAAC,CAAC,EACzB,GAAGnB,IAAIH,IAAI;IAaZ,sDAAsD;IACtD,MAAMgB,eAAeO,KAAKC,GAAG,CAACtC,mBAAmBqC,KAAKE,GAAG,CAACR,iBAAiBhC;IAC3E,MAAMiC,cAAcK,KAAKC,GAAG,CAACrC,kBAAkBgC;IAE/C,MAAMO,mBAAmBvB,IAAIwB,OAAO,CAACC,WAAW,CAACnB,eAAe;IAChE,IAAI,CAACiB,kBAAkB;QACrB,OAAOG,SAASC,IAAI,CAClB;YAAEC,OAAO,CAAC,qBAAqB,EAAEtB,eAAe,UAAU,CAAC;QAAC,GAC5D;YAAEuB,QAAQ;QAAI;IAElB;IAEA,MAAMC,eAAeP,iBAAiBQ,MAAM,CAACC,MAAM,EAAE,CAAC,uBAAuB;IAC7E,MAAMC,WAAW,MAAMxC,aAAa;QAClCiB,OAAOoB,cAAcnB;QACrBX;IACF;IAEA,MAAMkC,SAASC,MAAMC,OAAO,CAAC3B,WAAWA,OAAOR,MAAM,GAAG,IAAIV,UAAUkB,UAAU4B;IAChF,MAAM9B,QAAQC,iBAAiB;IAC/B,MAAM8B,wBAAwBC,QAAQhB,iBAAiBQ,MAAM,CAACS,QAAQ;IAEtE,mDAAmD;IACnD,MAAMC,iBAAwBH,wBAAwB;QAAEI,SAAS;YAAEC,QAAQ;QAAY;IAAE,IAAI,CAAC;IAE9F,MAAMzB,QAAe;QACnB0B,KAAK;YAACzB;YAAcZ,QAAQ,CAAC,IAAIkC;SAAe;IAClD;IAEA,4CAA4C;IAC5C,MAAMI,cAAc,MAAM7C,IAAIwB,OAAO,CAACsB,KAAK,CAAC;QAC1CC,YAAYzC;QACZ0C,gBAAgB;QAChBhD;QACAkB;IACF;IAEA,MAAM+B,oBAAoBJ,YAAYK,SAAS;IAE/C,6EAA6E;IAC7E,IAAIC,iBAAiBF;IAErB,wCAAwC;IACxC,IAAItC,eAAeA,cAAc,GAAG;QAClCwC,iBAAiB/B,KAAKE,GAAG,CAAC6B,gBAAgBxC;IAC5C;IAEA,gCAAgC;IAChC,IAAI,OAAOsB,aAAa,YAAYA,WAAW,GAAG;QAChDkB,iBAAiB/B,KAAKE,GAAG,CAAC6B,gBAAgBlB;IAC5C;IAEA,MAAMmB,kBAAkBD;IAExB,0DAA0D;IAC1D,+DAA+D;IAC/D,MAAME,oBAAoB,AAACtC,CAAAA,cAAc,CAAA,IAAKF;IAE9C,uEAAuE;IACvE,MAAMyC,oBAAoBF,oBAAoB,IAAI,IAAIhC,KAAKmC,IAAI,CAACH,kBAAkBvC;IAElF,MAAM2C,QAAQxD,KAAKH,MAAME,WAAW;IAEpC,0DAA0D;IAC1D,MAAM0D,cACJ7C,WAAW,SAASZ,IAAIwB,OAAO,CAACO,MAAM,CAAC2B,YAAY,GAC/C1D,IAAIwB,OAAO,CAACO,MAAM,CAAC2B,YAAY,CAACD,WAAW,GAC3CpB;IAEN,oCAAoC;IACpC,MAAMsB,iBACJpC,iBAAiBQ,MAAM,CAAC6B,KAAK,EAAE5B,QAAQ,CAAC,uBAAuB,EAAE2B,kBAAkB,EAAE;IAEvF,0FAA0F;IAC1F,MAAME,gBAAgBL,QAClBnE,iBAAiB;QACfyE,kBAAkBvC,iBAAiBQ,MAAM;QACzC4B;QACAlD;QACAG,QAAQA,UAAUyB;QAClBoB;IACF,KACApB;IAEJ,0FAA0F;IAC1F,IAAI0B,UAAUF;IAEd,oGAAoG;IACpG,IAAIT,kBAAkB,KAAKC,qBAAqBD,iBAAiB;QAC/D,MAAMY,WAAkC;YACtCD;YACAE,MAAM,EAAE;YACRb;YACAc,aAAa;YACbC,aAAapD,cAAc;YAC3BL,OAAOG;YACPoB;YACAmC,MAAMrD;YACNmC,WAAWE;YACXiB,YAAYf;QACd;QACA,OAAO5B,SAASC,IAAI,CAACqC;IACvB;IAEA,sFAAsF;IACtF,sEAAsE;IACtE,MAAMM,SAAS,MAAMtE,IAAIwB,OAAO,CAAC+C,IAAI,CAAC;QACpCxB,YAAYzC;QACZkE,OAAO;QACPjE;QACAG,OAAOG;QACPD;QACAoC,gBAAgB;QAChBoB,MAAMrD;QACNf;QACAkC;QACAjB;QACAC;IACF;IAEA,iFAAiF;IACjF,IAAI+C,OAAOK,OAAOL,IAAI;IACtB,IAAIb,kBAAkB,GAAG;QACvB,MAAMqB,oBAAoBrB,kBAAkBC;QAC5C,IAAIoB,oBAAoBR,KAAKhE,MAAM,EAAE;YACnCgE,OAAOA,KAAKS,KAAK,CAAC,GAAGD;QACvB;IACF;IAEA,iCAAiC;IACjC,IAAIE;IAEJ,MAAMC,mBAAmBzF,wBAAwB;QAC/CsB,QAAQc,iBAAiBQ,MAAM,CAAC8C,eAAe;IACjD;IAEA,MAAMC,cAAcvD,iBAAiBQ,MAAM,CAACC,MAAM,EAAE,CAAC,uBAAuB,EAAE8C;IAE9E,IAAItB,OAAO;QACT,MAAMuB,eAAe3F,sBAAsBmC,iBAAiBQ,MAAM,CAAC8C,eAAe,EAAE,IAAI;YACtFpB;QACF;QAEA,kGAAkG;QAClG,wFAAwF;QACxFkB,cAAcV,KAAKe,GAAG,CAAC,CAACC,MACtB/F,cAAc;gBACZW,MAAMoF;gBACNL;gBACAnE;gBACAV,QAAQ;gBACRC;YACF;QAGF2E,cAAc,MAAMhF,sBAAsBmF,aAAaI,QAAQP,aAAaV,MAAM,OAAOjE;QAEzF,IAAI6D,iBAAiBc,YAAY1E,MAAM,GAAG,GAAG;YAC3C,MAAMkF,cAAwB,EAAE;YAChC,MAAMC,WAAW,IAAIC;YACrB,KAAK,MAAMC,OAAOX,YAAa;gBAC7B,KAAK,MAAMY,OAAOC,OAAOC,IAAI,CAACH,KAAM;oBAClC,IAAI,CAACF,SAASM,GAAG,CAACH,MAAM;wBACtBH,SAASO,GAAG,CAACJ;wBACbJ,YAAYS,IAAI,CAACL;oBACnB;gBACF;YACF;YACA,MAAMM,gBAAgBvG,aAAauE,eAAesB;YAClDpB,UACExB,QAAQuC,aAAaI,WAAWP,YAAY1E,MAAM,GAAG,IACjD4F,cAAcC,MAAM,CAAC,CAACC,MAAQZ,YAAYa,QAAQ,CAACD,QACnDF;QACR;QAEA,+EAA+E;QAC/E,IAAI,CAACpF,UAAUA,OAAOR,MAAM,KAAK,GAAG;YAClC,MAAMgG,cAAclC,WAAWgB;YAC/B,KAAK,MAAMO,OAAOX,YAAa;gBAC7B,KAAK,MAAMY,OAAOU,YAAa;oBAC7B,IAAI,CAAEV,CAAAA,OAAOD,GAAE,GAAI;wBACjBA,GAAG,CAACC,IAAI,GAAG;oBACb;gBACF;YACF;QACF;IACF,OAAO;QACLZ,cAAcV,KAAKe,GAAG,CAAC,CAACC;YACtB,iDAAiD;YACjD,IAAIiB,SAAkCjH,gBAAgB;gBACpDkH,MAAM;gBACNtG,MAAMoF;gBACNmB,YAAYxB;gBACZnE,QAAQc,iBAAiBQ,MAAM,CAAC8C,eAAe;gBAC/C9E,QAAQ;gBACRsG,WAAW;gBACXrG;YACF;YAEA,yBAAyB;YACzBkG,SAAS1G,qBAAqB0G,QAAQvC;YAEtC,6DAA6D;YAC7D,IAAIxB,MAAMC,OAAO,CAAC3B,WAAWA,OAAOR,MAAM,GAAG,GAAG;gBAC9C,MAAMqG,UAAmC,CAAC;gBAE1C,KAAK,MAAMf,OAAO9E,OAAQ;oBACxB,MAAM8F,QAAQ3H,qBAAqBsH,QAAQX;oBAC3C7F,eAAe4G,SAASf,KAAKgB,SAAS,MAAML;gBAC9C;gBAEAA,SAASI;YACX;YAEA,OAAOJ;QACT;QAEAvB,cAAc,MAAMhF,sBAAsBmF,aAAaI,QAAQP,aAAaV,MAAM,QAAQjE;IAC5F;IAEA,MAAMkE,cAAcnD,cAAcuC;IAClC,MAAMa,cAAcpD,cAAc;IAElC,MAAMiD,WAAkC;QACtCD;QACAE,MAAMU;QACNvB;QACAc;QACAC;QACAzD,OAAOG;QACPoB;QACAmC,MAAMrD;QACNmC,WAAWE;QACXiB,YAAYf;IACd;IAEA,OAAO5B,SAASC,IAAI,CAACqC;AACvB,EAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fieldPath.d.ts","sourceRoot":"","sources":["../../src/utilities/fieldPath.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,8BAA8B,aAAc,MAAM,EAAE,KAAG,OACG,CAAA"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
const unsupportedFieldPathSegments = new Set([
|
|
2
|
+
'__proto__',
|
|
3
|
+
'constructor',
|
|
4
|
+
'prototype'
|
|
5
|
+
]);
|
|
6
|
+
export const hasUnsupportedFieldPathSegment = (segments)=>segments.some((segment)=>unsupportedFieldPathSegments.has(segment));
|
|
7
|
+
|
|
8
|
+
//# sourceMappingURL=fieldPath.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/fieldPath.ts"],"sourcesContent":["const unsupportedFieldPathSegments = new Set(['__proto__', 'constructor', 'prototype'])\n\nexport const hasUnsupportedFieldPathSegment = (segments: string[]): boolean =>\n segments.some((segment) => unsupportedFieldPathSegments.has(segment))\n"],"names":["unsupportedFieldPathSegments","Set","hasUnsupportedFieldPathSegment","segments","some","segment","has"],"mappings":"AAAA,MAAMA,+BAA+B,IAAIC,IAAI;IAAC;IAAa;IAAe;CAAY;AAEtF,OAAO,MAAMC,iCAAiC,CAACC,WAC7CA,SAASC,IAAI,CAAC,CAACC,UAAYL,6BAA6BM,GAAG,CAACD,UAAS"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getSelect.d.ts","sourceRoot":"","sources":["../../src/utilities/getSelect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"getSelect.d.ts","sourceRoot":"","sources":["../../src/utilities/getSelect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAA;AAQhD;;;;;;;GAOG;AACH,eAAO,MAAM,SAAS,WAAY,MAAM,EAAE,KAAG,iBAyB5C,CAAA"}
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { APIError } from 'payload';
|
|
2
|
+
import { hasUnsupportedFieldPathSegment } from './fieldPath.js';
|
|
3
|
+
const createSelect = ()=>Object.create(null);
|
|
1
4
|
/**
|
|
2
5
|
* Takes an input of array of string paths in dot notation and returns a select object.
|
|
3
6
|
* Used for both export and import to build Payload's select query format.
|
|
@@ -6,16 +9,19 @@
|
|
|
6
9
|
* getSelect(['id', 'title', 'group.value', 'createdAt', 'updatedAt'])
|
|
7
10
|
* // Returns: { id: true, title: true, group: { value: true }, createdAt: true, updatedAt: true }
|
|
8
11
|
*/ export const getSelect = (fields)=>{
|
|
9
|
-
const select =
|
|
12
|
+
const select = createSelect();
|
|
10
13
|
fields.forEach((field)=>{
|
|
11
14
|
const segments = field.split('.');
|
|
15
|
+
if (hasUnsupportedFieldPathSegment(segments)) {
|
|
16
|
+
throw new APIError('Invalid field path.', 400, null, true);
|
|
17
|
+
}
|
|
12
18
|
let selectRef = select;
|
|
13
19
|
segments.forEach((segment, i)=>{
|
|
14
20
|
if (i === segments.length - 1) {
|
|
15
21
|
selectRef[segment] = true;
|
|
16
22
|
} else {
|
|
17
|
-
if (!selectRef
|
|
18
|
-
selectRef[segment] =
|
|
23
|
+
if (!Object.prototype.hasOwnProperty.call(selectRef, segment)) {
|
|
24
|
+
selectRef[segment] = createSelect();
|
|
19
25
|
}
|
|
20
26
|
selectRef = selectRef[segment];
|
|
21
27
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utilities/getSelect.ts"],"sourcesContent":["import type { SelectIncludeType } from 'payload'\n\n/**\n * Takes an input of array of string paths in dot notation and returns a select object.\n * Used for both export and import to build Payload's select query format.\n *\n * @example\n * getSelect(['id', 'title', 'group.value', 'createdAt', 'updatedAt'])\n * // Returns: { id: true, title: true, group: { value: true }, createdAt: true, updatedAt: true }\n */\nexport const getSelect = (fields: string[]): SelectIncludeType => {\n const select
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/getSelect.ts"],"sourcesContent":["import type { SelectIncludeType } from 'payload'\n\nimport { APIError } from 'payload'\n\nimport { hasUnsupportedFieldPathSegment } from './fieldPath.js'\n\nconst createSelect = (): SelectIncludeType => Object.create(null) as SelectIncludeType\n\n/**\n * Takes an input of array of string paths in dot notation and returns a select object.\n * Used for both export and import to build Payload's select query format.\n *\n * @example\n * getSelect(['id', 'title', 'group.value', 'createdAt', 'updatedAt'])\n * // Returns: { id: true, title: true, group: { value: true }, createdAt: true, updatedAt: true }\n */\nexport const getSelect = (fields: string[]): SelectIncludeType => {\n const select = createSelect()\n\n fields.forEach((field) => {\n const segments = field.split('.')\n\n if (hasUnsupportedFieldPathSegment(segments)) {\n throw new APIError('Invalid field path.', 400, null, true)\n }\n\n let selectRef = select\n\n segments.forEach((segment, i) => {\n if (i === segments.length - 1) {\n selectRef[segment] = true\n } else {\n if (!Object.prototype.hasOwnProperty.call(selectRef, segment)) {\n selectRef[segment] = createSelect()\n }\n selectRef = selectRef[segment] as SelectIncludeType\n }\n })\n })\n\n return select\n}\n"],"names":["APIError","hasUnsupportedFieldPathSegment","createSelect","Object","create","getSelect","fields","select","forEach","field","segments","split","selectRef","segment","i","length","prototype","hasOwnProperty","call"],"mappings":"AAEA,SAASA,QAAQ,QAAQ,UAAS;AAElC,SAASC,8BAA8B,QAAQ,iBAAgB;AAE/D,MAAMC,eAAe,IAAyBC,OAAOC,MAAM,CAAC;AAE5D;;;;;;;CAOC,GACD,OAAO,MAAMC,YAAY,CAACC;IACxB,MAAMC,SAASL;IAEfI,OAAOE,OAAO,CAAC,CAACC;QACd,MAAMC,WAAWD,MAAME,KAAK,CAAC;QAE7B,IAAIV,+BAA+BS,WAAW;YAC5C,MAAM,IAAIV,SAAS,uBAAuB,KAAK,MAAM;QACvD;QAEA,IAAIY,YAAYL;QAEhBG,SAASF,OAAO,CAAC,CAACK,SAASC;YACzB,IAAIA,MAAMJ,SAASK,MAAM,GAAG,GAAG;gBAC7BH,SAAS,CAACC,QAAQ,GAAG;YACvB,OAAO;gBACL,IAAI,CAACV,OAAOa,SAAS,CAACC,cAAc,CAACC,IAAI,CAACN,WAAWC,UAAU;oBAC7DD,SAAS,CAACC,QAAQ,GAAGX;gBACvB;gBACAU,YAAYA,SAAS,CAACC,QAAQ;YAChC;QACF;IACF;IAEA,OAAON;AACT,EAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { APIError } from 'payload';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { getSelect } from './getSelect.js';
|
|
4
|
+
const unsupportedSegments = [
|
|
5
|
+
'__proto__',
|
|
6
|
+
'constructor',
|
|
7
|
+
'prototype'
|
|
8
|
+
];
|
|
9
|
+
describe('getSelect', ()=>{
|
|
10
|
+
it.each(unsupportedSegments.flatMap((segment)=>[
|
|
11
|
+
[
|
|
12
|
+
`${segment}.field`,
|
|
13
|
+
segment,
|
|
14
|
+
'root'
|
|
15
|
+
],
|
|
16
|
+
[
|
|
17
|
+
`group.${segment}.field`,
|
|
18
|
+
segment,
|
|
19
|
+
'middle'
|
|
20
|
+
],
|
|
21
|
+
[
|
|
22
|
+
`group.${segment}`,
|
|
23
|
+
segment,
|
|
24
|
+
'leaf'
|
|
25
|
+
]
|
|
26
|
+
]))('rejects invalid field path %s', (path)=>{
|
|
27
|
+
try {
|
|
28
|
+
getSelect([
|
|
29
|
+
path
|
|
30
|
+
]);
|
|
31
|
+
expect.fail('Expected getSelect to reject the invalid field path');
|
|
32
|
+
} catch (error) {
|
|
33
|
+
expect(error).toBeInstanceOf(APIError);
|
|
34
|
+
if (error instanceof APIError) {
|
|
35
|
+
expect(error.status).toBe(400);
|
|
36
|
+
expect(error.isPublic).toBe(true);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
it('leaves global object state unchanged when rejecting invalid paths', ()=>{
|
|
41
|
+
expect(Object.prototype).not.toHaveProperty('syntheticMarker');
|
|
42
|
+
for (const path of [
|
|
43
|
+
'__proto__.syntheticMarker',
|
|
44
|
+
'constructor.prototype.syntheticMarker'
|
|
45
|
+
]){
|
|
46
|
+
expect(()=>getSelect([
|
|
47
|
+
path
|
|
48
|
+
])).toThrow(APIError);
|
|
49
|
+
}
|
|
50
|
+
expect(Object.prototype).not.toHaveProperty('syntheticMarker');
|
|
51
|
+
});
|
|
52
|
+
it('builds select objects and merges nested siblings', ()=>{
|
|
53
|
+
const select = getSelect([
|
|
54
|
+
'id',
|
|
55
|
+
'group.title',
|
|
56
|
+
'group.description'
|
|
57
|
+
]);
|
|
58
|
+
expect(select).toEqual({
|
|
59
|
+
group: {
|
|
60
|
+
description: true,
|
|
61
|
+
title: true
|
|
62
|
+
},
|
|
63
|
+
id: true
|
|
64
|
+
});
|
|
65
|
+
expect(Object.getPrototypeOf(select)).toBeNull();
|
|
66
|
+
expect(Object.getPrototypeOf(select.group)).toBeNull();
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
//# sourceMappingURL=getSelect.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/getSelect.spec.ts"],"sourcesContent":["import { APIError } from 'payload'\nimport { describe, expect, it } from 'vitest'\n\nimport { getSelect } from './getSelect.js'\n\nconst unsupportedSegments = ['__proto__', 'constructor', 'prototype']\n\ndescribe('getSelect', () => {\n it.each(\n unsupportedSegments.flatMap((segment) => [\n [`${segment}.field`, segment, 'root'],\n [`group.${segment}.field`, segment, 'middle'],\n [`group.${segment}`, segment, 'leaf'],\n ]),\n )('rejects invalid field path %s', (path) => {\n try {\n getSelect([path])\n expect.fail('Expected getSelect to reject the invalid field path')\n } catch (error) {\n expect(error).toBeInstanceOf(APIError)\n\n if (error instanceof APIError) {\n expect(error.status).toBe(400)\n expect(error.isPublic).toBe(true)\n }\n }\n })\n\n it('leaves global object state unchanged when rejecting invalid paths', () => {\n expect(Object.prototype).not.toHaveProperty('syntheticMarker')\n\n for (const path of ['__proto__.syntheticMarker', 'constructor.prototype.syntheticMarker']) {\n expect(() => getSelect([path])).toThrow(APIError)\n }\n\n expect(Object.prototype).not.toHaveProperty('syntheticMarker')\n })\n\n it('builds select objects and merges nested siblings', () => {\n const select = getSelect(['id', 'group.title', 'group.description'])\n\n expect(select).toEqual({\n group: {\n description: true,\n title: true,\n },\n id: true,\n })\n expect(Object.getPrototypeOf(select)).toBeNull()\n expect(Object.getPrototypeOf(select.group)).toBeNull()\n })\n})\n"],"names":["APIError","describe","expect","it","getSelect","unsupportedSegments","each","flatMap","segment","path","fail","error","toBeInstanceOf","status","toBe","isPublic","Object","prototype","not","toHaveProperty","toThrow","select","toEqual","group","description","title","id","getPrototypeOf","toBeNull"],"mappings":"AAAA,SAASA,QAAQ,QAAQ,UAAS;AAClC,SAASC,QAAQ,EAAEC,MAAM,EAAEC,EAAE,QAAQ,SAAQ;AAE7C,SAASC,SAAS,QAAQ,iBAAgB;AAE1C,MAAMC,sBAAsB;IAAC;IAAa;IAAe;CAAY;AAErEJ,SAAS,aAAa;IACpBE,GAAGG,IAAI,CACLD,oBAAoBE,OAAO,CAAC,CAACC,UAAY;YACvC;gBAAC,GAAGA,QAAQ,MAAM,CAAC;gBAAEA;gBAAS;aAAO;YACrC;gBAAC,CAAC,MAAM,EAAEA,QAAQ,MAAM,CAAC;gBAAEA;gBAAS;aAAS;YAC7C;gBAAC,CAAC,MAAM,EAAEA,SAAS;gBAAEA;gBAAS;aAAO;SACtC,GACD,iCAAiC,CAACC;QAClC,IAAI;YACFL,UAAU;gBAACK;aAAK;YAChBP,OAAOQ,IAAI,CAAC;QACd,EAAE,OAAOC,OAAO;YACdT,OAAOS,OAAOC,cAAc,CAACZ;YAE7B,IAAIW,iBAAiBX,UAAU;gBAC7BE,OAAOS,MAAME,MAAM,EAAEC,IAAI,CAAC;gBAC1BZ,OAAOS,MAAMI,QAAQ,EAAED,IAAI,CAAC;YAC9B;QACF;IACF;IAEAX,GAAG,qEAAqE;QACtED,OAAOc,OAAOC,SAAS,EAAEC,GAAG,CAACC,cAAc,CAAC;QAE5C,KAAK,MAAMV,QAAQ;YAAC;YAA6B;SAAwC,CAAE;YACzFP,OAAO,IAAME,UAAU;oBAACK;iBAAK,GAAGW,OAAO,CAACpB;QAC1C;QAEAE,OAAOc,OAAOC,SAAS,EAAEC,GAAG,CAACC,cAAc,CAAC;IAC9C;IAEAhB,GAAG,oDAAoD;QACrD,MAAMkB,SAASjB,UAAU;YAAC;YAAM;YAAe;SAAoB;QAEnEF,OAAOmB,QAAQC,OAAO,CAAC;YACrBC,OAAO;gBACLC,aAAa;gBACbC,OAAO;YACT;YACAC,IAAI;QACN;QACAxB,OAAOc,OAAOW,cAAc,CAACN,SAASO,QAAQ;QAC9C1B,OAAOc,OAAOW,cAAc,CAACN,OAAOE,KAAK,GAAGK,QAAQ;IACtD;AACF"}
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
* @param obj - The target object to mutate.
|
|
15
15
|
* @param path - A dot-separated string path indicating where to assign the value.
|
|
16
16
|
* @param value - The value to set at the specified path.
|
|
17
|
+
* @param source - The source object used to validate array boundaries.
|
|
17
18
|
*/
|
|
18
|
-
export declare const setNestedValue: (obj: Record<string, unknown>, path: string, value: unknown) => void;
|
|
19
|
+
export declare const setNestedValue: (obj: Record<string, unknown>, path: string, value: unknown, source?: Record<string, unknown>) => void;
|
|
19
20
|
//# sourceMappingURL=setNestedValue.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setNestedValue.d.ts","sourceRoot":"","sources":["../../src/utilities/setNestedValue.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"setNestedValue.d.ts","sourceRoot":"","sources":["../../src/utilities/setNestedValue.ts"],"names":[],"mappings":"AAiDA;;;;;;;;;;;;;;;;;GAiBG;AAEH,eAAO,MAAM,cAAc,QACpB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,QACtB,MAAM,SACL,OAAO,WACL,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC/B,IAwCF,CAAA"}
|
|
@@ -1,3 +1,31 @@
|
|
|
1
|
+
import { APIError } from 'payload';
|
|
2
|
+
import { hasUnsupportedFieldPathSegment } from './fieldPath.js';
|
|
3
|
+
const MAX_UNVERIFIED_SPARSE_ARRAY_GAP = 1;
|
|
4
|
+
const createObject = ()=>Object.create(null);
|
|
5
|
+
const isArrayIndex = (part)=>{
|
|
6
|
+
if (!/^(?:0|[1-9]\d*)$/.test(part)) {
|
|
7
|
+
return false;
|
|
8
|
+
}
|
|
9
|
+
const index = Number(part);
|
|
10
|
+
return Number.isSafeInteger(index) && index >= 0;
|
|
11
|
+
};
|
|
12
|
+
const getPathKey = (target, part, source)=>{
|
|
13
|
+
if (!Array.isArray(target) || !isArrayIndex(part)) {
|
|
14
|
+
return part;
|
|
15
|
+
}
|
|
16
|
+
const index = Number(part);
|
|
17
|
+
if (Array.isArray(source) && index >= source.length || !Array.isArray(source) && index > target.length + MAX_UNVERIFIED_SPARSE_ARRAY_GAP) {
|
|
18
|
+
throw new APIError('Invalid field path.', 400, null, true);
|
|
19
|
+
}
|
|
20
|
+
return index;
|
|
21
|
+
};
|
|
22
|
+
const getSourceValue = (source, part)=>{
|
|
23
|
+
if (source === null || typeof source !== 'object') {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
const key = Array.isArray(source) && isArrayIndex(part) ? Number(part) : part;
|
|
27
|
+
return source[key];
|
|
28
|
+
};
|
|
1
29
|
/**
|
|
2
30
|
* Sets a value deeply into a nested object or array, based on a dot-notation path.
|
|
3
31
|
*
|
|
@@ -14,44 +42,33 @@
|
|
|
14
42
|
* @param obj - The target object to mutate.
|
|
15
43
|
* @param path - A dot-separated string path indicating where to assign the value.
|
|
16
44
|
* @param value - The value to set at the specified path.
|
|
17
|
-
|
|
45
|
+
* @param source - The source object used to validate array boundaries.
|
|
46
|
+
*/ export const setNestedValue = (obj, path, value, source)=>{
|
|
18
47
|
const parts = path.split('.');
|
|
48
|
+
if (hasUnsupportedFieldPathSegment(parts)) {
|
|
49
|
+
throw new APIError('Invalid field path.', 400, null, true);
|
|
50
|
+
}
|
|
51
|
+
const lastPart = parts.pop();
|
|
52
|
+
if (lastPart === undefined) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
19
55
|
let current = obj;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
const currentArray = current;
|
|
31
|
-
// Ensure the array slot is initialized
|
|
32
|
-
if (!currentArray[index]) {
|
|
33
|
-
currentArray[index] = {};
|
|
34
|
-
}
|
|
35
|
-
if (isLast) {
|
|
36
|
-
currentArray[index] = value;
|
|
37
|
-
} else {
|
|
38
|
-
current = currentArray[index];
|
|
39
|
-
}
|
|
40
|
-
} else {
|
|
41
|
-
const currentObj = current;
|
|
42
|
-
// Ensure the object key exists
|
|
43
|
-
if (isLast) {
|
|
44
|
-
if (typeof part === 'string') {
|
|
45
|
-
currentObj[part] = value;
|
|
46
|
-
}
|
|
47
|
-
} else {
|
|
48
|
-
if (typeof currentObj[part] !== 'object' || currentObj[part] === null) {
|
|
49
|
-
currentObj[part] = {};
|
|
50
|
-
}
|
|
51
|
-
current = currentObj[part];
|
|
52
|
-
}
|
|
56
|
+
let sourceCurrent = source;
|
|
57
|
+
for (const [i, part] of parts.entries()){
|
|
58
|
+
const key = getPathKey(current, part, sourceCurrent);
|
|
59
|
+
const currentRecord = current;
|
|
60
|
+
const nextPart = parts[i + 1] ?? lastPart;
|
|
61
|
+
const nextSource = getSourceValue(sourceCurrent, part);
|
|
62
|
+
const nextValue = currentRecord[key];
|
|
63
|
+
if (!Object.prototype.hasOwnProperty.call(currentRecord, key) || typeof nextValue !== 'object' || nextValue === null) {
|
|
64
|
+
currentRecord[key] = isArrayIndex(nextPart) ? [] : createObject();
|
|
53
65
|
}
|
|
66
|
+
current = currentRecord[key];
|
|
67
|
+
sourceCurrent = nextSource;
|
|
54
68
|
}
|
|
69
|
+
const lastKey = getPathKey(current, lastPart, sourceCurrent);
|
|
70
|
+
const finalRecord = current;
|
|
71
|
+
finalRecord[lastKey] = value;
|
|
55
72
|
};
|
|
56
73
|
|
|
57
74
|
//# sourceMappingURL=setNestedValue.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utilities/setNestedValue.ts"],"sourcesContent":["/**\n * Sets a value deeply into a nested object or array, based on a dot-notation path.\n *\n * This function:\n * - Supports array indexing (e.g., \"array.0.field1\")\n * - Creates intermediate arrays/objects as needed\n * - Mutates the target object directly\n *\n * @example\n * const obj = {}\n * setNestedValue(obj, 'group.array.0.field1', 'hello')\n * // Result: { group: { array: [ { field1: 'hello' } ] } }\n *\n * @param obj - The target object to mutate.\n * @param path - A dot-separated string path indicating where to assign the value.\n * @param value - The value to set at the specified path.\n */\n\nexport const setNestedValue = (\n obj: Record<string, unknown>,\n path: string,\n value: unknown,\n): void => {\n const parts = path.split('.')\n
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/setNestedValue.ts"],"sourcesContent":["import { APIError } from 'payload'\n\nimport { hasUnsupportedFieldPathSegment } from './fieldPath.js'\n\nconst MAX_UNVERIFIED_SPARSE_ARRAY_GAP = 1\n\nconst createObject = (): Record<string, unknown> => Object.create(null) as Record<string, unknown>\n\nconst isArrayIndex = (part: string): boolean => {\n if (!/^(?:0|[1-9]\\d*)$/.test(part)) {\n return false\n }\n\n const index = Number(part)\n\n return Number.isSafeInteger(index) && index >= 0\n}\n\nconst getPathKey = (\n target: Record<string, unknown> | unknown[],\n part: string,\n source: unknown,\n): number | string => {\n if (!Array.isArray(target) || !isArrayIndex(part)) {\n return part\n }\n\n const index = Number(part)\n\n if (\n (Array.isArray(source) && index >= source.length) ||\n (!Array.isArray(source) && index > target.length + MAX_UNVERIFIED_SPARSE_ARRAY_GAP)\n ) {\n throw new APIError('Invalid field path.', 400, null, true)\n }\n\n return index\n}\n\nconst getSourceValue = (source: unknown, part: string): unknown => {\n if (source === null || typeof source !== 'object') {\n return undefined\n }\n\n const key = Array.isArray(source) && isArrayIndex(part) ? Number(part) : part\n\n return (source as Record<number | string, unknown>)[key]\n}\n\n/**\n * Sets a value deeply into a nested object or array, based on a dot-notation path.\n *\n * This function:\n * - Supports array indexing (e.g., \"array.0.field1\")\n * - Creates intermediate arrays/objects as needed\n * - Mutates the target object directly\n *\n * @example\n * const obj = {}\n * setNestedValue(obj, 'group.array.0.field1', 'hello')\n * // Result: { group: { array: [ { field1: 'hello' } ] } }\n *\n * @param obj - The target object to mutate.\n * @param path - A dot-separated string path indicating where to assign the value.\n * @param value - The value to set at the specified path.\n * @param source - The source object used to validate array boundaries.\n */\n\nexport const setNestedValue = (\n obj: Record<string, unknown>,\n path: string,\n value: unknown,\n source?: Record<string, unknown>,\n): void => {\n const parts = path.split('.')\n\n if (hasUnsupportedFieldPathSegment(parts)) {\n throw new APIError('Invalid field path.', 400, null, true)\n }\n\n const lastPart = parts.pop()\n\n if (lastPart === undefined) {\n return\n }\n\n let current: Record<string, unknown> | unknown[] = obj\n let sourceCurrent: unknown = source\n\n for (const [i, part] of parts.entries()) {\n const key = getPathKey(current, part, sourceCurrent)\n const currentRecord = current as Record<number | string, unknown>\n const nextPart = parts[i + 1] ?? lastPart\n const nextSource = getSourceValue(sourceCurrent, part)\n\n const nextValue = currentRecord[key]\n\n if (\n !Object.prototype.hasOwnProperty.call(currentRecord, key) ||\n typeof nextValue !== 'object' ||\n nextValue === null\n ) {\n currentRecord[key] = isArrayIndex(nextPart) ? [] : createObject()\n }\n\n current = currentRecord[key] as Record<string, unknown> | unknown[]\n sourceCurrent = nextSource\n }\n\n const lastKey = getPathKey(current, lastPart, sourceCurrent)\n const finalRecord = current as Record<number | string, unknown>\n\n finalRecord[lastKey] = value\n}\n"],"names":["APIError","hasUnsupportedFieldPathSegment","MAX_UNVERIFIED_SPARSE_ARRAY_GAP","createObject","Object","create","isArrayIndex","part","test","index","Number","isSafeInteger","getPathKey","target","source","Array","isArray","length","getSourceValue","undefined","key","setNestedValue","obj","path","value","parts","split","lastPart","pop","current","sourceCurrent","i","entries","currentRecord","nextPart","nextSource","nextValue","prototype","hasOwnProperty","call","lastKey","finalRecord"],"mappings":"AAAA,SAASA,QAAQ,QAAQ,UAAS;AAElC,SAASC,8BAA8B,QAAQ,iBAAgB;AAE/D,MAAMC,kCAAkC;AAExC,MAAMC,eAAe,IAA+BC,OAAOC,MAAM,CAAC;AAElE,MAAMC,eAAe,CAACC;IACpB,IAAI,CAAC,mBAAmBC,IAAI,CAACD,OAAO;QAClC,OAAO;IACT;IAEA,MAAME,QAAQC,OAAOH;IAErB,OAAOG,OAAOC,aAAa,CAACF,UAAUA,SAAS;AACjD;AAEA,MAAMG,aAAa,CACjBC,QACAN,MACAO;IAEA,IAAI,CAACC,MAAMC,OAAO,CAACH,WAAW,CAACP,aAAaC,OAAO;QACjD,OAAOA;IACT;IAEA,MAAME,QAAQC,OAAOH;IAErB,IACE,AAACQ,MAAMC,OAAO,CAACF,WAAWL,SAASK,OAAOG,MAAM,IAC/C,CAACF,MAAMC,OAAO,CAACF,WAAWL,QAAQI,OAAOI,MAAM,GAAGf,iCACnD;QACA,MAAM,IAAIF,SAAS,uBAAuB,KAAK,MAAM;IACvD;IAEA,OAAOS;AACT;AAEA,MAAMS,iBAAiB,CAACJ,QAAiBP;IACvC,IAAIO,WAAW,QAAQ,OAAOA,WAAW,UAAU;QACjD,OAAOK;IACT;IAEA,MAAMC,MAAML,MAAMC,OAAO,CAACF,WAAWR,aAAaC,QAAQG,OAAOH,QAAQA;IAEzE,OAAO,AAACO,MAA2C,CAACM,IAAI;AAC1D;AAEA;;;;;;;;;;;;;;;;;CAiBC,GAED,OAAO,MAAMC,iBAAiB,CAC5BC,KACAC,MACAC,OACAV;IAEA,MAAMW,QAAQF,KAAKG,KAAK,CAAC;IAEzB,IAAIzB,+BAA+BwB,QAAQ;QACzC,MAAM,IAAIzB,SAAS,uBAAuB,KAAK,MAAM;IACvD;IAEA,MAAM2B,WAAWF,MAAMG,GAAG;IAE1B,IAAID,aAAaR,WAAW;QAC1B;IACF;IAEA,IAAIU,UAA+CP;IACnD,IAAIQ,gBAAyBhB;IAE7B,KAAK,MAAM,CAACiB,GAAGxB,KAAK,IAAIkB,MAAMO,OAAO,GAAI;QACvC,MAAMZ,MAAMR,WAAWiB,SAAStB,MAAMuB;QACtC,MAAMG,gBAAgBJ;QACtB,MAAMK,WAAWT,KAAK,CAACM,IAAI,EAAE,IAAIJ;QACjC,MAAMQ,aAAajB,eAAeY,eAAevB;QAEjD,MAAM6B,YAAYH,aAAa,CAACb,IAAI;QAEpC,IACE,CAAChB,OAAOiC,SAAS,CAACC,cAAc,CAACC,IAAI,CAACN,eAAeb,QACrD,OAAOgB,cAAc,YACrBA,cAAc,MACd;YACAH,aAAa,CAACb,IAAI,GAAGd,aAAa4B,YAAY,EAAE,GAAG/B;QACrD;QAEA0B,UAAUI,aAAa,CAACb,IAAI;QAC5BU,gBAAgBK;IAClB;IAEA,MAAMK,UAAU5B,WAAWiB,SAASF,UAAUG;IAC9C,MAAMW,cAAcZ;IAEpBY,WAAW,CAACD,QAAQ,GAAGhB;AACzB,EAAC"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { APIError } from 'payload';
|
|
2
|
+
import { describe, expect, it } from 'vitest';
|
|
3
|
+
import { setNestedValue } from './setNestedValue.js';
|
|
4
|
+
const unsupportedSegments = [
|
|
5
|
+
'__proto__',
|
|
6
|
+
'constructor',
|
|
7
|
+
'prototype'
|
|
8
|
+
];
|
|
9
|
+
const unsupportedPaths = unsupportedSegments.flatMap((segment)=>[
|
|
10
|
+
`${segment}.value`,
|
|
11
|
+
`group.${segment}.value`,
|
|
12
|
+
`group.${segment}`,
|
|
13
|
+
`items.${segment}.0.value`,
|
|
14
|
+
`items.0.${segment}.value`,
|
|
15
|
+
`items.0.${segment}`
|
|
16
|
+
]);
|
|
17
|
+
describe('setNestedValue', ()=>{
|
|
18
|
+
it.each(unsupportedPaths)('rejects invalid field path %s without changing the target', (path)=>{
|
|
19
|
+
const target = {
|
|
20
|
+
stable: {
|
|
21
|
+
value: true
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
const objectPrototypeBefore = Object.getOwnPropertyDescriptors(Object.prototype);
|
|
25
|
+
const targetPrototypeBefore = Object.getPrototypeOf(target);
|
|
26
|
+
try {
|
|
27
|
+
setNestedValue(target, path, true);
|
|
28
|
+
expect.fail('Expected setNestedValue to reject the invalid field path');
|
|
29
|
+
} catch (error) {
|
|
30
|
+
expect(error).toBeInstanceOf(APIError);
|
|
31
|
+
if (error instanceof APIError) {
|
|
32
|
+
expect(error.status).toBe(400);
|
|
33
|
+
expect(error.isPublic).toBe(true);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
expect(target).toEqual({
|
|
37
|
+
stable: {
|
|
38
|
+
value: true
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
expect(Object.getPrototypeOf(target)).toBe(targetPrototypeBefore);
|
|
42
|
+
expect(Object.getOwnPropertyDescriptors(Object.prototype)).toEqual(objectPrototypeBefore);
|
|
43
|
+
});
|
|
44
|
+
it('rejects field paths with out-of-range array indexes', ()=>{
|
|
45
|
+
const source = {
|
|
46
|
+
items: [
|
|
47
|
+
{
|
|
48
|
+
value: true
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
};
|
|
52
|
+
const target = {};
|
|
53
|
+
expect(()=>setNestedValue(target, 'items.4294967294.value', true, source)).toThrow(APIError);
|
|
54
|
+
expect(target).toEqual({
|
|
55
|
+
items: []
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
it('supports out-of-order array indexes that exist in the source document', ()=>{
|
|
59
|
+
const source = {
|
|
60
|
+
items: [
|
|
61
|
+
{
|
|
62
|
+
value: 'first'
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
value: 'second'
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
value: 'third'
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
};
|
|
72
|
+
const target = {};
|
|
73
|
+
setNestedValue(target, 'items.2.value', 'third', source);
|
|
74
|
+
expect(target).toEqual({
|
|
75
|
+
items: [
|
|
76
|
+
undefined,
|
|
77
|
+
undefined,
|
|
78
|
+
{
|
|
79
|
+
value: 'third'
|
|
80
|
+
}
|
|
81
|
+
]
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
it.each([
|
|
85
|
+
'-1',
|
|
86
|
+
'+1',
|
|
87
|
+
'01',
|
|
88
|
+
' 1',
|
|
89
|
+
'1 ',
|
|
90
|
+
'1e2',
|
|
91
|
+
'0x10',
|
|
92
|
+
'Infinity',
|
|
93
|
+
'9007199254740992'
|
|
94
|
+
])('treats noncanonical numeric segment %s as an object key', (segment)=>{
|
|
95
|
+
const target = {};
|
|
96
|
+
setNestedValue(target, `items.${segment}.value`, 'example');
|
|
97
|
+
expect(Array.isArray(target.items)).toBe(false);
|
|
98
|
+
expect(target).toEqual({
|
|
99
|
+
items: {
|
|
100
|
+
[segment]: {
|
|
101
|
+
value: 'example'
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
it('builds nested objects and arrays', ()=>{
|
|
107
|
+
const target = {};
|
|
108
|
+
setNestedValue(target, 'group.items.0.title', 'first');
|
|
109
|
+
setNestedValue(target, 'group.items.0.description', 'description');
|
|
110
|
+
setNestedValue(target, 'group.items.1.title', 'second');
|
|
111
|
+
expect(target).toEqual({
|
|
112
|
+
group: {
|
|
113
|
+
items: [
|
|
114
|
+
{
|
|
115
|
+
description: 'description',
|
|
116
|
+
title: 'first'
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
title: 'second'
|
|
120
|
+
}
|
|
121
|
+
]
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
const group = target.group;
|
|
125
|
+
const items = group.items;
|
|
126
|
+
expect(Object.getPrototypeOf(group)).toBeNull();
|
|
127
|
+
expect(Array.isArray(items)).toBe(true);
|
|
128
|
+
expect(Object.getPrototypeOf(items[0])).toBeNull();
|
|
129
|
+
expect(Object.getPrototypeOf(items[1])).toBeNull();
|
|
130
|
+
});
|
|
131
|
+
it('supports nested arrays using numeric lookahead', ()=>{
|
|
132
|
+
const target = {};
|
|
133
|
+
setNestedValue(target, 'matrix.0.1.value', 'nested');
|
|
134
|
+
expect(target).toEqual({
|
|
135
|
+
matrix: [
|
|
136
|
+
[
|
|
137
|
+
undefined,
|
|
138
|
+
{
|
|
139
|
+
value: 'nested'
|
|
140
|
+
}
|
|
141
|
+
]
|
|
142
|
+
]
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
it('creates own containers instead of traversing inherited properties', ()=>{
|
|
146
|
+
const inheritedGroup = {
|
|
147
|
+
inherited: true
|
|
148
|
+
};
|
|
149
|
+
const target = Object.create({
|
|
150
|
+
group: inheritedGroup
|
|
151
|
+
});
|
|
152
|
+
setNestedValue(target, 'group.value', 'own');
|
|
153
|
+
expect(Object.prototype.hasOwnProperty.call(target, 'group')).toBe(true);
|
|
154
|
+
expect(target.group).toEqual({
|
|
155
|
+
value: 'own'
|
|
156
|
+
});
|
|
157
|
+
expect(Object.getPrototypeOf(target.group)).toBeNull();
|
|
158
|
+
expect(inheritedGroup).toEqual({
|
|
159
|
+
inherited: true
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
//# sourceMappingURL=setNestedValue.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/setNestedValue.spec.ts"],"sourcesContent":["import { APIError } from 'payload'\nimport { describe, expect, it } from 'vitest'\n\nimport { setNestedValue } from './setNestedValue.js'\n\nconst unsupportedSegments = ['__proto__', 'constructor', 'prototype']\nconst unsupportedPaths = unsupportedSegments.flatMap((segment) => [\n `${segment}.value`,\n `group.${segment}.value`,\n `group.${segment}`,\n `items.${segment}.0.value`,\n `items.0.${segment}.value`,\n `items.0.${segment}`,\n])\n\ndescribe('setNestedValue', () => {\n it.each(unsupportedPaths)('rejects invalid field path %s without changing the target', (path) => {\n const target = { stable: { value: true } }\n const objectPrototypeBefore = Object.getOwnPropertyDescriptors(Object.prototype)\n const targetPrototypeBefore = Object.getPrototypeOf(target)\n\n try {\n setNestedValue(target, path, true)\n expect.fail('Expected setNestedValue to reject the invalid field path')\n } catch (error) {\n expect(error).toBeInstanceOf(APIError)\n\n if (error instanceof APIError) {\n expect(error.status).toBe(400)\n expect(error.isPublic).toBe(true)\n }\n }\n\n expect(target).toEqual({ stable: { value: true } })\n expect(Object.getPrototypeOf(target)).toBe(targetPrototypeBefore)\n expect(Object.getOwnPropertyDescriptors(Object.prototype)).toEqual(objectPrototypeBefore)\n })\n\n it('rejects field paths with out-of-range array indexes', () => {\n const source = { items: [{ value: true }] }\n const target: Record<string, unknown> = {}\n\n expect(() => setNestedValue(target, 'items.4294967294.value', true, source)).toThrow(APIError)\n expect(target).toEqual({ items: [] })\n })\n\n it('supports out-of-order array indexes that exist in the source document', () => {\n const source = { items: [{ value: 'first' }, { value: 'second' }, { value: 'third' }] }\n const target: Record<string, unknown> = {}\n\n setNestedValue(target, 'items.2.value', 'third', source)\n\n expect(target).toEqual({ items: [undefined, undefined, { value: 'third' }] })\n })\n\n it.each(['-1', '+1', '01', ' 1', '1 ', '1e2', '0x10', 'Infinity', '9007199254740992'])(\n 'treats noncanonical numeric segment %s as an object key',\n (segment) => {\n const target: Record<string, unknown> = {}\n\n setNestedValue(target, `items.${segment}.value`, 'example')\n\n expect(Array.isArray(target.items)).toBe(false)\n expect(target).toEqual({ items: { [segment]: { value: 'example' } } })\n },\n )\n\n it('builds nested objects and arrays', () => {\n const target: Record<string, unknown> = {}\n\n setNestedValue(target, 'group.items.0.title', 'first')\n setNestedValue(target, 'group.items.0.description', 'description')\n setNestedValue(target, 'group.items.1.title', 'second')\n\n expect(target).toEqual({\n group: {\n items: [{ description: 'description', title: 'first' }, { title: 'second' }],\n },\n })\n\n const group = target.group as Record<string, unknown>\n const items = group.items as Record<string, unknown>[]\n\n expect(Object.getPrototypeOf(group)).toBeNull()\n expect(Array.isArray(items)).toBe(true)\n expect(Object.getPrototypeOf(items[0])).toBeNull()\n expect(Object.getPrototypeOf(items[1])).toBeNull()\n })\n\n it('supports nested arrays using numeric lookahead', () => {\n const target: Record<string, unknown> = {}\n\n setNestedValue(target, 'matrix.0.1.value', 'nested')\n\n expect(target).toEqual({\n matrix: [[undefined, { value: 'nested' }]],\n })\n })\n\n it('creates own containers instead of traversing inherited properties', () => {\n const inheritedGroup = { inherited: true }\n const target = Object.create({ group: inheritedGroup }) as Record<string, unknown>\n\n setNestedValue(target, 'group.value', 'own')\n\n expect(Object.prototype.hasOwnProperty.call(target, 'group')).toBe(true)\n expect(target.group).toEqual({ value: 'own' })\n expect(Object.getPrototypeOf(target.group)).toBeNull()\n expect(inheritedGroup).toEqual({ inherited: true })\n })\n})\n"],"names":["APIError","describe","expect","it","setNestedValue","unsupportedSegments","unsupportedPaths","flatMap","segment","each","path","target","stable","value","objectPrototypeBefore","Object","getOwnPropertyDescriptors","prototype","targetPrototypeBefore","getPrototypeOf","fail","error","toBeInstanceOf","status","toBe","isPublic","toEqual","source","items","toThrow","undefined","Array","isArray","group","description","title","toBeNull","matrix","inheritedGroup","inherited","create","hasOwnProperty","call"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@payloadcms/plugin-import-export",
|
|
3
|
-
"version": "4.0.0-canary.
|
|
3
|
+
"version": "4.0.0-canary.28",
|
|
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": "8.0.1",
|
|
67
|
-
"@payloadcms/translations": "4.0.0-canary.
|
|
68
|
-
"@payloadcms/ui": "4.0.0-canary.
|
|
67
|
+
"@payloadcms/translations": "4.0.0-canary.28",
|
|
68
|
+
"@payloadcms/ui": "4.0.0-canary.28"
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@payloadcms/eslint-config": "3.28.0",
|
|
72
|
-
"@payloadcms/ui": "4.0.0-canary.
|
|
73
|
-
"payload": "4.0.0-canary.
|
|
72
|
+
"@payloadcms/ui": "4.0.0-canary.28",
|
|
73
|
+
"payload": "4.0.0-canary.28"
|
|
74
74
|
},
|
|
75
75
|
"peerDependencies": {
|
|
76
|
-
"@payloadcms/ui": "4.0.0-canary.
|
|
77
|
-
"payload": "4.0.0-canary.
|
|
76
|
+
"@payloadcms/ui": "4.0.0-canary.28",
|
|
77
|
+
"payload": "4.0.0-canary.28"
|
|
78
78
|
},
|
|
79
79
|
"homepage:": "https://payloadcms.com",
|
|
80
80
|
"scripts": {
|