@snaplet/copycat
Advanced tools
Comparing version 0.11.1 to 0.12.0-alpha.1
@@ -0,6 +1,10 @@ | ||
import { Input, JSONPrimitive, PlainNested } from 'fictional'; | ||
interface ScrambleOptions { | ||
preserve?: string[]; | ||
charMaps?: CharMapEntry[]; | ||
} | ||
export declare const scramble: (input: string, options?: ScrambleOptions) => string; | ||
declare type ScrambleInput = PlainNested<Date | JSONPrimitive>; | ||
declare type CharMapEntry = [[number, number], (input: Input) => string]; | ||
export declare const scramble: <Value extends ScrambleInput>(input: Value, options?: ScrambleOptions | undefined) => Value; | ||
export {}; | ||
//# sourceMappingURL=scramble.d.ts.map |
var __defProp = Object.defineProperty; | ||
var __defProps = Object.defineProperties; | ||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | ||
var __getOwnPropDescs = Object.getOwnPropertyDescriptors; | ||
var __getOwnPropNames = Object.getOwnPropertyNames; | ||
var __getOwnPropSymbols = Object.getOwnPropertySymbols; | ||
var __hasOwnProp = Object.prototype.hasOwnProperty; | ||
var __propIsEnum = Object.prototype.propertyIsEnumerable; | ||
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; | ||
var __spreadValues = (a, b) => { | ||
for (var prop in b || (b = {})) | ||
if (__hasOwnProp.call(b, prop)) | ||
__defNormalProp(a, prop, b[prop]); | ||
if (__getOwnPropSymbols) | ||
for (var prop of __getOwnPropSymbols(b)) { | ||
if (__propIsEnum.call(b, prop)) | ||
__defNormalProp(a, prop, b[prop]); | ||
} | ||
return a; | ||
}; | ||
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); | ||
var __export = (target, all) => { | ||
@@ -39,5 +56,34 @@ for (var name in all) | ||
const FALLBACK_MAKER = import_fictional.char.inRanges([import_fictional.char.ascii, import_fictional.char.latin1]); | ||
const scramble = (input, options = {}) => { | ||
const scramble = (input, options) => { | ||
if (input == null || typeof input === "boolean") { | ||
return input; | ||
} | ||
if (typeof input === "string") { | ||
return scrambleString(input, options); | ||
} | ||
if (typeof input === "number") { | ||
return scrambleNumber(input, options); | ||
} | ||
if (input instanceof Date) { | ||
return scrambleDate(input, options); | ||
} | ||
if (Array.isArray(input)) { | ||
return input.map((value) => scramble(value, options)); | ||
} | ||
if (typeof input === "object") { | ||
return scrambleObject(input, options); | ||
} | ||
throw new Error(`copycat.scramble() received value of type ${typeof input}, this type cannot be scrambled`); | ||
}; | ||
const scrambleObject = (input, options) => { | ||
const result = {}; | ||
for (const k of Object.keys(input)) { | ||
result[k] = scramble(input[k], options); | ||
} | ||
return result; | ||
}; | ||
const scrambleString = (input, options = {}) => { | ||
const { preserve = [" "] } = options; | ||
const preserveSet = new Set(preserve); | ||
const charMaps = [...options.charMaps ?? [], ...CHAR_RANGES_TO_MAKERS]; | ||
let i = -1; | ||
@@ -50,3 +96,3 @@ let result = ""; | ||
} else { | ||
const maker = findMatchingMaker(char2); | ||
const maker = findMatchingMaker(char2, charMaps); | ||
result += maker([input, i]); | ||
@@ -57,5 +103,5 @@ } | ||
}; | ||
const findMatchingMaker = (char2) => { | ||
const findMatchingMaker = (char2, charMaps) => { | ||
const code = char2.charCodeAt(0); | ||
for (const [[start, end], maker] of CHAR_RANGES_TO_MAKERS) { | ||
for (const [[start, end], maker] of charMaps) { | ||
if (start <= code && code <= end) { | ||
@@ -67,2 +113,19 @@ return maker; | ||
}; | ||
const digitRange = [codeOf("0"), codeOf("9")]; | ||
const nonZeroDigitRange = [codeOf("1"), codeOf("9")]; | ||
const scrambleDate = (input, options) => { | ||
const year = scrambleNumber(input.getUTCFullYear(), options); | ||
const month = scrambleNumber(input.getUTCMonth(), options) % 12; | ||
const day = scrambleNumber(input.getUTCMonth(), options) % 27 + 1; | ||
const hours = scrambleTimeSegment(input.getUTCHours()); | ||
const mins = scrambleTimeSegment(input.getUTCMinutes()); | ||
const seconds = scrambleTimeSegment(input.getUTCSeconds()); | ||
const milliseconds = scrambleNumber(input.getUTCMilliseconds()); | ||
return new Date(Date.UTC(year, month, day, hours, mins, seconds, milliseconds)); | ||
}; | ||
const scrambleTimeSegment = (input) => scrambleNumber(input) % 60; | ||
const scrambleNumber = (input, options) => +scrambleString(input.toString(), __spreadProps(__spreadValues({}, options), { | ||
preserve: ["."], | ||
charMaps: [[digitRange, import_fictional.char.inRanges([nonZeroDigitRange])]] | ||
})); | ||
// Annotate the CommonJS export names for ESM import in node: | ||
@@ -69,0 +132,0 @@ 0 && (module.exports = { |
@@ -12,1 +12,37 @@ var import__ = require("."); | ||
}); | ||
test("numbers", () => { | ||
expect(import__.copycat.scramble(999999999)).toMatchInlineSnapshot(`682197452`); | ||
expect(import__.copycat.scramble(782364.902374)).toMatchInlineSnapshot(`387998.531441`); | ||
}); | ||
test("dates", () => { | ||
expect(import__.copycat.scramble(new Date(89723948723948))).toMatchInlineSnapshot(`7754-02-02T15:03:19.862Z`); | ||
}); | ||
test("booleans", () => { | ||
expect(import__.copycat.scramble(false)).toBe(false); | ||
expect(import__.copycat.scramble(true)).toBe(true); | ||
}); | ||
test("nulls", () => { | ||
expect(import__.copycat.scramble(null)).toEqual(null); | ||
}); | ||
test("nested values", () => { | ||
expect(import__.copycat.scramble({ | ||
a: [ | ||
{ | ||
b: 23, | ||
c: "foo" | ||
} | ||
] | ||
})).toMatchInlineSnapshot(` | ||
Object { | ||
"a": Array [ | ||
Object { | ||
"b": 19, | ||
"c": "ebp", | ||
}, | ||
], | ||
} | ||
`); | ||
}); | ||
test("unsupported types", () => { | ||
expect(() => import__.copycat.scramble(Symbol("\u{1F918}"))).toThrow(/symbol/); | ||
}); |
{ | ||
"name": "@snaplet/copycat", | ||
"version": "0.11.1", | ||
"version": "0.12.0-alpha.1+scramble-everything", | ||
"description": "", | ||
@@ -17,3 +17,3 @@ "main": "dist/index.js", | ||
"@faker-js/faker": "^6.2.0", | ||
"fictional": "^0.7.4", | ||
"fictional": "^0.7.6", | ||
"uuid": "^8.3.2" | ||
@@ -20,0 +20,0 @@ }, |
@@ -125,5 +125,7 @@ # ![copycat](https://user-images.githubusercontent.com/1731223/167850970-584e6953-6543-4085-af5a-f9d8b7ffe988.png) | ||
### `copycat.scramble(string[, options])` | ||
### `copycat.scramble(input[, options])` | ||
Takes in a `string` value, and returns a string with the same length, but with each character replaced with a different character in the same character range: | ||
Takes in an `input` value, and returns a value of the same type and length, but with each character/digit replaced with a different character/digit. | ||
For string, the replacement characters will be in the same character range: | ||
* By default, spaces are preserved (see `preserve` option below) | ||
@@ -141,2 +143,42 @@ * Lower case ASCII characters are replaced with lower case ASCII letters | ||
If a number is given, each digit will be replaced, and the floating point (if relevant) will be preserved: | ||
```js | ||
copycat.scramble(782364.902374) | ||
// => 387998.531441 | ||
``` | ||
If an object or array is given, the values inside the object or array will be recursively scrambled: | ||
```js | ||
copycat.scramble({ | ||
a: [ | ||
{ | ||
b: 23, | ||
c: 'foo', | ||
}, | ||
], | ||
}) | ||
/* => | ||
{ | ||
"a": [{ | ||
"b": 19, | ||
"c": "ebp" | ||
}] | ||
} | ||
*/ | ||
``` | ||
If a date is given, each segment in the date will be scrambled: | ||
```js | ||
copycat.scramble(new Date('2022-10-25T19:08:39.374Z')) | ||
// => Date(6332-05-05T02:01:15.366Z) | ||
``` | ||
If a boolean or null value is given, the value will simply be returned. | ||
If a value of any other type is given, an error will be thrown | ||
#### `options` | ||
@@ -143,0 +185,0 @@ |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
6719460
2881
575
2
Updatedfictional@^0.7.6