forked from paularmstrong/normalizr
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add 'transform', 'keyTransformer', and port to typescript. :arrow_Up:…
… 2.0.0
- Loading branch information
1 parent
6314d9c
commit ae72d65
Showing
29 changed files
with
710 additions
and
232 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
src | ||
test |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import ISchema from "./Schema"; | ||
export default class EntitySchema implements ISchema { | ||
_key: string; | ||
_getId: AttributeGetter; | ||
_idAttribute: string | AttributeGetter; | ||
constructor(key: string, options?: IEntitySchemaOptions); | ||
getKey(): string; | ||
getId(entity: any): any; | ||
getIdAttribute(): string | AttributeGetter; | ||
define(nestedSchema: INestedSchema): void; | ||
} | ||
export declare type AttributeGetter = (x: any) => any; | ||
export interface IEntitySchemaOptions { | ||
idAttribute?: string | AttributeGetter; | ||
} | ||
export interface INestedSchema { | ||
[key: string]: ISchema; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
class EntitySchema { | ||
constructor(key, options = {}) { | ||
if (!key || typeof key !== "string") { | ||
throw new Error("A string non-empty key is required"); | ||
} | ||
this._key = key; | ||
const idAttribute = options.idAttribute || "id"; | ||
this._getId = typeof idAttribute === "function" ? idAttribute : (x) => x[idAttribute]; | ||
this._idAttribute = idAttribute; | ||
} | ||
getKey() { | ||
return this._key; | ||
} | ||
getId(entity) { | ||
return this._getId(entity); | ||
} | ||
getIdAttribute() { | ||
return this._idAttribute; | ||
} | ||
define(nestedSchema) { | ||
for (const key of Object.keys(nestedSchema)) { | ||
this[key] = nestedSchema[key]; | ||
} | ||
} | ||
} | ||
exports.default = EntitySchema; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import ISchema from "./Schema"; | ||
export default class ArraySchema implements ISchema { | ||
_itemSchema: ISchema; | ||
constructor(itemSchema: ISchema); | ||
getItemSchema(): ISchema; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
class ArraySchema { | ||
constructor(itemSchema) { | ||
if (!itemSchema) { | ||
throw new Error("Iterable schema needs a valid item schema"); | ||
} | ||
this._itemSchema = itemSchema; | ||
} | ||
getItemSchema() { | ||
return this._itemSchema; | ||
} | ||
} | ||
exports.default = ArraySchema; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export default class ISchema { | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
class ISchema { | ||
} | ||
exports.default = ISchema; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import ISchema from "./Schema"; | ||
export default class TransformerSchema implements ISchema { | ||
_transformer: ITransformer; | ||
constructor(transformer: ITransformer); | ||
} | ||
export declare type ITransformer = (x: any) => any; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
class TransformerSchema { | ||
constructor(transformer) { | ||
this._transformer = transformer; | ||
} | ||
} | ||
exports.default = TransformerSchema; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import ISchema from "./Schema"; | ||
import EntitySchema from "./EntitySchema"; | ||
import IterableSchema from "./IterableSchema"; | ||
import TransformerSchema, { ITransformer } from "./TransformerSchema"; | ||
export declare const Schema: typeof EntitySchema; | ||
export declare function arrayOf(schema: ISchema): IterableSchema; | ||
export declare function valuesOf(schema: ISchema): IterableSchema; | ||
export declare function transform(transformer: ITransformer): TransformerSchema; | ||
export declare function normalize(obj: IVisitable, schema: ISchema, userOptions?: IVisitOptions): { | ||
entities: IBag; | ||
result: any; | ||
}; | ||
export declare type IVisitable = { | ||
[key: string]: IVisitable; | ||
} | { | ||
[key: number]: IVisitable; | ||
} | object; | ||
export interface IBag { | ||
[schemaName: string]: { | ||
[id: string]: any; | ||
}; | ||
} | ||
export declare type IKeyTransformer = (key: string) => string; | ||
export interface IVisitOptions { | ||
keyTransformer?: IKeyTransformer; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const EntitySchema_1 = require("./EntitySchema"); | ||
const IterableSchema_1 = require("./IterableSchema"); | ||
const TransformerSchema_1 = require("./TransformerSchema"); | ||
const nodash_1 = require("./nodash"); | ||
function visitObject(obj, schema, bag, opts) { | ||
const k = opts.keyTransformer; | ||
const normalized = {}; | ||
for (const key of Object.keys(obj)) { | ||
const itemSchema = schema[key]; | ||
const result = visit(obj[key], itemSchema, bag, opts); | ||
if (itemSchema instanceof EntitySchema_1.default) { | ||
normalized[k(key + "_id")] = result; | ||
} | ||
else if (isIterableSchema(itemSchema) && Array.isArray(result)) { | ||
normalized[k(key.replace(/s$/, "") + "_ids")] = result; | ||
} | ||
else if (isTransformerSchema(itemSchema)) { | ||
normalized[k(key)] = itemSchema._transformer(result); | ||
} | ||
else { | ||
normalized[k(key)] = result; | ||
} | ||
} | ||
return normalized; | ||
} | ||
function visitIterable(obj, iterableSchema, bag, opts) { | ||
const itemSchema = iterableSchema.getItemSchema(); | ||
const k = opts.keyTransformer; | ||
const f = (fobj) => visit(fobj, itemSchema, bag, opts); | ||
if (Array.isArray(obj)) { | ||
return obj.map(f); | ||
} | ||
else { | ||
const normalized = {}; | ||
for (const key of Object.keys(obj)) { | ||
const result = f(obj[key]); | ||
if (itemSchema instanceof EntitySchema_1.default) { | ||
normalized[k(key + "_id")] = result; | ||
} | ||
else if (itemSchema instanceof IterableSchema_1.default && Array.isArray(result)) { | ||
normalized[k(key.replace(/s$/, "") + "_ids")] = result; | ||
} | ||
} | ||
return normalized; | ||
} | ||
} | ||
function mergeIntoEntity(entityA, entityB, entityKey) { | ||
for (const key of Object.keys(entityB)) { | ||
if (!entityA.hasOwnProperty(key) || nodash_1.isEqual(entityA[key], entityB[key])) { | ||
entityA[key] = entityB[key]; | ||
continue; | ||
} | ||
// tslint:disable-next-line | ||
console.warn("When merging two " + entityKey + ', found unequal data in their "' + key + '" values. Using the earlier value.', entityA[key], entityB[key]); | ||
} | ||
} | ||
function visitEntity(entity, entitySchema, bag, opts) { | ||
const entityKey = entitySchema.getKey(); | ||
const id = entitySchema.getId(entity); | ||
if (!bag.hasOwnProperty(entityKey)) { | ||
bag[entityKey] = {}; | ||
} | ||
if (!bag[entityKey].hasOwnProperty(id)) { | ||
bag[entityKey][id] = {}; | ||
} | ||
const stored = bag[entityKey][id]; | ||
const normalized = visitObject(entity, entitySchema, bag, opts); | ||
mergeIntoEntity(stored, normalized, entityKey); | ||
return id; | ||
} | ||
function visit(obj, schema, bag, opts) { | ||
if (!nodash_1.isObject(obj) || !nodash_1.isObject(schema)) { | ||
return obj; | ||
} | ||
if (isEntitySchema(schema)) { | ||
return visitEntity(obj, schema, bag, opts); | ||
} | ||
else if (isIterableSchema(schema)) { | ||
return visitIterable(obj, schema, bag, opts); | ||
} | ||
else { | ||
return visitObject(obj, schema, bag, opts); | ||
} | ||
} | ||
exports.Schema = EntitySchema_1.default; | ||
function arrayOf(schema) { | ||
return new IterableSchema_1.default(schema); | ||
} | ||
exports.arrayOf = arrayOf; | ||
function valuesOf(schema) { | ||
return new IterableSchema_1.default(schema); | ||
} | ||
exports.valuesOf = valuesOf; | ||
function transform(transformer) { | ||
return new TransformerSchema_1.default(transformer); | ||
} | ||
exports.transform = transform; | ||
function normalize(obj, schema, userOptions = {}) { | ||
const opts = Object.assign({}, userOptions); | ||
if (!opts.keyTransformer) { | ||
opts.keyTransformer = (x) => x; | ||
} | ||
if (!nodash_1.isObject(obj) && !Array.isArray(obj)) { | ||
throw new Error("Normalize accepts an object or an array as its input."); | ||
} | ||
if (!nodash_1.isObject(schema) || Array.isArray(schema)) { | ||
throw new Error("Normalize accepts an object for schema."); | ||
} | ||
const bag = {}; | ||
const result = visit(obj, schema, bag, opts); | ||
return { | ||
entities: bag, | ||
result, | ||
}; | ||
} | ||
exports.normalize = normalize; | ||
function isEntitySchema(s) { | ||
return s instanceof EntitySchema_1.default; | ||
} | ||
function isTransformerSchema(s) { | ||
return s instanceof TransformerSchema_1.default; | ||
} | ||
function isIterableSchema(s) { | ||
return s instanceof IterableSchema_1.default; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export declare function isObject(obj: any): boolean; | ||
export import isEqual = require("deep-equal"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
function isObject(obj) { | ||
return obj && typeof obj === "object"; | ||
} | ||
exports.isObject = isObject; | ||
exports.isEqual = require("deep-equal"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.