payload-sanitizer 0.2.0 → 0.3.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/LICENSE +0 -0
- package/README.md +87 -103
- package/dist/index.cjs +1 -164
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +47 -20
- package/dist/index.d.ts +47 -20
- package/dist/index.global.js +2 -0
- package/dist/index.global.js.map +1 -0
- package/dist/index.js +1 -160
- package/dist/index.js.map +1 -1
- package/package.json +13 -11
package/LICENSE
CHANGED
|
File without changes
|
package/README.md
CHANGED
|
@@ -4,24 +4,17 @@
|
|
|
4
4
|
[](https://www.npmjs.com/package/payload-sanitizer)
|
|
5
5
|
[](./LICENSE)
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
Tiny zero‑dependency sanitizer for JS/TS payloads that removes common junk (empty strings, whitespace-only strings, `null`, `undefined`, optional dash marker, `NaN`) without mutating the original value. Works in both frontend and backend code.
|
|
7
|
+
Tiny zero-dependency sanitizer for JS/TS payloads that removes common junk (`""`, whitespace-only strings, `null`, `undefined`, optional `"-"`, `NaN`) without mutating the original value.
|
|
10
8
|
|
|
11
9
|
## Install
|
|
12
10
|
|
|
13
11
|
```bash
|
|
14
|
-
# pnpm
|
|
15
12
|
pnpm add payload-sanitizer
|
|
16
|
-
|
|
17
|
-
#
|
|
18
|
-
npm i payload-sanitizer
|
|
19
|
-
|
|
20
|
-
# yarn
|
|
21
|
-
yarn add payload-sanitizer
|
|
13
|
+
# or npm i payload-sanitizer
|
|
14
|
+
# or yarn add payload-sanitizer
|
|
22
15
|
```
|
|
23
16
|
|
|
24
|
-
## Quick
|
|
17
|
+
## Quick Start
|
|
25
18
|
|
|
26
19
|
```ts
|
|
27
20
|
import { sanitize } from "payload-sanitizer";
|
|
@@ -32,124 +25,123 @@ const input = {
|
|
|
32
25
|
fromDate: " 2026-02-01 ",
|
|
33
26
|
toDate: null,
|
|
34
27
|
page: 1,
|
|
35
|
-
includeInactive: false,
|
|
36
28
|
};
|
|
37
29
|
|
|
38
30
|
const clean = sanitize(input, {
|
|
39
31
|
drop: ["undefined", "null", "emptyString", "whitespaceString", "dash"],
|
|
40
32
|
});
|
|
41
33
|
|
|
42
|
-
|
|
43
|
-
// {
|
|
44
|
-
// fromDate: "2026-02-01",
|
|
45
|
-
// page: 1,
|
|
46
|
-
// includeInactive: false
|
|
47
|
-
// }
|
|
34
|
+
// { fromDate: "2026-02-01", page: 1 }
|
|
48
35
|
```
|
|
49
36
|
|
|
50
|
-
|
|
37
|
+
## API
|
|
51
38
|
|
|
52
|
-
|
|
39
|
+
### `sanitize(payload, options?)`
|
|
53
40
|
|
|
54
|
-
|
|
41
|
+
Returns a cleaned clone of payload.
|
|
55
42
|
|
|
56
|
-
|
|
57
|
-
const cleaned = sanitize(formValues);
|
|
58
|
-
const parsed = schema.parse(cleaned);
|
|
59
|
-
```
|
|
43
|
+
Options:
|
|
60
44
|
|
|
61
|
-
|
|
45
|
+
- `deep` (default `true`): recurse into nested objects.
|
|
46
|
+
- `trimStrings` (default `true`): trim strings before checks.
|
|
47
|
+
- `cleanArrays` (default `true`): sanitize array items and remove dropped values.
|
|
48
|
+
- `drop` (default `["undefined", "null", "emptyString", "whitespaceString"]`): drop presets.
|
|
49
|
+
- `dropEmptyObjects` (default `false`): drop objects that become empty.
|
|
50
|
+
- `dropEmptyArrays` (default `false`): drop arrays that become empty.
|
|
51
|
+
- `keepKeys`, `dropKeys`: key-based keep/drop controls.
|
|
52
|
+
- `keepPaths`, `dropPaths`: exact path-based keep/drop controls.
|
|
53
|
+
- `dropValues`: explicit values to drop (uses `Object.is`).
|
|
54
|
+
- `shouldDrop(value, keyPath)`: custom drop predicate.
|
|
55
|
+
- `strict` (default `false`): validates option shapes and throws on invalid config.
|
|
56
|
+
- `debug` (default `false`): emit debug events.
|
|
57
|
+
- `logger(event)`: custom debug logger.
|
|
58
|
+
|
|
59
|
+
Drop presets:
|
|
60
|
+
|
|
61
|
+
`"undefined" | "null" | "emptyString" | "whitespaceString" | "dash" | "nan"`
|
|
62
62
|
|
|
63
|
-
### `sanitize(
|
|
63
|
+
### `sanitize.with(baseOptions)`
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
Create a reusable sanitizer with base options.
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
### `createSanitizer(baseOptions)`
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
- `trimStrings` (default `true`): `value.trim()` on strings before checks.
|
|
71
|
-
- `cleanArrays` (default `true`): sanitize array items and drop ones that should be removed.
|
|
72
|
-
- `drop` (defaults to `["undefined","null","emptyString","whitespaceString"]`): presets to remove. Presets: `"undefined" | "null" | "emptyString" | "whitespaceString" | "dash" | "nan"`.
|
|
73
|
-
- `dropEmptyObjects` (default `false`): remove objects that become empty after sanitizing.
|
|
74
|
-
- `dropEmptyArrays` (default `false`): remove arrays that become empty after sanitizing.
|
|
75
|
-
- `keepKeys`: key names to always keep even if value looks droppable.
|
|
76
|
-
- `keepPaths`: exact paths to always keep (e.g., `"filters.status"`).
|
|
77
|
-
- `dropKeys`: key names to always remove.
|
|
78
|
-
- `dropPaths`: exact paths to always drop (e.g., `"meta.debug"`).
|
|
79
|
-
- `dropValues`: explicit values to remove (uses `Object.is`).
|
|
80
|
-
- `shouldDrop(value, keyPath)`: custom predicate; return `true` to drop. `keyPath` is an array of keys/indexes from root.
|
|
69
|
+
Factory equivalent of `sanitize.with`.
|
|
81
70
|
|
|
82
|
-
|
|
71
|
+
### `sanitizeWith(baseOptions)`
|
|
83
72
|
|
|
84
|
-
|
|
85
|
-
- If everything is dropped, arrays become `[]`, objects become `{}`; primitives are returned as-is.
|
|
73
|
+
Alias of `sanitize.with`.
|
|
86
74
|
|
|
87
|
-
|
|
75
|
+
## Debug (Global + Instance)
|
|
88
76
|
|
|
89
77
|
```ts
|
|
90
|
-
sanitize
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
78
|
+
import { configureDebug, sanitize } from "payload-sanitizer";
|
|
79
|
+
|
|
80
|
+
configureDebug({
|
|
81
|
+
debug: true,
|
|
82
|
+
logger: (event) => {
|
|
83
|
+
console.log(event.type, event.path.join("."));
|
|
84
|
+
},
|
|
94
85
|
});
|
|
95
|
-
```
|
|
96
86
|
|
|
97
|
-
|
|
87
|
+
sanitize({ q: " " });
|
|
98
88
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
89
|
+
sanitize(
|
|
90
|
+
{ q: " " },
|
|
91
|
+
{
|
|
92
|
+
debug: true,
|
|
93
|
+
logger: (event) => console.log("instance", event),
|
|
94
|
+
},
|
|
95
|
+
);
|
|
104
96
|
```
|
|
105
97
|
|
|
106
|
-
|
|
98
|
+
Exports:
|
|
107
99
|
|
|
108
|
-
|
|
100
|
+
- `configureDebug(options)`
|
|
101
|
+
- `getDebugOptions()`
|
|
102
|
+
- `resetDebug()`
|
|
109
103
|
|
|
110
|
-
|
|
111
|
-
const sanitizeSearch = sanitize.with({
|
|
112
|
-
drop: ["undefined", "null", "emptyString", "whitespaceString", "dash"],
|
|
113
|
-
});
|
|
104
|
+
Debug event types:
|
|
114
105
|
|
|
115
|
-
|
|
116
|
-
// { q: "hello" }
|
|
117
|
-
```
|
|
106
|
+
`"normalize" | "drop" | "keep" | "empty-object" | "empty-array" | "circular-skip"`
|
|
118
107
|
|
|
119
|
-
|
|
108
|
+
## Circular Reference Safety
|
|
120
109
|
|
|
121
|
-
|
|
110
|
+
Circular references are detected and skipped safely during traversal to avoid infinite recursion.
|
|
111
|
+
|
|
112
|
+
## Utility APIs
|
|
122
113
|
|
|
123
114
|
```ts
|
|
124
|
-
import {
|
|
125
|
-
|
|
115
|
+
import {
|
|
116
|
+
pick,
|
|
117
|
+
omit,
|
|
118
|
+
isEmpty,
|
|
119
|
+
compact,
|
|
120
|
+
diff,
|
|
121
|
+
safeParse,
|
|
122
|
+
} from "payload-sanitizer";
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
- `pick(obj, keys)`
|
|
126
|
+
- `omit(obj, keys)`
|
|
127
|
+
- `isEmpty(value)`
|
|
128
|
+
- `compact(array)`
|
|
129
|
+
- `diff(before, after)`
|
|
130
|
+
- `safeParse(json, fallback?)`
|
|
131
|
+
|
|
132
|
+
## CDN (IIFE Global)
|
|
133
|
+
|
|
134
|
+
```html
|
|
135
|
+
<script src="https://cdn.jsdelivr.net/npm/payload-sanitizer@0.3.0/dist/index.global.js"></script>
|
|
136
|
+
<script>
|
|
137
|
+
const out = PayloadSanitizer.sanitize({ q: " hello " });
|
|
138
|
+
console.log(out);
|
|
139
|
+
</script>
|
|
126
140
|
```
|
|
127
141
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
-
|
|
131
|
-
```ts
|
|
132
|
-
await api.post("/search", sanitize(values));
|
|
133
|
-
```
|
|
134
|
-
- **Backend filters** — strip empty query params:
|
|
135
|
-
```ts
|
|
136
|
-
const filters = sanitize(req.query, { drop: ["dash"] });
|
|
137
|
-
db.find(filters);
|
|
138
|
-
```
|
|
139
|
-
- **Custom rule** — drop empty `filters` objects:
|
|
140
|
-
```ts
|
|
141
|
-
sanitize(payload, {
|
|
142
|
-
shouldDrop: (value, path) =>
|
|
143
|
-
path.at(-1) === "filters" &&
|
|
144
|
-
typeof value === "object" &&
|
|
145
|
-
value !== null &&
|
|
146
|
-
Object.keys(value as any).length === 0,
|
|
147
|
-
});
|
|
148
|
-
```
|
|
149
|
-
- **Drop exact values**:
|
|
150
|
-
```ts
|
|
151
|
-
sanitize(data, { dropValues: ["N/A", Number.NaN] });
|
|
152
|
-
```
|
|
142
|
+
Also available via unpkg:
|
|
143
|
+
|
|
144
|
+
`https://unpkg.com/payload-sanitizer@0.3.0/dist/index.global.js`
|
|
153
145
|
|
|
154
146
|
## Development
|
|
155
147
|
|
|
@@ -157,17 +149,9 @@ const sanitizePayload = createSanitizer({ deep: true });
|
|
|
157
149
|
pnpm install
|
|
158
150
|
pnpm test
|
|
159
151
|
pnpm build
|
|
152
|
+
pnpm typecheck
|
|
160
153
|
```
|
|
161
154
|
|
|
162
|
-
## Contributing
|
|
163
|
-
|
|
164
|
-
Contributions are welcome!
|
|
165
|
-
If you have ideas, edge cases, or want to improve performance/docs, please open an issue or PR.
|
|
166
|
-
|
|
167
|
-
- Read: `CONTRIBUTING.md`
|
|
168
|
-
- Report bugs: GitHub Issues
|
|
169
|
-
- Feature requests: GitHub Issues
|
|
170
|
-
|
|
171
155
|
## License
|
|
172
156
|
|
|
173
157
|
MIT
|
package/dist/index.cjs
CHANGED
|
@@ -1,165 +1,2 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
// src/index.ts
|
|
4
|
-
var DEFAULT_DROP = [
|
|
5
|
-
"undefined",
|
|
6
|
-
"null",
|
|
7
|
-
"emptyString",
|
|
8
|
-
"whitespaceString"
|
|
9
|
-
];
|
|
10
|
-
var DEFAULT_OPTIONS = {
|
|
11
|
-
deep: true,
|
|
12
|
-
trimStrings: true,
|
|
13
|
-
cleanArrays: true,
|
|
14
|
-
dropEmptyObjects: false,
|
|
15
|
-
dropEmptyArrays: false,
|
|
16
|
-
drop: DEFAULT_DROP
|
|
17
|
-
};
|
|
18
|
-
function isPlainObject(value) {
|
|
19
|
-
if (value === null || typeof value !== "object") return false;
|
|
20
|
-
const proto = Object.getPrototypeOf(value);
|
|
21
|
-
return proto === Object.prototype || proto === null;
|
|
22
|
-
}
|
|
23
|
-
function normalizeValue(value, opts) {
|
|
24
|
-
if (typeof value === "string" && opts.trimStrings) {
|
|
25
|
-
return value.trim();
|
|
26
|
-
}
|
|
27
|
-
return value;
|
|
28
|
-
}
|
|
29
|
-
function shouldDropPreset(value, drop) {
|
|
30
|
-
for (const d of drop) {
|
|
31
|
-
switch (d) {
|
|
32
|
-
case "undefined":
|
|
33
|
-
if (value === void 0) return true;
|
|
34
|
-
break;
|
|
35
|
-
case "null":
|
|
36
|
-
if (value === null) return true;
|
|
37
|
-
break;
|
|
38
|
-
case "emptyString":
|
|
39
|
-
if (value === "") return true;
|
|
40
|
-
break;
|
|
41
|
-
case "whitespaceString":
|
|
42
|
-
if (typeof value === "string" && value.trim() === "") return true;
|
|
43
|
-
break;
|
|
44
|
-
case "dash":
|
|
45
|
-
if (value === "-") return true;
|
|
46
|
-
break;
|
|
47
|
-
case "nan":
|
|
48
|
-
if (typeof value === "number" && Number.isNaN(value)) return true;
|
|
49
|
-
break;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
return false;
|
|
53
|
-
}
|
|
54
|
-
function shouldDropExact(value, exactValues) {
|
|
55
|
-
if (!exactValues || exactValues.length === 0) return false;
|
|
56
|
-
for (const v of exactValues) {
|
|
57
|
-
if (Object.is(value, v)) return true;
|
|
58
|
-
}
|
|
59
|
-
return false;
|
|
60
|
-
}
|
|
61
|
-
function hasKey(list, key) {
|
|
62
|
-
return !!list && list.includes(key);
|
|
63
|
-
}
|
|
64
|
-
function toKeyPath(path) {
|
|
65
|
-
if (Array.isArray(path)) return path;
|
|
66
|
-
if (path.trim() === "") return [];
|
|
67
|
-
return path.split(".").map((seg) => {
|
|
68
|
-
const n = Number(seg);
|
|
69
|
-
return Number.isInteger(n) && String(n) === seg ? n : seg;
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
function pathEquals(a, b) {
|
|
73
|
-
if (a.length !== b.length) return false;
|
|
74
|
-
for (let i = 0; i < a.length; i++) {
|
|
75
|
-
if (a[i] !== b[i]) return false;
|
|
76
|
-
}
|
|
77
|
-
return true;
|
|
78
|
-
}
|
|
79
|
-
function hasPath(list, path) {
|
|
80
|
-
if (!list || list.length === 0) return false;
|
|
81
|
-
for (const item of list) {
|
|
82
|
-
if (pathEquals(toKeyPath(item), path)) return true;
|
|
83
|
-
}
|
|
84
|
-
return false;
|
|
85
|
-
}
|
|
86
|
-
function sanitizeAny(input, options, path) {
|
|
87
|
-
const normalized = normalizeValue(input, options);
|
|
88
|
-
if (hasPath(options.dropPaths, path)) return void 0;
|
|
89
|
-
const isKeptPath = hasPath(options.keepPaths, path);
|
|
90
|
-
if (!isKeptPath) {
|
|
91
|
-
if (shouldDropPreset(normalized, options.drop)) return void 0;
|
|
92
|
-
if (shouldDropExact(normalized, options.dropValues)) return void 0;
|
|
93
|
-
if (options.shouldDrop?.(normalized, path)) return void 0;
|
|
94
|
-
}
|
|
95
|
-
if (Array.isArray(normalized)) {
|
|
96
|
-
if (!options.cleanArrays) return normalized.slice();
|
|
97
|
-
const out = [];
|
|
98
|
-
for (let i = 0; i < normalized.length; i++) {
|
|
99
|
-
const next = sanitizeAny(normalized[i], options, path.concat(i));
|
|
100
|
-
if (next !== void 0) out.push(next);
|
|
101
|
-
}
|
|
102
|
-
if (options.dropEmptyArrays && out.length === 0) return void 0;
|
|
103
|
-
return out;
|
|
104
|
-
}
|
|
105
|
-
if (isPlainObject(normalized)) {
|
|
106
|
-
if (!options.deep) {
|
|
107
|
-
const out2 = {};
|
|
108
|
-
for (const [k, v] of Object.entries(normalized)) {
|
|
109
|
-
if (hasKey(options.dropKeys, k)) continue;
|
|
110
|
-
if (hasKey(options.keepKeys, k)) {
|
|
111
|
-
out2[k] = v;
|
|
112
|
-
continue;
|
|
113
|
-
}
|
|
114
|
-
const next = sanitizeAny(v, options, path.concat(k));
|
|
115
|
-
if (next !== void 0) out2[k] = next;
|
|
116
|
-
}
|
|
117
|
-
if (options.dropEmptyObjects && Object.keys(out2).length === 0)
|
|
118
|
-
return void 0;
|
|
119
|
-
return out2;
|
|
120
|
-
}
|
|
121
|
-
const out = {};
|
|
122
|
-
for (const [k, v] of Object.entries(normalized)) {
|
|
123
|
-
if (hasKey(options.dropKeys, k)) continue;
|
|
124
|
-
if (hasKey(options.keepKeys, k)) {
|
|
125
|
-
out[k] = v;
|
|
126
|
-
continue;
|
|
127
|
-
}
|
|
128
|
-
const next = sanitizeAny(v, options, path.concat(k));
|
|
129
|
-
if (next !== void 0) out[k] = next;
|
|
130
|
-
}
|
|
131
|
-
if (options.dropEmptyObjects && Object.keys(out).length === 0)
|
|
132
|
-
return void 0;
|
|
133
|
-
return out;
|
|
134
|
-
}
|
|
135
|
-
return normalized;
|
|
136
|
-
}
|
|
137
|
-
function sanitize(payload, options = {}) {
|
|
138
|
-
const merged = {
|
|
139
|
-
...DEFAULT_OPTIONS,
|
|
140
|
-
...options,
|
|
141
|
-
drop: options.drop ?? DEFAULT_OPTIONS.drop
|
|
142
|
-
};
|
|
143
|
-
const result = sanitizeAny(
|
|
144
|
-
payload,
|
|
145
|
-
merged,
|
|
146
|
-
[]
|
|
147
|
-
);
|
|
148
|
-
if (result === void 0) {
|
|
149
|
-
if (isPlainObject(payload)) return {};
|
|
150
|
-
if (Array.isArray(payload)) return [];
|
|
151
|
-
return payload;
|
|
152
|
-
}
|
|
153
|
-
return result;
|
|
154
|
-
}
|
|
155
|
-
var createSanitizer = (baseOptions = {}) => {
|
|
156
|
-
return (payload, options = {}) => sanitize(payload, { ...baseOptions, ...options });
|
|
157
|
-
};
|
|
158
|
-
sanitize.with = (baseOptions = {}) => createSanitizer(baseOptions);
|
|
159
|
-
var sanitizeWith = sanitize.with;
|
|
160
|
-
|
|
161
|
-
exports.createSanitizer = createSanitizer;
|
|
162
|
-
exports.sanitize = sanitize;
|
|
163
|
-
exports.sanitizeWith = sanitizeWith;
|
|
164
|
-
//# sourceMappingURL=index.cjs.map
|
|
1
|
+
'use strict';function k(){let e=new WeakSet;return {has(t){return e.has(t)},add(t){e.add(t);}}}var y={};function K(e={}){y={...y,...e};}function A(){return y}function S(){y={};}function E(e){return {debug:e.debug??y.debug??false,logger:e.logger??y.logger??z}}function z(e){globalThis.console?.log("[payload-sanitizer]",e);}function a(e,t){let r=E(e);r.debug&&r.logger(t);}function g(e){if(e===null||typeof e!="object")return false;let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null}function c(e,t){if(!e)throw new Error(`[payload-sanitizer] ${t}`)}function j(e){return Array.isArray(e)?e:e.trim()===""?[]:e.split(".").map(t=>{let r=Number(t);return Number.isInteger(r)&&String(r)===t?r:t})}function R(e,t){if(e.length!==t.length)return false;for(let r=0;r<e.length;r++)if(e[r]!==t[r])return false;return true}function l(e,t){if(!e||e.length===0)return false;for(let r of e)if(R(j(r),t))return true;return false}var h=["undefined","null","emptyString","whitespaceString"];function D(e,t){for(let r of t)switch(r){case "undefined":if(e===void 0)return true;break;case "null":if(e===null)return true;break;case "emptyString":if(e==="")return true;break;case "whitespaceString":if(typeof e=="string"&&e.trim()==="")return true;break;case "dash":if(e==="-")return true;break;case "nan":if(typeof e=="number"&&Number.isNaN(e))return true;break}return false}var P={deep:true,trimStrings:true,cleanArrays:true,dropEmptyObjects:false,dropEmptyArrays:false,drop:h};function v(e,t){return typeof e=="string"&&t?e.trim():e}function N(e,t){if(!t||t.length===0)return false;for(let r of t)if(Object.is(e,r))return true;return false}function O(e,t){return !!e&&e.includes(t)}function C(e){c(e.drop===void 0||Array.isArray(e.drop),"`drop` must be an array"),c(e.keepKeys===void 0||Array.isArray(e.keepKeys),"`keepKeys` must be an array"),c(e.dropKeys===void 0||Array.isArray(e.dropKeys),"`dropKeys` must be an array"),c(e.dropValues===void 0||Array.isArray(e.dropValues),"`dropValues` must be an array"),c(e.keepPaths===void 0||Array.isArray(e.keepPaths),"`keepPaths` must be an array"),c(e.dropPaths===void 0||Array.isArray(e.dropPaths),"`dropPaths` must be an array"),c(e.shouldDrop===void 0||typeof e.shouldDrop=="function","`shouldDrop` must be a function");}function x(e,t={}){let r={...P,...t,drop:t.drop??P.drop};r.strict&&C(r);let s=k();function d(b,o){let n=v(b,r.trimStrings);if(a(r,{type:"normalize",path:o,original:b,result:n}),l(r.dropPaths,o)){a(r,{type:"drop",path:o,original:n});return}if(l(r.keepPaths,o))a(r,{type:"keep",path:o,original:n});else {if(D(n,r.drop)){a(r,{type:"drop",path:o,original:n});return}if(N(n,r.dropValues)){a(r,{type:"drop",path:o,original:n});return}if(r.shouldDrop?.(n,o)){a(r,{type:"drop",path:o,original:n});return}}if(Array.isArray(n)){if(s.has(n))return a(r,{type:"circular-skip",path:o,original:n}),n;if(s.add(n),!r.cleanArrays)return n.slice();let p=[];for(let u=0;u<n.length;u++){let f=d(n[u],o.concat(u));f!==void 0&&p.push(f);}if(r.dropEmptyArrays&&p.length===0){a(r,{type:"empty-array",path:o,original:n});return}return p}if(g(n)){if(s.has(n))return a(r,{type:"circular-skip",path:o,original:n}),n;s.add(n);let p={};for(let[u,f]of Object.entries(n)){if(O(r.dropKeys,u))continue;if(O(r.keepKeys,u)){a(r,{type:"keep",path:o.concat(u),original:f}),p[u]=f;continue}if(!r.deep&&g(f)){p[u]=f;continue}let m=d(f,o.concat(u));m!==void 0&&(p[u]=m);}if(r.dropEmptyObjects&&Object.keys(p).length===0){a(r,{type:"empty-object",path:o,original:n});return}return p}return n}let i=d(e,[]);return i===void 0?g(e)?{}:Array.isArray(e)?[]:e:i}var T=(e={})=>(t,r={})=>x(t,{...e,...r}),w=Object.assign(x,{with:(e={})=>T(e)}),F=w.with;function L(e,t){let r={};for(let s of t)s in e&&(r[s]=e[s]);return r}function V(e,t){let r={...e};for(let s of t)delete r[s];return r}function q(e){return Array.isArray(e)?e.length===0:e&&typeof e=="object"?Object.keys(e).length===0:false}function I(e){return e.filter(Boolean)}function U(e,t){let r={},s={},d={};for(let i of Object.keys(e)){if(!(i in t)){s[i]=e[i];continue}Object.is(e[i],t[i])||(d[i]={from:e[i],to:t[i]});}for(let i of Object.keys(t))i in e||(r[i]=t[i]);return {added:r,removed:s,changed:d}}function W(e,t){try{return JSON.parse(e)}catch{return t}}exports.compact=I;exports.configureDebug=K;exports.createSanitizer=T;exports.diff=U;exports.getDebugOptions=A;exports.isEmpty=q;exports.omit=V;exports.pick=L;exports.resetDebug=S;exports.safeParse=W;exports.sanitize=w;exports.sanitizeWith=F;//# sourceMappingURL=index.cjs.map
|
|
165
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":["out"],"mappings":"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","file":"index.cjs","sourcesContent":["export type DropPreset =\n | \"null\"\n | \"undefined\"\n | \"emptyString\"\n | \"whitespaceString\"\n | \"dash\"\n | \"nan\";\n\nexport type KeyPath = Array<string | number>;\n\nexport type SanitizeOptions = {\n deep?: boolean;\n trimStrings?: boolean;\n cleanArrays?: boolean;\n drop?: DropPreset[];\n keepKeys?: string[];\n dropKeys?: string[];\n dropValues?: unknown[];\n /**\n * Always keep these paths (even if value is droppable).\n * Supports \"a.b.c\" or [\"a\",\"b\",\"c\"].\n */\n keepPaths?: Array<string | KeyPath>;\n /**\n * Always drop these paths (even if value is meaningful).\n * Supports \"a.b.c\" or [\"a\",\"b\",\"c\"].\n */\n dropPaths?: Array<string | KeyPath>;\n shouldDrop?: (value: unknown, keyPath: KeyPath) => boolean;\n /**\n * Drop objects that become empty after sanitizing.\n * Default: false\n */\n dropEmptyObjects?: boolean;\n\n /**\n * Drop arrays that become empty after sanitizing.\n * Default: false\n */\n dropEmptyArrays?: boolean;\n};\n\nconst DEFAULT_DROP: DropPreset[] = [\n \"undefined\",\n \"null\",\n \"emptyString\",\n \"whitespaceString\",\n];\n\nconst DEFAULT_OPTIONS = {\n deep: true,\n trimStrings: true,\n cleanArrays: true,\n dropEmptyObjects: false,\n dropEmptyArrays: false,\n drop: DEFAULT_DROP,\n} satisfies Required<\n Pick<\n SanitizeOptions,\n | \"deep\"\n | \"trimStrings\"\n | \"cleanArrays\"\n | \"dropEmptyObjects\"\n | \"dropEmptyArrays\"\n >\n> & { drop: DropPreset[] };\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (value === null || typeof value !== \"object\") return false;\n const proto = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n}\n\nfunction normalizeValue(value: unknown, opts: typeof DEFAULT_OPTIONS) {\n if (typeof value === \"string\" && opts.trimStrings) {\n return value.trim();\n }\n return value;\n}\n\nfunction shouldDropPreset(value: unknown, drop: DropPreset[]): boolean {\n for (const d of drop) {\n switch (d) {\n case \"undefined\":\n if (value === undefined) return true;\n break;\n case \"null\":\n if (value === null) return true;\n break;\n case \"emptyString\":\n if (value === \"\") return true;\n break;\n case \"whitespaceString\":\n // only matters if trimStrings is false; but still safe:\n if (typeof value === \"string\" && value.trim() === \"\") return true;\n break;\n case \"dash\":\n if (value === \"-\") return true;\n break;\n case \"nan\":\n if (typeof value === \"number\" && Number.isNaN(value)) return true;\n break;\n }\n }\n return false;\n}\n\nfunction shouldDropExact(value: unknown, exactValues?: unknown[]): boolean {\n if (!exactValues || exactValues.length === 0) return false;\n for (const v of exactValues) {\n if (Object.is(value, v)) return true;\n }\n return false;\n}\n\nfunction hasKey(list: string[] | undefined, key: string): boolean {\n return !!list && list.includes(key);\n}\n\nfunction toKeyPath(path: string | KeyPath): KeyPath {\n if (Array.isArray(path)) return path;\n if (path.trim() === \"\") return [];\n return path.split(\".\").map((seg) => {\n const n = Number(seg);\n return Number.isInteger(n) && String(n) === seg ? n : seg;\n });\n}\n\nfunction pathEquals(a: KeyPath, b: KeyPath): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false;\n }\n return true;\n}\n\nfunction hasPath(list: Array<string | KeyPath> | undefined, path: KeyPath): boolean {\n if (!list || list.length === 0) return false;\n for (const item of list) {\n if (pathEquals(toKeyPath(item), path)) return true;\n }\n return false;\n}\n\nfunction sanitizeAny(\n input: unknown,\n options: typeof DEFAULT_OPTIONS & SanitizeOptions,\n path: KeyPath,\n): unknown {\n const normalized = normalizeValue(input, options);\n\n // Path-based overrides (highest priority)\n if (hasPath(options.dropPaths, path)) return undefined;\n\n const isKeptPath = hasPath(options.keepPaths, path);\n\n if (!isKeptPath) {\n if (shouldDropPreset(normalized, options.drop)) return undefined;\n if (shouldDropExact(normalized, options.dropValues)) return undefined;\n if (options.shouldDrop?.(normalized, path)) return undefined;\n }\n\n if (Array.isArray(normalized)) {\n if (!options.cleanArrays) return normalized.slice();\n const out: unknown[] = [];\n for (let i = 0; i < normalized.length; i++) {\n const next = sanitizeAny(normalized[i], options, path.concat(i));\n if (next !== undefined) out.push(next);\n }\n if (options.dropEmptyArrays && out.length === 0) return undefined;\n return out;\n }\n\n if (isPlainObject(normalized)) {\n if (!options.deep) {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(normalized)) {\n if (hasKey(options.dropKeys, k)) continue;\n if (hasKey(options.keepKeys, k)) {\n out[k] = v;\n continue;\n }\n const next = sanitizeAny(v, options, path.concat(k));\n if (next !== undefined) out[k] = next;\n }\n if (options.dropEmptyObjects && Object.keys(out).length === 0)\n return undefined;\n return out;\n }\n\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(normalized)) {\n if (hasKey(options.dropKeys, k)) continue;\n\n if (hasKey(options.keepKeys, k)) {\n out[k] = v;\n continue;\n }\n\n const next = sanitizeAny(v, options, path.concat(k));\n if (next !== undefined) out[k] = next;\n }\n if (options.dropEmptyObjects && Object.keys(out).length === 0)\n return undefined;\n return out;\n }\n\n return normalized;\n}\n\nexport function sanitize<T>(payload: T, options: SanitizeOptions = {}): T {\n const merged = {\n ...DEFAULT_OPTIONS,\n ...options,\n drop: options.drop ?? DEFAULT_OPTIONS.drop,\n };\n\n const result = sanitizeAny(\n payload,\n merged as typeof DEFAULT_OPTIONS & SanitizeOptions,\n [],\n );\n\n if (result === undefined) {\n if (isPlainObject(payload)) return {} as T;\n if (Array.isArray(payload)) return [] as T;\n return payload;\n }\n\n return result as T;\n}\n\ntype SanitizerFn = {\n <T>(payload: T, options?: SanitizeOptions): T;\n with: (baseOptions?: SanitizeOptions) => ReturnType<typeof createSanitizer>;\n};\n\nexport const createSanitizer = (baseOptions: SanitizeOptions = {}) => {\n return <T>(payload: T, options: SanitizeOptions = {}) =>\n sanitize(payload, { ...baseOptions, ...options });\n};\n\n(sanitize as SanitizerFn).with = (baseOptions: SanitizeOptions = {}) =>\n createSanitizer(baseOptions);\n\nexport const sanitizeWith = (sanitize as SanitizerFn).with;\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/core/circular.ts","../src/core/debug.ts","../src/core/guards.ts","../src/core/path.ts","../src/core/presets.ts","../src/core/sanitize.ts","../src/utils/pick.ts","../src/utils/omit.ts","../src/utils/isEmpty.ts","../src/utils/compact.ts","../src/utils/diff.ts","../src/utils/safeParse.ts"],"names":["createCircularTracker","seen","value","globalDebugOptions","configureDebug","options","getDebugOptions","resetDebug","resolveDebugOptions","opts","defaultLogger","event","emitDebug","resolved","isPlainObject","proto","assert","condition","message","toKeyPath","path","seg","n","pathEquals","a","b","i","hasPath","list","item","DEFAULT_DROP","shouldDropPreset","drop","d","DEFAULT_OPTIONS","normalizeValue","trim","shouldDropExact","exactValues","v","hasKey","key","validateStrict","sanitizeImpl","payload","merged","circular","walk","input","normalized","out","next","k","result","createSanitizer","baseOptions","sanitize","sanitizeWith","pick","obj","keys","omit","isEmpty","compact","arr","diff","before","after","added","removed","changed","safeParse","json","fallback"],"mappings":"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","file":"index.cjs","sourcesContent":["export function createCircularTracker() {\n const seen = new WeakSet<object>();\n\n return {\n has(value: object) {\n return seen.has(value);\n },\n add(value: object) {\n seen.add(value);\n },\n };\n}\n","import type { KeyPath } from \"./path\";\n\nexport type DebugEventType =\n | \"normalize\"\n | \"drop\"\n | \"keep\"\n | \"empty-object\"\n | \"empty-array\"\n | \"circular-skip\";\n\nexport interface DebugEvent {\n type: DebugEventType;\n path: KeyPath;\n original: unknown;\n result?: unknown;\n}\n\nexport type DebugOptions = {\n debug?: boolean;\n logger?: (event: DebugEvent) => void;\n};\n\nlet globalDebugOptions: DebugOptions = {};\n\nexport function configureDebug(options: DebugOptions = {}): void {\n globalDebugOptions = { ...globalDebugOptions, ...options };\n}\n\nexport function getDebugOptions(): DebugOptions {\n return globalDebugOptions;\n}\n\nexport function resetDebug(): void {\n globalDebugOptions = {};\n}\n\nfunction resolveDebugOptions(opts: DebugOptions): Required<DebugOptions> {\n return {\n debug: opts.debug ?? globalDebugOptions.debug ?? false,\n logger: opts.logger ?? globalDebugOptions.logger ?? defaultLogger,\n };\n}\n\nfunction defaultLogger(event: DebugEvent): void {\n const c = (globalThis as { console?: { log: (...args: unknown[]) => void } })\n .console;\n c?.log(\"[payload-sanitizer]\", event);\n}\n\nexport function emitDebug(opts: DebugOptions, event: DebugEvent): void {\n const resolved = resolveDebugOptions(opts);\n if (!resolved.debug) return;\n resolved.logger(event);\n}\n","export function isPlainObject(value: unknown): value is Record<string, unknown> {\n if (value === null || typeof value !== \"object\") return false;\n const proto = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n}\n\nexport function assert(condition: unknown, message: string): asserts condition {\n if (!condition) {\n throw new Error(`[payload-sanitizer] ${message}`);\n }\n}\n","export type KeyPath = Array<string | number>;\n\nexport function toKeyPath(path: string | KeyPath): KeyPath {\n if (Array.isArray(path)) return path;\n if (path.trim() === \"\") return [];\n return path.split(\".\").map((seg) => {\n const n = Number(seg);\n return Number.isInteger(n) && String(n) === seg ? n : seg;\n });\n}\n\nexport function pathEquals(a: KeyPath, b: KeyPath): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false;\n }\n return true;\n}\n\nexport function hasPath(\n list: Array<string | KeyPath> | undefined,\n path: KeyPath,\n): boolean {\n if (!list || list.length === 0) return false;\n for (const item of list) {\n if (pathEquals(toKeyPath(item), path)) return true;\n }\n return false;\n}\n","export type DropPreset =\n | \"null\"\n | \"undefined\"\n | \"emptyString\"\n | \"whitespaceString\"\n | \"dash\"\n | \"nan\";\n\nexport const DEFAULT_DROP: DropPreset[] = [\n \"undefined\",\n \"null\",\n \"emptyString\",\n \"whitespaceString\",\n];\n\nexport function shouldDropPreset(value: unknown, drop: DropPreset[]): boolean {\n for (const d of drop) {\n switch (d) {\n case \"undefined\":\n if (value === undefined) return true;\n break;\n case \"null\":\n if (value === null) return true;\n break;\n case \"emptyString\":\n if (value === \"\") return true;\n break;\n case \"whitespaceString\":\n if (typeof value === \"string\" && value.trim() === \"\") return true;\n break;\n case \"dash\":\n if (value === \"-\") return true;\n break;\n case \"nan\":\n if (typeof value === \"number\" && Number.isNaN(value)) return true;\n break;\n }\n }\n return false;\n}\n","import { createCircularTracker } from \"./circular\";\nimport type { DebugOptions } from \"./debug\";\nimport { emitDebug } from \"./debug\";\nimport { assert, isPlainObject } from \"./guards\";\nimport { hasPath, type KeyPath } from \"./path\";\nimport { DEFAULT_DROP, type DropPreset, shouldDropPreset } from \"./presets\";\n\nexport type SanitizeOptions = DebugOptions & {\n deep?: boolean;\n trimStrings?: boolean;\n cleanArrays?: boolean;\n drop?: DropPreset[];\n keepKeys?: string[];\n dropKeys?: string[];\n dropValues?: unknown[];\n keepPaths?: Array<string | KeyPath>;\n dropPaths?: Array<string | KeyPath>;\n shouldDrop?: (value: unknown, keyPath: KeyPath) => boolean;\n dropEmptyObjects?: boolean;\n dropEmptyArrays?: boolean;\n strict?: boolean;\n};\n\nconst DEFAULT_OPTIONS = {\n deep: true,\n trimStrings: true,\n cleanArrays: true,\n dropEmptyObjects: false,\n dropEmptyArrays: false,\n drop: DEFAULT_DROP,\n} satisfies Required<\n Pick<\n SanitizeOptions,\n | \"deep\"\n | \"trimStrings\"\n | \"cleanArrays\"\n | \"dropEmptyObjects\"\n | \"dropEmptyArrays\"\n >\n> & { drop: DropPreset[] };\n\nfunction normalizeValue(value: unknown, trim: boolean): unknown {\n if (typeof value === \"string\" && trim) {\n return value.trim();\n }\n return value;\n}\n\nfunction shouldDropExact(value: unknown, exactValues?: unknown[]): boolean {\n if (!exactValues || exactValues.length === 0) return false;\n for (const v of exactValues) {\n if (Object.is(value, v)) return true;\n }\n return false;\n}\n\nfunction hasKey(list: string[] | undefined, key: string): boolean {\n return !!list && list.includes(key);\n}\n\nfunction validateStrict(options: SanitizeOptions): void {\n assert(\n options.drop === undefined || Array.isArray(options.drop),\n \"`drop` must be an array\",\n );\n assert(\n options.keepKeys === undefined || Array.isArray(options.keepKeys),\n \"`keepKeys` must be an array\",\n );\n assert(\n options.dropKeys === undefined || Array.isArray(options.dropKeys),\n \"`dropKeys` must be an array\",\n );\n assert(\n options.dropValues === undefined || Array.isArray(options.dropValues),\n \"`dropValues` must be an array\",\n );\n assert(\n options.keepPaths === undefined || Array.isArray(options.keepPaths),\n \"`keepPaths` must be an array\",\n );\n assert(\n options.dropPaths === undefined || Array.isArray(options.dropPaths),\n \"`dropPaths` must be an array\",\n );\n assert(\n options.shouldDrop === undefined || typeof options.shouldDrop === \"function\",\n \"`shouldDrop` must be a function\",\n );\n}\n\nfunction sanitizeImpl<T>(payload: T, options: SanitizeOptions = {}): T {\n const merged = {\n ...DEFAULT_OPTIONS,\n ...options,\n drop: options.drop ?? DEFAULT_OPTIONS.drop,\n };\n\n if (merged.strict) {\n validateStrict(merged);\n }\n\n const circular = createCircularTracker();\n\n function walk(input: unknown, path: KeyPath): unknown {\n const normalized = normalizeValue(input, merged.trimStrings);\n\n emitDebug(merged, {\n type: \"normalize\",\n path,\n original: input,\n result: normalized,\n });\n\n if (hasPath(merged.dropPaths, path)) {\n emitDebug(merged, { type: \"drop\", path, original: normalized });\n return undefined;\n }\n\n const isKeptPath = hasPath(merged.keepPaths, path);\n\n if (isKeptPath) {\n emitDebug(merged, { type: \"keep\", path, original: normalized });\n } else {\n if (shouldDropPreset(normalized, merged.drop)) {\n emitDebug(merged, { type: \"drop\", path, original: normalized });\n return undefined;\n }\n\n if (shouldDropExact(normalized, merged.dropValues)) {\n emitDebug(merged, { type: \"drop\", path, original: normalized });\n return undefined;\n }\n\n if (merged.shouldDrop?.(normalized, path)) {\n emitDebug(merged, { type: \"drop\", path, original: normalized });\n return undefined;\n }\n }\n\n if (Array.isArray(normalized)) {\n if (circular.has(normalized)) {\n emitDebug(merged, { type: \"circular-skip\", path, original: normalized });\n return normalized;\n }\n circular.add(normalized);\n\n if (!merged.cleanArrays) return normalized.slice();\n\n const out: unknown[] = [];\n for (let i = 0; i < normalized.length; i++) {\n const next = walk(normalized[i], path.concat(i));\n if (next !== undefined) out.push(next);\n }\n\n if (merged.dropEmptyArrays && out.length === 0) {\n emitDebug(merged, { type: \"empty-array\", path, original: normalized });\n return undefined;\n }\n\n return out;\n }\n\n if (isPlainObject(normalized)) {\n if (circular.has(normalized)) {\n emitDebug(merged, { type: \"circular-skip\", path, original: normalized });\n return normalized;\n }\n circular.add(normalized);\n\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(normalized)) {\n if (hasKey(merged.dropKeys, k)) continue;\n\n if (hasKey(merged.keepKeys, k)) {\n emitDebug(merged, { type: \"keep\", path: path.concat(k), original: v });\n out[k] = v;\n continue;\n }\n\n if (!merged.deep && isPlainObject(v)) {\n out[k] = v;\n continue;\n }\n\n const next = walk(v, path.concat(k));\n if (next !== undefined) out[k] = next;\n }\n\n if (merged.dropEmptyObjects && Object.keys(out).length === 0) {\n emitDebug(merged, { type: \"empty-object\", path, original: normalized });\n return undefined;\n }\n\n return out;\n }\n\n return normalized;\n }\n\n const result = walk(payload, []);\n\n if (result === undefined) {\n if (isPlainObject(payload)) return {} as T;\n if (Array.isArray(payload)) return [] as T;\n return payload;\n }\n\n return result as T;\n}\n\ntype SanitizerFn = {\n <T>(payload: T, options?: SanitizeOptions): T;\n with: (baseOptions?: SanitizeOptions) => ReturnType<typeof createSanitizer>;\n};\n\nexport const createSanitizer = (baseOptions: SanitizeOptions = {}) => {\n return <T>(payload: T, options: SanitizeOptions = {}) =>\n sanitizeImpl(payload, { ...baseOptions, ...options });\n};\n\nexport const sanitize: SanitizerFn = Object.assign(sanitizeImpl, {\n with: (baseOptions: SanitizeOptions = {}) => createSanitizer(baseOptions),\n});\n\nexport const sanitizeWith = sanitize.with;\n","export function pick<T extends object, K extends keyof T>(\n obj: T,\n keys: K[],\n): Pick<T, K> {\n const out = {} as Pick<T, K>;\n for (const k of keys) {\n if (k in obj) out[k] = obj[k];\n }\n return out;\n}\n","export function omit<T extends object, K extends keyof T>(\n obj: T,\n keys: K[],\n): Omit<T, K> {\n const out = { ...obj };\n for (const k of keys) {\n delete out[k];\n }\n return out;\n}\n","export function isEmpty(value: unknown): boolean {\n if (Array.isArray(value)) return value.length === 0;\n if (value && typeof value === \"object\") {\n return Object.keys(value as object).length === 0;\n }\n return false;\n}\n","export function compact<T>(arr: T[]): T[] {\n return arr.filter(Boolean);\n}\n","export type ChangedEntry = {\n from: unknown;\n to: unknown;\n};\n\nexport type DiffResult = {\n added: Record<string, unknown>;\n removed: Record<string, unknown>;\n changed: Record<string, ChangedEntry>;\n};\n\nexport function diff(\n before: Record<string, unknown>,\n after: Record<string, unknown>,\n): DiffResult {\n const added: Record<string, unknown> = {};\n const removed: Record<string, unknown> = {};\n const changed: Record<string, ChangedEntry> = {};\n\n for (const key of Object.keys(before)) {\n if (!(key in after)) {\n removed[key] = before[key];\n continue;\n }\n\n if (!Object.is(before[key], after[key])) {\n changed[key] = { from: before[key], to: after[key] };\n }\n }\n\n for (const key of Object.keys(after)) {\n if (!(key in before)) {\n added[key] = after[key];\n }\n }\n\n return { added, removed, changed };\n}\n","export function safeParse<T>(json: string, fallback?: T): T | undefined {\n try {\n return JSON.parse(json) as T;\n } catch {\n return fallback;\n }\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,23 @@
|
|
|
1
|
-
type DropPreset = "null" | "undefined" | "emptyString" | "whitespaceString" | "dash" | "nan";
|
|
2
1
|
type KeyPath = Array<string | number>;
|
|
3
|
-
|
|
2
|
+
|
|
3
|
+
type DebugEventType = "normalize" | "drop" | "keep" | "empty-object" | "empty-array" | "circular-skip";
|
|
4
|
+
interface DebugEvent {
|
|
5
|
+
type: DebugEventType;
|
|
6
|
+
path: KeyPath;
|
|
7
|
+
original: unknown;
|
|
8
|
+
result?: unknown;
|
|
9
|
+
}
|
|
10
|
+
type DebugOptions = {
|
|
11
|
+
debug?: boolean;
|
|
12
|
+
logger?: (event: DebugEvent) => void;
|
|
13
|
+
};
|
|
14
|
+
declare function configureDebug(options?: DebugOptions): void;
|
|
15
|
+
declare function getDebugOptions(): DebugOptions;
|
|
16
|
+
declare function resetDebug(): void;
|
|
17
|
+
|
|
18
|
+
type DropPreset = "null" | "undefined" | "emptyString" | "whitespaceString" | "dash" | "nan";
|
|
19
|
+
|
|
20
|
+
type SanitizeOptions = DebugOptions & {
|
|
4
21
|
deep?: boolean;
|
|
5
22
|
trimStrings?: boolean;
|
|
6
23
|
cleanArrays?: boolean;
|
|
@@ -8,30 +25,40 @@ type SanitizeOptions = {
|
|
|
8
25
|
keepKeys?: string[];
|
|
9
26
|
dropKeys?: string[];
|
|
10
27
|
dropValues?: unknown[];
|
|
11
|
-
/**
|
|
12
|
-
* Always keep these paths (even if value is droppable).
|
|
13
|
-
* Supports "a.b.c" or ["a","b","c"].
|
|
14
|
-
*/
|
|
15
28
|
keepPaths?: Array<string | KeyPath>;
|
|
16
|
-
/**
|
|
17
|
-
* Always drop these paths (even if value is meaningful).
|
|
18
|
-
* Supports "a.b.c" or ["a","b","c"].
|
|
19
|
-
*/
|
|
20
29
|
dropPaths?: Array<string | KeyPath>;
|
|
21
30
|
shouldDrop?: (value: unknown, keyPath: KeyPath) => boolean;
|
|
22
|
-
/**
|
|
23
|
-
* Drop objects that become empty after sanitizing.
|
|
24
|
-
* Default: false
|
|
25
|
-
*/
|
|
26
31
|
dropEmptyObjects?: boolean;
|
|
27
|
-
/**
|
|
28
|
-
* Drop arrays that become empty after sanitizing.
|
|
29
|
-
* Default: false
|
|
30
|
-
*/
|
|
31
32
|
dropEmptyArrays?: boolean;
|
|
33
|
+
strict?: boolean;
|
|
34
|
+
};
|
|
35
|
+
type SanitizerFn = {
|
|
36
|
+
<T>(payload: T, options?: SanitizeOptions): T;
|
|
37
|
+
with: (baseOptions?: SanitizeOptions) => ReturnType<typeof createSanitizer>;
|
|
32
38
|
};
|
|
33
|
-
declare function sanitize<T>(payload: T, options?: SanitizeOptions): T;
|
|
34
39
|
declare const createSanitizer: (baseOptions?: SanitizeOptions) => <T>(payload: T, options?: SanitizeOptions) => T;
|
|
40
|
+
declare const sanitize: SanitizerFn;
|
|
35
41
|
declare const sanitizeWith: (baseOptions?: SanitizeOptions) => ReturnType<typeof createSanitizer>;
|
|
36
42
|
|
|
37
|
-
|
|
43
|
+
declare function pick<T extends object, K extends keyof T>(obj: T, keys: K[]): Pick<T, K>;
|
|
44
|
+
|
|
45
|
+
declare function omit<T extends object, K extends keyof T>(obj: T, keys: K[]): Omit<T, K>;
|
|
46
|
+
|
|
47
|
+
declare function isEmpty(value: unknown): boolean;
|
|
48
|
+
|
|
49
|
+
declare function compact<T>(arr: T[]): T[];
|
|
50
|
+
|
|
51
|
+
type ChangedEntry = {
|
|
52
|
+
from: unknown;
|
|
53
|
+
to: unknown;
|
|
54
|
+
};
|
|
55
|
+
type DiffResult = {
|
|
56
|
+
added: Record<string, unknown>;
|
|
57
|
+
removed: Record<string, unknown>;
|
|
58
|
+
changed: Record<string, ChangedEntry>;
|
|
59
|
+
};
|
|
60
|
+
declare function diff(before: Record<string, unknown>, after: Record<string, unknown>): DiffResult;
|
|
61
|
+
|
|
62
|
+
declare function safeParse<T>(json: string, fallback?: T): T | undefined;
|
|
63
|
+
|
|
64
|
+
export { type ChangedEntry, type DebugEvent, type DebugEventType, type DebugOptions, type DiffResult, type DropPreset, type KeyPath, type SanitizeOptions, compact, configureDebug, createSanitizer, diff, getDebugOptions, isEmpty, omit, pick, resetDebug, safeParse, sanitize, sanitizeWith };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,23 @@
|
|
|
1
|
-
type DropPreset = "null" | "undefined" | "emptyString" | "whitespaceString" | "dash" | "nan";
|
|
2
1
|
type KeyPath = Array<string | number>;
|
|
3
|
-
|
|
2
|
+
|
|
3
|
+
type DebugEventType = "normalize" | "drop" | "keep" | "empty-object" | "empty-array" | "circular-skip";
|
|
4
|
+
interface DebugEvent {
|
|
5
|
+
type: DebugEventType;
|
|
6
|
+
path: KeyPath;
|
|
7
|
+
original: unknown;
|
|
8
|
+
result?: unknown;
|
|
9
|
+
}
|
|
10
|
+
type DebugOptions = {
|
|
11
|
+
debug?: boolean;
|
|
12
|
+
logger?: (event: DebugEvent) => void;
|
|
13
|
+
};
|
|
14
|
+
declare function configureDebug(options?: DebugOptions): void;
|
|
15
|
+
declare function getDebugOptions(): DebugOptions;
|
|
16
|
+
declare function resetDebug(): void;
|
|
17
|
+
|
|
18
|
+
type DropPreset = "null" | "undefined" | "emptyString" | "whitespaceString" | "dash" | "nan";
|
|
19
|
+
|
|
20
|
+
type SanitizeOptions = DebugOptions & {
|
|
4
21
|
deep?: boolean;
|
|
5
22
|
trimStrings?: boolean;
|
|
6
23
|
cleanArrays?: boolean;
|
|
@@ -8,30 +25,40 @@ type SanitizeOptions = {
|
|
|
8
25
|
keepKeys?: string[];
|
|
9
26
|
dropKeys?: string[];
|
|
10
27
|
dropValues?: unknown[];
|
|
11
|
-
/**
|
|
12
|
-
* Always keep these paths (even if value is droppable).
|
|
13
|
-
* Supports "a.b.c" or ["a","b","c"].
|
|
14
|
-
*/
|
|
15
28
|
keepPaths?: Array<string | KeyPath>;
|
|
16
|
-
/**
|
|
17
|
-
* Always drop these paths (even if value is meaningful).
|
|
18
|
-
* Supports "a.b.c" or ["a","b","c"].
|
|
19
|
-
*/
|
|
20
29
|
dropPaths?: Array<string | KeyPath>;
|
|
21
30
|
shouldDrop?: (value: unknown, keyPath: KeyPath) => boolean;
|
|
22
|
-
/**
|
|
23
|
-
* Drop objects that become empty after sanitizing.
|
|
24
|
-
* Default: false
|
|
25
|
-
*/
|
|
26
31
|
dropEmptyObjects?: boolean;
|
|
27
|
-
/**
|
|
28
|
-
* Drop arrays that become empty after sanitizing.
|
|
29
|
-
* Default: false
|
|
30
|
-
*/
|
|
31
32
|
dropEmptyArrays?: boolean;
|
|
33
|
+
strict?: boolean;
|
|
34
|
+
};
|
|
35
|
+
type SanitizerFn = {
|
|
36
|
+
<T>(payload: T, options?: SanitizeOptions): T;
|
|
37
|
+
with: (baseOptions?: SanitizeOptions) => ReturnType<typeof createSanitizer>;
|
|
32
38
|
};
|
|
33
|
-
declare function sanitize<T>(payload: T, options?: SanitizeOptions): T;
|
|
34
39
|
declare const createSanitizer: (baseOptions?: SanitizeOptions) => <T>(payload: T, options?: SanitizeOptions) => T;
|
|
40
|
+
declare const sanitize: SanitizerFn;
|
|
35
41
|
declare const sanitizeWith: (baseOptions?: SanitizeOptions) => ReturnType<typeof createSanitizer>;
|
|
36
42
|
|
|
37
|
-
|
|
43
|
+
declare function pick<T extends object, K extends keyof T>(obj: T, keys: K[]): Pick<T, K>;
|
|
44
|
+
|
|
45
|
+
declare function omit<T extends object, K extends keyof T>(obj: T, keys: K[]): Omit<T, K>;
|
|
46
|
+
|
|
47
|
+
declare function isEmpty(value: unknown): boolean;
|
|
48
|
+
|
|
49
|
+
declare function compact<T>(arr: T[]): T[];
|
|
50
|
+
|
|
51
|
+
type ChangedEntry = {
|
|
52
|
+
from: unknown;
|
|
53
|
+
to: unknown;
|
|
54
|
+
};
|
|
55
|
+
type DiffResult = {
|
|
56
|
+
added: Record<string, unknown>;
|
|
57
|
+
removed: Record<string, unknown>;
|
|
58
|
+
changed: Record<string, ChangedEntry>;
|
|
59
|
+
};
|
|
60
|
+
declare function diff(before: Record<string, unknown>, after: Record<string, unknown>): DiffResult;
|
|
61
|
+
|
|
62
|
+
declare function safeParse<T>(json: string, fallback?: T): T | undefined;
|
|
63
|
+
|
|
64
|
+
export { type ChangedEntry, type DebugEvent, type DebugEventType, type DebugOptions, type DiffResult, type DropPreset, type KeyPath, type SanitizeOptions, compact, configureDebug, createSanitizer, diff, getDebugOptions, isEmpty, omit, pick, resetDebug, safeParse, sanitize, sanitizeWith };
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var PayloadSanitizer=(function(exports){'use strict';function k(){let e=new WeakSet;return {has(t){return e.has(t)},add(t){e.add(t);}}}var y={};function K(e={}){y={...y,...e};}function A(){return y}function S(){y={};}function E(e){return {debug:e.debug??y.debug??false,logger:e.logger??y.logger??z}}function z(e){globalThis.console?.log("[payload-sanitizer]",e);}function a(e,t){let r=E(e);r.debug&&r.logger(t);}function g(e){if(e===null||typeof e!="object")return false;let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null}function c(e,t){if(!e)throw new Error(`[payload-sanitizer] ${t}`)}function j(e){return Array.isArray(e)?e:e.trim()===""?[]:e.split(".").map(t=>{let r=Number(t);return Number.isInteger(r)&&String(r)===t?r:t})}function R(e,t){if(e.length!==t.length)return false;for(let r=0;r<e.length;r++)if(e[r]!==t[r])return false;return true}function l(e,t){if(!e||e.length===0)return false;for(let r of e)if(R(j(r),t))return true;return false}var h=["undefined","null","emptyString","whitespaceString"];function D(e,t){for(let r of t)switch(r){case "undefined":if(e===void 0)return true;break;case "null":if(e===null)return true;break;case "emptyString":if(e==="")return true;break;case "whitespaceString":if(typeof e=="string"&&e.trim()==="")return true;break;case "dash":if(e==="-")return true;break;case "nan":if(typeof e=="number"&&Number.isNaN(e))return true;break}return false}var P={deep:true,trimStrings:true,cleanArrays:true,dropEmptyObjects:false,dropEmptyArrays:false,drop:h};function v(e,t){return typeof e=="string"&&t?e.trim():e}function N(e,t){if(!t||t.length===0)return false;for(let r of t)if(Object.is(e,r))return true;return false}function O(e,t){return !!e&&e.includes(t)}function C(e){c(e.drop===void 0||Array.isArray(e.drop),"`drop` must be an array"),c(e.keepKeys===void 0||Array.isArray(e.keepKeys),"`keepKeys` must be an array"),c(e.dropKeys===void 0||Array.isArray(e.dropKeys),"`dropKeys` must be an array"),c(e.dropValues===void 0||Array.isArray(e.dropValues),"`dropValues` must be an array"),c(e.keepPaths===void 0||Array.isArray(e.keepPaths),"`keepPaths` must be an array"),c(e.dropPaths===void 0||Array.isArray(e.dropPaths),"`dropPaths` must be an array"),c(e.shouldDrop===void 0||typeof e.shouldDrop=="function","`shouldDrop` must be a function");}function x(e,t={}){let r={...P,...t,drop:t.drop??P.drop};r.strict&&C(r);let s=k();function d(b,o){let n=v(b,r.trimStrings);if(a(r,{type:"normalize",path:o,original:b,result:n}),l(r.dropPaths,o)){a(r,{type:"drop",path:o,original:n});return}if(l(r.keepPaths,o))a(r,{type:"keep",path:o,original:n});else {if(D(n,r.drop)){a(r,{type:"drop",path:o,original:n});return}if(N(n,r.dropValues)){a(r,{type:"drop",path:o,original:n});return}if(r.shouldDrop?.(n,o)){a(r,{type:"drop",path:o,original:n});return}}if(Array.isArray(n)){if(s.has(n))return a(r,{type:"circular-skip",path:o,original:n}),n;if(s.add(n),!r.cleanArrays)return n.slice();let p=[];for(let u=0;u<n.length;u++){let f=d(n[u],o.concat(u));f!==void 0&&p.push(f);}if(r.dropEmptyArrays&&p.length===0){a(r,{type:"empty-array",path:o,original:n});return}return p}if(g(n)){if(s.has(n))return a(r,{type:"circular-skip",path:o,original:n}),n;s.add(n);let p={};for(let[u,f]of Object.entries(n)){if(O(r.dropKeys,u))continue;if(O(r.keepKeys,u)){a(r,{type:"keep",path:o.concat(u),original:f}),p[u]=f;continue}if(!r.deep&&g(f)){p[u]=f;continue}let m=d(f,o.concat(u));m!==void 0&&(p[u]=m);}if(r.dropEmptyObjects&&Object.keys(p).length===0){a(r,{type:"empty-object",path:o,original:n});return}return p}return n}let i=d(e,[]);return i===void 0?g(e)?{}:Array.isArray(e)?[]:e:i}var T=(e={})=>(t,r={})=>x(t,{...e,...r}),w=Object.assign(x,{with:(e={})=>T(e)}),F=w.with;function L(e,t){let r={};for(let s of t)s in e&&(r[s]=e[s]);return r}function V(e,t){let r={...e};for(let s of t)delete r[s];return r}function q(e){return Array.isArray(e)?e.length===0:e&&typeof e=="object"?Object.keys(e).length===0:false}function I(e){return e.filter(Boolean)}function U(e,t){let r={},s={},d={};for(let i of Object.keys(e)){if(!(i in t)){s[i]=e[i];continue}Object.is(e[i],t[i])||(d[i]={from:e[i],to:t[i]});}for(let i of Object.keys(t))i in e||(r[i]=t[i]);return {added:r,removed:s,changed:d}}function W(e,t){try{return JSON.parse(e)}catch{return t}}exports.compact=I;exports.configureDebug=K;exports.createSanitizer=T;exports.diff=U;exports.getDebugOptions=A;exports.isEmpty=q;exports.omit=V;exports.pick=L;exports.resetDebug=S;exports.safeParse=W;exports.sanitize=w;exports.sanitizeWith=F;return exports;})({});//# sourceMappingURL=index.global.js.map
|
|
2
|
+
//# sourceMappingURL=index.global.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/circular.ts","../src/core/debug.ts","../src/core/guards.ts","../src/core/path.ts","../src/core/presets.ts","../src/core/sanitize.ts","../src/utils/pick.ts","../src/utils/omit.ts","../src/utils/isEmpty.ts","../src/utils/compact.ts","../src/utils/diff.ts","../src/utils/safeParse.ts"],"names":["createCircularTracker","seen","value","globalDebugOptions","configureDebug","options","getDebugOptions","resetDebug","resolveDebugOptions","opts","defaultLogger","event","emitDebug","resolved","isPlainObject","proto","assert","condition","message","toKeyPath","path","seg","n","pathEquals","a","b","i","hasPath","list","item","DEFAULT_DROP","shouldDropPreset","drop","d","DEFAULT_OPTIONS","normalizeValue","trim","shouldDropExact","exactValues","v","hasKey","key","validateStrict","sanitizeImpl","payload","merged","circular","walk","input","normalized","out","next","k","result","createSanitizer","baseOptions","sanitize","sanitizeWith","pick","obj","keys","omit","isEmpty","compact","arr","diff","before","after","added","removed","changed","safeParse","json","fallback"],"mappings":"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","file":"index.global.js","sourcesContent":["export function createCircularTracker() {\n const seen = new WeakSet<object>();\n\n return {\n has(value: object) {\n return seen.has(value);\n },\n add(value: object) {\n seen.add(value);\n },\n };\n}\n","import type { KeyPath } from \"./path\";\n\nexport type DebugEventType =\n | \"normalize\"\n | \"drop\"\n | \"keep\"\n | \"empty-object\"\n | \"empty-array\"\n | \"circular-skip\";\n\nexport interface DebugEvent {\n type: DebugEventType;\n path: KeyPath;\n original: unknown;\n result?: unknown;\n}\n\nexport type DebugOptions = {\n debug?: boolean;\n logger?: (event: DebugEvent) => void;\n};\n\nlet globalDebugOptions: DebugOptions = {};\n\nexport function configureDebug(options: DebugOptions = {}): void {\n globalDebugOptions = { ...globalDebugOptions, ...options };\n}\n\nexport function getDebugOptions(): DebugOptions {\n return globalDebugOptions;\n}\n\nexport function resetDebug(): void {\n globalDebugOptions = {};\n}\n\nfunction resolveDebugOptions(opts: DebugOptions): Required<DebugOptions> {\n return {\n debug: opts.debug ?? globalDebugOptions.debug ?? false,\n logger: opts.logger ?? globalDebugOptions.logger ?? defaultLogger,\n };\n}\n\nfunction defaultLogger(event: DebugEvent): void {\n const c = (globalThis as { console?: { log: (...args: unknown[]) => void } })\n .console;\n c?.log(\"[payload-sanitizer]\", event);\n}\n\nexport function emitDebug(opts: DebugOptions, event: DebugEvent): void {\n const resolved = resolveDebugOptions(opts);\n if (!resolved.debug) return;\n resolved.logger(event);\n}\n","export function isPlainObject(value: unknown): value is Record<string, unknown> {\n if (value === null || typeof value !== \"object\") return false;\n const proto = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n}\n\nexport function assert(condition: unknown, message: string): asserts condition {\n if (!condition) {\n throw new Error(`[payload-sanitizer] ${message}`);\n }\n}\n","export type KeyPath = Array<string | number>;\n\nexport function toKeyPath(path: string | KeyPath): KeyPath {\n if (Array.isArray(path)) return path;\n if (path.trim() === \"\") return [];\n return path.split(\".\").map((seg) => {\n const n = Number(seg);\n return Number.isInteger(n) && String(n) === seg ? n : seg;\n });\n}\n\nexport function pathEquals(a: KeyPath, b: KeyPath): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false;\n }\n return true;\n}\n\nexport function hasPath(\n list: Array<string | KeyPath> | undefined,\n path: KeyPath,\n): boolean {\n if (!list || list.length === 0) return false;\n for (const item of list) {\n if (pathEquals(toKeyPath(item), path)) return true;\n }\n return false;\n}\n","export type DropPreset =\n | \"null\"\n | \"undefined\"\n | \"emptyString\"\n | \"whitespaceString\"\n | \"dash\"\n | \"nan\";\n\nexport const DEFAULT_DROP: DropPreset[] = [\n \"undefined\",\n \"null\",\n \"emptyString\",\n \"whitespaceString\",\n];\n\nexport function shouldDropPreset(value: unknown, drop: DropPreset[]): boolean {\n for (const d of drop) {\n switch (d) {\n case \"undefined\":\n if (value === undefined) return true;\n break;\n case \"null\":\n if (value === null) return true;\n break;\n case \"emptyString\":\n if (value === \"\") return true;\n break;\n case \"whitespaceString\":\n if (typeof value === \"string\" && value.trim() === \"\") return true;\n break;\n case \"dash\":\n if (value === \"-\") return true;\n break;\n case \"nan\":\n if (typeof value === \"number\" && Number.isNaN(value)) return true;\n break;\n }\n }\n return false;\n}\n","import { createCircularTracker } from \"./circular\";\nimport type { DebugOptions } from \"./debug\";\nimport { emitDebug } from \"./debug\";\nimport { assert, isPlainObject } from \"./guards\";\nimport { hasPath, type KeyPath } from \"./path\";\nimport { DEFAULT_DROP, type DropPreset, shouldDropPreset } from \"./presets\";\n\nexport type SanitizeOptions = DebugOptions & {\n deep?: boolean;\n trimStrings?: boolean;\n cleanArrays?: boolean;\n drop?: DropPreset[];\n keepKeys?: string[];\n dropKeys?: string[];\n dropValues?: unknown[];\n keepPaths?: Array<string | KeyPath>;\n dropPaths?: Array<string | KeyPath>;\n shouldDrop?: (value: unknown, keyPath: KeyPath) => boolean;\n dropEmptyObjects?: boolean;\n dropEmptyArrays?: boolean;\n strict?: boolean;\n};\n\nconst DEFAULT_OPTIONS = {\n deep: true,\n trimStrings: true,\n cleanArrays: true,\n dropEmptyObjects: false,\n dropEmptyArrays: false,\n drop: DEFAULT_DROP,\n} satisfies Required<\n Pick<\n SanitizeOptions,\n | \"deep\"\n | \"trimStrings\"\n | \"cleanArrays\"\n | \"dropEmptyObjects\"\n | \"dropEmptyArrays\"\n >\n> & { drop: DropPreset[] };\n\nfunction normalizeValue(value: unknown, trim: boolean): unknown {\n if (typeof value === \"string\" && trim) {\n return value.trim();\n }\n return value;\n}\n\nfunction shouldDropExact(value: unknown, exactValues?: unknown[]): boolean {\n if (!exactValues || exactValues.length === 0) return false;\n for (const v of exactValues) {\n if (Object.is(value, v)) return true;\n }\n return false;\n}\n\nfunction hasKey(list: string[] | undefined, key: string): boolean {\n return !!list && list.includes(key);\n}\n\nfunction validateStrict(options: SanitizeOptions): void {\n assert(\n options.drop === undefined || Array.isArray(options.drop),\n \"`drop` must be an array\",\n );\n assert(\n options.keepKeys === undefined || Array.isArray(options.keepKeys),\n \"`keepKeys` must be an array\",\n );\n assert(\n options.dropKeys === undefined || Array.isArray(options.dropKeys),\n \"`dropKeys` must be an array\",\n );\n assert(\n options.dropValues === undefined || Array.isArray(options.dropValues),\n \"`dropValues` must be an array\",\n );\n assert(\n options.keepPaths === undefined || Array.isArray(options.keepPaths),\n \"`keepPaths` must be an array\",\n );\n assert(\n options.dropPaths === undefined || Array.isArray(options.dropPaths),\n \"`dropPaths` must be an array\",\n );\n assert(\n options.shouldDrop === undefined || typeof options.shouldDrop === \"function\",\n \"`shouldDrop` must be a function\",\n );\n}\n\nfunction sanitizeImpl<T>(payload: T, options: SanitizeOptions = {}): T {\n const merged = {\n ...DEFAULT_OPTIONS,\n ...options,\n drop: options.drop ?? DEFAULT_OPTIONS.drop,\n };\n\n if (merged.strict) {\n validateStrict(merged);\n }\n\n const circular = createCircularTracker();\n\n function walk(input: unknown, path: KeyPath): unknown {\n const normalized = normalizeValue(input, merged.trimStrings);\n\n emitDebug(merged, {\n type: \"normalize\",\n path,\n original: input,\n result: normalized,\n });\n\n if (hasPath(merged.dropPaths, path)) {\n emitDebug(merged, { type: \"drop\", path, original: normalized });\n return undefined;\n }\n\n const isKeptPath = hasPath(merged.keepPaths, path);\n\n if (isKeptPath) {\n emitDebug(merged, { type: \"keep\", path, original: normalized });\n } else {\n if (shouldDropPreset(normalized, merged.drop)) {\n emitDebug(merged, { type: \"drop\", path, original: normalized });\n return undefined;\n }\n\n if (shouldDropExact(normalized, merged.dropValues)) {\n emitDebug(merged, { type: \"drop\", path, original: normalized });\n return undefined;\n }\n\n if (merged.shouldDrop?.(normalized, path)) {\n emitDebug(merged, { type: \"drop\", path, original: normalized });\n return undefined;\n }\n }\n\n if (Array.isArray(normalized)) {\n if (circular.has(normalized)) {\n emitDebug(merged, { type: \"circular-skip\", path, original: normalized });\n return normalized;\n }\n circular.add(normalized);\n\n if (!merged.cleanArrays) return normalized.slice();\n\n const out: unknown[] = [];\n for (let i = 0; i < normalized.length; i++) {\n const next = walk(normalized[i], path.concat(i));\n if (next !== undefined) out.push(next);\n }\n\n if (merged.dropEmptyArrays && out.length === 0) {\n emitDebug(merged, { type: \"empty-array\", path, original: normalized });\n return undefined;\n }\n\n return out;\n }\n\n if (isPlainObject(normalized)) {\n if (circular.has(normalized)) {\n emitDebug(merged, { type: \"circular-skip\", path, original: normalized });\n return normalized;\n }\n circular.add(normalized);\n\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(normalized)) {\n if (hasKey(merged.dropKeys, k)) continue;\n\n if (hasKey(merged.keepKeys, k)) {\n emitDebug(merged, { type: \"keep\", path: path.concat(k), original: v });\n out[k] = v;\n continue;\n }\n\n if (!merged.deep && isPlainObject(v)) {\n out[k] = v;\n continue;\n }\n\n const next = walk(v, path.concat(k));\n if (next !== undefined) out[k] = next;\n }\n\n if (merged.dropEmptyObjects && Object.keys(out).length === 0) {\n emitDebug(merged, { type: \"empty-object\", path, original: normalized });\n return undefined;\n }\n\n return out;\n }\n\n return normalized;\n }\n\n const result = walk(payload, []);\n\n if (result === undefined) {\n if (isPlainObject(payload)) return {} as T;\n if (Array.isArray(payload)) return [] as T;\n return payload;\n }\n\n return result as T;\n}\n\ntype SanitizerFn = {\n <T>(payload: T, options?: SanitizeOptions): T;\n with: (baseOptions?: SanitizeOptions) => ReturnType<typeof createSanitizer>;\n};\n\nexport const createSanitizer = (baseOptions: SanitizeOptions = {}) => {\n return <T>(payload: T, options: SanitizeOptions = {}) =>\n sanitizeImpl(payload, { ...baseOptions, ...options });\n};\n\nexport const sanitize: SanitizerFn = Object.assign(sanitizeImpl, {\n with: (baseOptions: SanitizeOptions = {}) => createSanitizer(baseOptions),\n});\n\nexport const sanitizeWith = sanitize.with;\n","export function pick<T extends object, K extends keyof T>(\n obj: T,\n keys: K[],\n): Pick<T, K> {\n const out = {} as Pick<T, K>;\n for (const k of keys) {\n if (k in obj) out[k] = obj[k];\n }\n return out;\n}\n","export function omit<T extends object, K extends keyof T>(\n obj: T,\n keys: K[],\n): Omit<T, K> {\n const out = { ...obj };\n for (const k of keys) {\n delete out[k];\n }\n return out;\n}\n","export function isEmpty(value: unknown): boolean {\n if (Array.isArray(value)) return value.length === 0;\n if (value && typeof value === \"object\") {\n return Object.keys(value as object).length === 0;\n }\n return false;\n}\n","export function compact<T>(arr: T[]): T[] {\n return arr.filter(Boolean);\n}\n","export type ChangedEntry = {\n from: unknown;\n to: unknown;\n};\n\nexport type DiffResult = {\n added: Record<string, unknown>;\n removed: Record<string, unknown>;\n changed: Record<string, ChangedEntry>;\n};\n\nexport function diff(\n before: Record<string, unknown>,\n after: Record<string, unknown>,\n): DiffResult {\n const added: Record<string, unknown> = {};\n const removed: Record<string, unknown> = {};\n const changed: Record<string, ChangedEntry> = {};\n\n for (const key of Object.keys(before)) {\n if (!(key in after)) {\n removed[key] = before[key];\n continue;\n }\n\n if (!Object.is(before[key], after[key])) {\n changed[key] = { from: before[key], to: after[key] };\n }\n }\n\n for (const key of Object.keys(after)) {\n if (!(key in before)) {\n added[key] = after[key];\n }\n }\n\n return { added, removed, changed };\n}\n","export function safeParse<T>(json: string, fallback?: T): T | undefined {\n try {\n return JSON.parse(json) as T;\n } catch {\n return fallback;\n }\n}\n"]}
|
package/dist/index.js
CHANGED
|
@@ -1,161 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
var DEFAULT_DROP = [
|
|
3
|
-
"undefined",
|
|
4
|
-
"null",
|
|
5
|
-
"emptyString",
|
|
6
|
-
"whitespaceString"
|
|
7
|
-
];
|
|
8
|
-
var DEFAULT_OPTIONS = {
|
|
9
|
-
deep: true,
|
|
10
|
-
trimStrings: true,
|
|
11
|
-
cleanArrays: true,
|
|
12
|
-
dropEmptyObjects: false,
|
|
13
|
-
dropEmptyArrays: false,
|
|
14
|
-
drop: DEFAULT_DROP
|
|
15
|
-
};
|
|
16
|
-
function isPlainObject(value) {
|
|
17
|
-
if (value === null || typeof value !== "object") return false;
|
|
18
|
-
const proto = Object.getPrototypeOf(value);
|
|
19
|
-
return proto === Object.prototype || proto === null;
|
|
20
|
-
}
|
|
21
|
-
function normalizeValue(value, opts) {
|
|
22
|
-
if (typeof value === "string" && opts.trimStrings) {
|
|
23
|
-
return value.trim();
|
|
24
|
-
}
|
|
25
|
-
return value;
|
|
26
|
-
}
|
|
27
|
-
function shouldDropPreset(value, drop) {
|
|
28
|
-
for (const d of drop) {
|
|
29
|
-
switch (d) {
|
|
30
|
-
case "undefined":
|
|
31
|
-
if (value === void 0) return true;
|
|
32
|
-
break;
|
|
33
|
-
case "null":
|
|
34
|
-
if (value === null) return true;
|
|
35
|
-
break;
|
|
36
|
-
case "emptyString":
|
|
37
|
-
if (value === "") return true;
|
|
38
|
-
break;
|
|
39
|
-
case "whitespaceString":
|
|
40
|
-
if (typeof value === "string" && value.trim() === "") return true;
|
|
41
|
-
break;
|
|
42
|
-
case "dash":
|
|
43
|
-
if (value === "-") return true;
|
|
44
|
-
break;
|
|
45
|
-
case "nan":
|
|
46
|
-
if (typeof value === "number" && Number.isNaN(value)) return true;
|
|
47
|
-
break;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
return false;
|
|
51
|
-
}
|
|
52
|
-
function shouldDropExact(value, exactValues) {
|
|
53
|
-
if (!exactValues || exactValues.length === 0) return false;
|
|
54
|
-
for (const v of exactValues) {
|
|
55
|
-
if (Object.is(value, v)) return true;
|
|
56
|
-
}
|
|
57
|
-
return false;
|
|
58
|
-
}
|
|
59
|
-
function hasKey(list, key) {
|
|
60
|
-
return !!list && list.includes(key);
|
|
61
|
-
}
|
|
62
|
-
function toKeyPath(path) {
|
|
63
|
-
if (Array.isArray(path)) return path;
|
|
64
|
-
if (path.trim() === "") return [];
|
|
65
|
-
return path.split(".").map((seg) => {
|
|
66
|
-
const n = Number(seg);
|
|
67
|
-
return Number.isInteger(n) && String(n) === seg ? n : seg;
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
function pathEquals(a, b) {
|
|
71
|
-
if (a.length !== b.length) return false;
|
|
72
|
-
for (let i = 0; i < a.length; i++) {
|
|
73
|
-
if (a[i] !== b[i]) return false;
|
|
74
|
-
}
|
|
75
|
-
return true;
|
|
76
|
-
}
|
|
77
|
-
function hasPath(list, path) {
|
|
78
|
-
if (!list || list.length === 0) return false;
|
|
79
|
-
for (const item of list) {
|
|
80
|
-
if (pathEquals(toKeyPath(item), path)) return true;
|
|
81
|
-
}
|
|
82
|
-
return false;
|
|
83
|
-
}
|
|
84
|
-
function sanitizeAny(input, options, path) {
|
|
85
|
-
const normalized = normalizeValue(input, options);
|
|
86
|
-
if (hasPath(options.dropPaths, path)) return void 0;
|
|
87
|
-
const isKeptPath = hasPath(options.keepPaths, path);
|
|
88
|
-
if (!isKeptPath) {
|
|
89
|
-
if (shouldDropPreset(normalized, options.drop)) return void 0;
|
|
90
|
-
if (shouldDropExact(normalized, options.dropValues)) return void 0;
|
|
91
|
-
if (options.shouldDrop?.(normalized, path)) return void 0;
|
|
92
|
-
}
|
|
93
|
-
if (Array.isArray(normalized)) {
|
|
94
|
-
if (!options.cleanArrays) return normalized.slice();
|
|
95
|
-
const out = [];
|
|
96
|
-
for (let i = 0; i < normalized.length; i++) {
|
|
97
|
-
const next = sanitizeAny(normalized[i], options, path.concat(i));
|
|
98
|
-
if (next !== void 0) out.push(next);
|
|
99
|
-
}
|
|
100
|
-
if (options.dropEmptyArrays && out.length === 0) return void 0;
|
|
101
|
-
return out;
|
|
102
|
-
}
|
|
103
|
-
if (isPlainObject(normalized)) {
|
|
104
|
-
if (!options.deep) {
|
|
105
|
-
const out2 = {};
|
|
106
|
-
for (const [k, v] of Object.entries(normalized)) {
|
|
107
|
-
if (hasKey(options.dropKeys, k)) continue;
|
|
108
|
-
if (hasKey(options.keepKeys, k)) {
|
|
109
|
-
out2[k] = v;
|
|
110
|
-
continue;
|
|
111
|
-
}
|
|
112
|
-
const next = sanitizeAny(v, options, path.concat(k));
|
|
113
|
-
if (next !== void 0) out2[k] = next;
|
|
114
|
-
}
|
|
115
|
-
if (options.dropEmptyObjects && Object.keys(out2).length === 0)
|
|
116
|
-
return void 0;
|
|
117
|
-
return out2;
|
|
118
|
-
}
|
|
119
|
-
const out = {};
|
|
120
|
-
for (const [k, v] of Object.entries(normalized)) {
|
|
121
|
-
if (hasKey(options.dropKeys, k)) continue;
|
|
122
|
-
if (hasKey(options.keepKeys, k)) {
|
|
123
|
-
out[k] = v;
|
|
124
|
-
continue;
|
|
125
|
-
}
|
|
126
|
-
const next = sanitizeAny(v, options, path.concat(k));
|
|
127
|
-
if (next !== void 0) out[k] = next;
|
|
128
|
-
}
|
|
129
|
-
if (options.dropEmptyObjects && Object.keys(out).length === 0)
|
|
130
|
-
return void 0;
|
|
131
|
-
return out;
|
|
132
|
-
}
|
|
133
|
-
return normalized;
|
|
134
|
-
}
|
|
135
|
-
function sanitize(payload, options = {}) {
|
|
136
|
-
const merged = {
|
|
137
|
-
...DEFAULT_OPTIONS,
|
|
138
|
-
...options,
|
|
139
|
-
drop: options.drop ?? DEFAULT_OPTIONS.drop
|
|
140
|
-
};
|
|
141
|
-
const result = sanitizeAny(
|
|
142
|
-
payload,
|
|
143
|
-
merged,
|
|
144
|
-
[]
|
|
145
|
-
);
|
|
146
|
-
if (result === void 0) {
|
|
147
|
-
if (isPlainObject(payload)) return {};
|
|
148
|
-
if (Array.isArray(payload)) return [];
|
|
149
|
-
return payload;
|
|
150
|
-
}
|
|
151
|
-
return result;
|
|
152
|
-
}
|
|
153
|
-
var createSanitizer = (baseOptions = {}) => {
|
|
154
|
-
return (payload, options = {}) => sanitize(payload, { ...baseOptions, ...options });
|
|
155
|
-
};
|
|
156
|
-
sanitize.with = (baseOptions = {}) => createSanitizer(baseOptions);
|
|
157
|
-
var sanitizeWith = sanitize.with;
|
|
158
|
-
|
|
159
|
-
export { createSanitizer, sanitize, sanitizeWith };
|
|
160
|
-
//# sourceMappingURL=index.js.map
|
|
1
|
+
function k(){let e=new WeakSet;return {has(t){return e.has(t)},add(t){e.add(t);}}}var y={};function K(e={}){y={...y,...e};}function A(){return y}function S(){y={};}function E(e){return {debug:e.debug??y.debug??false,logger:e.logger??y.logger??z}}function z(e){globalThis.console?.log("[payload-sanitizer]",e);}function a(e,t){let r=E(e);r.debug&&r.logger(t);}function g(e){if(e===null||typeof e!="object")return false;let t=Object.getPrototypeOf(e);return t===Object.prototype||t===null}function c(e,t){if(!e)throw new Error(`[payload-sanitizer] ${t}`)}function j(e){return Array.isArray(e)?e:e.trim()===""?[]:e.split(".").map(t=>{let r=Number(t);return Number.isInteger(r)&&String(r)===t?r:t})}function R(e,t){if(e.length!==t.length)return false;for(let r=0;r<e.length;r++)if(e[r]!==t[r])return false;return true}function l(e,t){if(!e||e.length===0)return false;for(let r of e)if(R(j(r),t))return true;return false}var h=["undefined","null","emptyString","whitespaceString"];function D(e,t){for(let r of t)switch(r){case "undefined":if(e===void 0)return true;break;case "null":if(e===null)return true;break;case "emptyString":if(e==="")return true;break;case "whitespaceString":if(typeof e=="string"&&e.trim()==="")return true;break;case "dash":if(e==="-")return true;break;case "nan":if(typeof e=="number"&&Number.isNaN(e))return true;break}return false}var P={deep:true,trimStrings:true,cleanArrays:true,dropEmptyObjects:false,dropEmptyArrays:false,drop:h};function v(e,t){return typeof e=="string"&&t?e.trim():e}function N(e,t){if(!t||t.length===0)return false;for(let r of t)if(Object.is(e,r))return true;return false}function O(e,t){return !!e&&e.includes(t)}function C(e){c(e.drop===void 0||Array.isArray(e.drop),"`drop` must be an array"),c(e.keepKeys===void 0||Array.isArray(e.keepKeys),"`keepKeys` must be an array"),c(e.dropKeys===void 0||Array.isArray(e.dropKeys),"`dropKeys` must be an array"),c(e.dropValues===void 0||Array.isArray(e.dropValues),"`dropValues` must be an array"),c(e.keepPaths===void 0||Array.isArray(e.keepPaths),"`keepPaths` must be an array"),c(e.dropPaths===void 0||Array.isArray(e.dropPaths),"`dropPaths` must be an array"),c(e.shouldDrop===void 0||typeof e.shouldDrop=="function","`shouldDrop` must be a function");}function x(e,t={}){let r={...P,...t,drop:t.drop??P.drop};r.strict&&C(r);let s=k();function d(b,o){let n=v(b,r.trimStrings);if(a(r,{type:"normalize",path:o,original:b,result:n}),l(r.dropPaths,o)){a(r,{type:"drop",path:o,original:n});return}if(l(r.keepPaths,o))a(r,{type:"keep",path:o,original:n});else {if(D(n,r.drop)){a(r,{type:"drop",path:o,original:n});return}if(N(n,r.dropValues)){a(r,{type:"drop",path:o,original:n});return}if(r.shouldDrop?.(n,o)){a(r,{type:"drop",path:o,original:n});return}}if(Array.isArray(n)){if(s.has(n))return a(r,{type:"circular-skip",path:o,original:n}),n;if(s.add(n),!r.cleanArrays)return n.slice();let p=[];for(let u=0;u<n.length;u++){let f=d(n[u],o.concat(u));f!==void 0&&p.push(f);}if(r.dropEmptyArrays&&p.length===0){a(r,{type:"empty-array",path:o,original:n});return}return p}if(g(n)){if(s.has(n))return a(r,{type:"circular-skip",path:o,original:n}),n;s.add(n);let p={};for(let[u,f]of Object.entries(n)){if(O(r.dropKeys,u))continue;if(O(r.keepKeys,u)){a(r,{type:"keep",path:o.concat(u),original:f}),p[u]=f;continue}if(!r.deep&&g(f)){p[u]=f;continue}let m=d(f,o.concat(u));m!==void 0&&(p[u]=m);}if(r.dropEmptyObjects&&Object.keys(p).length===0){a(r,{type:"empty-object",path:o,original:n});return}return p}return n}let i=d(e,[]);return i===void 0?g(e)?{}:Array.isArray(e)?[]:e:i}var T=(e={})=>(t,r={})=>x(t,{...e,...r}),w=Object.assign(x,{with:(e={})=>T(e)}),F=w.with;function L(e,t){let r={};for(let s of t)s in e&&(r[s]=e[s]);return r}function V(e,t){let r={...e};for(let s of t)delete r[s];return r}function q(e){return Array.isArray(e)?e.length===0:e&&typeof e=="object"?Object.keys(e).length===0:false}function I(e){return e.filter(Boolean)}function U(e,t){let r={},s={},d={};for(let i of Object.keys(e)){if(!(i in t)){s[i]=e[i];continue}Object.is(e[i],t[i])||(d[i]={from:e[i],to:t[i]});}for(let i of Object.keys(t))i in e||(r[i]=t[i]);return {added:r,removed:s,changed:d}}function W(e,t){try{return JSON.parse(e)}catch{return t}}export{I as compact,K as configureDebug,T as createSanitizer,U as diff,A as getDebugOptions,q as isEmpty,V as omit,L as pick,S as resetDebug,W as safeParse,w as sanitize,F as sanitizeWith};//# sourceMappingURL=index.js.map
|
|
161
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"names":["out"],"mappings":";AA0CA,IAAM,YAAA,GAA6B;AAAA,EACjC,WAAA;AAAA,EACA,MAAA;AAAA,EACA,aAAA;AAAA,EACA;AACF,CAAA;AAEA,IAAM,eAAA,GAAkB;AAAA,EACtB,IAAA,EAAM,IAAA;AAAA,EACN,WAAA,EAAa,IAAA;AAAA,EACb,WAAA,EAAa,IAAA;AAAA,EACb,gBAAA,EAAkB,KAAA;AAAA,EAClB,eAAA,EAAiB,KAAA;AAAA,EACjB,IAAA,EAAM;AACR,CAAA;AAWA,SAAS,cAAc,KAAA,EAAkD;AACvE,EAAA,IAAI,KAAA,KAAU,IAAA,IAAQ,OAAO,KAAA,KAAU,UAAU,OAAO,KAAA;AACxD,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,cAAA,CAAe,KAAK,CAAA;AACzC,EAAA,OAAO,KAAA,KAAU,MAAA,CAAO,SAAA,IAAa,KAAA,KAAU,IAAA;AACjD;AAEA,SAAS,cAAA,CAAe,OAAgB,IAAA,EAA8B;AACpE,EAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,IAAA,CAAK,WAAA,EAAa;AACjD,IAAA,OAAO,MAAM,IAAA,EAAK;AAAA,EACpB;AACA,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,gBAAA,CAAiB,OAAgB,IAAA,EAA6B;AACrE,EAAA,KAAA,MAAW,KAAK,IAAA,EAAM;AACpB,IAAA,QAAQ,CAAA;AAAG,MACT,KAAK,WAAA;AACH,QAAA,IAAI,KAAA,KAAU,QAAW,OAAO,IAAA;AAChC,QAAA;AAAA,MACF,KAAK,MAAA;AACH,QAAA,IAAI,KAAA,KAAU,MAAM,OAAO,IAAA;AAC3B,QAAA;AAAA,MACF,KAAK,aAAA;AACH,QAAA,IAAI,KAAA,KAAU,IAAI,OAAO,IAAA;AACzB,QAAA;AAAA,MACF,KAAK,kBAAA;AAEH,QAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,MAAM,IAAA,EAAK,KAAM,IAAI,OAAO,IAAA;AAC7D,QAAA;AAAA,MACF,KAAK,MAAA;AACH,QAAA,IAAI,KAAA,KAAU,KAAK,OAAO,IAAA;AAC1B,QAAA;AAAA,MACF,KAAK,KAAA;AACH,QAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,OAAO,KAAA,CAAM,KAAK,GAAG,OAAO,IAAA;AAC7D,QAAA;AAAA;AACJ,EACF;AACA,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,eAAA,CAAgB,OAAgB,WAAA,EAAkC;AACzE,EAAA,IAAI,CAAC,WAAA,IAAe,WAAA,CAAY,MAAA,KAAW,GAAG,OAAO,KAAA;AACrD,EAAA,KAAA,MAAW,KAAK,WAAA,EAAa;AAC3B,IAAA,IAAI,MAAA,CAAO,EAAA,CAAG,KAAA,EAAO,CAAC,GAAG,OAAO,IAAA;AAAA,EAClC;AACA,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,MAAA,CAAO,MAA4B,GAAA,EAAsB;AAChE,EAAA,OAAO,CAAC,CAAC,IAAA,IAAQ,IAAA,CAAK,SAAS,GAAG,CAAA;AACpC;AAEA,SAAS,UAAU,IAAA,EAAiC;AAClD,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA,EAAG,OAAO,IAAA;AAChC,EAAA,IAAI,IAAA,CAAK,IAAA,EAAK,KAAM,EAAA,SAAW,EAAC;AAChC,EAAA,OAAO,KAAK,KAAA,CAAM,GAAG,CAAA,CAAE,GAAA,CAAI,CAAC,GAAA,KAAQ;AAClC,IAAA,MAAM,CAAA,GAAI,OAAO,GAAG,CAAA;AACpB,IAAA,OAAO,MAAA,CAAO,UAAU,CAAC,CAAA,IAAK,OAAO,CAAC,CAAA,KAAM,MAAM,CAAA,GAAI,GAAA;AAAA,EACxD,CAAC,CAAA;AACH;AAEA,SAAS,UAAA,CAAW,GAAY,CAAA,EAAqB;AACnD,EAAA,IAAI,CAAA,CAAE,MAAA,KAAW,CAAA,CAAE,MAAA,EAAQ,OAAO,KAAA;AAClC,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,CAAA,CAAE,QAAQ,CAAA,EAAA,EAAK;AACjC,IAAA,IAAI,EAAE,CAAC,CAAA,KAAM,CAAA,CAAE,CAAC,GAAG,OAAO,KAAA;AAAA,EAC5B;AACA,EAAA,OAAO,IAAA;AACT;AAEA,SAAS,OAAA,CAAQ,MAA2C,IAAA,EAAwB;AAClF,EAAA,IAAI,CAAC,IAAA,IAAQ,IAAA,CAAK,MAAA,KAAW,GAAG,OAAO,KAAA;AACvC,EAAA,KAAA,MAAW,QAAQ,IAAA,EAAM;AACvB,IAAA,IAAI,WAAW,SAAA,CAAU,IAAI,CAAA,EAAG,IAAI,GAAG,OAAO,IAAA;AAAA,EAChD;AACA,EAAA,OAAO,KAAA;AACT;AAEA,SAAS,WAAA,CACP,KAAA,EACA,OAAA,EACA,IAAA,EACS;AACT,EAAA,MAAM,UAAA,GAAa,cAAA,CAAe,KAAA,EAAO,OAAO,CAAA;AAGhD,EAAA,IAAI,OAAA,CAAQ,OAAA,CAAQ,SAAA,EAAW,IAAI,GAAG,OAAO,MAAA;AAE7C,EAAA,MAAM,UAAA,GAAa,OAAA,CAAQ,OAAA,CAAQ,SAAA,EAAW,IAAI,CAAA;AAElD,EAAA,IAAI,CAAC,UAAA,EAAY;AACf,IAAA,IAAI,gBAAA,CAAiB,UAAA,EAAY,OAAA,CAAQ,IAAI,GAAG,OAAO,MAAA;AACvD,IAAA,IAAI,eAAA,CAAgB,UAAA,EAAY,OAAA,CAAQ,UAAU,GAAG,OAAO,MAAA;AAC5D,IAAA,IAAI,OAAA,CAAQ,UAAA,GAAa,UAAA,EAAY,IAAI,GAAG,OAAO,MAAA;AAAA,EACrD;AAEA,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,UAAU,CAAA,EAAG;AAC7B,IAAA,IAAI,CAAC,OAAA,CAAQ,WAAA,EAAa,OAAO,WAAW,KAAA,EAAM;AAClD,IAAA,MAAM,MAAiB,EAAC;AACxB,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,UAAA,CAAW,QAAQ,CAAA,EAAA,EAAK;AAC1C,MAAA,MAAM,IAAA,GAAO,YAAY,UAAA,CAAW,CAAC,GAAG,OAAA,EAAS,IAAA,CAAK,MAAA,CAAO,CAAC,CAAC,CAAA;AAC/D,MAAA,IAAI,IAAA,KAAS,MAAA,EAAW,GAAA,CAAI,IAAA,CAAK,IAAI,CAAA;AAAA,IACvC;AACA,IAAA,IAAI,OAAA,CAAQ,eAAA,IAAmB,GAAA,CAAI,MAAA,KAAW,GAAG,OAAO,MAAA;AACxD,IAAA,OAAO,GAAA;AAAA,EACT;AAEA,EAAA,IAAI,aAAA,CAAc,UAAU,CAAA,EAAG;AAC7B,IAAA,IAAI,CAAC,QAAQ,IAAA,EAAM;AACjB,MAAA,MAAMA,OAA+B,EAAC;AACtC,MAAA,KAAA,MAAW,CAAC,CAAA,EAAG,CAAC,KAAK,MAAA,CAAO,OAAA,CAAQ,UAAU,CAAA,EAAG;AAC/C,QAAA,IAAI,MAAA,CAAO,OAAA,CAAQ,QAAA,EAAU,CAAC,CAAA,EAAG;AACjC,QAAA,IAAI,MAAA,CAAO,OAAA,CAAQ,QAAA,EAAU,CAAC,CAAA,EAAG;AAC/B,UAAAA,IAAAA,CAAI,CAAC,CAAA,GAAI,CAAA;AACT,UAAA;AAAA,QACF;AACA,QAAA,MAAM,OAAO,WAAA,CAAY,CAAA,EAAG,SAAS,IAAA,CAAK,MAAA,CAAO,CAAC,CAAC,CAAA;AACnD,QAAA,IAAI,IAAA,KAAS,MAAA,EAAWA,IAAAA,CAAI,CAAC,CAAA,GAAI,IAAA;AAAA,MACnC;AACA,MAAA,IAAI,QAAQ,gBAAA,IAAoB,MAAA,CAAO,IAAA,CAAKA,IAAG,EAAE,MAAA,KAAW,CAAA;AAC1D,QAAA,OAAO,MAAA;AACT,MAAA,OAAOA,IAAAA;AAAA,IACT;AAEA,IAAA,MAAM,MAA+B,EAAC;AACtC,IAAA,KAAA,MAAW,CAAC,CAAA,EAAG,CAAC,KAAK,MAAA,CAAO,OAAA,CAAQ,UAAU,CAAA,EAAG;AAC/C,MAAA,IAAI,MAAA,CAAO,OAAA,CAAQ,QAAA,EAAU,CAAC,CAAA,EAAG;AAEjC,MAAA,IAAI,MAAA,CAAO,OAAA,CAAQ,QAAA,EAAU,CAAC,CAAA,EAAG;AAC/B,QAAA,GAAA,CAAI,CAAC,CAAA,GAAI,CAAA;AACT,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,OAAO,WAAA,CAAY,CAAA,EAAG,SAAS,IAAA,CAAK,MAAA,CAAO,CAAC,CAAC,CAAA;AACnD,MAAA,IAAI,IAAA,KAAS,MAAA,EAAW,GAAA,CAAI,CAAC,CAAA,GAAI,IAAA;AAAA,IACnC;AACA,IAAA,IAAI,QAAQ,gBAAA,IAAoB,MAAA,CAAO,IAAA,CAAK,GAAG,EAAE,MAAA,KAAW,CAAA;AAC1D,MAAA,OAAO,MAAA;AACT,IAAA,OAAO,GAAA;AAAA,EACT;AAEA,EAAA,OAAO,UAAA;AACT;AAEO,SAAS,QAAA,CAAY,OAAA,EAAY,OAAA,GAA2B,EAAC,EAAM;AACxE,EAAA,MAAM,MAAA,GAAS;AAAA,IACb,GAAG,eAAA;AAAA,IACH,GAAG,OAAA;AAAA,IACH,IAAA,EAAM,OAAA,CAAQ,IAAA,IAAQ,eAAA,CAAgB;AAAA,GACxC;AAEA,EAAA,MAAM,MAAA,GAAS,WAAA;AAAA,IACb,OAAA;AAAA,IACA,MAAA;AAAA,IACA;AAAC,GACH;AAEA,EAAA,IAAI,WAAW,MAAA,EAAW;AACxB,IAAA,IAAI,aAAA,CAAc,OAAO,CAAA,EAAG,OAAO,EAAC;AACpC,IAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,OAAO,CAAA,SAAU,EAAC;AACpC,IAAA,OAAO,OAAA;AAAA,EACT;AAEA,EAAA,OAAO,MAAA;AACT;AAOO,IAAM,eAAA,GAAkB,CAAC,WAAA,GAA+B,EAAC,KAAM;AACpE,EAAA,OAAO,CAAI,OAAA,EAAY,OAAA,GAA2B,EAAC,KACjD,QAAA,CAAS,OAAA,EAAS,EAAE,GAAG,WAAA,EAAa,GAAG,OAAA,EAAS,CAAA;AACpD;AAEC,QAAA,CAAyB,OAAO,CAAC,WAAA,GAA+B,EAAC,KAChE,gBAAgB,WAAW,CAAA;AAEtB,IAAM,eAAgB,QAAA,CAAyB","file":"index.js","sourcesContent":["export type DropPreset =\n | \"null\"\n | \"undefined\"\n | \"emptyString\"\n | \"whitespaceString\"\n | \"dash\"\n | \"nan\";\n\nexport type KeyPath = Array<string | number>;\n\nexport type SanitizeOptions = {\n deep?: boolean;\n trimStrings?: boolean;\n cleanArrays?: boolean;\n drop?: DropPreset[];\n keepKeys?: string[];\n dropKeys?: string[];\n dropValues?: unknown[];\n /**\n * Always keep these paths (even if value is droppable).\n * Supports \"a.b.c\" or [\"a\",\"b\",\"c\"].\n */\n keepPaths?: Array<string | KeyPath>;\n /**\n * Always drop these paths (even if value is meaningful).\n * Supports \"a.b.c\" or [\"a\",\"b\",\"c\"].\n */\n dropPaths?: Array<string | KeyPath>;\n shouldDrop?: (value: unknown, keyPath: KeyPath) => boolean;\n /**\n * Drop objects that become empty after sanitizing.\n * Default: false\n */\n dropEmptyObjects?: boolean;\n\n /**\n * Drop arrays that become empty after sanitizing.\n * Default: false\n */\n dropEmptyArrays?: boolean;\n};\n\nconst DEFAULT_DROP: DropPreset[] = [\n \"undefined\",\n \"null\",\n \"emptyString\",\n \"whitespaceString\",\n];\n\nconst DEFAULT_OPTIONS = {\n deep: true,\n trimStrings: true,\n cleanArrays: true,\n dropEmptyObjects: false,\n dropEmptyArrays: false,\n drop: DEFAULT_DROP,\n} satisfies Required<\n Pick<\n SanitizeOptions,\n | \"deep\"\n | \"trimStrings\"\n | \"cleanArrays\"\n | \"dropEmptyObjects\"\n | \"dropEmptyArrays\"\n >\n> & { drop: DropPreset[] };\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n if (value === null || typeof value !== \"object\") return false;\n const proto = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n}\n\nfunction normalizeValue(value: unknown, opts: typeof DEFAULT_OPTIONS) {\n if (typeof value === \"string\" && opts.trimStrings) {\n return value.trim();\n }\n return value;\n}\n\nfunction shouldDropPreset(value: unknown, drop: DropPreset[]): boolean {\n for (const d of drop) {\n switch (d) {\n case \"undefined\":\n if (value === undefined) return true;\n break;\n case \"null\":\n if (value === null) return true;\n break;\n case \"emptyString\":\n if (value === \"\") return true;\n break;\n case \"whitespaceString\":\n // only matters if trimStrings is false; but still safe:\n if (typeof value === \"string\" && value.trim() === \"\") return true;\n break;\n case \"dash\":\n if (value === \"-\") return true;\n break;\n case \"nan\":\n if (typeof value === \"number\" && Number.isNaN(value)) return true;\n break;\n }\n }\n return false;\n}\n\nfunction shouldDropExact(value: unknown, exactValues?: unknown[]): boolean {\n if (!exactValues || exactValues.length === 0) return false;\n for (const v of exactValues) {\n if (Object.is(value, v)) return true;\n }\n return false;\n}\n\nfunction hasKey(list: string[] | undefined, key: string): boolean {\n return !!list && list.includes(key);\n}\n\nfunction toKeyPath(path: string | KeyPath): KeyPath {\n if (Array.isArray(path)) return path;\n if (path.trim() === \"\") return [];\n return path.split(\".\").map((seg) => {\n const n = Number(seg);\n return Number.isInteger(n) && String(n) === seg ? n : seg;\n });\n}\n\nfunction pathEquals(a: KeyPath, b: KeyPath): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false;\n }\n return true;\n}\n\nfunction hasPath(list: Array<string | KeyPath> | undefined, path: KeyPath): boolean {\n if (!list || list.length === 0) return false;\n for (const item of list) {\n if (pathEquals(toKeyPath(item), path)) return true;\n }\n return false;\n}\n\nfunction sanitizeAny(\n input: unknown,\n options: typeof DEFAULT_OPTIONS & SanitizeOptions,\n path: KeyPath,\n): unknown {\n const normalized = normalizeValue(input, options);\n\n // Path-based overrides (highest priority)\n if (hasPath(options.dropPaths, path)) return undefined;\n\n const isKeptPath = hasPath(options.keepPaths, path);\n\n if (!isKeptPath) {\n if (shouldDropPreset(normalized, options.drop)) return undefined;\n if (shouldDropExact(normalized, options.dropValues)) return undefined;\n if (options.shouldDrop?.(normalized, path)) return undefined;\n }\n\n if (Array.isArray(normalized)) {\n if (!options.cleanArrays) return normalized.slice();\n const out: unknown[] = [];\n for (let i = 0; i < normalized.length; i++) {\n const next = sanitizeAny(normalized[i], options, path.concat(i));\n if (next !== undefined) out.push(next);\n }\n if (options.dropEmptyArrays && out.length === 0) return undefined;\n return out;\n }\n\n if (isPlainObject(normalized)) {\n if (!options.deep) {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(normalized)) {\n if (hasKey(options.dropKeys, k)) continue;\n if (hasKey(options.keepKeys, k)) {\n out[k] = v;\n continue;\n }\n const next = sanitizeAny(v, options, path.concat(k));\n if (next !== undefined) out[k] = next;\n }\n if (options.dropEmptyObjects && Object.keys(out).length === 0)\n return undefined;\n return out;\n }\n\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(normalized)) {\n if (hasKey(options.dropKeys, k)) continue;\n\n if (hasKey(options.keepKeys, k)) {\n out[k] = v;\n continue;\n }\n\n const next = sanitizeAny(v, options, path.concat(k));\n if (next !== undefined) out[k] = next;\n }\n if (options.dropEmptyObjects && Object.keys(out).length === 0)\n return undefined;\n return out;\n }\n\n return normalized;\n}\n\nexport function sanitize<T>(payload: T, options: SanitizeOptions = {}): T {\n const merged = {\n ...DEFAULT_OPTIONS,\n ...options,\n drop: options.drop ?? DEFAULT_OPTIONS.drop,\n };\n\n const result = sanitizeAny(\n payload,\n merged as typeof DEFAULT_OPTIONS & SanitizeOptions,\n [],\n );\n\n if (result === undefined) {\n if (isPlainObject(payload)) return {} as T;\n if (Array.isArray(payload)) return [] as T;\n return payload;\n }\n\n return result as T;\n}\n\ntype SanitizerFn = {\n <T>(payload: T, options?: SanitizeOptions): T;\n with: (baseOptions?: SanitizeOptions) => ReturnType<typeof createSanitizer>;\n};\n\nexport const createSanitizer = (baseOptions: SanitizeOptions = {}) => {\n return <T>(payload: T, options: SanitizeOptions = {}) =>\n sanitize(payload, { ...baseOptions, ...options });\n};\n\n(sanitize as SanitizerFn).with = (baseOptions: SanitizeOptions = {}) =>\n createSanitizer(baseOptions);\n\nexport const sanitizeWith = (sanitize as SanitizerFn).with;\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/core/circular.ts","../src/core/debug.ts","../src/core/guards.ts","../src/core/path.ts","../src/core/presets.ts","../src/core/sanitize.ts","../src/utils/pick.ts","../src/utils/omit.ts","../src/utils/isEmpty.ts","../src/utils/compact.ts","../src/utils/diff.ts","../src/utils/safeParse.ts"],"names":["createCircularTracker","seen","value","globalDebugOptions","configureDebug","options","getDebugOptions","resetDebug","resolveDebugOptions","opts","defaultLogger","event","emitDebug","resolved","isPlainObject","proto","assert","condition","message","toKeyPath","path","seg","n","pathEquals","a","b","i","hasPath","list","item","DEFAULT_DROP","shouldDropPreset","drop","d","DEFAULT_OPTIONS","normalizeValue","trim","shouldDropExact","exactValues","v","hasKey","key","validateStrict","sanitizeImpl","payload","merged","circular","walk","input","normalized","out","next","k","result","createSanitizer","baseOptions","sanitize","sanitizeWith","pick","obj","keys","omit","isEmpty","compact","arr","diff","before","after","added","removed","changed","safeParse","json","fallback"],"mappings":"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","file":"index.js","sourcesContent":["export function createCircularTracker() {\n const seen = new WeakSet<object>();\n\n return {\n has(value: object) {\n return seen.has(value);\n },\n add(value: object) {\n seen.add(value);\n },\n };\n}\n","import type { KeyPath } from \"./path\";\n\nexport type DebugEventType =\n | \"normalize\"\n | \"drop\"\n | \"keep\"\n | \"empty-object\"\n | \"empty-array\"\n | \"circular-skip\";\n\nexport interface DebugEvent {\n type: DebugEventType;\n path: KeyPath;\n original: unknown;\n result?: unknown;\n}\n\nexport type DebugOptions = {\n debug?: boolean;\n logger?: (event: DebugEvent) => void;\n};\n\nlet globalDebugOptions: DebugOptions = {};\n\nexport function configureDebug(options: DebugOptions = {}): void {\n globalDebugOptions = { ...globalDebugOptions, ...options };\n}\n\nexport function getDebugOptions(): DebugOptions {\n return globalDebugOptions;\n}\n\nexport function resetDebug(): void {\n globalDebugOptions = {};\n}\n\nfunction resolveDebugOptions(opts: DebugOptions): Required<DebugOptions> {\n return {\n debug: opts.debug ?? globalDebugOptions.debug ?? false,\n logger: opts.logger ?? globalDebugOptions.logger ?? defaultLogger,\n };\n}\n\nfunction defaultLogger(event: DebugEvent): void {\n const c = (globalThis as { console?: { log: (...args: unknown[]) => void } })\n .console;\n c?.log(\"[payload-sanitizer]\", event);\n}\n\nexport function emitDebug(opts: DebugOptions, event: DebugEvent): void {\n const resolved = resolveDebugOptions(opts);\n if (!resolved.debug) return;\n resolved.logger(event);\n}\n","export function isPlainObject(value: unknown): value is Record<string, unknown> {\n if (value === null || typeof value !== \"object\") return false;\n const proto = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n}\n\nexport function assert(condition: unknown, message: string): asserts condition {\n if (!condition) {\n throw new Error(`[payload-sanitizer] ${message}`);\n }\n}\n","export type KeyPath = Array<string | number>;\n\nexport function toKeyPath(path: string | KeyPath): KeyPath {\n if (Array.isArray(path)) return path;\n if (path.trim() === \"\") return [];\n return path.split(\".\").map((seg) => {\n const n = Number(seg);\n return Number.isInteger(n) && String(n) === seg ? n : seg;\n });\n}\n\nexport function pathEquals(a: KeyPath, b: KeyPath): boolean {\n if (a.length !== b.length) return false;\n for (let i = 0; i < a.length; i++) {\n if (a[i] !== b[i]) return false;\n }\n return true;\n}\n\nexport function hasPath(\n list: Array<string | KeyPath> | undefined,\n path: KeyPath,\n): boolean {\n if (!list || list.length === 0) return false;\n for (const item of list) {\n if (pathEquals(toKeyPath(item), path)) return true;\n }\n return false;\n}\n","export type DropPreset =\n | \"null\"\n | \"undefined\"\n | \"emptyString\"\n | \"whitespaceString\"\n | \"dash\"\n | \"nan\";\n\nexport const DEFAULT_DROP: DropPreset[] = [\n \"undefined\",\n \"null\",\n \"emptyString\",\n \"whitespaceString\",\n];\n\nexport function shouldDropPreset(value: unknown, drop: DropPreset[]): boolean {\n for (const d of drop) {\n switch (d) {\n case \"undefined\":\n if (value === undefined) return true;\n break;\n case \"null\":\n if (value === null) return true;\n break;\n case \"emptyString\":\n if (value === \"\") return true;\n break;\n case \"whitespaceString\":\n if (typeof value === \"string\" && value.trim() === \"\") return true;\n break;\n case \"dash\":\n if (value === \"-\") return true;\n break;\n case \"nan\":\n if (typeof value === \"number\" && Number.isNaN(value)) return true;\n break;\n }\n }\n return false;\n}\n","import { createCircularTracker } from \"./circular\";\nimport type { DebugOptions } from \"./debug\";\nimport { emitDebug } from \"./debug\";\nimport { assert, isPlainObject } from \"./guards\";\nimport { hasPath, type KeyPath } from \"./path\";\nimport { DEFAULT_DROP, type DropPreset, shouldDropPreset } from \"./presets\";\n\nexport type SanitizeOptions = DebugOptions & {\n deep?: boolean;\n trimStrings?: boolean;\n cleanArrays?: boolean;\n drop?: DropPreset[];\n keepKeys?: string[];\n dropKeys?: string[];\n dropValues?: unknown[];\n keepPaths?: Array<string | KeyPath>;\n dropPaths?: Array<string | KeyPath>;\n shouldDrop?: (value: unknown, keyPath: KeyPath) => boolean;\n dropEmptyObjects?: boolean;\n dropEmptyArrays?: boolean;\n strict?: boolean;\n};\n\nconst DEFAULT_OPTIONS = {\n deep: true,\n trimStrings: true,\n cleanArrays: true,\n dropEmptyObjects: false,\n dropEmptyArrays: false,\n drop: DEFAULT_DROP,\n} satisfies Required<\n Pick<\n SanitizeOptions,\n | \"deep\"\n | \"trimStrings\"\n | \"cleanArrays\"\n | \"dropEmptyObjects\"\n | \"dropEmptyArrays\"\n >\n> & { drop: DropPreset[] };\n\nfunction normalizeValue(value: unknown, trim: boolean): unknown {\n if (typeof value === \"string\" && trim) {\n return value.trim();\n }\n return value;\n}\n\nfunction shouldDropExact(value: unknown, exactValues?: unknown[]): boolean {\n if (!exactValues || exactValues.length === 0) return false;\n for (const v of exactValues) {\n if (Object.is(value, v)) return true;\n }\n return false;\n}\n\nfunction hasKey(list: string[] | undefined, key: string): boolean {\n return !!list && list.includes(key);\n}\n\nfunction validateStrict(options: SanitizeOptions): void {\n assert(\n options.drop === undefined || Array.isArray(options.drop),\n \"`drop` must be an array\",\n );\n assert(\n options.keepKeys === undefined || Array.isArray(options.keepKeys),\n \"`keepKeys` must be an array\",\n );\n assert(\n options.dropKeys === undefined || Array.isArray(options.dropKeys),\n \"`dropKeys` must be an array\",\n );\n assert(\n options.dropValues === undefined || Array.isArray(options.dropValues),\n \"`dropValues` must be an array\",\n );\n assert(\n options.keepPaths === undefined || Array.isArray(options.keepPaths),\n \"`keepPaths` must be an array\",\n );\n assert(\n options.dropPaths === undefined || Array.isArray(options.dropPaths),\n \"`dropPaths` must be an array\",\n );\n assert(\n options.shouldDrop === undefined || typeof options.shouldDrop === \"function\",\n \"`shouldDrop` must be a function\",\n );\n}\n\nfunction sanitizeImpl<T>(payload: T, options: SanitizeOptions = {}): T {\n const merged = {\n ...DEFAULT_OPTIONS,\n ...options,\n drop: options.drop ?? DEFAULT_OPTIONS.drop,\n };\n\n if (merged.strict) {\n validateStrict(merged);\n }\n\n const circular = createCircularTracker();\n\n function walk(input: unknown, path: KeyPath): unknown {\n const normalized = normalizeValue(input, merged.trimStrings);\n\n emitDebug(merged, {\n type: \"normalize\",\n path,\n original: input,\n result: normalized,\n });\n\n if (hasPath(merged.dropPaths, path)) {\n emitDebug(merged, { type: \"drop\", path, original: normalized });\n return undefined;\n }\n\n const isKeptPath = hasPath(merged.keepPaths, path);\n\n if (isKeptPath) {\n emitDebug(merged, { type: \"keep\", path, original: normalized });\n } else {\n if (shouldDropPreset(normalized, merged.drop)) {\n emitDebug(merged, { type: \"drop\", path, original: normalized });\n return undefined;\n }\n\n if (shouldDropExact(normalized, merged.dropValues)) {\n emitDebug(merged, { type: \"drop\", path, original: normalized });\n return undefined;\n }\n\n if (merged.shouldDrop?.(normalized, path)) {\n emitDebug(merged, { type: \"drop\", path, original: normalized });\n return undefined;\n }\n }\n\n if (Array.isArray(normalized)) {\n if (circular.has(normalized)) {\n emitDebug(merged, { type: \"circular-skip\", path, original: normalized });\n return normalized;\n }\n circular.add(normalized);\n\n if (!merged.cleanArrays) return normalized.slice();\n\n const out: unknown[] = [];\n for (let i = 0; i < normalized.length; i++) {\n const next = walk(normalized[i], path.concat(i));\n if (next !== undefined) out.push(next);\n }\n\n if (merged.dropEmptyArrays && out.length === 0) {\n emitDebug(merged, { type: \"empty-array\", path, original: normalized });\n return undefined;\n }\n\n return out;\n }\n\n if (isPlainObject(normalized)) {\n if (circular.has(normalized)) {\n emitDebug(merged, { type: \"circular-skip\", path, original: normalized });\n return normalized;\n }\n circular.add(normalized);\n\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(normalized)) {\n if (hasKey(merged.dropKeys, k)) continue;\n\n if (hasKey(merged.keepKeys, k)) {\n emitDebug(merged, { type: \"keep\", path: path.concat(k), original: v });\n out[k] = v;\n continue;\n }\n\n if (!merged.deep && isPlainObject(v)) {\n out[k] = v;\n continue;\n }\n\n const next = walk(v, path.concat(k));\n if (next !== undefined) out[k] = next;\n }\n\n if (merged.dropEmptyObjects && Object.keys(out).length === 0) {\n emitDebug(merged, { type: \"empty-object\", path, original: normalized });\n return undefined;\n }\n\n return out;\n }\n\n return normalized;\n }\n\n const result = walk(payload, []);\n\n if (result === undefined) {\n if (isPlainObject(payload)) return {} as T;\n if (Array.isArray(payload)) return [] as T;\n return payload;\n }\n\n return result as T;\n}\n\ntype SanitizerFn = {\n <T>(payload: T, options?: SanitizeOptions): T;\n with: (baseOptions?: SanitizeOptions) => ReturnType<typeof createSanitizer>;\n};\n\nexport const createSanitizer = (baseOptions: SanitizeOptions = {}) => {\n return <T>(payload: T, options: SanitizeOptions = {}) =>\n sanitizeImpl(payload, { ...baseOptions, ...options });\n};\n\nexport const sanitize: SanitizerFn = Object.assign(sanitizeImpl, {\n with: (baseOptions: SanitizeOptions = {}) => createSanitizer(baseOptions),\n});\n\nexport const sanitizeWith = sanitize.with;\n","export function pick<T extends object, K extends keyof T>(\n obj: T,\n keys: K[],\n): Pick<T, K> {\n const out = {} as Pick<T, K>;\n for (const k of keys) {\n if (k in obj) out[k] = obj[k];\n }\n return out;\n}\n","export function omit<T extends object, K extends keyof T>(\n obj: T,\n keys: K[],\n): Omit<T, K> {\n const out = { ...obj };\n for (const k of keys) {\n delete out[k];\n }\n return out;\n}\n","export function isEmpty(value: unknown): boolean {\n if (Array.isArray(value)) return value.length === 0;\n if (value && typeof value === \"object\") {\n return Object.keys(value as object).length === 0;\n }\n return false;\n}\n","export function compact<T>(arr: T[]): T[] {\n return arr.filter(Boolean);\n}\n","export type ChangedEntry = {\n from: unknown;\n to: unknown;\n};\n\nexport type DiffResult = {\n added: Record<string, unknown>;\n removed: Record<string, unknown>;\n changed: Record<string, ChangedEntry>;\n};\n\nexport function diff(\n before: Record<string, unknown>,\n after: Record<string, unknown>,\n): DiffResult {\n const added: Record<string, unknown> = {};\n const removed: Record<string, unknown> = {};\n const changed: Record<string, ChangedEntry> = {};\n\n for (const key of Object.keys(before)) {\n if (!(key in after)) {\n removed[key] = before[key];\n continue;\n }\n\n if (!Object.is(before[key], after[key])) {\n changed[key] = { from: before[key], to: after[key] };\n }\n }\n\n for (const key of Object.keys(after)) {\n if (!(key in before)) {\n added[key] = after[key];\n }\n }\n\n return { added, removed, changed };\n}\n","export function safeParse<T>(json: string, fallback?: T): T | undefined {\n try {\n return JSON.parse(json) as T;\n } catch {\n return fallback;\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "payload-sanitizer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Tiny zero-dependency payload sanitizer for JS/TS (frontend + backend).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanitize",
|
|
@@ -28,18 +28,10 @@
|
|
|
28
28
|
"LICENSE"
|
|
29
29
|
],
|
|
30
30
|
"sideEffects": false,
|
|
31
|
-
"scripts": {
|
|
32
|
-
"build": "tsup",
|
|
33
|
-
"dev": "tsup --watch",
|
|
34
|
-
"test": "vitest",
|
|
35
|
-
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
36
|
-
"lint": "eslint .",
|
|
37
|
-
"prepublishOnly": "pnpm build && pnpm test && pnpm typecheck"
|
|
38
|
-
},
|
|
39
|
-
"packageManager": "pnpm@10.29.3",
|
|
40
31
|
"devDependencies": {
|
|
41
32
|
"tsup": "^8.5.1",
|
|
42
33
|
"typescript": "^5.9.3",
|
|
34
|
+
"vitepress": "^1.6.4",
|
|
43
35
|
"vitest": "^4.0.18"
|
|
44
36
|
},
|
|
45
37
|
"publishConfig": {
|
|
@@ -47,5 +39,15 @@
|
|
|
47
39
|
},
|
|
48
40
|
"engines": {
|
|
49
41
|
"node": ">=18"
|
|
42
|
+
},
|
|
43
|
+
"scripts": {
|
|
44
|
+
"build": "tsup",
|
|
45
|
+
"dev": "tsup --watch",
|
|
46
|
+
"test": "vitest",
|
|
47
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
48
|
+
"lint": "tsc -p tsconfig.json --noEmit",
|
|
49
|
+
"docs:dev": "vitepress dev docs",
|
|
50
|
+
"docs:build": "vitepress build docs",
|
|
51
|
+
"docs:preview": "vitepress preview docs"
|
|
50
52
|
}
|
|
51
|
-
}
|
|
53
|
+
}
|