Join our webinar on Wednesday, June 26, at 1pm EDTHow Chia Mitigates Risk in the Crypto Industry.Register
Socket
Socket
Sign inDemoInstall

scrubbr

Package Overview
Dependencies
67
Maintainers
1
Versions
16
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 0.0.1-alpha.6 to 0.0.1-alpha.7

.github/workflows/docs.yml

4

dist/index.d.ts

@@ -1,6 +0,6 @@

import Scrubbr from './Scrubbr';
export { ScrubbrOptions, TypeSerializer, PathSerializer, JSONSchemaDefinitions, } from './Scrubbr';
export type { ScrubbrOptions, JSONSchemaDefinitions, TypeSerializer, GenericSerializer, } from './types';
export { ScrubbrState } from './ScrubbrState';
export { LogLevel } from './Logger';
export { useType } from './helpers';
import Scrubbr from './Scrubbr';
export default Scrubbr;

@@ -7,3 +7,2 @@ "use strict";

exports.useType = exports.LogLevel = exports.ScrubbrState = void 0;
var Scrubbr_1 = __importDefault(require("./Scrubbr"));
var ScrubbrState_1 = require("./ScrubbrState");

@@ -15,3 +14,4 @@ Object.defineProperty(exports, "ScrubbrState", { enumerable: true, get: function () { return ScrubbrState_1.ScrubbrState; } });

Object.defineProperty(exports, "useType", { enumerable: true, get: function () { return helpers_1.useType; } });
var Scrubbr_1 = __importDefault(require("./Scrubbr"));
exports.default = Scrubbr_1.default;
//# sourceMappingURL=index.js.map

@@ -1,2 +0,2 @@

