@strapi/utils 5.58.0 → 5.59.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/async.js +2 -2
- package/dist/async.js.map +1 -1
- package/dist/async.mjs +1 -1
- package/dist/async.mjs.map +1 -1
- package/dist/content-types.d.ts.map +1 -1
- package/dist/content-types.js +3 -3
- package/dist/content-types.js.map +1 -1
- package/dist/content-types.mjs +3 -3
- package/dist/content-types.mjs.map +1 -1
- package/dist/curry.d.ts +26 -0
- package/dist/curry.d.ts.map +1 -0
- package/dist/curry.js +26 -0
- package/dist/curry.js.map +1 -0
- package/dist/curry.mjs +24 -0
- package/dist/curry.mjs.map +1 -0
- package/dist/parse-type.js +7 -7
- package/dist/parse-type.js.map +1 -1
- package/dist/parse-type.mjs +7 -7
- package/dist/parse-type.mjs.map +1 -1
- package/dist/sanitize/sanitizers.d.ts.map +1 -1
- package/dist/sanitize/sanitizers.js +5 -4
- package/dist/sanitize/sanitizers.js.map +1 -1
- package/dist/sanitize/sanitizers.mjs +2 -1
- package/dist/sanitize/sanitizers.mjs.map +1 -1
- package/dist/traverse/factory.d.ts.map +1 -1
- package/dist/traverse/factory.js +68 -31
- package/dist/traverse/factory.js.map +1 -1
- package/dist/traverse/factory.mjs +68 -31
- package/dist/traverse/factory.mjs.map +1 -1
- package/dist/traverse/query-fields.d.ts.map +1 -1
- package/dist/traverse/query-fields.js +2 -1
- package/dist/traverse/query-fields.js.map +1 -1
- package/dist/traverse/query-fields.mjs +2 -1
- package/dist/traverse/query-fields.mjs.map +1 -1
- package/dist/traverse/query-filters.d.ts.map +1 -1
- package/dist/traverse/query-filters.js +2 -1
- package/dist/traverse/query-filters.js.map +1 -1
- package/dist/traverse/query-filters.mjs +2 -1
- package/dist/traverse/query-filters.mjs.map +1 -1
- package/dist/traverse/query-populate.d.ts.map +1 -1
- package/dist/traverse/query-populate.js +2 -1
- package/dist/traverse/query-populate.js.map +1 -1
- package/dist/traverse/query-populate.mjs +2 -1
- package/dist/traverse/query-populate.mjs.map +1 -1
- package/dist/traverse/query-sort.d.ts.map +1 -1
- package/dist/traverse/query-sort.js +2 -1
- package/dist/traverse/query-sort.js.map +1 -1
- package/dist/traverse/query-sort.mjs +2 -1
- package/dist/traverse/query-sort.mjs.map +1 -1
- package/dist/traverse-entity.d.ts.map +1 -1
- package/dist/traverse-entity.js +2 -1
- package/dist/traverse-entity.js.map +1 -1
- package/dist/traverse-entity.mjs +2 -1
- package/dist/traverse-entity.mjs.map +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/validate/index.js +3 -3
- package/dist/validate/index.js.map +1 -1
- package/dist/validate/index.mjs +3 -3
- package/dist/validate/index.mjs.map +1 -1
- package/dist/validate/utils.d.ts.map +1 -1
- package/dist/validate/utils.js +2 -9
- package/dist/validate/utils.js.map +1 -1
- package/dist/validate/utils.mjs +2 -9
- package/dist/validate/utils.mjs.map +1 -1
- package/dist/validate/validators.mjs +17 -17
- package/dist/validate/validators.mjs.map +1 -1
- package/package.json +4 -4
package/dist/parse-type.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse-type.js","sources":["../src/parse-type.ts"],"sourcesContent":["import * as _ from 'lodash';\nimport * as dates from 'date-fns';\n\nconst timeRegex = /^(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\\.[0-9]{1,3})?$/;\n\nconst isDate = (v: unknown): v is Date => {\n return dates.isDate(v);\n};\n\nconst parseTime = (value: unknown): string => {\n if (isDate(value)) {\n return dates.format(value, 'HH:mm:ss.SSS');\n }\n\n if (typeof value !== 'string') {\n throw new Error(`Expected a string, got a ${typeof value}`);\n }\n const result = value.match(timeRegex);\n\n if (result === null) {\n throw new Error('Invalid time format, expected HH:mm:ss.SSS');\n }\n\n const [, hours, minutes, seconds, fraction = '.000'] = result;\n const fractionPart = _.padEnd(fraction.slice(1), 3, '0');\n\n return `${hours}:${minutes}:${seconds}.${fractionPart}`;\n};\n\nconst parseDate = (value: unknown) => {\n if (isDate(value)) {\n return dates.format(value, 'yyyy-MM-dd');\n }\n\n if (typeof value !== 'string') {\n throw new Error(`Expected a string, got a ${typeof value}`);\n }\n\n try {\n const date = dates.parseISO(value);\n\n if (dates.isValid(date)) return dates.format(date, 'yyyy-MM-dd');\n\n throw new Error(`Invalid format, expected an ISO compatible date`);\n } catch {\n throw new Error(`Invalid format, expected an ISO compatible date`);\n }\n};\n\nconst parseDateTimeOrTimestamp = (value: unknown) => {\n if (isDate(value)) {\n return value;\n }\n\n if (typeof value !== 'string') {\n throw new Error(`Expected a string, got a ${typeof value}`);\n }\n\n try {\n const date = dates.parseISO(value);\n if (dates.isValid(date)) return date;\n\n const milliUnixDate = dates.parse(value, 'T', new Date());\n if (dates.isValid(milliUnixDate)) return milliUnixDate;\n\n throw new Error(`Invalid format, expected a timestamp or an ISO date`);\n } catch {\n throw new Error(`Invalid format, expected a timestamp or an ISO date`);\n }\n};\n\ntype TypeMap = {\n boolean: boolean;\n integer: number;\n biginteger: number;\n float: number;\n decimal: number;\n time: string;\n date: string;\n timestamp: Date;\n datetime: Date;\n};\n\nexport interface ParseTypeOptions<T extends keyof TypeMap> {\n type: T;\n value: unknown;\n forceCast?: boolean;\n}\n\n/**\n * Hoisted out of `parseBoolean`, which allocated both of these arrays on every call.\n * Query validation calls it once per node of the populate tree of every request, which\n * made those two throwaway allocations one of the largest single sources of GC pressure\n * in a read: 4.3% of on-CPU time in a profiled LaunchPad run.\n */\nconst TRUTHY_INPUTS
|
|
1
|
+
{"version":3,"file":"parse-type.js","sources":["../src/parse-type.ts"],"sourcesContent":["import * as _ from 'lodash';\nimport * as dates from 'date-fns';\n\nconst timeRegex = /^(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\\.[0-9]{1,3})?$/;\n\nconst isDate = (v: unknown): v is Date => {\n return dates.isDate(v);\n};\n\nconst parseTime = (value: unknown): string => {\n if (isDate(value)) {\n return dates.format(value, 'HH:mm:ss.SSS');\n }\n\n if (typeof value !== 'string') {\n throw new Error(`Expected a string, got a ${typeof value}`);\n }\n const result = value.match(timeRegex);\n\n if (result === null) {\n throw new Error('Invalid time format, expected HH:mm:ss.SSS');\n }\n\n const [, hours, minutes, seconds, fraction = '.000'] = result;\n const fractionPart = _.padEnd(fraction.slice(1), 3, '0');\n\n return `${hours}:${minutes}:${seconds}.${fractionPart}`;\n};\n\nconst parseDate = (value: unknown) => {\n if (isDate(value)) {\n return dates.format(value, 'yyyy-MM-dd');\n }\n\n if (typeof value !== 'string') {\n throw new Error(`Expected a string, got a ${typeof value}`);\n }\n\n try {\n const date = dates.parseISO(value);\n\n if (dates.isValid(date)) return dates.format(date, 'yyyy-MM-dd');\n\n throw new Error(`Invalid format, expected an ISO compatible date`);\n } catch {\n throw new Error(`Invalid format, expected an ISO compatible date`);\n }\n};\n\nconst parseDateTimeOrTimestamp = (value: unknown) => {\n if (isDate(value)) {\n return value;\n }\n\n if (typeof value !== 'string') {\n throw new Error(`Expected a string, got a ${typeof value}`);\n }\n\n try {\n const date = dates.parseISO(value);\n if (dates.isValid(date)) return date;\n\n const milliUnixDate = dates.parse(value, 'T', new Date());\n if (dates.isValid(milliUnixDate)) return milliUnixDate;\n\n throw new Error(`Invalid format, expected a timestamp or an ISO date`);\n } catch {\n throw new Error(`Invalid format, expected a timestamp or an ISO date`);\n }\n};\n\ntype TypeMap = {\n boolean: boolean;\n integer: number;\n biginteger: number;\n float: number;\n decimal: number;\n time: string;\n date: string;\n timestamp: Date;\n datetime: Date;\n};\n\nexport interface ParseTypeOptions<T extends keyof TypeMap> {\n type: T;\n value: unknown;\n forceCast?: boolean;\n}\n\n/**\n * Hoisted out of `parseBoolean`, which allocated both of these arrays on every call.\n * Query validation calls it once per node of the populate tree of every request, which\n * made those two throwaway allocations one of the largest single sources of GC pressure\n * in a read: 4.3% of on-CPU time in a profiled LaunchPad run.\n */\nconst TRUTHY_INPUTS = new Set<string | number>(['true', 't', '1', 1]);\nconst FALSY_INPUTS = new Set<string | number>(['false', 'f', '0', 0]);\n\n/**\n * Whether `parseBoolean` would accept this value without `forceCast`.\n *\n * Exists so callers can ask the question without using an exception as control flow.\n * Query validation asked it once per populate key by calling `parseType` inside a\n * `try`/`catch`, so every key that is not a boolean keyword — which is nearly all of\n * them — built an Error and captured a stack trace only to discard it. Stack capture is\n * the expensive part, and it made this the second hottest function in a read.\n *\n * Kept in lockstep with `parseBoolean`'s accept conditions below.\n */\nconst isBooleanLike = (value: unknown): boolean => {\n if (typeof value === 'boolean') {\n return true;\n }\n\n if (typeof value === 'string' || typeof value === 'number') {\n return TRUTHY_INPUTS.has(value) || FALSY_INPUTS.has(value);\n }\n\n return false;\n};\n\nconst parseBoolean = (value: unknown, options: { forceCast?: boolean }): boolean => {\n const { forceCast = false } = options;\n\n if (typeof value === 'boolean') {\n return value;\n }\n\n if (typeof value === 'string' || typeof value === 'number') {\n if (TRUTHY_INPUTS.has(value)) {\n return true;\n }\n\n if (FALSY_INPUTS.has(value)) {\n return false;\n }\n }\n\n if (forceCast) {\n return Boolean(value);\n }\n\n throw new Error('Invalid boolean input. Expected \"t\",\"1\",\"true\",\"false\",\"0\",\"f\"');\n};\n\n/**\n * Cast basic values based on attribute type\n */\nconst parseType = <Type extends keyof TypeMap>(options: ParseTypeOptions<Type>): TypeMap[Type] => {\n const { type, value, forceCast } = options;\n\n switch (type) {\n case 'boolean':\n return parseBoolean(value, { forceCast }) as TypeMap[Type];\n case 'integer':\n case 'biginteger':\n case 'float':\n case 'decimal': {\n return _.toNumber(value) as TypeMap[Type];\n }\n case 'time': {\n return parseTime(value) as TypeMap[Type];\n }\n case 'date': {\n return parseDate(value) as TypeMap[Type];\n }\n case 'timestamp':\n case 'datetime': {\n return parseDateTimeOrTimestamp(value) as TypeMap[Type];\n }\n default:\n return value as TypeMap[Type];\n }\n};\n\nexport { isBooleanLike };\nexport default parseType;\n"],"names":["timeRegex","isDate","v","dates","parseTime","value","format","Error","result","match","hours","minutes","seconds","fraction","fractionPart","_","padEnd","slice","parseDate","date","parseISO","isValid","parseDateTimeOrTimestamp","milliUnixDate","parse","Date","TRUTHY_INPUTS","Set","FALSY_INPUTS","isBooleanLike","has","parseBoolean","options","forceCast","Boolean","parseType","type","toNumber"],"mappings":"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"}
|
package/dist/parse-type.mjs
CHANGED
|
@@ -57,18 +57,18 @@ const parseDateTimeOrTimestamp = (value)=>{
|
|
|
57
57
|
* Query validation calls it once per node of the populate tree of every request, which
|
|
58
58
|
* made those two throwaway allocations one of the largest single sources of GC pressure
|
|
59
59
|
* in a read: 4.3% of on-CPU time in a profiled LaunchPad run.
|
|
60
|
-
*/ const TRUTHY_INPUTS = [
|
|
60
|
+
*/ const TRUTHY_INPUTS = new Set([
|
|
61
61
|
'true',
|
|
62
62
|
't',
|
|
63
63
|
'1',
|
|
64
64
|
1
|
|
65
|
-
];
|
|
66
|
-
const FALSY_INPUTS = [
|
|
65
|
+
]);
|
|
66
|
+
const FALSY_INPUTS = new Set([
|
|
67
67
|
'false',
|
|
68
68
|
'f',
|
|
69
69
|
'0',
|
|
70
70
|
0
|
|
71
|
-
];
|
|
71
|
+
]);
|
|
72
72
|
/**
|
|
73
73
|
* Whether `parseBoolean` would accept this value without `forceCast`.
|
|
74
74
|
*
|
|
@@ -84,7 +84,7 @@ const FALSY_INPUTS = [
|
|
|
84
84
|
return true;
|
|
85
85
|
}
|
|
86
86
|
if (typeof value === 'string' || typeof value === 'number') {
|
|
87
|
-
return TRUTHY_INPUTS.
|
|
87
|
+
return TRUTHY_INPUTS.has(value) || FALSY_INPUTS.has(value);
|
|
88
88
|
}
|
|
89
89
|
return false;
|
|
90
90
|
};
|
|
@@ -94,10 +94,10 @@ const parseBoolean = (value, options)=>{
|
|
|
94
94
|
return value;
|
|
95
95
|
}
|
|
96
96
|
if (typeof value === 'string' || typeof value === 'number') {
|
|
97
|
-
if (TRUTHY_INPUTS.
|
|
97
|
+
if (TRUTHY_INPUTS.has(value)) {
|
|
98
98
|
return true;
|
|
99
99
|
}
|
|
100
|
-
if (FALSY_INPUTS.
|
|
100
|
+
if (FALSY_INPUTS.has(value)) {
|
|
101
101
|
return false;
|
|
102
102
|
}
|
|
103
103
|
}
|
package/dist/parse-type.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse-type.mjs","sources":["../src/parse-type.ts"],"sourcesContent":["import * as _ from 'lodash';\nimport * as dates from 'date-fns';\n\nconst timeRegex = /^(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\\.[0-9]{1,3})?$/;\n\nconst isDate = (v: unknown): v is Date => {\n return dates.isDate(v);\n};\n\nconst parseTime = (value: unknown): string => {\n if (isDate(value)) {\n return dates.format(value, 'HH:mm:ss.SSS');\n }\n\n if (typeof value !== 'string') {\n throw new Error(`Expected a string, got a ${typeof value}`);\n }\n const result = value.match(timeRegex);\n\n if (result === null) {\n throw new Error('Invalid time format, expected HH:mm:ss.SSS');\n }\n\n const [, hours, minutes, seconds, fraction = '.000'] = result;\n const fractionPart = _.padEnd(fraction.slice(1), 3, '0');\n\n return `${hours}:${minutes}:${seconds}.${fractionPart}`;\n};\n\nconst parseDate = (value: unknown) => {\n if (isDate(value)) {\n return dates.format(value, 'yyyy-MM-dd');\n }\n\n if (typeof value !== 'string') {\n throw new Error(`Expected a string, got a ${typeof value}`);\n }\n\n try {\n const date = dates.parseISO(value);\n\n if (dates.isValid(date)) return dates.format(date, 'yyyy-MM-dd');\n\n throw new Error(`Invalid format, expected an ISO compatible date`);\n } catch {\n throw new Error(`Invalid format, expected an ISO compatible date`);\n }\n};\n\nconst parseDateTimeOrTimestamp = (value: unknown) => {\n if (isDate(value)) {\n return value;\n }\n\n if (typeof value !== 'string') {\n throw new Error(`Expected a string, got a ${typeof value}`);\n }\n\n try {\n const date = dates.parseISO(value);\n if (dates.isValid(date)) return date;\n\n const milliUnixDate = dates.parse(value, 'T', new Date());\n if (dates.isValid(milliUnixDate)) return milliUnixDate;\n\n throw new Error(`Invalid format, expected a timestamp or an ISO date`);\n } catch {\n throw new Error(`Invalid format, expected a timestamp or an ISO date`);\n }\n};\n\ntype TypeMap = {\n boolean: boolean;\n integer: number;\n biginteger: number;\n float: number;\n decimal: number;\n time: string;\n date: string;\n timestamp: Date;\n datetime: Date;\n};\n\nexport interface ParseTypeOptions<T extends keyof TypeMap> {\n type: T;\n value: unknown;\n forceCast?: boolean;\n}\n\n/**\n * Hoisted out of `parseBoolean`, which allocated both of these arrays on every call.\n * Query validation calls it once per node of the populate tree of every request, which\n * made those two throwaway allocations one of the largest single sources of GC pressure\n * in a read: 4.3% of on-CPU time in a profiled LaunchPad run.\n */\nconst TRUTHY_INPUTS
|
|
1
|
+
{"version":3,"file":"parse-type.mjs","sources":["../src/parse-type.ts"],"sourcesContent":["import * as _ from 'lodash';\nimport * as dates from 'date-fns';\n\nconst timeRegex = /^(2[0-3]|[01][0-9]):([0-5][0-9]):([0-5][0-9])(\\.[0-9]{1,3})?$/;\n\nconst isDate = (v: unknown): v is Date => {\n return dates.isDate(v);\n};\n\nconst parseTime = (value: unknown): string => {\n if (isDate(value)) {\n return dates.format(value, 'HH:mm:ss.SSS');\n }\n\n if (typeof value !== 'string') {\n throw new Error(`Expected a string, got a ${typeof value}`);\n }\n const result = value.match(timeRegex);\n\n if (result === null) {\n throw new Error('Invalid time format, expected HH:mm:ss.SSS');\n }\n\n const [, hours, minutes, seconds, fraction = '.000'] = result;\n const fractionPart = _.padEnd(fraction.slice(1), 3, '0');\n\n return `${hours}:${minutes}:${seconds}.${fractionPart}`;\n};\n\nconst parseDate = (value: unknown) => {\n if (isDate(value)) {\n return dates.format(value, 'yyyy-MM-dd');\n }\n\n if (typeof value !== 'string') {\n throw new Error(`Expected a string, got a ${typeof value}`);\n }\n\n try {\n const date = dates.parseISO(value);\n\n if (dates.isValid(date)) return dates.format(date, 'yyyy-MM-dd');\n\n throw new Error(`Invalid format, expected an ISO compatible date`);\n } catch {\n throw new Error(`Invalid format, expected an ISO compatible date`);\n }\n};\n\nconst parseDateTimeOrTimestamp = (value: unknown) => {\n if (isDate(value)) {\n return value;\n }\n\n if (typeof value !== 'string') {\n throw new Error(`Expected a string, got a ${typeof value}`);\n }\n\n try {\n const date = dates.parseISO(value);\n if (dates.isValid(date)) return date;\n\n const milliUnixDate = dates.parse(value, 'T', new Date());\n if (dates.isValid(milliUnixDate)) return milliUnixDate;\n\n throw new Error(`Invalid format, expected a timestamp or an ISO date`);\n } catch {\n throw new Error(`Invalid format, expected a timestamp or an ISO date`);\n }\n};\n\ntype TypeMap = {\n boolean: boolean;\n integer: number;\n biginteger: number;\n float: number;\n decimal: number;\n time: string;\n date: string;\n timestamp: Date;\n datetime: Date;\n};\n\nexport interface ParseTypeOptions<T extends keyof TypeMap> {\n type: T;\n value: unknown;\n forceCast?: boolean;\n}\n\n/**\n * Hoisted out of `parseBoolean`, which allocated both of these arrays on every call.\n * Query validation calls it once per node of the populate tree of every request, which\n * made those two throwaway allocations one of the largest single sources of GC pressure\n * in a read: 4.3% of on-CPU time in a profiled LaunchPad run.\n */\nconst TRUTHY_INPUTS = new Set<string | number>(['true', 't', '1', 1]);\nconst FALSY_INPUTS = new Set<string | number>(['false', 'f', '0', 0]);\n\n/**\n * Whether `parseBoolean` would accept this value without `forceCast`.\n *\n * Exists so callers can ask the question without using an exception as control flow.\n * Query validation asked it once per populate key by calling `parseType` inside a\n * `try`/`catch`, so every key that is not a boolean keyword — which is nearly all of\n * them — built an Error and captured a stack trace only to discard it. Stack capture is\n * the expensive part, and it made this the second hottest function in a read.\n *\n * Kept in lockstep with `parseBoolean`'s accept conditions below.\n */\nconst isBooleanLike = (value: unknown): boolean => {\n if (typeof value === 'boolean') {\n return true;\n }\n\n if (typeof value === 'string' || typeof value === 'number') {\n return TRUTHY_INPUTS.has(value) || FALSY_INPUTS.has(value);\n }\n\n return false;\n};\n\nconst parseBoolean = (value: unknown, options: { forceCast?: boolean }): boolean => {\n const { forceCast = false } = options;\n\n if (typeof value === 'boolean') {\n return value;\n }\n\n if (typeof value === 'string' || typeof value === 'number') {\n if (TRUTHY_INPUTS.has(value)) {\n return true;\n }\n\n if (FALSY_INPUTS.has(value)) {\n return false;\n }\n }\n\n if (forceCast) {\n return Boolean(value);\n }\n\n throw new Error('Invalid boolean input. Expected \"t\",\"1\",\"true\",\"false\",\"0\",\"f\"');\n};\n\n/**\n * Cast basic values based on attribute type\n */\nconst parseType = <Type extends keyof TypeMap>(options: ParseTypeOptions<Type>): TypeMap[Type] => {\n const { type, value, forceCast } = options;\n\n switch (type) {\n case 'boolean':\n return parseBoolean(value, { forceCast }) as TypeMap[Type];\n case 'integer':\n case 'biginteger':\n case 'float':\n case 'decimal': {\n return _.toNumber(value) as TypeMap[Type];\n }\n case 'time': {\n return parseTime(value) as TypeMap[Type];\n }\n case 'date': {\n return parseDate(value) as TypeMap[Type];\n }\n case 'timestamp':\n case 'datetime': {\n return parseDateTimeOrTimestamp(value) as TypeMap[Type];\n }\n default:\n return value as TypeMap[Type];\n }\n};\n\nexport { isBooleanLike };\nexport default parseType;\n"],"names":["timeRegex","isDate","v","dates","parseTime","value","format","Error","result","match","hours","minutes","seconds","fraction","fractionPart","_","padEnd","slice","parseDate","date","parseISO","isValid","parseDateTimeOrTimestamp","milliUnixDate","parse","Date","TRUTHY_INPUTS","Set","FALSY_INPUTS","isBooleanLike","has","parseBoolean","options","forceCast","Boolean","parseType","type","toNumber"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sanitizers.d.ts","sourceRoot":"","sources":["../../src/sanitize/sanitizers.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sanitizers.d.ts","sourceRoot":"","sources":["../../src/sanitize/sanitizers.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAElD,UAAU,OAAO;IACf,MAAM,EAAE,KAAK,CAAC;IACd,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,KAAK,CAAC;IACnC,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAID,QAAA,MAAM,iBAAiB,GAAI,KAAK,OAAO,MAAY,QAAQ,IAAI,kBAM9D,CAAC;AAEF,QAAA,MAAM,qBAAqB,GAAU,KAAK,OAAO,EAAE,QAAQ,IAAI,kBAe9D,CAAC;AAEF,QAAA,MAAM,sBAAsB,uEAsC1B,CAAC;AAEH,QAAA,MAAM,mBAAmB,uEAuCvB,CAAC;AAEH,QAAA,MAAM,qBAAqB,uEAyBzB,CAAC;AAEH,QAAA,MAAM,uBAAuB,uEAiC3B,CAAC;AAEH,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACtB,mBAAmB,EACnB,qBAAqB,EACrB,uBAAuB,GACxB,CAAC"}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
var _ = require('lodash');
|
|
4
4
|
var async = require('../async.js');
|
|
5
|
+
var curry = require('../curry.js');
|
|
5
6
|
var traverseEntity = require('../traverse-entity.js');
|
|
6
7
|
var contentTypes = require('../content-types.js');
|
|
7
8
|
var queryFilters = require('../traverse/query-filters.js');
|
|
@@ -34,7 +35,7 @@ const defaultSanitizeOutput = async (ctx, entity)=>{
|
|
|
34
35
|
removePrivate(visitorOptions, visitorUtils);
|
|
35
36
|
}, ctx, entity);
|
|
36
37
|
};
|
|
37
|
-
const defaultSanitizeFilters =
|
|
38
|
+
const defaultSanitizeFilters = curry.curry((ctx, filters)=>{
|
|
38
39
|
if (!ctx.schema) {
|
|
39
40
|
throw new Error('Missing schema in defaultSanitizeFilters');
|
|
40
41
|
}
|
|
@@ -66,7 +67,7 @@ const defaultSanitizeFilters = _.curry((ctx, filters)=>{
|
|
|
66
67
|
}
|
|
67
68
|
}, ctx))(filters);
|
|
68
69
|
});
|
|
69
|
-
const defaultSanitizeSort =
|
|
70
|
+
const defaultSanitizeSort = curry.curry((ctx, sort)=>{
|
|
70
71
|
if (!ctx.schema) {
|
|
71
72
|
throw new Error('Missing schema in defaultSanitizeSort');
|
|
72
73
|
}
|
|
@@ -102,7 +103,7 @@ const defaultSanitizeSort = _.curry((ctx, sort)=>{
|
|
|
102
103
|
}
|
|
103
104
|
}, ctx))(sort);
|
|
104
105
|
});
|
|
105
|
-
const defaultSanitizeFields =
|
|
106
|
+
const defaultSanitizeFields = curry.curry((ctx, fields)=>{
|
|
106
107
|
if (!ctx.schema) {
|
|
107
108
|
throw new Error('Missing schema in defaultSanitizeFields');
|
|
108
109
|
}
|
|
@@ -124,7 +125,7 @@ const defaultSanitizeFields = _.curry((ctx, fields)=>{
|
|
|
124
125
|
queryFields(removePassword, ctx), // Remove nil values from fields array
|
|
125
126
|
(value)=>Array.isArray(value) ? value.filter((field)=>field != null) : value)(fields);
|
|
126
127
|
});
|
|
127
|
-
const defaultSanitizePopulate =
|
|
128
|
+
const defaultSanitizePopulate = curry.curry((ctx, populate)=>{
|
|
128
129
|
if (!ctx.schema) {
|
|
129
130
|
throw new Error('Missing schema in defaultSanitizePopulate');
|
|
130
131
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sanitizers.js","sources":["../../src/sanitize/sanitizers.ts"],"sourcesContent":["import { curry, isEmpty, isPlainObject } from 'lodash';\n\nimport { pipe as pipeAsync } from '../async';\nimport traverseEntity from '../traverse-entity';\nimport { isScalarAttribute, constants } from '../content-types';\n\nimport {\n traverseQueryFilters,\n traverseQuerySort,\n traverseQueryPopulate,\n traverseQueryFields,\n} from '../traverse';\n\nimport {\n removePassword,\n removePrivate,\n removeDynamicZones,\n removeMorphToRelations,\n expandWildcardPopulate,\n} from './visitors';\nimport { isOperator } from '../operators';\n\nimport type { Model, Data } from '../types';\nimport type { Parent } from '../traverse/factory';\n\ninterface Context {\n schema: Model;\n getModel: (model: string) => Model;\n parent?: Parent;\n}\n\nconst { ID_ATTRIBUTE, DOC_ID_ATTRIBUTE } = constants;\n\nconst sanitizePasswords = (ctx: Context) => async (entity: Data) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in sanitizePasswords');\n }\n\n return traverseEntity(removePassword, ctx, entity);\n};\n\nconst defaultSanitizeOutput = async (ctx: Context, entity: Data) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizeOutput');\n }\n\n // Named parameters rather than a rest-spread: this runs once per key, per node, per\n // entity, and `(...args)` allocated a fresh array on every call.\n return traverseEntity(\n (visitorOptions, visitorUtils) => {\n removePassword(visitorOptions, visitorUtils);\n removePrivate(visitorOptions, visitorUtils);\n },\n ctx,\n entity\n );\n};\n\nconst defaultSanitizeFilters = curry((ctx: Context, filters: unknown) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizeFilters');\n }\n\n return pipeAsync(\n // Remove keys that are not attributes or valid operators\n traverseQueryFilters(({ key, attribute }, { remove }) => {\n const isAttribute = !!attribute;\n\n // ID is not an attribute per se, so we need to make\n // an extra check to ensure we're not checking it\n if ([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE].includes(key)) {\n return;\n }\n\n if (!isAttribute && !isOperator(key)) {\n remove(key);\n }\n }, ctx),\n // Remove dynamic zones from filters\n traverseQueryFilters(removeDynamicZones, ctx),\n // Remove morpTo relations from filters\n traverseQueryFilters(removeMorphToRelations, ctx),\n // Remove passwords from filters\n traverseQueryFilters(removePassword, ctx),\n // Remove private from filters\n traverseQueryFilters(removePrivate, ctx),\n // Remove empty plain objects and empty arrays. Do not use lodash isObject+isEmpty: built-ins with no\n // enumerable keys (Date, RegExp, boxed primitives, etc.) are \"empty\" and would wrongly drop valid operands.\n traverseQueryFilters(({ key, value }, { remove }) => {\n const isEmptyPlainObject = isPlainObject(value) && isEmpty(value);\n const isEmptyArrayOperand = Array.isArray(value) && value.length === 0;\n if (isEmptyPlainObject || isEmptyArrayOperand) {\n remove(key);\n }\n }, ctx)\n )(filters);\n});\n\nconst defaultSanitizeSort = curry((ctx: Context, sort: unknown) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizeSort');\n }\n\n return pipeAsync(\n // Remove non attribute keys\n traverseQuerySort(({ key, attribute }, { remove }) => {\n // ID is not an attribute per se, so we need to make\n // an extra check to ensure we're not checking it\n if ([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE].includes(key)) {\n return;\n }\n\n if (!attribute) {\n remove(key);\n }\n }, ctx),\n // Remove dynamic zones from sort\n traverseQuerySort(removeDynamicZones, ctx),\n // Remove morpTo relations from sort\n traverseQuerySort(removeMorphToRelations, ctx),\n // Remove private from sort\n traverseQuerySort(removePrivate, ctx),\n // Remove passwords from filters\n traverseQuerySort(removePassword, ctx),\n // Remove keys for empty non-scalar values\n traverseQuerySort(({ key, attribute, value }, { remove }) => {\n // ID is not an attribute per se, so we need to make\n // an extra check to ensure we're not removing it\n if ([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE].includes(key)) {\n return;\n }\n\n if (!isScalarAttribute(attribute) && isEmpty(value)) {\n remove(key);\n }\n }, ctx)\n )(sort);\n});\n\nconst defaultSanitizeFields = curry((ctx: Context, fields: unknown) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizeFields');\n }\n\n return pipeAsync(\n // Only keep scalar attributes\n traverseQueryFields(({ key, attribute }, { remove }) => {\n // ID is not an attribute per se, so we need to make\n // an extra check to ensure we're not checking it\n if ([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE].includes(key)) {\n return;\n }\n\n if (attribute == null || !isScalarAttribute(attribute)) {\n remove(key);\n }\n }, ctx),\n // Remove private fields\n traverseQueryFields(removePrivate, ctx),\n // Remove password fields\n traverseQueryFields(removePassword, ctx),\n // Remove nil values from fields array\n (value) => (Array.isArray(value) ? value.filter((field) => field != null) : value)\n )(fields);\n});\n\nconst defaultSanitizePopulate = curry((ctx: Context, populate: unknown) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizePopulate');\n }\n\n return pipeAsync(\n traverseQueryPopulate(expandWildcardPopulate, ctx),\n traverseQueryPopulate(async ({ key, value, schema, attribute, getModel, path }, { set }) => {\n if (attribute) {\n return;\n }\n\n const parent = { key, path, schema, attribute } satisfies Parent;\n\n if (key === 'sort') {\n set(key, await defaultSanitizeSort({ schema, getModel, parent }, value));\n }\n\n if (key === 'filters') {\n set(key, await defaultSanitizeFilters({ schema, getModel, parent }, value));\n }\n\n if (key === 'fields') {\n set(key, await defaultSanitizeFields({ schema, getModel, parent }, value));\n }\n\n if (key === 'populate') {\n set(key, await defaultSanitizePopulate({ schema, getModel, parent }, value));\n }\n }, ctx),\n // Remove private fields\n traverseQueryPopulate(removePrivate, ctx)\n )(populate);\n});\n\nexport {\n sanitizePasswords,\n defaultSanitizeOutput,\n defaultSanitizeFilters,\n defaultSanitizeSort,\n defaultSanitizeFields,\n defaultSanitizePopulate,\n};\n"],"names":["ID_ATTRIBUTE","DOC_ID_ATTRIBUTE","constants","sanitizePasswords","ctx","entity","schema","Error","traverseEntity","removePassword","defaultSanitizeOutput","visitorOptions","visitorUtils","removePrivate","defaultSanitizeFilters","curry","filters","pipeAsync","traverseQueryFilters","key","attribute","remove","isAttribute","includes","isOperator","removeDynamicZones","removeMorphToRelations","value","isEmptyPlainObject","isPlainObject","isEmpty","isEmptyArrayOperand","Array","isArray","length","defaultSanitizeSort","sort","traverseQuerySort","isScalarAttribute","defaultSanitizeFields","fields","traverseQueryFields","filter","field","defaultSanitizePopulate","populate","traverseQueryPopulate","expandWildcardPopulate","getModel","path","set","parent"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sanitizers.js","sources":["../../src/sanitize/sanitizers.ts"],"sourcesContent":["import { isEmpty, isPlainObject } from 'lodash';\n\nimport { pipe as pipeAsync } from '../async';\nimport { curry } from '../curry';\nimport traverseEntity from '../traverse-entity';\nimport { isScalarAttribute, constants } from '../content-types';\n\nimport {\n traverseQueryFilters,\n traverseQuerySort,\n traverseQueryPopulate,\n traverseQueryFields,\n} from '../traverse';\n\nimport {\n removePassword,\n removePrivate,\n removeDynamicZones,\n removeMorphToRelations,\n expandWildcardPopulate,\n} from './visitors';\nimport { isOperator } from '../operators';\n\nimport type { Model, Data } from '../types';\nimport type { Parent } from '../traverse/factory';\n\ninterface Context {\n schema: Model;\n getModel: (model: string) => Model;\n parent?: Parent;\n}\n\nconst { ID_ATTRIBUTE, DOC_ID_ATTRIBUTE } = constants;\n\nconst sanitizePasswords = (ctx: Context) => async (entity: Data) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in sanitizePasswords');\n }\n\n return traverseEntity(removePassword, ctx, entity);\n};\n\nconst defaultSanitizeOutput = async (ctx: Context, entity: Data) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizeOutput');\n }\n\n // Named parameters rather than a rest-spread: this runs once per key, per node, per\n // entity, and `(...args)` allocated a fresh array on every call.\n return traverseEntity(\n (visitorOptions, visitorUtils) => {\n removePassword(visitorOptions, visitorUtils);\n removePrivate(visitorOptions, visitorUtils);\n },\n ctx,\n entity\n );\n};\n\nconst defaultSanitizeFilters = curry((ctx: Context, filters: unknown) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizeFilters');\n }\n\n return pipeAsync(\n // Remove keys that are not attributes or valid operators\n traverseQueryFilters(({ key, attribute }, { remove }) => {\n const isAttribute = !!attribute;\n\n // ID is not an attribute per se, so we need to make\n // an extra check to ensure we're not checking it\n if ([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE].includes(key)) {\n return;\n }\n\n if (!isAttribute && !isOperator(key)) {\n remove(key);\n }\n }, ctx),\n // Remove dynamic zones from filters\n traverseQueryFilters(removeDynamicZones, ctx),\n // Remove morpTo relations from filters\n traverseQueryFilters(removeMorphToRelations, ctx),\n // Remove passwords from filters\n traverseQueryFilters(removePassword, ctx),\n // Remove private from filters\n traverseQueryFilters(removePrivate, ctx),\n // Remove empty plain objects and empty arrays. Do not use lodash isObject+isEmpty: built-ins with no\n // enumerable keys (Date, RegExp, boxed primitives, etc.) are \"empty\" and would wrongly drop valid operands.\n traverseQueryFilters(({ key, value }, { remove }) => {\n const isEmptyPlainObject = isPlainObject(value) && isEmpty(value);\n const isEmptyArrayOperand = Array.isArray(value) && value.length === 0;\n if (isEmptyPlainObject || isEmptyArrayOperand) {\n remove(key);\n }\n }, ctx)\n )(filters);\n});\n\nconst defaultSanitizeSort = curry((ctx: Context, sort: unknown) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizeSort');\n }\n\n return pipeAsync(\n // Remove non attribute keys\n traverseQuerySort(({ key, attribute }, { remove }) => {\n // ID is not an attribute per se, so we need to make\n // an extra check to ensure we're not checking it\n if ([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE].includes(key)) {\n return;\n }\n\n if (!attribute) {\n remove(key);\n }\n }, ctx),\n // Remove dynamic zones from sort\n traverseQuerySort(removeDynamicZones, ctx),\n // Remove morpTo relations from sort\n traverseQuerySort(removeMorphToRelations, ctx),\n // Remove private from sort\n traverseQuerySort(removePrivate, ctx),\n // Remove passwords from filters\n traverseQuerySort(removePassword, ctx),\n // Remove keys for empty non-scalar values\n traverseQuerySort(({ key, attribute, value }, { remove }) => {\n // ID is not an attribute per se, so we need to make\n // an extra check to ensure we're not removing it\n if ([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE].includes(key)) {\n return;\n }\n\n if (!isScalarAttribute(attribute) && isEmpty(value)) {\n remove(key);\n }\n }, ctx)\n )(sort);\n});\n\nconst defaultSanitizeFields = curry((ctx: Context, fields: unknown) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizeFields');\n }\n\n return pipeAsync(\n // Only keep scalar attributes\n traverseQueryFields(({ key, attribute }, { remove }) => {\n // ID is not an attribute per se, so we need to make\n // an extra check to ensure we're not checking it\n if ([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE].includes(key)) {\n return;\n }\n\n if (attribute == null || !isScalarAttribute(attribute)) {\n remove(key);\n }\n }, ctx),\n // Remove private fields\n traverseQueryFields(removePrivate, ctx),\n // Remove password fields\n traverseQueryFields(removePassword, ctx),\n // Remove nil values from fields array\n (value) => (Array.isArray(value) ? value.filter((field) => field != null) : value)\n )(fields);\n});\n\nconst defaultSanitizePopulate = curry((ctx: Context, populate: unknown) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizePopulate');\n }\n\n return pipeAsync(\n traverseQueryPopulate(expandWildcardPopulate, ctx),\n traverseQueryPopulate(async ({ key, value, schema, attribute, getModel, path }, { set }) => {\n if (attribute) {\n return;\n }\n\n const parent = { key, path, schema, attribute } satisfies Parent;\n\n if (key === 'sort') {\n set(key, await defaultSanitizeSort({ schema, getModel, parent }, value));\n }\n\n if (key === 'filters') {\n set(key, await defaultSanitizeFilters({ schema, getModel, parent }, value));\n }\n\n if (key === 'fields') {\n set(key, await defaultSanitizeFields({ schema, getModel, parent }, value));\n }\n\n if (key === 'populate') {\n set(key, await defaultSanitizePopulate({ schema, getModel, parent }, value));\n }\n }, ctx),\n // Remove private fields\n traverseQueryPopulate(removePrivate, ctx)\n )(populate);\n});\n\nexport {\n sanitizePasswords,\n defaultSanitizeOutput,\n defaultSanitizeFilters,\n defaultSanitizeSort,\n defaultSanitizeFields,\n defaultSanitizePopulate,\n};\n"],"names":["ID_ATTRIBUTE","DOC_ID_ATTRIBUTE","constants","sanitizePasswords","ctx","entity","schema","Error","traverseEntity","removePassword","defaultSanitizeOutput","visitorOptions","visitorUtils","removePrivate","defaultSanitizeFilters","curry","filters","pipeAsync","traverseQueryFilters","key","attribute","remove","isAttribute","includes","isOperator","removeDynamicZones","removeMorphToRelations","value","isEmptyPlainObject","isPlainObject","isEmpty","isEmptyArrayOperand","Array","isArray","length","defaultSanitizeSort","sort","traverseQuerySort","isScalarAttribute","defaultSanitizeFields","fields","traverseQueryFields","filter","field","defaultSanitizePopulate","populate","traverseQueryPopulate","expandWildcardPopulate","getModel","path","set","parent"],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isPlainObject, isEmpty } from 'lodash';
|
|
2
2
|
import { pipe } from '../async.mjs';
|
|
3
|
+
import { curry } from '../curry.mjs';
|
|
3
4
|
import traverseEntity from '../traverse-entity.mjs';
|
|
4
5
|
import { constants, isScalarAttribute } from '../content-types.mjs';
|
|
5
6
|
import traverseQueryFilters from '../traverse/query-filters.mjs';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sanitizers.mjs","sources":["../../src/sanitize/sanitizers.ts"],"sourcesContent":["import { curry, isEmpty, isPlainObject } from 'lodash';\n\nimport { pipe as pipeAsync } from '../async';\nimport traverseEntity from '../traverse-entity';\nimport { isScalarAttribute, constants } from '../content-types';\n\nimport {\n traverseQueryFilters,\n traverseQuerySort,\n traverseQueryPopulate,\n traverseQueryFields,\n} from '../traverse';\n\nimport {\n removePassword,\n removePrivate,\n removeDynamicZones,\n removeMorphToRelations,\n expandWildcardPopulate,\n} from './visitors';\nimport { isOperator } from '../operators';\n\nimport type { Model, Data } from '../types';\nimport type { Parent } from '../traverse/factory';\n\ninterface Context {\n schema: Model;\n getModel: (model: string) => Model;\n parent?: Parent;\n}\n\nconst { ID_ATTRIBUTE, DOC_ID_ATTRIBUTE } = constants;\n\nconst sanitizePasswords = (ctx: Context) => async (entity: Data) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in sanitizePasswords');\n }\n\n return traverseEntity(removePassword, ctx, entity);\n};\n\nconst defaultSanitizeOutput = async (ctx: Context, entity: Data) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizeOutput');\n }\n\n // Named parameters rather than a rest-spread: this runs once per key, per node, per\n // entity, and `(...args)` allocated a fresh array on every call.\n return traverseEntity(\n (visitorOptions, visitorUtils) => {\n removePassword(visitorOptions, visitorUtils);\n removePrivate(visitorOptions, visitorUtils);\n },\n ctx,\n entity\n );\n};\n\nconst defaultSanitizeFilters = curry((ctx: Context, filters: unknown) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizeFilters');\n }\n\n return pipeAsync(\n // Remove keys that are not attributes or valid operators\n traverseQueryFilters(({ key, attribute }, { remove }) => {\n const isAttribute = !!attribute;\n\n // ID is not an attribute per se, so we need to make\n // an extra check to ensure we're not checking it\n if ([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE].includes(key)) {\n return;\n }\n\n if (!isAttribute && !isOperator(key)) {\n remove(key);\n }\n }, ctx),\n // Remove dynamic zones from filters\n traverseQueryFilters(removeDynamicZones, ctx),\n // Remove morpTo relations from filters\n traverseQueryFilters(removeMorphToRelations, ctx),\n // Remove passwords from filters\n traverseQueryFilters(removePassword, ctx),\n // Remove private from filters\n traverseQueryFilters(removePrivate, ctx),\n // Remove empty plain objects and empty arrays. Do not use lodash isObject+isEmpty: built-ins with no\n // enumerable keys (Date, RegExp, boxed primitives, etc.) are \"empty\" and would wrongly drop valid operands.\n traverseQueryFilters(({ key, value }, { remove }) => {\n const isEmptyPlainObject = isPlainObject(value) && isEmpty(value);\n const isEmptyArrayOperand = Array.isArray(value) && value.length === 0;\n if (isEmptyPlainObject || isEmptyArrayOperand) {\n remove(key);\n }\n }, ctx)\n )(filters);\n});\n\nconst defaultSanitizeSort = curry((ctx: Context, sort: unknown) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizeSort');\n }\n\n return pipeAsync(\n // Remove non attribute keys\n traverseQuerySort(({ key, attribute }, { remove }) => {\n // ID is not an attribute per se, so we need to make\n // an extra check to ensure we're not checking it\n if ([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE].includes(key)) {\n return;\n }\n\n if (!attribute) {\n remove(key);\n }\n }, ctx),\n // Remove dynamic zones from sort\n traverseQuerySort(removeDynamicZones, ctx),\n // Remove morpTo relations from sort\n traverseQuerySort(removeMorphToRelations, ctx),\n // Remove private from sort\n traverseQuerySort(removePrivate, ctx),\n // Remove passwords from filters\n traverseQuerySort(removePassword, ctx),\n // Remove keys for empty non-scalar values\n traverseQuerySort(({ key, attribute, value }, { remove }) => {\n // ID is not an attribute per se, so we need to make\n // an extra check to ensure we're not removing it\n if ([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE].includes(key)) {\n return;\n }\n\n if (!isScalarAttribute(attribute) && isEmpty(value)) {\n remove(key);\n }\n }, ctx)\n )(sort);\n});\n\nconst defaultSanitizeFields = curry((ctx: Context, fields: unknown) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizeFields');\n }\n\n return pipeAsync(\n // Only keep scalar attributes\n traverseQueryFields(({ key, attribute }, { remove }) => {\n // ID is not an attribute per se, so we need to make\n // an extra check to ensure we're not checking it\n if ([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE].includes(key)) {\n return;\n }\n\n if (attribute == null || !isScalarAttribute(attribute)) {\n remove(key);\n }\n }, ctx),\n // Remove private fields\n traverseQueryFields(removePrivate, ctx),\n // Remove password fields\n traverseQueryFields(removePassword, ctx),\n // Remove nil values from fields array\n (value) => (Array.isArray(value) ? value.filter((field) => field != null) : value)\n )(fields);\n});\n\nconst defaultSanitizePopulate = curry((ctx: Context, populate: unknown) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizePopulate');\n }\n\n return pipeAsync(\n traverseQueryPopulate(expandWildcardPopulate, ctx),\n traverseQueryPopulate(async ({ key, value, schema, attribute, getModel, path }, { set }) => {\n if (attribute) {\n return;\n }\n\n const parent = { key, path, schema, attribute } satisfies Parent;\n\n if (key === 'sort') {\n set(key, await defaultSanitizeSort({ schema, getModel, parent }, value));\n }\n\n if (key === 'filters') {\n set(key, await defaultSanitizeFilters({ schema, getModel, parent }, value));\n }\n\n if (key === 'fields') {\n set(key, await defaultSanitizeFields({ schema, getModel, parent }, value));\n }\n\n if (key === 'populate') {\n set(key, await defaultSanitizePopulate({ schema, getModel, parent }, value));\n }\n }, ctx),\n // Remove private fields\n traverseQueryPopulate(removePrivate, ctx)\n )(populate);\n});\n\nexport {\n sanitizePasswords,\n defaultSanitizeOutput,\n defaultSanitizeFilters,\n defaultSanitizeSort,\n defaultSanitizeFields,\n defaultSanitizePopulate,\n};\n"],"names":["ID_ATTRIBUTE","DOC_ID_ATTRIBUTE","constants","sanitizePasswords","ctx","entity","schema","Error","traverseEntity","removePassword","defaultSanitizeOutput","visitorOptions","visitorUtils","removePrivate","defaultSanitizeFilters","curry","filters","pipeAsync","traverseQueryFilters","key","attribute","remove","isAttribute","includes","isOperator","removeDynamicZones","removeMorphToRelations","value","isEmptyPlainObject","isPlainObject","isEmpty","isEmptyArrayOperand","Array","isArray","length","defaultSanitizeSort","sort","traverseQuerySort","isScalarAttribute","defaultSanitizeFields","fields","traverseQueryFields","filter","field","defaultSanitizePopulate","populate","traverseQueryPopulate","expandWildcardPopulate","getModel","path","set","parent"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"sanitizers.mjs","sources":["../../src/sanitize/sanitizers.ts"],"sourcesContent":["import { isEmpty, isPlainObject } from 'lodash';\n\nimport { pipe as pipeAsync } from '../async';\nimport { curry } from '../curry';\nimport traverseEntity from '../traverse-entity';\nimport { isScalarAttribute, constants } from '../content-types';\n\nimport {\n traverseQueryFilters,\n traverseQuerySort,\n traverseQueryPopulate,\n traverseQueryFields,\n} from '../traverse';\n\nimport {\n removePassword,\n removePrivate,\n removeDynamicZones,\n removeMorphToRelations,\n expandWildcardPopulate,\n} from './visitors';\nimport { isOperator } from '../operators';\n\nimport type { Model, Data } from '../types';\nimport type { Parent } from '../traverse/factory';\n\ninterface Context {\n schema: Model;\n getModel: (model: string) => Model;\n parent?: Parent;\n}\n\nconst { ID_ATTRIBUTE, DOC_ID_ATTRIBUTE } = constants;\n\nconst sanitizePasswords = (ctx: Context) => async (entity: Data) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in sanitizePasswords');\n }\n\n return traverseEntity(removePassword, ctx, entity);\n};\n\nconst defaultSanitizeOutput = async (ctx: Context, entity: Data) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizeOutput');\n }\n\n // Named parameters rather than a rest-spread: this runs once per key, per node, per\n // entity, and `(...args)` allocated a fresh array on every call.\n return traverseEntity(\n (visitorOptions, visitorUtils) => {\n removePassword(visitorOptions, visitorUtils);\n removePrivate(visitorOptions, visitorUtils);\n },\n ctx,\n entity\n );\n};\n\nconst defaultSanitizeFilters = curry((ctx: Context, filters: unknown) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizeFilters');\n }\n\n return pipeAsync(\n // Remove keys that are not attributes or valid operators\n traverseQueryFilters(({ key, attribute }, { remove }) => {\n const isAttribute = !!attribute;\n\n // ID is not an attribute per se, so we need to make\n // an extra check to ensure we're not checking it\n if ([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE].includes(key)) {\n return;\n }\n\n if (!isAttribute && !isOperator(key)) {\n remove(key);\n }\n }, ctx),\n // Remove dynamic zones from filters\n traverseQueryFilters(removeDynamicZones, ctx),\n // Remove morpTo relations from filters\n traverseQueryFilters(removeMorphToRelations, ctx),\n // Remove passwords from filters\n traverseQueryFilters(removePassword, ctx),\n // Remove private from filters\n traverseQueryFilters(removePrivate, ctx),\n // Remove empty plain objects and empty arrays. Do not use lodash isObject+isEmpty: built-ins with no\n // enumerable keys (Date, RegExp, boxed primitives, etc.) are \"empty\" and would wrongly drop valid operands.\n traverseQueryFilters(({ key, value }, { remove }) => {\n const isEmptyPlainObject = isPlainObject(value) && isEmpty(value);\n const isEmptyArrayOperand = Array.isArray(value) && value.length === 0;\n if (isEmptyPlainObject || isEmptyArrayOperand) {\n remove(key);\n }\n }, ctx)\n )(filters);\n});\n\nconst defaultSanitizeSort = curry((ctx: Context, sort: unknown) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizeSort');\n }\n\n return pipeAsync(\n // Remove non attribute keys\n traverseQuerySort(({ key, attribute }, { remove }) => {\n // ID is not an attribute per se, so we need to make\n // an extra check to ensure we're not checking it\n if ([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE].includes(key)) {\n return;\n }\n\n if (!attribute) {\n remove(key);\n }\n }, ctx),\n // Remove dynamic zones from sort\n traverseQuerySort(removeDynamicZones, ctx),\n // Remove morpTo relations from sort\n traverseQuerySort(removeMorphToRelations, ctx),\n // Remove private from sort\n traverseQuerySort(removePrivate, ctx),\n // Remove passwords from filters\n traverseQuerySort(removePassword, ctx),\n // Remove keys for empty non-scalar values\n traverseQuerySort(({ key, attribute, value }, { remove }) => {\n // ID is not an attribute per se, so we need to make\n // an extra check to ensure we're not removing it\n if ([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE].includes(key)) {\n return;\n }\n\n if (!isScalarAttribute(attribute) && isEmpty(value)) {\n remove(key);\n }\n }, ctx)\n )(sort);\n});\n\nconst defaultSanitizeFields = curry((ctx: Context, fields: unknown) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizeFields');\n }\n\n return pipeAsync(\n // Only keep scalar attributes\n traverseQueryFields(({ key, attribute }, { remove }) => {\n // ID is not an attribute per se, so we need to make\n // an extra check to ensure we're not checking it\n if ([ID_ATTRIBUTE, DOC_ID_ATTRIBUTE].includes(key)) {\n return;\n }\n\n if (attribute == null || !isScalarAttribute(attribute)) {\n remove(key);\n }\n }, ctx),\n // Remove private fields\n traverseQueryFields(removePrivate, ctx),\n // Remove password fields\n traverseQueryFields(removePassword, ctx),\n // Remove nil values from fields array\n (value) => (Array.isArray(value) ? value.filter((field) => field != null) : value)\n )(fields);\n});\n\nconst defaultSanitizePopulate = curry((ctx: Context, populate: unknown) => {\n if (!ctx.schema) {\n throw new Error('Missing schema in defaultSanitizePopulate');\n }\n\n return pipeAsync(\n traverseQueryPopulate(expandWildcardPopulate, ctx),\n traverseQueryPopulate(async ({ key, value, schema, attribute, getModel, path }, { set }) => {\n if (attribute) {\n return;\n }\n\n const parent = { key, path, schema, attribute } satisfies Parent;\n\n if (key === 'sort') {\n set(key, await defaultSanitizeSort({ schema, getModel, parent }, value));\n }\n\n if (key === 'filters') {\n set(key, await defaultSanitizeFilters({ schema, getModel, parent }, value));\n }\n\n if (key === 'fields') {\n set(key, await defaultSanitizeFields({ schema, getModel, parent }, value));\n }\n\n if (key === 'populate') {\n set(key, await defaultSanitizePopulate({ schema, getModel, parent }, value));\n }\n }, ctx),\n // Remove private fields\n traverseQueryPopulate(removePrivate, ctx)\n )(populate);\n});\n\nexport {\n sanitizePasswords,\n defaultSanitizeOutput,\n defaultSanitizeFilters,\n defaultSanitizeSort,\n defaultSanitizeFields,\n defaultSanitizePopulate,\n};\n"],"names":["ID_ATTRIBUTE","DOC_ID_ATTRIBUTE","constants","sanitizePasswords","ctx","entity","schema","Error","traverseEntity","removePassword","defaultSanitizeOutput","visitorOptions","visitorUtils","removePrivate","defaultSanitizeFilters","curry","filters","pipeAsync","traverseQueryFilters","key","attribute","remove","isAttribute","includes","isOperator","removeDynamicZones","removeMorphToRelations","value","isEmptyPlainObject","isPlainObject","isEmpty","isEmptyArrayOperand","Array","isArray","length","defaultSanitizeSort","sort","traverseQuerySort","isScalarAttribute","defaultSanitizeFields","fields","traverseQueryFields","filter","field","defaultSanitizePopulate","populate","traverseQueryPopulate","expandWildcardPopulate","getModel","path","set","parent"],"mappings":";;;;;;;;;;;;;;;;;AAgCA,MAAM,EAAEA,YAAY,EAAEC,gBAAgB,EAAE,GAAGC,SAAAA;AAE3C,MAAMC,iBAAAA,GAAoB,CAACC,GAAAA,GAAiB,OAAOC,MAAAA,GAAAA;QACjD,IAAI,CAACD,GAAAA,CAAIE,MAAM,EAAE;AACf,YAAA,MAAM,IAAIC,KAAAA,CAAM,qCAAA,CAAA;AAClB,QAAA;QAEA,OAAOC,cAAAA,CAAeC,WAAgBL,GAAAA,EAAKC,MAAAA,CAAAA;AAC7C,IAAA;AAEA,MAAMK,qBAAAA,GAAwB,OAAON,GAAAA,EAAcC,MAAAA,GAAAA;IACjD,IAAI,CAACD,GAAAA,CAAIE,MAAM,EAAE;AACf,QAAA,MAAM,IAAIC,KAAAA,CAAM,yCAAA,CAAA;AAClB,IAAA;;;IAIA,OAAOC,cAAAA,CACL,CAACG,cAAAA,EAAgBC,YAAAA,GAAAA;AACfH,QAAAA,SAAAA,CAAeE,cAAAA,EAAgBC,YAAAA,CAAAA;AAC/BC,QAAAA,OAAAA,CAAcF,cAAAA,EAAgBC,YAAAA,CAAAA;AAChC,IAAA,CAAA,EACAR,GAAAA,EACAC,MAAAA,CAAAA;AAEJ;AAEA,MAAMS,sBAAAA,GAAyBC,KAAAA,CAAM,CAACX,GAAAA,EAAcY,OAAAA,GAAAA;IAClD,IAAI,CAACZ,GAAAA,CAAIE,MAAM,EAAE;AACf,QAAA,MAAM,IAAIC,KAAAA,CAAM,0CAAA,CAAA;AAClB,IAAA;AAEA,IAAA,OAAOU;IAELC,oBAAAA,CAAqB,CAAC,EAAEC,GAAG,EAAEC,SAAS,EAAE,EAAE,EAAEC,MAAM,EAAE,GAAA;QAClD,MAAMC,WAAAA,GAAc,CAAC,CAACF,SAAAA;;;QAItB,IAAI;AAACpB,YAAAA,YAAAA;AAAcC,YAAAA;SAAiB,CAACsB,QAAQ,CAACJ,GAAAA,CAAAA,EAAM;AAClD,YAAA;AACF,QAAA;AAEA,QAAA,IAAI,CAACG,WAAAA,IAAe,CAACE,UAAAA,CAAWL,GAAAA,CAAAA,EAAM;YACpCE,MAAAA,CAAOF,GAAAA,CAAAA;AACT,QAAA;AACF,IAAA,CAAA,EAAGf;IAEHc,oBAAAA,CAAqBO,SAAAA,EAAoBrB;IAEzCc,oBAAAA,CAAqBQ,SAAAA,EAAwBtB;IAE7Cc,oBAAAA,CAAqBT,SAAAA,EAAgBL;IAErCc,oBAAAA,CAAqBL,OAAAA,EAAeT;;IAGpCc,oBAAAA,CAAqB,CAAC,EAAEC,GAAG,EAAEQ,KAAK,EAAE,EAAE,EAAEN,MAAM,EAAE,GAAA;QAC9C,MAAMO,kBAAAA,GAAqBC,aAAAA,CAAcF,KAAAA,CAAAA,IAAUG,OAAAA,CAAQH,KAAAA,CAAAA;AAC3D,QAAA,MAAMI,sBAAsBC,KAAAA,CAAMC,OAAO,CAACN,KAAAA,CAAAA,IAAUA,KAAAA,CAAMO,MAAM,KAAK,CAAA;AACrE,QAAA,IAAIN,sBAAsBG,mBAAAA,EAAqB;YAC7CV,MAAAA,CAAOF,GAAAA,CAAAA;AACT,QAAA;AACF,IAAA,CAAA,EAAGf,GAAAA,CAAAA,CAAAA,CACHY,OAAAA,CAAAA;AACJ,CAAA;AAEA,MAAMmB,mBAAAA,GAAsBpB,KAAAA,CAAM,CAACX,GAAAA,EAAcgC,IAAAA,GAAAA;IAC/C,IAAI,CAAChC,GAAAA,CAAIE,MAAM,EAAE;AACf,QAAA,MAAM,IAAIC,KAAAA,CAAM,uCAAA,CAAA;AAClB,IAAA;AAEA,IAAA,OAAOU;IAELoB,iBAAAA,CAAkB,CAAC,EAAElB,GAAG,EAAEC,SAAS,EAAE,EAAE,EAAEC,MAAM,EAAE,GAAA;;;QAG/C,IAAI;AAACrB,YAAAA,YAAAA;AAAcC,YAAAA;SAAiB,CAACsB,QAAQ,CAACJ,GAAAA,CAAAA,EAAM;AAClD,YAAA;AACF,QAAA;AAEA,QAAA,IAAI,CAACC,SAAAA,EAAW;YACdC,MAAAA,CAAOF,GAAAA,CAAAA;AACT,QAAA;AACF,IAAA,CAAA,EAAGf;IAEHiC,iBAAAA,CAAkBZ,SAAAA,EAAoBrB;IAEtCiC,iBAAAA,CAAkBX,SAAAA,EAAwBtB;IAE1CiC,iBAAAA,CAAkBxB,OAAAA,EAAeT;IAEjCiC,iBAAAA,CAAkB5B,SAAAA,EAAgBL;IAElCiC,iBAAAA,CAAkB,CAAC,EAAElB,GAAG,EAAEC,SAAS,EAAEO,KAAK,EAAE,EAAE,EAAEN,MAAM,EAAE,GAAA;;;QAGtD,IAAI;AAACrB,YAAAA,YAAAA;AAAcC,YAAAA;SAAiB,CAACsB,QAAQ,CAACJ,GAAAA,CAAAA,EAAM;AAClD,YAAA;AACF,QAAA;AAEA,QAAA,IAAI,CAACmB,iBAAAA,CAAkBlB,SAAAA,CAAAA,IAAcU,OAAAA,CAAQH,KAAAA,CAAAA,EAAQ;YACnDN,MAAAA,CAAOF,GAAAA,CAAAA;AACT,QAAA;AACF,IAAA,CAAA,EAAGf,GAAAA,CAAAA,CAAAA,CACHgC,IAAAA,CAAAA;AACJ,CAAA;AAEA,MAAMG,qBAAAA,GAAwBxB,KAAAA,CAAM,CAACX,GAAAA,EAAcoC,MAAAA,GAAAA;IACjD,IAAI,CAACpC,GAAAA,CAAIE,MAAM,EAAE;AACf,QAAA,MAAM,IAAIC,KAAAA,CAAM,yCAAA,CAAA;AAClB,IAAA;AAEA,IAAA,OAAOU;IAELwB,mBAAAA,CAAoB,CAAC,EAAEtB,GAAG,EAAEC,SAAS,EAAE,EAAE,EAAEC,MAAM,EAAE,GAAA;;;QAGjD,IAAI;AAACrB,YAAAA,YAAAA;AAAcC,YAAAA;SAAiB,CAACsB,QAAQ,CAACJ,GAAAA,CAAAA,EAAM;AAClD,YAAA;AACF,QAAA;AAEA,QAAA,IAAIC,SAAAA,IAAa,IAAA,IAAQ,CAACkB,iBAAAA,CAAkBlB,SAAAA,CAAAA,EAAY;YACtDC,MAAAA,CAAOF,GAAAA,CAAAA;AACT,QAAA;AACF,IAAA,CAAA,EAAGf;IAEHqC,mBAAAA,CAAoB5B,OAAAA,EAAeT;IAEnCqC,mBAAAA,CAAoBhC,SAAAA,EAAgBL;AAEpC,IAAA,CAACuB,KAAAA,GAAWK,KAAAA,CAAMC,OAAO,CAACN,KAAAA,CAAAA,GAASA,KAAAA,CAAMe,MAAM,CAAC,CAACC,KAAAA,GAAUA,KAAAA,IAAS,IAAA,CAAA,GAAQhB,KAAAA,CAAAA,CAC5Ea,MAAAA,CAAAA;AACJ,CAAA;AAEA,MAAMI,uBAAAA,GAA0B7B,KAAAA,CAAM,CAACX,GAAAA,EAAcyC,QAAAA,GAAAA;IACnD,IAAI,CAACzC,GAAAA,CAAIE,MAAM,EAAE;AACf,QAAA,MAAM,IAAIC,KAAAA,CAAM,2CAAA,CAAA;AAClB,IAAA;IAEA,OAAOU,IAAAA,CACL6B,sBAAsBC,SAAAA,EAAwB3C,GAAAA,CAAAA,EAC9C0C,sBAAsB,OAAO,EAAE3B,GAAG,EAAEQ,KAAK,EAAErB,MAAM,EAAEc,SAAS,EAAE4B,QAAQ,EAAEC,IAAI,EAAE,EAAE,EAAEC,GAAG,EAAE,GAAA;AACrF,QAAA,IAAI9B,SAAAA,EAAW;AACb,YAAA;AACF,QAAA;AAEA,QAAA,MAAM+B,MAAAA,GAAS;AAAEhC,YAAAA,GAAAA;AAAK8B,YAAAA,IAAAA;AAAM3C,YAAAA,MAAAA;AAAQc,YAAAA;AAAU,SAAA;AAE9C,QAAA,IAAID,QAAQ,MAAA,EAAQ;YAClB+B,GAAAA,CAAI/B,GAAAA,EAAK,MAAMgB,mBAAAA,CAAoB;AAAE7B,gBAAAA,MAAAA;AAAQ0C,gBAAAA,QAAAA;AAAUG,gBAAAA;aAAO,EAAGxB,KAAAA,CAAAA,CAAAA;AACnE,QAAA;AAEA,QAAA,IAAIR,QAAQ,SAAA,EAAW;YACrB+B,GAAAA,CAAI/B,GAAAA,EAAK,MAAML,sBAAAA,CAAuB;AAAER,gBAAAA,MAAAA;AAAQ0C,gBAAAA,QAAAA;AAAUG,gBAAAA;aAAO,EAAGxB,KAAAA,CAAAA,CAAAA;AACtE,QAAA;AAEA,QAAA,IAAIR,QAAQ,QAAA,EAAU;YACpB+B,GAAAA,CAAI/B,GAAAA,EAAK,MAAMoB,qBAAAA,CAAsB;AAAEjC,gBAAAA,MAAAA;AAAQ0C,gBAAAA,QAAAA;AAAUG,gBAAAA;aAAO,EAAGxB,KAAAA,CAAAA,CAAAA;AACrE,QAAA;AAEA,QAAA,IAAIR,QAAQ,UAAA,EAAY;YACtB+B,GAAAA,CAAI/B,GAAAA,EAAK,MAAMyB,uBAAAA,CAAwB;AAAEtC,gBAAAA,MAAAA;AAAQ0C,gBAAAA,QAAAA;AAAUG,gBAAAA;aAAO,EAAGxB,KAAAA,CAAAA,CAAAA;AACvE,QAAA;AACF,IAAA,CAAA,EAAGvB;AAEH0C,IAAAA,qBAAAA,CAAsBjC,SAAeT,GAAAA,CAAAA,CAAAA,CACrCyC,QAAAA,CAAAA;AACJ,CAAA;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/traverse/factory.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/traverse/factory.ts"],"names":[],"mappings":"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"}
|
package/dist/traverse/factory.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const DEFAULT_PATH = {
|
|
3
|
+
/* eslint-disable @typescript-eslint/no-loop-func */ const DEFAULT_PATH = {
|
|
6
4
|
raw: null,
|
|
7
5
|
attribute: null
|
|
8
6
|
};
|
|
@@ -36,15 +34,53 @@ var traverseFactory = (()=>{
|
|
|
36
34
|
// main loop
|
|
37
35
|
let out = utils.transform(data);
|
|
38
36
|
const keys = utils.keys(out);
|
|
37
|
+
// Built once per traversal rather than once per key. `state.handlers` is populated
|
|
38
|
+
// while the traversal is being defined and is fixed by the time it runs, so spreading
|
|
39
|
+
// both lists on every key allocated a fresh array to hold the same handlers. This
|
|
40
|
+
// loop runs for every key of every node of every query, which made it one of the
|
|
41
|
+
// hottest allocation sites in a request.
|
|
42
|
+
const handlers = [
|
|
43
|
+
...state.handlers.common,
|
|
44
|
+
...state.handlers.attributes
|
|
45
|
+
];
|
|
46
|
+
// Also hoisted: none of these close over `key` (each method takes it as an argument),
|
|
47
|
+
// so the previous code allocated three closures per key to no end. They still mutate
|
|
48
|
+
// the same `out` binding, so behaviour is unchanged.
|
|
49
|
+
const transformUtils = {
|
|
50
|
+
remove (key) {
|
|
51
|
+
out = utils.remove(key, out);
|
|
52
|
+
},
|
|
53
|
+
set (key, value) {
|
|
54
|
+
out = utils.set(key, value, out);
|
|
55
|
+
},
|
|
56
|
+
recurse: traverse
|
|
57
|
+
};
|
|
58
|
+
// Pre-picked instead of calling lodash `pick` per key, which allocated both the
|
|
59
|
+
// key-list array literal and a fresh result object every time.
|
|
60
|
+
const visitorUtils = {
|
|
61
|
+
remove: transformUtils.remove,
|
|
62
|
+
set: transformUtils.set
|
|
63
|
+
};
|
|
64
|
+
const handlerUtils = {
|
|
65
|
+
set: transformUtils.set,
|
|
66
|
+
recurse: transformUtils.recurse
|
|
67
|
+
};
|
|
39
68
|
for (const key of keys){
|
|
40
69
|
const attribute = schema?.attributes?.[key];
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
newPath.raw = path.raw == null ? key : `${path.raw}.${key}`;
|
|
70
|
+
// The attribute segment only grows when the key maps to an attribute; otherwise the
|
|
71
|
+
// parent's value carries through unchanged.
|
|
72
|
+
let attributePath = path.attribute;
|
|
45
73
|
if (attribute != null) {
|
|
46
|
-
|
|
74
|
+
attributePath = path.attribute == null ? key : `${path.attribute}.${key}`;
|
|
47
75
|
}
|
|
76
|
+
// A single literal rather than a spread followed by conditional assignment: the
|
|
77
|
+
// spread produced an object whose hidden class then transitioned on each write.
|
|
78
|
+
// `Path` is closed over `raw` and `attribute` and callers never supply their own,
|
|
79
|
+
// so nothing can be dropped by building it directly.
|
|
80
|
+
const newPath = {
|
|
81
|
+
raw: path.raw == null ? key : `${path.raw}.${key}`,
|
|
82
|
+
attribute: attributePath
|
|
83
|
+
};
|
|
48
84
|
// visitors
|
|
49
85
|
const visitorOptions = {
|
|
50
86
|
key,
|
|
@@ -56,19 +92,16 @@ var traverseFactory = (()=>{
|
|
|
56
92
|
getModel,
|
|
57
93
|
parent
|
|
58
94
|
};
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
await visitor(visitorOptions,
|
|
69
|
-
'remove',
|
|
70
|
-
'set'
|
|
71
|
-
]));
|
|
95
|
+
// Awaited unconditionally. Most visitors are synchronous, and awaiting a
|
|
96
|
+
// non-thenable still schedules a microtask, but skipping that await changes
|
|
97
|
+
// the order of branches that recurse concurrently via Promise.all.
|
|
98
|
+
//
|
|
99
|
+
// That reordering used to drop nested populate in content-manager's
|
|
100
|
+
// getQueryPopulate: a shallow `relation` write replaced the subtree a deeper
|
|
101
|
+
// sibling had written at `relation.populate.component`. #27236 fixed that
|
|
102
|
+
// visitor by merging paths. Re-measuring the skip afterward showed no
|
|
103
|
+
// throughput gain, so the await stays.
|
|
104
|
+
await visitor(visitorOptions, visitorUtils);
|
|
72
105
|
const value = utils.get(key, out);
|
|
73
106
|
const createContext = ()=>({
|
|
74
107
|
key,
|
|
@@ -88,18 +121,22 @@ var traverseFactory = (()=>{
|
|
|
88
121
|
continue;
|
|
89
122
|
}
|
|
90
123
|
// handlers
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
124
|
+
//
|
|
125
|
+
// `for await` over a plain array awaits every element, allocating a promise per
|
|
126
|
+
// handler per key even though the elements are ordinary objects. A plain `for...of`
|
|
127
|
+
// with explicit thenable checks is equivalent for non-promise elements, and the
|
|
128
|
+
// predicates in practice are synchronous.
|
|
129
|
+
for (const handler of handlers){
|
|
96
130
|
const ctx = createContext();
|
|
97
|
-
|
|
131
|
+
// A fresh context per handler is deliberate: a handler may call `set`, which
|
|
132
|
+
// reassigns `out`, and the next handler must observe the updated `data`.
|
|
133
|
+
const predicated = handler.predicate(ctx);
|
|
134
|
+
const pass = predicated != null && typeof predicated.then === 'function' ? await predicated : predicated;
|
|
98
135
|
if (pass) {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
136
|
+
const handled = handler.handler(ctx, handlerUtils);
|
|
137
|
+
if (handled != null && typeof handled.then === 'function') {
|
|
138
|
+
await handled;
|
|
139
|
+
}
|
|
103
140
|
}
|
|
104
141
|
}
|
|
105
142
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.js","sources":["../../src/traverse/factory.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-loop-func */\nimport { pick } from 'lodash';\n\nimport {\n AnyAttribute,\n Attribute,\n ComponentAttribute,\n DynamicZoneAttribute,\n Model,\n RelationalAttribute,\n} from '../types';\n\nexport interface Path {\n raw: string | null;\n attribute: string | null;\n}\n\nexport interface Parent {\n attribute?: Attribute;\n key: string | null;\n path: Path;\n schema: Model;\n}\n\nexport interface TraverseOptions {\n schema: Model;\n path?: Path;\n parent?: Parent;\n getModel(uid: string): Model;\n}\n\nexport interface VisitorOptions {\n data: unknown;\n value: unknown;\n schema: Model;\n key: string;\n attribute?: AnyAttribute;\n path: Path;\n parent?: Parent;\n getModel(uid: string): Model;\n}\n\nexport type Traverse = (\n visitor: Visitor,\n options: TraverseOptions,\n data: unknown\n) => Promise<unknown>;\n\nexport interface Visitor {\n (visitorOptions: VisitorOptions, opts: Pick<TransformUtils, 'set' | 'remove'>): void;\n}\n\ninterface Interceptor<T = unknown> {\n predicate(data: unknown): data is T;\n handler(\n visitor: Visitor,\n options: TraverseOptions,\n data: T,\n recurseOptions: { recurse: Traverse }\n ): void;\n}\n\ninterface ParseUtils<T> {\n transform(data: T): unknown;\n remove(key: string, data: T): unknown;\n set(key: string, value: unknown, data: T): unknown;\n keys(data: T): string[];\n get(key: string, data: T): unknown;\n}\n\ninterface Parser<T = unknown> {\n predicate(data: unknown): data is T;\n parser(data: T): ParseUtils<T>;\n}\n\ninterface Ignore {\n (ctx: Context): boolean;\n}\n\ninterface AttributeHandler<AttributeType = Attribute> {\n predicate(ctx: Context<AttributeType>): boolean;\n handler(ctx: Context<AttributeType>, opts: Pick<TransformUtils, 'set' | 'recurse'>): void;\n}\ninterface CommonHandler<AttributeType = Attribute> {\n predicate(ctx: Context<AttributeType>): boolean;\n handler(ctx: Context<AttributeType>, opts: Pick<TransformUtils, 'set' | 'recurse'>): void;\n}\n\nexport interface TransformUtils {\n remove(key: string): void;\n set(key: string, value: unknown): void;\n recurse: Traverse;\n}\n\ninterface Context<AttributeType = Attribute> {\n key: string;\n value: unknown;\n attribute: AttributeType;\n schema: Model;\n path: Path;\n data: unknown;\n visitor: Visitor;\n parent?: Parent;\n getModel(uid: string): Model;\n}\n\ninterface State {\n parsers: Parser[];\n interceptors: Interceptor[];\n ignore: Ignore[];\n handlers: {\n attributes: AttributeHandler[];\n common: CommonHandler[];\n };\n}\n\nconst DEFAULT_PATH = { raw: null, attribute: null } satisfies Path;\n\nexport default () => {\n const state: State = {\n parsers: [],\n interceptors: [],\n ignore: [],\n handlers: {\n attributes: [],\n common: [],\n },\n };\n\n const traverse: Traverse = async (visitor, options, data) => {\n const { path = DEFAULT_PATH, parent, schema, getModel } = options ?? {};\n\n // interceptors\n for (const { predicate, handler } of state.interceptors) {\n if (predicate(data)) {\n return handler(visitor, options, data, { recurse: traverse });\n }\n }\n\n // parsers\n const parser = state.parsers.find((parser) => parser.predicate(data))?.parser;\n const utils = parser?.(data);\n\n // Return the data untouched if we don't know how to traverse it\n if (!utils) {\n return data;\n }\n\n // main loop\n let out = utils.transform(data);\n const keys = utils.keys(out);\n\n for (const key of keys) {\n const attribute = schema?.attributes?.[key];\n\n const newPath = { ...path };\n\n newPath.raw = path.raw == null ? key : `${path.raw}.${key}`;\n\n if (attribute != null) {\n newPath.attribute = path.attribute == null ? key : `${path.attribute}.${key}`;\n }\n\n // visitors\n const visitorOptions: VisitorOptions = {\n key,\n value: utils.get(key, out),\n attribute,\n schema,\n path: newPath,\n data: out,\n getModel,\n parent,\n };\n\n const transformUtils: TransformUtils = {\n remove(key) {\n out = utils.remove(key, out);\n },\n set(key, value) {\n out = utils.set(key, value, out);\n },\n recurse: traverse,\n };\n\n await visitor(visitorOptions, pick(transformUtils, ['remove', 'set']));\n\n const value = utils.get(key, out);\n\n const createContext = (): Context => ({\n key,\n value,\n attribute,\n schema,\n path: newPath,\n data: out,\n visitor,\n getModel,\n parent,\n });\n\n // ignore\n const ignoreCtx = createContext();\n const shouldIgnore = state.ignore.some((predicate) => predicate(ignoreCtx));\n\n if (shouldIgnore) {\n continue;\n }\n\n // handlers\n const handlers = [...state.handlers.common, ...state.handlers.attributes];\n\n for await (const handler of handlers) {\n const ctx = createContext();\n const pass = await handler.predicate(ctx);\n\n if (pass) {\n await handler.handler(ctx, pick(transformUtils, ['recurse', 'set']));\n }\n }\n }\n\n return out;\n };\n\n return {\n traverse,\n\n intercept<T>(predicate: Interceptor<T>['predicate'], handler: Interceptor<T>['handler']) {\n state.interceptors.push({ predicate, handler });\n return this;\n },\n\n parse<T>(predicate: Parser<T>['predicate'], parser: Parser<T>['parser']) {\n state.parsers.push({ predicate, parser });\n return this;\n },\n\n ignore(predicate: Ignore) {\n state.ignore.push(predicate);\n return this;\n },\n\n on(predicate: CommonHandler['predicate'], handler: CommonHandler['handler']) {\n state.handlers.common.push({ predicate, handler });\n return this;\n },\n\n onAttribute(predicate: AttributeHandler['predicate'], handler: AttributeHandler['handler']) {\n state.handlers.attributes.push({ predicate, handler });\n return this;\n },\n\n onRelation(handler: AttributeHandler<RelationalAttribute>['handler']) {\n return this.onAttribute(({ attribute }) => attribute?.type === 'relation', handler);\n },\n\n onMedia(handler: AttributeHandler<RelationalAttribute>['handler']) {\n return this.onAttribute(({ attribute }) => attribute?.type === 'media', handler);\n },\n\n onComponent(handler: AttributeHandler<ComponentAttribute>['handler']) {\n return this.onAttribute(({ attribute }) => attribute?.type === 'component', handler);\n },\n\n onDynamicZone(handler: AttributeHandler<DynamicZoneAttribute>['handler']) {\n return this.onAttribute(({ attribute }) => attribute?.type === 'dynamiczone', handler);\n },\n };\n};\n"],"names":["DEFAULT_PATH","raw","attribute","state","parsers","interceptors","ignore","handlers","attributes","common","traverse","visitor","options","data","path","parent","schema","getModel","predicate","handler","recurse","parser","find","utils","out","transform","keys","key","newPath","visitorOptions","value","get","transformUtils","remove","set","pick","createContext","ignoreCtx","shouldIgnore","some","ctx","pass","intercept","push","parse","on","onAttribute","onRelation","type","onMedia","onComponent","onDynamicZone"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"factory.js","sources":["../../src/traverse/factory.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-loop-func */\nimport {\n AnyAttribute,\n Attribute,\n ComponentAttribute,\n DynamicZoneAttribute,\n Model,\n RelationalAttribute,\n} from '../types';\n\nexport interface Path {\n raw: string | null;\n attribute: string | null;\n}\n\nexport interface Parent {\n attribute?: Attribute;\n key: string | null;\n path: Path;\n schema: Model;\n}\n\nexport interface TraverseOptions {\n schema: Model;\n path?: Path;\n parent?: Parent;\n getModel(uid: string): Model;\n}\n\nexport interface VisitorOptions {\n data: unknown;\n value: unknown;\n schema: Model;\n key: string;\n attribute?: AnyAttribute;\n path: Path;\n parent?: Parent;\n getModel(uid: string): Model;\n}\n\nexport type Traverse = (\n visitor: Visitor,\n options: TraverseOptions,\n data: unknown\n) => Promise<unknown>;\n\nexport interface Visitor {\n (visitorOptions: VisitorOptions, opts: Pick<TransformUtils, 'set' | 'remove'>): void;\n}\n\ninterface Interceptor<T = unknown> {\n predicate(data: unknown): data is T;\n handler(\n visitor: Visitor,\n options: TraverseOptions,\n data: T,\n recurseOptions: { recurse: Traverse }\n ): void;\n}\n\ninterface ParseUtils<T> {\n transform(data: T): unknown;\n remove(key: string, data: T): unknown;\n set(key: string, value: unknown, data: T): unknown;\n keys(data: T): string[];\n get(key: string, data: T): unknown;\n}\n\ninterface Parser<T = unknown> {\n predicate(data: unknown): data is T;\n parser(data: T): ParseUtils<T>;\n}\n\ninterface Ignore {\n (ctx: Context): boolean;\n}\n\ninterface AttributeHandler<AttributeType = Attribute> {\n predicate(ctx: Context<AttributeType>): boolean;\n handler(ctx: Context<AttributeType>, opts: Pick<TransformUtils, 'set' | 'recurse'>): void;\n}\ninterface CommonHandler<AttributeType = Attribute> {\n predicate(ctx: Context<AttributeType>): boolean;\n handler(ctx: Context<AttributeType>, opts: Pick<TransformUtils, 'set' | 'recurse'>): void;\n}\n\nexport interface TransformUtils {\n remove(key: string): void;\n set(key: string, value: unknown): void;\n recurse: Traverse;\n}\n\ninterface Context<AttributeType = Attribute> {\n key: string;\n value: unknown;\n attribute: AttributeType;\n schema: Model;\n path: Path;\n data: unknown;\n visitor: Visitor;\n parent?: Parent;\n getModel(uid: string): Model;\n}\n\ninterface State {\n parsers: Parser[];\n interceptors: Interceptor[];\n ignore: Ignore[];\n handlers: {\n attributes: AttributeHandler[];\n common: CommonHandler[];\n };\n}\n\nconst DEFAULT_PATH = { raw: null, attribute: null } satisfies Path;\n\nexport default () => {\n const state: State = {\n parsers: [],\n interceptors: [],\n ignore: [],\n handlers: {\n attributes: [],\n common: [],\n },\n };\n\n const traverse: Traverse = async (visitor, options, data) => {\n const { path = DEFAULT_PATH, parent, schema, getModel } = options ?? {};\n\n // interceptors\n for (const { predicate, handler } of state.interceptors) {\n if (predicate(data)) {\n return handler(visitor, options, data, { recurse: traverse });\n }\n }\n\n // parsers\n const parser = state.parsers.find((parser) => parser.predicate(data))?.parser;\n const utils = parser?.(data);\n\n // Return the data untouched if we don't know how to traverse it\n if (!utils) {\n return data;\n }\n\n // main loop\n let out = utils.transform(data);\n const keys = utils.keys(out);\n\n // Built once per traversal rather than once per key. `state.handlers` is populated\n // while the traversal is being defined and is fixed by the time it runs, so spreading\n // both lists on every key allocated a fresh array to hold the same handlers. This\n // loop runs for every key of every node of every query, which made it one of the\n // hottest allocation sites in a request.\n const handlers = [...state.handlers.common, ...state.handlers.attributes];\n\n // Also hoisted: none of these close over `key` (each method takes it as an argument),\n // so the previous code allocated three closures per key to no end. They still mutate\n // the same `out` binding, so behaviour is unchanged.\n const transformUtils: TransformUtils = {\n remove(key) {\n out = utils.remove(key, out);\n },\n set(key, value) {\n out = utils.set(key, value, out);\n },\n recurse: traverse,\n };\n\n // Pre-picked instead of calling lodash `pick` per key, which allocated both the\n // key-list array literal and a fresh result object every time.\n const visitorUtils: Pick<TransformUtils, 'set' | 'remove'> = {\n remove: transformUtils.remove,\n set: transformUtils.set,\n };\n const handlerUtils: Pick<TransformUtils, 'set' | 'recurse'> = {\n set: transformUtils.set,\n recurse: transformUtils.recurse,\n };\n\n for (const key of keys) {\n const attribute = schema?.attributes?.[key];\n\n // The attribute segment only grows when the key maps to an attribute; otherwise the\n // parent's value carries through unchanged.\n let attributePath = path.attribute;\n if (attribute != null) {\n attributePath = path.attribute == null ? key : `${path.attribute}.${key}`;\n }\n\n // A single literal rather than a spread followed by conditional assignment: the\n // spread produced an object whose hidden class then transitioned on each write.\n // `Path` is closed over `raw` and `attribute` and callers never supply their own,\n // so nothing can be dropped by building it directly.\n const newPath: Path = {\n raw: path.raw == null ? key : `${path.raw}.${key}`,\n attribute: attributePath,\n };\n\n // visitors\n const visitorOptions: VisitorOptions = {\n key,\n value: utils.get(key, out),\n attribute,\n schema,\n path: newPath,\n data: out,\n getModel,\n parent,\n };\n\n // Awaited unconditionally. Most visitors are synchronous, and awaiting a\n // non-thenable still schedules a microtask, but skipping that await changes\n // the order of branches that recurse concurrently via Promise.all.\n //\n // That reordering used to drop nested populate in content-manager's\n // getQueryPopulate: a shallow `relation` write replaced the subtree a deeper\n // sibling had written at `relation.populate.component`. #27236 fixed that\n // visitor by merging paths. Re-measuring the skip afterward showed no\n // throughput gain, so the await stays.\n await visitor(visitorOptions, visitorUtils);\n\n const value = utils.get(key, out);\n\n const createContext = (): Context => ({\n key,\n value,\n attribute,\n schema,\n path: newPath,\n data: out,\n visitor,\n getModel,\n parent,\n });\n\n // ignore\n const ignoreCtx = createContext();\n const shouldIgnore = state.ignore.some((predicate) => predicate(ignoreCtx));\n\n if (shouldIgnore) {\n continue;\n }\n\n // handlers\n //\n // `for await` over a plain array awaits every element, allocating a promise per\n // handler per key even though the elements are ordinary objects. A plain `for...of`\n // with explicit thenable checks is equivalent for non-promise elements, and the\n // predicates in practice are synchronous.\n for (const handler of handlers) {\n const ctx = createContext();\n\n // A fresh context per handler is deliberate: a handler may call `set`, which\n // reassigns `out`, and the next handler must observe the updated `data`.\n const predicated = handler.predicate(ctx) as unknown;\n const pass =\n predicated != null && typeof (predicated as PromiseLike<boolean>).then === 'function'\n ? await (predicated as PromiseLike<boolean>)\n : predicated;\n\n if (pass) {\n const handled = handler.handler(ctx, handlerUtils) as unknown;\n\n if (handled != null && typeof (handled as PromiseLike<void>).then === 'function') {\n await handled;\n }\n }\n }\n }\n\n return out;\n };\n\n return {\n traverse,\n\n intercept<T>(predicate: Interceptor<T>['predicate'], handler: Interceptor<T>['handler']) {\n state.interceptors.push({ predicate, handler });\n return this;\n },\n\n parse<T>(predicate: Parser<T>['predicate'], parser: Parser<T>['parser']) {\n state.parsers.push({ predicate, parser });\n return this;\n },\n\n ignore(predicate: Ignore) {\n state.ignore.push(predicate);\n return this;\n },\n\n on(predicate: CommonHandler['predicate'], handler: CommonHandler['handler']) {\n state.handlers.common.push({ predicate, handler });\n return this;\n },\n\n onAttribute(predicate: AttributeHandler['predicate'], handler: AttributeHandler['handler']) {\n state.handlers.attributes.push({ predicate, handler });\n return this;\n },\n\n onRelation(handler: AttributeHandler<RelationalAttribute>['handler']) {\n return this.onAttribute(({ attribute }) => attribute?.type === 'relation', handler);\n },\n\n onMedia(handler: AttributeHandler<RelationalAttribute>['handler']) {\n return this.onAttribute(({ attribute }) => attribute?.type === 'media', handler);\n },\n\n onComponent(handler: AttributeHandler<ComponentAttribute>['handler']) {\n return this.onAttribute(({ attribute }) => attribute?.type === 'component', handler);\n },\n\n onDynamicZone(handler: AttributeHandler<DynamicZoneAttribute>['handler']) {\n return this.onAttribute(({ attribute }) => attribute?.type === 'dynamiczone', handler);\n },\n };\n};\n"],"names":["DEFAULT_PATH","raw","attribute","state","parsers","interceptors","ignore","handlers","attributes","common","traverse","visitor","options","data","path","parent","schema","getModel","predicate","handler","recurse","parser","find","utils","out","transform","keys","transformUtils","remove","key","set","value","visitorUtils","handlerUtils","attributePath","newPath","visitorOptions","get","createContext","ignoreCtx","shouldIgnore","some","ctx","predicated","pass","then","handled","intercept","push","parse","on","onAttribute","onRelation","type","onMedia","onComponent","onDynamicZone"],"mappings":"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"}
|