@edge.app/x-cleaners 0.1.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/README.md +14 -0
- package/dist/cjs/index.js +96 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cleaners/asHealingArray.d.ts +25 -0
- package/dist/cleaners/asHealingObject.d.ts +58 -0
- package/dist/cleaners/asHealingTuple.d.ts +40 -0
- package/dist/esm/index.js +64 -0
- package/dist/index.d.ts +3 -0
- package/package.json +52 -0
package/README.md
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# @edge.app/x-cleaners
|
|
2
|
+
|
|
3
|
+
A helpful utility library of cleaners.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
yarn add @edge.app/x-cleaners
|
|
9
|
+
bun i @edge.app/x-cleaners # or use any other package manager that supports NPM
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Documentation
|
|
13
|
+
|
|
14
|
+
All exported cleaners are documented in the [`src/cleaners/`](./src/cleaners/) directory. Each cleaner includes TypeScript type definitions and JSDoc comments explaining its usage.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __moduleCache = /* @__PURE__ */ new WeakMap;
|
|
6
|
+
var __toCommonJS = (from) => {
|
|
7
|
+
var entry = __moduleCache.get(from), desc;
|
|
8
|
+
if (entry)
|
|
9
|
+
return entry;
|
|
10
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function")
|
|
12
|
+
__getOwnPropNames(from).map((key) => !__hasOwnProp.call(entry, key) && __defProp(entry, key, {
|
|
13
|
+
get: () => from[key],
|
|
14
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
15
|
+
}));
|
|
16
|
+
__moduleCache.set(from, entry);
|
|
17
|
+
return entry;
|
|
18
|
+
};
|
|
19
|
+
var __export = (target, all) => {
|
|
20
|
+
for (var name in all)
|
|
21
|
+
__defProp(target, name, {
|
|
22
|
+
get: all[name],
|
|
23
|
+
enumerable: true,
|
|
24
|
+
configurable: true,
|
|
25
|
+
set: (newValue) => all[name] = () => newValue
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// src/index.ts
|
|
30
|
+
var exports_src = {};
|
|
31
|
+
__export(exports_src, {
|
|
32
|
+
asHealingTuple: () => asHealingTuple,
|
|
33
|
+
asHealingObject: () => asHealingObject,
|
|
34
|
+
asHealingArray: () => asHealingArray
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(exports_src);
|
|
37
|
+
|
|
38
|
+
// src/cleaners/asHealingArray.ts
|
|
39
|
+
function asHealingArray(cleaner) {
|
|
40
|
+
return function asHealingArrayCleaner(raw) {
|
|
41
|
+
if (!Array.isArray(raw))
|
|
42
|
+
return [];
|
|
43
|
+
const out = [];
|
|
44
|
+
for (const item of raw) {
|
|
45
|
+
try {
|
|
46
|
+
out.push(cleaner(item));
|
|
47
|
+
} catch (error) {}
|
|
48
|
+
}
|
|
49
|
+
return out;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
// src/cleaners/asHealingObject.ts
|
|
53
|
+
var import_cleaners = require("cleaners");
|
|
54
|
+
function asHealingObject(shape, fallback) {
|
|
55
|
+
if (typeof shape === "function") {
|
|
56
|
+
return function asMaybeObject(raw) {
|
|
57
|
+
if (typeof raw !== "object" || raw == null)
|
|
58
|
+
return {};
|
|
59
|
+
const out = {};
|
|
60
|
+
const keys = fallback == null ? Object.keys(raw) : Object.keys({ ...raw, ...fallback });
|
|
61
|
+
for (let i = 0;i < keys.length; ++i) {
|
|
62
|
+
const key = keys[i];
|
|
63
|
+
if (key === "__proto__")
|
|
64
|
+
continue;
|
|
65
|
+
if (fallback?.[key] == null) {
|
|
66
|
+
try {
|
|
67
|
+
out[key] = shape(raw[key]);
|
|
68
|
+
} catch (error) {}
|
|
69
|
+
} else {
|
|
70
|
+
out[key] = import_cleaners.asMaybe(shape, fallback?.[key])(raw[key]);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return out;
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
const safeShape = { ...shape };
|
|
77
|
+
for (const key of Object.keys(shape)) {
|
|
78
|
+
safeShape[key] = import_cleaners.asMaybe(shape[key], fallback[key]);
|
|
79
|
+
}
|
|
80
|
+
return import_cleaners.asMaybe(import_cleaners.asObject(safeShape), fallback);
|
|
81
|
+
}
|
|
82
|
+
// src/cleaners/asHealingTuple.ts
|
|
83
|
+
var import_cleaners2 = require("cleaners");
|
|
84
|
+
function asHealingTuple(cleaner, fallback) {
|
|
85
|
+
return function asMaybeTuple(raw) {
|
|
86
|
+
if (!Array.isArray(raw)) {
|
|
87
|
+
return [...fallback];
|
|
88
|
+
}
|
|
89
|
+
const out = [];
|
|
90
|
+
const length = fallback.length;
|
|
91
|
+
for (let i = 0;i < length; ++i) {
|
|
92
|
+
out.push(import_cleaners2.asMaybe(cleaner, fallback[i])(raw[i]));
|
|
93
|
+
}
|
|
94
|
+
return out;
|
|
95
|
+
};
|
|
96
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "type": "commonjs" }
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Cleaner } from 'cleaners';
|
|
2
|
+
/**
|
|
3
|
+
* Cleans an array that may contain errors.
|
|
4
|
+
*
|
|
5
|
+
* Invalid entries are removed from the resulting array (the healing process).
|
|
6
|
+
*
|
|
7
|
+
* @param cleaner - The cleaner function to apply to each array element
|
|
8
|
+
* @returns A cleaner function that returns an array of cleaned values
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { asHealingArray } from '@edge.app/x-cleaners'
|
|
13
|
+
* import { asNumber } from 'cleaners'
|
|
14
|
+
*
|
|
15
|
+
* const cleaner = asHealingArray(asNumber)
|
|
16
|
+
* const result = cleaner([1, 'invalid', 3, null, 5])
|
|
17
|
+
* // Returns: [1, 3, 5]
|
|
18
|
+
* // - Invalid entries are removed
|
|
19
|
+
*
|
|
20
|
+
* // Non-array input returns empty array
|
|
21
|
+
* const result2 = cleaner('not-an-array')
|
|
22
|
+
* // Returns: []
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare function asHealingArray<T>(cleaner: Cleaner<T>): Cleaner<T[]>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { Cleaner, CleanerShape } from 'cleaners';
|
|
2
|
+
/**
|
|
3
|
+
* Cleans an object that may contain errors.
|
|
4
|
+
*
|
|
5
|
+
* Tries to fix individual properties when possible.
|
|
6
|
+
* For key-value objects, this will drop invalid entries unless an optional
|
|
7
|
+
* fallback is provided. For shape objects, this will use the matching property
|
|
8
|
+
* on the required fallback object.
|
|
9
|
+
*
|
|
10
|
+
* @param cleaner - The cleaner function to apply to each object value (for key-value objects)
|
|
11
|
+
* @param fallback - Optional fallback object providing default values for keys that fail validation
|
|
12
|
+
* @returns A cleaner function that returns a cleaned key-value object
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* import { asHealingObject } from '@edge.app/x-cleaners'
|
|
17
|
+
* import { asNumber } from 'cleaners'
|
|
18
|
+
*
|
|
19
|
+
* // Key-value object with fallback
|
|
20
|
+
* const cleaner = asHealingObject(asNumber, { age: 0, count: 0 })
|
|
21
|
+
* const result = cleaner({ age: '25', count: 'invalid', extra: '10' })
|
|
22
|
+
* // Returns: { age: 25, count: 0, extra: 10 }
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* // Key-value object without fallback (invalid entries are dropped)
|
|
28
|
+
* const cleaner = asHealingObject(asNumber)
|
|
29
|
+
* const result = cleaner({ valid: '42', invalid: 'not-a-number' })
|
|
30
|
+
* // Returns: { valid: 42 }
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare function asHealingObject<T>(cleaner: Cleaner<T>, fallback?: Record<string, T>): Cleaner<Record<string, T>>;
|
|
34
|
+
/**
|
|
35
|
+
* Cleans a shape object that may contain errors.
|
|
36
|
+
*
|
|
37
|
+
* @param shape - A shape object with cleaner functions as values
|
|
38
|
+
* @param fallback - Required fallback object providing default values for all properties
|
|
39
|
+
* @returns A cleaner function that returns a cleaned shape object
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* import { asHealingObject } from '@edge.app/x-cleaners'
|
|
44
|
+
* import { asString, asNumber } from 'cleaners'
|
|
45
|
+
*
|
|
46
|
+
* // Shape object with fallback
|
|
47
|
+
* const shapeCleaner = asHealingObject(
|
|
48
|
+
* { name: asString, age: asNumber },
|
|
49
|
+
* { name: 'Unknown', age: 0 }
|
|
50
|
+
* )
|
|
51
|
+
* const result = shapeCleaner({ name: 'John', age: 'invalid' })
|
|
52
|
+
* // Returns: { name: 'John', age: 0 }
|
|
53
|
+
*
|
|
54
|
+
* const result2 = shapeCleaner({ name: 'John' })
|
|
55
|
+
* // Returns: { name: 'John', age: 0 }
|
|
56
|
+
* ```
|
|
57
|
+
*/
|
|
58
|
+
export declare function asHealingObject<T extends object>(shape: CleanerShape<T>, fallback: T): Cleaner<T>;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { type Cleaner } from 'cleaners';
|
|
2
|
+
/**
|
|
3
|
+
* Cleans a tuple that may contain errors.
|
|
4
|
+
*
|
|
5
|
+
* Tries to fix individual elements when possible.
|
|
6
|
+
* The fallback array determines the tuple length and provides default values
|
|
7
|
+
* for invalid entries.
|
|
8
|
+
*
|
|
9
|
+
* @param cleaner - The cleaner function to apply to each tuple element
|
|
10
|
+
* @param fallback - Array of fallback values that defines the tuple length.
|
|
11
|
+
* If an element at index `i` fails validation, `fallback[i]` will be used.
|
|
12
|
+
* @returns A cleaner function that returns a tuple of cleaned values with fixed length
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```typescript
|
|
16
|
+
* import { asHealingTuple } from '@edge.app/x-cleaners'
|
|
17
|
+
* import { asNumber } from 'cleaners'
|
|
18
|
+
*
|
|
19
|
+
* // Tuple with fallback (invalid entries use fallback at same index)
|
|
20
|
+
* const cleaner = asHealingTuple(asNumber, [0, 0, 0] as const)
|
|
21
|
+
* const result = cleaner([1, 'invalid', 3])
|
|
22
|
+
* // Returns: [1, 0, 3] with type [number, number, number]
|
|
23
|
+
* // - Index 0: 1 is valid number (kept)
|
|
24
|
+
* // - Index 1: 'invalid' fails validation, uses fallback[1] = 0
|
|
25
|
+
* // - Index 2: 3 is valid number (kept)
|
|
26
|
+
*
|
|
27
|
+
* // Tuple size is fixed to fallback length
|
|
28
|
+
* const cleaner2 = asHealingTuple(asNumber, [10, 20] as const)
|
|
29
|
+
* const result2 = cleaner2([1, 2, 3, 4, 5])
|
|
30
|
+
* // Returns: [1, 2] with type [number, number]
|
|
31
|
+
* // - Only first 2 elements are kept (fallback length = 2)
|
|
32
|
+
*
|
|
33
|
+
* // Non-array input returns fallback tuple
|
|
34
|
+
* const result3 = cleaner2('not-an-array')
|
|
35
|
+
* // Returns: [10, 20]
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare function asHealingTuple<T, const F extends readonly T[]>(cleaner: Cleaner<T>, fallback: F): Cleaner<{
|
|
39
|
+
-readonly [K in keyof F]: T;
|
|
40
|
+
}>;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// src/cleaners/asHealingArray.ts
|
|
2
|
+
function asHealingArray(cleaner) {
|
|
3
|
+
return function asHealingArrayCleaner(raw) {
|
|
4
|
+
if (!Array.isArray(raw))
|
|
5
|
+
return [];
|
|
6
|
+
const out = [];
|
|
7
|
+
for (const item of raw) {
|
|
8
|
+
try {
|
|
9
|
+
out.push(cleaner(item));
|
|
10
|
+
} catch (error) {}
|
|
11
|
+
}
|
|
12
|
+
return out;
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
// src/cleaners/asHealingObject.ts
|
|
16
|
+
import { asMaybe, asObject } from "cleaners";
|
|
17
|
+
function asHealingObject(shape, fallback) {
|
|
18
|
+
if (typeof shape === "function") {
|
|
19
|
+
return function asMaybeObject(raw) {
|
|
20
|
+
if (typeof raw !== "object" || raw == null)
|
|
21
|
+
return {};
|
|
22
|
+
const out = {};
|
|
23
|
+
const keys = fallback == null ? Object.keys(raw) : Object.keys({ ...raw, ...fallback });
|
|
24
|
+
for (let i = 0;i < keys.length; ++i) {
|
|
25
|
+
const key = keys[i];
|
|
26
|
+
if (key === "__proto__")
|
|
27
|
+
continue;
|
|
28
|
+
if (fallback?.[key] == null) {
|
|
29
|
+
try {
|
|
30
|
+
out[key] = shape(raw[key]);
|
|
31
|
+
} catch (error) {}
|
|
32
|
+
} else {
|
|
33
|
+
out[key] = asMaybe(shape, fallback?.[key])(raw[key]);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return out;
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
const safeShape = { ...shape };
|
|
40
|
+
for (const key of Object.keys(shape)) {
|
|
41
|
+
safeShape[key] = asMaybe(shape[key], fallback[key]);
|
|
42
|
+
}
|
|
43
|
+
return asMaybe(asObject(safeShape), fallback);
|
|
44
|
+
}
|
|
45
|
+
// src/cleaners/asHealingTuple.ts
|
|
46
|
+
import { asMaybe as asMaybe2 } from "cleaners";
|
|
47
|
+
function asHealingTuple(cleaner, fallback) {
|
|
48
|
+
return function asMaybeTuple(raw) {
|
|
49
|
+
if (!Array.isArray(raw)) {
|
|
50
|
+
return [...fallback];
|
|
51
|
+
}
|
|
52
|
+
const out = [];
|
|
53
|
+
const length = fallback.length;
|
|
54
|
+
for (let i = 0;i < length; ++i) {
|
|
55
|
+
out.push(asMaybe2(cleaner, fallback[i])(raw[i]));
|
|
56
|
+
}
|
|
57
|
+
return out;
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export {
|
|
61
|
+
asHealingTuple,
|
|
62
|
+
asHealingObject,
|
|
63
|
+
asHealingArray
|
|
64
|
+
};
|
package/dist/index.d.ts
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@edge.app/x-cleaners",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"repository": "https://github.com/EdgeApp/x-cleaners",
|
|
5
|
+
"author": "Edge (Airbitz Inc.)",
|
|
6
|
+
"contributors": [
|
|
7
|
+
"Sam Holmes <sam@edge.app>"
|
|
8
|
+
],
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"type": "module",
|
|
11
|
+
"source": "./src/index.ts",
|
|
12
|
+
"main": "./dist/cjs/index.js",
|
|
13
|
+
"module": "./dist/esm/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"import": "./dist/esm/index.js",
|
|
18
|
+
"require": "./dist/cjs/index.js",
|
|
19
|
+
"types": "./dist/index.d.ts"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"clean": "bun -e \"const fs=require('fs');fs.rmSync('dist',{recursive:true,force:true});\"",
|
|
27
|
+
"build:esm": "bun build ./src/index.ts --outdir ./dist/esm --format esm --packages external",
|
|
28
|
+
"build:cjs": "bun build ./src/index.ts --outdir ./dist/cjs --format cjs --packages external && cp cjs-package.json ./dist/cjs/package.json",
|
|
29
|
+
"build:types": "bunx tsc --project tsconfig.build.json",
|
|
30
|
+
"build:copy-types": "bun -e \"const fs=require('fs');fs.mkdirSync('dist',{recursive:true});fs.copyFileSync('src/pouchdb-selector-core.d.ts','dist/pouchdb-selector-core.d.ts');\"",
|
|
31
|
+
"build": "bun run clean && bun run build:esm && bun run build:cjs && bun run build:types && bun run build:copy-types",
|
|
32
|
+
"precommit": "eslint --fix . && bun run test && bun run build",
|
|
33
|
+
"prepare": "(husky || true) && bun run build",
|
|
34
|
+
"release": "bun run prepare && bunx jsr publish && npm publish",
|
|
35
|
+
"test": "bun test",
|
|
36
|
+
"format": "prettier --write ."
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/bun": "latest",
|
|
40
|
+
"eslint": "^9.39.2",
|
|
41
|
+
"eslint-config-standard-kit": "^1.0.0",
|
|
42
|
+
"husky": "^9.0.11",
|
|
43
|
+
"prettier": "^3.6.2",
|
|
44
|
+
"typescript": "^5.6.3"
|
|
45
|
+
},
|
|
46
|
+
"peerDependencies": {
|
|
47
|
+
"typescript": "^5"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"cleaners": "^0.3.17"
|
|
51
|
+
}
|
|
52
|
+
}
|