import { ScrubbrOptions } from './Scrubbr';
import { ScrubbrOptions } from './';
export declare enum LogLevel {

@@ -3,0 +3,0 @@ DEBUG = 4,

import { JSONSchema7 } from 'json-schema';
import { LogLevel } from './Logger';
import { ScrubbrState } from './ScrubbrState';
export declare type TypeSerializer = (data: any, state: ScrubbrState) => any | Promise<any>;
export declare type PathSerializer = (data: any, state: ScrubbrState) => any | Promise<any>;
export declare type ScrubbrOptions = {
/**
* Set the logger level: LogLevel.NONE, LogLevel.ERROR, LogLevel.WARN, LogLevel.INFO, LogLevel.DEBUG
* @default LogLevel.NONE
*/
logLevel?: LogLevel;
/**
* Add indents to better show where in the object it is.
* This is most useful when logLevel is set to LogLevel.DEBUG.
* @default false
*/
logNesting?: boolean | string;
/**
* A string prefix you want to precede all log messages
* @default ""
*/
logPrefix?: string;
/**
* Throw an exception on errors that could effect the integrity of your data.
* Otherwise, the error will just be logged if the log level is set to LogLevel.ERROR or above.
* @default true
*/
throwOnError?: boolean;
};
export declare type JSONSchemaDefinitions = JSONSchema7 | {
definitions: {
[k: string]: JSONSchema7;
};
};
import { ScrubbrOptions, JSONSchemaDefinitions, TypeSerializer, GenericSerializer } from './types';
export default class Scrubbr {

@@ -40,3 +9,4 @@ options: ScrubbrOptions;

private typeSerializers;
private pathSerializers;
private genericSerializers;
private globalContext;
/**

@@ -65,3 +35,3 @@ * Create new scrubbr serializer

*/
getSchemaForType(typeName: string): JSONSchema7 | null;
getSchemaFor(typeName: string): JSONSchema7 | null;
/**

@@ -74,7 +44,18 @@ * Add a function to serialize a schema type

/**
* Add a custom serializer function that's called for each node in the object.
* Add a generic custom serializer function that's called for each node in the object.
* @param {function} serializer - The serializer function.
*/
addPathSerializer(serializer: PathSerializer): void;
addGenericSerializer(serializer: GenericSerializer): void;
/**
* Set the global context object, that will be automatically merged with the context passed to the serialize function.
* You can use this for setting things like the logged-in user, at a global level.
* @param {object} context - Any object you want to set as the context.
* @param {boolean} merge - Automatically merge this context with the existing global context (defaults false)
*/
setGlobalContext(context: object, merge?: boolean): void;
/**
* Retrieve the global context object.
*/
getGlobalContext(): object;
/**
* Serialize data based on a TypeScript type.

@@ -85,3 +66,3 @@ * @param {string} schemaType - The name of the typescript type to serialize the data with.

*/
serialize<Type = any>(schemaType: string, data: Object, context?: any): Promise<Type>;
serialize<Type = any>(schemaType: string, data: object, context?: object): Promise<Type>;
/**

@@ -122,3 +103,3 @@ * Traverse into a node of data on an object to serialize.

*/
private runPathSerializers;
private runGenericSerializers;
/**

@@ -125,0 +106,0 @@ * Run serializers on property data

@@ -91,3 +91,4 @@ "use strict";

this.typeSerializers = new Map();
this.pathSerializers = [];
this.genericSerializers = [];
this.globalContext = {};
this.options = __assign(__assign({}, defaultOptions), options);

@@ -102,4 +103,4 @@ this.logger = new Logger_1.Logger(options);

var cloned = new Scrubbr(this.schema, options);
this.pathSerializers.forEach(function (serializerFn) {
cloned.addPathSerializer(serializerFn);
this.genericSerializers.forEach(function (serializerFn) {
cloned.addGenericSerializer(serializerFn);
});

@@ -147,3 +148,3 @@ this.typeSerializers.forEach(function (serializers, typeName) {

*/
Scrubbr.prototype.getSchemaForType = function (typeName) {
Scrubbr.prototype.getSchemaFor = function (typeName) {
var _a;

@@ -167,9 +168,30 @@ var definitions = ((_a = this.schema) === null || _a === void 0 ? void 0 : _a.definitions) || {};

/**
* Add a custom serializer function that's called for each node in the object.
* Add a generic custom serializer function that's called for each node in the object.
* @param {function} serializer - The serializer function.
*/
Scrubbr.prototype.addPathSerializer = function (serializer) {
this.pathSerializers.push(serializer);
Scrubbr.prototype.addGenericSerializer = function (serializer) {
this.genericSerializers.push(serializer);
};
/**
* Set the global context object, that will be automatically merged with the context passed to the serialize function.
* You can use this for setting things like the logged-in user, at a global level.
* @param {object} context - Any object you want to set as the context.
* @param {boolean} merge - Automatically merge this context with the existing global context (defaults false)
*/
Scrubbr.prototype.setGlobalContext = function (context, merge) {
if (merge === void 0) { merge = false; }
if (merge) {
this.globalContext = __assign(__assign({}, this.globalContext), context);
}
else {
this.globalContext = context;
}
};
/**
* Retrieve the global context object.
*/
Scrubbr.prototype.getGlobalContext = function () {
return this.globalContext;
};
/**
* Serialize data based on a TypeScript type.

@@ -181,3 +203,3 @@ * @param {string} schemaType - The name of the typescript type to serialize the data with.

Scrubbr.prototype.serialize = function (schemaType, data, context) {
if (context === void 0) { context = null; }
if (context === void 0) { context = {}; }
return __awaiter(this, void 0, void 0, function () {

@@ -189,3 +211,3 @@ var schema, cloned, state, serialized;

this.logger.info("Serializing data with TS type: '" + schemaType + "'");
schema = this.getSchemaForType(schemaType);
schema = this.getSchemaFor(schemaType);
if (!schema) {

@@ -195,2 +217,5 @@ throw new Error("Could not find the type: " + schemaType);

cloned = JSON.parse(JSON.stringify(data));
// Merge contexts
context = __assign(__assign({}, this.globalContext), context);
this.logger.debug("Using context: '" + JSON.stringify(context, null, ' ') + "'");
state = new ScrubbrState_1.ScrubbrState(data, schema, this.options, context);

@@ -258,3 +283,3 @@ state.rootSchemaType = schemaType;

state.logger.debug("[PATH] " + propPath);
propState = state.createNodeState(propPath, propSchema);
propState = state.createNodeState(value, name_1, propPath, propSchema);
// Property not defined in the schema, do not serialize property

@@ -306,3 +331,3 @@ if (!propSchema) {

state.logger.debug("[PATH] " + itemPath);
itemState = state.createNodeState(itemPath, itemSchema);
itemState = state.createListState(value, i, itemPath, itemSchema);
// Skip items past the tuple length

@@ -347,3 +372,3 @@ if (isTuple && i >= tupleSchema.length) {

}
return [4 /*yield*/, this.runPathSerializers(data, state)];
return [4 /*yield*/, this.runGenericSerializers(data, state)];
case 1:

@@ -393,3 +418,3 @@ // Run serializers

typeName = decodeURI(typeName);
var type = _this.getSchemaForType(typeName);
var type = _this.getSchemaFor(typeName);
if (type) {

@@ -447,3 +472,3 @@ foundTypes.set(typeName, type);

else {
var schemaDef = this.getSchemaForType(schemaType);
var schemaDef = this.getSchemaFor(schemaType);
if (!schemaDef) {

@@ -466,11 +491,11 @@ this.error("Could not find a type definition for '" + schemaType + "'", state);

*/
Scrubbr.prototype.runPathSerializers = function (dataNode, state) {
Scrubbr.prototype.runGenericSerializers = function (dataNode, state) {
return __awaiter(this, void 0, void 0, function () {
var _this = this;
return __generator(this, function (_a) {
if (!this.pathSerializers.length) {
if (!this.genericSerializers.length) {
return [2 /*return*/, dataNode];
}
state.logger.debug("Running " + this.pathSerializers.length + " path serializers");
return [2 /*return*/, this.pathSerializers.reduce(function (promise, serializerFn) {
state.logger.debug("Running " + this.genericSerializers.length + " generic serializers");
return [2 /*return*/, this.genericSerializers.reduce(function (promise, serializerFn) {
return promise.then(function (data) {

@@ -502,3 +527,3 @@ var serialized = serializerFn(data, state);

}
if (!this.getSchemaForType(typeName)) {
if (!this.getSchemaFor(typeName)) {
this.error("No type named '" + typeName + "'.", state);

@@ -505,0 +530,0 @@ return [2 /*return*/, dataNode];

import { JSONSchema7 } from 'json-schema';
import { Logger } from './Logger';
import { ScrubbrOptions } from './Scrubbr';
import { ScrubbrOptions } from './types';
export declare class ScrubbrState {
/**
* The current object path
*/
path: string;
/**
* The property name of the data being serialized.
*/
name: string;
/**
* If we're currently serializing an array, this is the array index
*/
index: number | null;
/**
* The state of the parent node
*/
parent: ScrubbrState | null;
/**
* Unserialized data at this node.
*/
originalData: any;
/**
* The schema type we're serializing the document with.
*/
rootSchemaType: string;
/**
* The schema type of the current data node.
*/
schemaType: string | null;
/**
* JSON Schema object of the current data node type.
*/
schemaDef: JSONSchema7;
data: any;
/**
* The context object passed in to the serialize function.
*/
context: any;
originalData: any;
/**
* The nesting level at this node of the data being serialized
*/
nesting: number;
/**
* The schema types that have been used to serialize this node.
*/
seenTypes: string[];

@@ -18,5 +53,9 @@ logger: Logger;

/**
* Create a child state off of this one
* Create a child property node state, derived off of this state.
*/
createNodeState(path: string, schema: JSONSchema7): ScrubbrState;
createNodeState(data: any, name: string, path: string, schema: JSONSchema7): ScrubbrState;
/**
* Create a child array index state, derived off of this state.
*/
createListState(data: any, index: number, path: string, schema: JSONSchema7): ScrubbrState;
}

@@ -9,10 +9,40 @@ "use strict";

if (nesting === void 0) { nesting = 0; }
this.path = '/';
/**
* The current object path
*/
this.path = '';
/**
* The property name of the data being serialized.
*/
this.name = '';
/**
* If we're currently serializing an array, this is the array index
*/
this.index = null;
/**
* The state of the parent node
*/
this.parent = null;
/**
* The schema type we're serializing the document with.
*/
this.rootSchemaType = '';
/**
* The schema type of the current data node.
*/
this.schemaType = null;
/**
* The context object passed in to the serialize function.
*/
this.context = {};
/**
* The nesting level at this node of the data being serialized
*/
this.nesting = 0;
/**
* The schema types that have been used to serialize this node.
*/
this.seenTypes = [];
this.context = context;
this.data = data;
this.originalData = data;
this.schemaDef = schema;

@@ -25,9 +55,21 @@ this.path = path;

/**
* Create a child state off of this one
* Create a child property node state, derived off of this state.
*/
ScrubbrState.prototype.createNodeState = function (path, schema) {
var state = new ScrubbrState(this.originalData, schema, this.options, this.context, path, this.nesting + 1);
ScrubbrState.prototype.createNodeState = function (data, name, path, schema) {
var state = new ScrubbrState(data, schema, this.options, this.context, path, this.nesting + 1);
state.name = name;
state.parent = this;
state.rootSchemaType = this.rootSchemaType;
return state;
};
/**
* Create a child array index state, derived off of this state.
*/
ScrubbrState.prototype.createListState = function (data, index, path, schema) {
var state = new ScrubbrState(data, schema, this.options, this.context, path, this.nesting + 1);
state.index = index;
state.parent = this;
state.rootSchemaType = this.rootSchemaType;
return state;
};
return ScrubbrState;

@@ -34,0 +76,0 @@ }());

{
"name": "scrubbr",
"version": "0.0.1-alpha.6",
"version": "0.0.1-alpha.7",
"description": "Serialize and sanitize JSON data using TypeScript.",

@@ -12,3 +12,4 @@ "repository": "https://github.com/jgillick/scrubbr",

"example": "ts-node ./example/index.ts",
"schema": "ts-json-schema-generator -p ./test/typescript/schema.ts -o ./dist/schema.json -e all"
"docs": "mkdocs serve",
"docs:build": "mkdocs build"
},

@@ -15,0 +16,0 @@ "author": "Jeremy Gillick",

@@ -5,7 +5,6 @@ # Scrubbr

[![npm version](https://img.shields.io/npm/v/scrubbr)](https://badge.fury.io/js/scrubbr)
[![downloads](https://img.shields.io/npm/dm/Scrubbr)](https://www.npmjs.com/package/scrubbr)
<!-- [![downloads](https://img.shields.io/npm/dm/Scrubbr)](https://www.npmjs.com/package/scrubbr) -->
Serialize JSON data using TypeScript.
Serialize and sanitize JSON data using TypeScript.
![Simple Example](https://github.com/jgillick/scrubbr/raw/main/example.png)

@@ -15,15 +14,4 @@

## Table of contents
[Documentation](https://jgillick.github.io/scrubbr/)
- Install
- Quick Start
- Custom Serializer Functions
- Type Serializers
- Path Serializers
- Cache the generated schema to disk
- Schema Validation
- Troubleshooting
- Look at the generated schema
- Enable debug logging
## Install

@@ -37,2 +25,19 @@

The simplest example is to filter out sensitive data.
In this example we want to filter the email and password out of this sample data:
```javascript
{
users: [
{
name: 'John Doe',
image: 'http://i.pravatar.cc/300',
email: 'donotspam@me.com',
password: 'xxxsecretxxx',
},
],
};
```
1. Define a TypeScript file as your master schema:

@@ -58,4 +63,4 @@

// Load the typescript schema file
// PERFORMANCE NOTE: this is a synchronous call! Load early and cache to a shared variable.
// PERFORMANCE NOTE: this is a synchronous call!
// Load early and cache to a shared variable.
const scrubbr = new Scrubbr('./schema.ts');

@@ -69,21 +74,7 @@

}
// Raw unsanitized data
function getUsers() {
return {
users: [
{
name: 'John Doe',
image: 'http://i.pravatar.cc/300',
email: 'donotspam@me.com',
password: 'xxxsecretxxx',
},
],
};
}
```
3. Output
3. Ouput
```json
```typescript
{

@@ -99,162 +90,8 @@ "users": [

## Custom Serializer Functions
# Documentation
You can define additional functions for custom serializations.
Read the [documentation](https://jgillick.github.io/scrubbr/) to learn how do do more with Scrubbr.
### Type Serializers
Type serializer functions are called every time a matching TypeScript type is encountered.
For example, if you want to use another type to serialize a logged-in user:
```typescript
import Scrubbr, { useType } from 'scrubbr';
// Called every time scrubbr finds a User type object
scrubbr.addTypeSerializer('User', (data, state) => {
// `context` is a value you pass to scrubbr.serialize (see below)
if (data.id === state.context.loggedInUserId) {
return useType('UserPrivileged');
}
// You can manually transform the data here
return data;
});
// Context can be anything you want
const context = {
loggedInUserId: 10,
};
const serialized = await scrubbr.serialize('PostList', data, context);
```
### Path Serializers
This serializer is called at each node of the data object, regardless of type. It's called a path serializer because you'll use the `state.path` value to determine which node you're serializing.
In this example we want to convert every `createdAt` date value to the local timezone.
```typescript
import moment from 'moment-timezone';
import Scrubbr, { useType } from 'scrubbr';
// Convert date-like strings from UTC to local time
scrubbr.addPathSerializer((data, state) => {
const path = state.path;
if (path.match(/\.createdAt$/)) {
return moment(data).tz(state.context.timezone).format();
}
return data;
});
const context = {
timezone: 'America/Los_Angeles',
};
const serialized = await scrubbr.serialize('PostList', data, context);
```
## Try it yourself
It's easy to try it yourself with the included example in `example/index.ts`. Just clone this repo, install the dependencies (`npm install`) and then run the example app with:
```shell
npm run example
```
## Caching the generated schema to disk
To optimize startup time, you can save the schema object scrubbr uses internally to disk during your build step and then load it directly when you initialize scrubbr. Internally, scrubbr uses the [ts-json-schema-generator](https://www.npmjs.com/package/ts-json-schema-generator) library to convert TypeScript to a JSON schema file. NOTE: you cannot load any JSON schema file into scrubbr, it needs to follow the conventions of ts-json-schema-generator.
**Build**
```shell
npx ts-json-schema-generator -f ./tsconfig.json -e all -p ./schema.ts -o ./dist/schema.json
```
**Runtime code**
```typescript
import Scrubbr, { JSONSchemaDefinitions } from 'scrubbr';
// Set resolveJsonModule to true in your tsconfig, otherwise use require()
import * as schema from './schema.json';
const scrubbr = new Scrubbr(schema as JSONSchemaDefinitions);
```
## Schema Validation
For the sake of performance and simplicity, scrubber does not perform a schema validation step (it outputs data, not validates). However, under the hood scrubbr converts TypeScript to JSONSchema (via the great [ts-json-schema-generator](https://www.npmjs.com/package/ts-json-schema-generator) package). So you can easily use [ajv](https://www.npmjs.com/package/ajv) to validate the serialized object.
```typescript
import Ajv from 'ajv';
import Scrubbr from 'scrubbr';
const scrubbr = new Scrubbr('./schema.ts');
async function main() {
// Serialize
const output = await scrubbr.serialize('UserList', data);
const jsonSchema = scrubbr.getSchema();
// Validate
const ajv = new Ajv();
const schemaValidator = ajv.compile(jsonSchema);
const isValid = schemaValidator(output);
if (!isValid) {
console.error(schemaValidator.errors);
}
}
```
## Troubleshooting
### Look at the generated schema
If scrubbr is not returning the data you're expecting, the first place to look is at the internal schema definitions:
```typescript
console.log(scrubbr.getSchema());
```
_This is a [JSON schema](https://json-schema.org/understanding-json-schema/) that is created from your TypeScript file._
Next look at the schema definition for the TypeScript type you're trying to serialize to.
```typescript
// return scrubbr.serialize('UserList', data);
console.log(scrubbr.getSchemaForType('UserList'));
```
Verify that this returns a JSON Schema object and that it contains the properties you want serialized.
### Debugging output
Enable debug logging:
```typescript
import Scrubbr, { LogLevel } from 'scrubbr';
const scrubbr = new Scrubbr('./schema.ts', { logLevel: LogLevel.DEBUG });
```
Scrubbr can also nest the logs to make it easier to read:
```typescript
const scrubbr = new Scrubbr('./schema.ts', {
logLevel: LogLevel.DEBUG,
logNesting: true,
});
```
And you can even enter the indent string to use for each level of nesting:
```typescript
const scrubbr = new Scrubbr('./schema.ts', {
logLevel: LogLevel.DEBUG,
logNesting: '~~>',
});
```
# License
[MIT](https://github.com/ajv-validator/ajv/blob/HEAD/LICENSE)

@@ -1,9 +0,8 @@

import Scrubbr from './Scrubbr';
export {
export type {
ScrubbrOptions,
JSONSchemaDefinitions,
TypeSerializer,
PathSerializer,
JSONSchemaDefinitions,
} from './Scrubbr';
GenericSerializer,
} from './types';
export { ScrubbrState } from './ScrubbrState';

@@ -13,2 +12,3 @@ export { LogLevel } from './Logger';

import Scrubbr from './Scrubbr';
export default Scrubbr;

@@ -1,2 +0,2 @@

import { ScrubbrOptions } from './Scrubbr';
import { ScrubbrOptions } from './';

@@ -3,0 +3,0 @@ export enum LogLevel {

@@ -8,41 +8,9 @@ import * as fs from 'fs';

import { UseType } from './helpers';
import {
ScrubbrOptions,
JSONSchemaDefinitions,
TypeSerializer,
GenericSerializer,
} from './types';
export type TypeSerializer = (
data: any,
state: ScrubbrState
) => any | Promise<any>;
export type PathSerializer = (
data: any,
state: ScrubbrState
) => any | Promise<any>;
export type ScrubbrOptions = {
/**
* Set the logger level: LogLevel.NONE, LogLevel.ERROR, LogLevel.WARN, LogLevel.INFO, LogLevel.DEBUG
* @default LogLevel.NONE
*/
logLevel?: LogLevel;
/**
* Add indents to better show where in the object it is.
* This is most useful when logLevel is set to LogLevel.DEBUG.
* @default false
*/
logNesting?: boolean | string;
/**
* A string prefix you want to precede all log messages
* @default ""
*/
logPrefix?: string;
/**
* Throw an exception on errors that could effect the integrity of your data.
* Otherwise, the error will just be logged if the log level is set to LogLevel.ERROR or above.
* @default true
*/
throwOnError?: boolean;
};
const defaultOptions = {

@@ -56,9 +24,2 @@ logLevel: LogLevel.NONE,

type ObjectNode = Record<string, any>;
export type JSONSchemaDefinitions =
| JSONSchema7
| {
definitions: {
[k: string]: JSONSchema7;
};
};

@@ -70,3 +31,4 @@ export default class Scrubbr {

private typeSerializers = new Map<string, TypeSerializer[]>();
private pathSerializers: PathSerializer[] = [];
private genericSerializers: GenericSerializer[] = [];
private globalContext: object = {};

@@ -96,4 +58,4 @@ /**

this.pathSerializers.forEach((serializerFn) => {
cloned.addPathSerializer(serializerFn);
this.genericSerializers.forEach((serializerFn) => {
cloned.addGenericSerializer(serializerFn);
});

@@ -150,3 +112,3 @@ this.typeSerializers.forEach((serializers, typeName) => {

*/
getSchemaForType(typeName: string): JSONSchema7 | null {
getSchemaFor(typeName: string): JSONSchema7 | null {
const definitions = this.schema?.definitions || {};

@@ -171,10 +133,34 @@ if (typeof definitions[typeName] === 'undefined') {

/**
* Add a custom serializer function that's called for each node in the object.
* Add a generic custom serializer function that's called for each node in the object.
* @param {function} serializer - The serializer function.
*/
addPathSerializer(serializer: PathSerializer) {
this.pathSerializers.push(serializer);
addGenericSerializer(serializer: GenericSerializer) {
this.genericSerializers.push(serializer);
}
/**
* Set the global context object, that will be automatically merged with the context passed to the serialize function.
* You can use this for setting things like the logged-in user, at a global level.
* @param {object} context - Any object you want to set as the context.
* @param {boolean} merge - Automatically merge this context with the existing global context (defaults false)
*/
setGlobalContext(context: object, merge: boolean = false) {
if (merge) {
this.globalContext = {
...this.globalContext,
...context,
};
} else {
this.globalContext = context;
}
}
/**
* Retrieve the global context object.
*/
getGlobalContext() {
return this.globalContext;
}
/**
* Serialize data based on a TypeScript type.

@@ -187,8 +173,8 @@ * @param {string} schemaType - The name of the typescript type to serialize the data with.

schemaType: string,
data: Object,
context: any = null
data: object,
context: object = {}
): Promise<Type> {
this.logger.info(`Serializing data with TS type: '${schemaType}'`);
const schema = this.getSchemaForType(schemaType);
const schema = this.getSchemaFor(schemaType);
if (!schema) {

@@ -201,2 +187,10 @@ throw new Error(`Could not find the type: ${schemaType}`);

// Merge contexts
context = {
...this.globalContext,
...context,
}
this.logger.debug(`Using context: '${JSON.stringify(context, null, ' ')}'`);
// Serialize
const state: ScrubbrState = new ScrubbrState(

@@ -252,3 +246,3 @@ data,

state.logger.debug(`[PATH] ${propPath}`);
const propState = state.createNodeState(propPath, propSchema);
const propState = state.createNodeState(value, name, propPath, propSchema);

@@ -290,5 +284,7 @@ // Property not defined in the schema, do not serialize property

state.logger.debug(`[PATH] ${itemPath}`);
const itemState = state.createNodeState(
const itemState = state.createListState(
value,
i,
itemPath,
itemSchema as JSONSchema7
itemSchema as JSONSchema7,
);

@@ -327,3 +323,3 @@

// Run serializers
data = await this.runPathSerializers(data, state);
data = await this.runGenericSerializers(data, state);
data = await this.runTypeSerializers(data, state);

@@ -375,3 +371,3 @@

typeName = decodeURI(typeName);
const type = this.getSchemaForType(typeName);
const type = this.getSchemaFor(typeName);
if (type) {

@@ -437,3 +433,3 @@ foundTypes.set(typeName, type);

} else {
const schemaDef = this.getSchemaForType(schemaType);
const schemaDef = this.getSchemaFor(schemaType);
if (!schemaDef) {

@@ -462,7 +458,7 @@ this.error(

*/
private async runPathSerializers(
private async runGenericSerializers(
dataNode: Object,
state: ScrubbrState
): Promise<Object> {
if (!this.pathSerializers.length) {
if (!this.genericSerializers.length) {
return dataNode;

@@ -472,6 +468,6 @@ }

state.logger.debug(
`Running ${this.pathSerializers.length} path serializers`
`Running ${this.genericSerializers.length} generic serializers`
);
return this.pathSerializers.reduce((promise, serializerFn) => {
return this.genericSerializers.reduce((promise, serializerFn) => {
return promise.then((data) => {

@@ -501,3 +497,3 @@ const serialized = serializerFn(data, state);

if (!this.getSchemaForType(typeName)) {
if (!this.getSchemaFor(typeName)) {
this.error(`No type named '${typeName}'.`, state);

@@ -504,0 +500,0 @@ return dataNode;

import { JSONSchema7 } from 'json-schema';
import { LogLevel, Logger } from './Logger';
import { ScrubbrOptions } from './Scrubbr';
import { ScrubbrOptions } from './types';
export class ScrubbrState {
path: string = '/';
/**
* The current object path
*/
path: string = '';
/**
* The property name of the data being serialized.
*/
name: string = '';
/**
* If we're currently serializing an array, this is the array index
*/
index: number | null = null;
/**
* The state of the parent node
*/
parent: ScrubbrState | null = null;
/**
* Unserialized data at this node.
*/
originalData: any;
/**
* The schema type we're serializing the document with.
*/
rootSchemaType: string = '';
/**
* The schema type of the current data node.
*/
schemaType: string | null = null;
/**
* JSON Schema object of the current data node type.
*/
schemaDef: JSONSchema7;
data: any;
/**
* The context object passed in to the serialize function.
*/
context: any = {};
originalData: any;
/**
* The nesting level at this node of the data being serialized
*/
nesting: number = 0;
/**
* The schema types that have been used to serialize this node.
*/
seenTypes: string[] = [];
logger: Logger;

@@ -27,3 +73,3 @@ options: ScrubbrOptions;

this.context = context;
this.data = data;
this.originalData = data;
this.schemaDef = schema;

@@ -38,7 +84,7 @@ this.path = path;

/**
* Create a child state off of this one
* Create a child property node state, derived off of this state.
*/
createNodeState(path: string, schema: JSONSchema7): ScrubbrState {
createNodeState(data: any, name: string, path: string, schema: JSONSchema7): ScrubbrState {
const state = new ScrubbrState(
this.originalData,
data,
schema,

@@ -50,5 +96,25 @@ this.options,

);
state.name = name;
state.parent = this;
state.rootSchemaType = this.rootSchemaType;
return state;
}
/**
* Create a child array index state, derived off of this state.
*/
createListState(data: any, index: number, path: string, schema: JSONSchema7): ScrubbrState {
const state = new ScrubbrState(
data,
schema,
this.options,
this.context,
path,
this.nesting + 1
);
state.index = index;
state.parent = this;
state.rootSchemaType = this.rootSchemaType;
return state;
}
}
import 'jest';
import Scrubbr, { useType } from '../src/';
import Scrubbr, { useType, ScrubbrState } from '../src/';

@@ -13,5 +13,5 @@ describe('Union types', () => {

// Track what type is chosen for ever path node
firstSerializerFn = jest.fn((data, _state) => data);
scrubbr.addPathSerializer(firstSerializerFn);
scrubbr.addPathSerializer((data, state) => {
firstSerializerFn = jest.fn((data: any, _state: ScrubbrState) => data);
scrubbr.addGenericSerializer(firstSerializerFn);
scrubbr.addGenericSerializer((data: any, state: ScrubbrState) => {
pathTypes.set(state.path, state.schemaType);

@@ -18,0 +18,0 @@ return data;

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc