mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 18:14:17 +00:00
added hal serializer
This commit is contained in:
16
npm-shrinkwrap.json
generated
16
npm-shrinkwrap.json
generated
@@ -220,6 +220,12 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.5.41.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"@types/jsonschema": {
|
||||
"version": "0.0.5",
|
||||
"from": "@types/jsonschema@0.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/jsonschema/-/jsonschema-0.0.5.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"@types/lodash": {
|
||||
"version": "4.14.50",
|
||||
"from": "@types/lodash@>=4.14.37 <5.0.0",
|
||||
@@ -951,6 +957,11 @@
|
||||
"resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"cerialize": {
|
||||
"version": "0.1.13",
|
||||
"from": "cerialize@>=0.1.13 <0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/cerialize/-/cerialize-0.1.13.tgz"
|
||||
},
|
||||
"chalk": {
|
||||
"version": "1.1.3",
|
||||
"from": "chalk@>=1.1.3 <2.0.0",
|
||||
@@ -3150,6 +3161,11 @@
|
||||
"resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz",
|
||||
"dev": true
|
||||
},
|
||||
"jsonschema": {
|
||||
"version": "1.1.1",
|
||||
"from": "jsonschema@>=1.1.1 <2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.1.1.tgz"
|
||||
},
|
||||
"jsprim": {
|
||||
"version": "1.3.1",
|
||||
"from": "jsprim@>=1.2.2 <2.0.0",
|
||||
|
@@ -83,6 +83,7 @@
|
||||
"@ngrx/router-store": "^1.2.5",
|
||||
"@ngrx/store": "^2.2.1",
|
||||
"@ngrx/store-devtools": "^3.2.2",
|
||||
"@types/jsonschema": "0.0.5",
|
||||
"angular2-express-engine": "2.1.0-rc.1",
|
||||
"angular2-platform-node": "2.1.0-rc.1",
|
||||
"angular2-universal": "2.1.0-rc.1",
|
||||
@@ -90,11 +91,13 @@
|
||||
"autoprefixer": "^6.5.4",
|
||||
"body-parser": "1.15.2",
|
||||
"bootstrap": "4.0.0-alpha.5",
|
||||
"cerialize": "^0.1.13",
|
||||
"compression": "1.6.2",
|
||||
"express": "4.14.0",
|
||||
"font-awesome": "4.7.0",
|
||||
"http-server": "^0.9.0",
|
||||
"js.clone": "0.0.3",
|
||||
"jsonschema": "^1.1.1",
|
||||
"methods": "1.1.2",
|
||||
"morgan": "1.7.0",
|
||||
"ng2-translate": "4.2.0",
|
||||
|
@@ -15,6 +15,7 @@ import { StoreDevtoolsModule } from "@ngrx/store-devtools";
|
||||
|
||||
import { rootReducer } from './app.reducers';
|
||||
import { effects } from './app.effects';
|
||||
import { CoreModule } from "./core/core.module";
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
@@ -25,6 +26,7 @@ import { effects } from './app.effects';
|
||||
imports: [
|
||||
SharedModule,
|
||||
HomeModule,
|
||||
CoreModule.forRoot(),
|
||||
AppRoutingModule,
|
||||
/**
|
||||
* StoreModule.provideStore is imported once in the root module, accepting a reducer
|
||||
|
42
src/app/core/core.module.ts
Normal file
42
src/app/core/core.module.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
import { NgModule, Optional, SkipSelf, ModuleWithProviders } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { SharedModule } from "../shared/shared.module";
|
||||
import { isNotEmpty } from "../shared/empty.util";
|
||||
|
||||
const IMPORTS = [
|
||||
CommonModule,
|
||||
];
|
||||
|
||||
const DECLARATIONS = [
|
||||
|
||||
];
|
||||
|
||||
const EXPORTS = [
|
||||
];
|
||||
|
||||
const PROVIDERS = [
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [ ...IMPORTS ],
|
||||
declarations: [...DECLARATIONS],
|
||||
exports: [...EXPORTS],
|
||||
providers: [...PROVIDERS]
|
||||
})
|
||||
export class CoreModule {
|
||||
constructor (@Optional() @SkipSelf() parentModule: CoreModule) {
|
||||
if (isNotEmpty(parentModule)) {
|
||||
throw new Error(
|
||||
'CoreModule is already loaded. Import it in the AppModule only');
|
||||
}
|
||||
}
|
||||
|
||||
static forRoot(): ModuleWithProviders {
|
||||
return {
|
||||
ngModule: SharedModule,
|
||||
providers: [
|
||||
...PROVIDERS
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
@@ -0,0 +1,4 @@
|
||||
export interface DSpaceRESTV2Response {
|
||||
_embedded?: any;
|
||||
_links?: any;
|
||||
}
|
93
src/app/core/dspace-rest-v2/dspace-rest-v2.schema.json
Normal file
93
src/app/core/dspace-rest-v2/dspace-rest-v2.schema.json
Normal file
@@ -0,0 +1,93 @@
|
||||
{
|
||||
"title": "DSpace REST v2 json-schema",
|
||||
"description": "Based on http://hyperschema.org/mediatypes/hal",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"_links": {
|
||||
"$ref": "#/definitions/links"
|
||||
},
|
||||
"_embedded": {
|
||||
"$ref": "#/definitions/embedded"
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"links": {
|
||||
"title": "HAL Links",
|
||||
"description": "Object of links with the rels as the keys",
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/definitions/linkObject"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/linkArray"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"linkArray": {
|
||||
"title": "HAL Link Array",
|
||||
"description": "An array of linkObjects of the same link relation",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/linkObject"
|
||||
}
|
||||
},
|
||||
"linkObject": {
|
||||
"title": "HAL Link Object",
|
||||
"description": "An object with link information",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {
|
||||
"$ref": "http://hyperschema.org/core/base#/definitions/name"
|
||||
},
|
||||
"href": {
|
||||
"anyOf": [
|
||||
{
|
||||
"$ref": "http://hyperschema.org/core/link#/definitions/href"
|
||||
},
|
||||
{
|
||||
"$ref": "http://hyperschema.org/core/link#/definitions/hrefTemplated"
|
||||
}
|
||||
]
|
||||
},
|
||||
"templated": {
|
||||
"$ref": "http://hyperschema.org/core/link#/definitions/isTemplated"
|
||||
},
|
||||
"type": {
|
||||
"$ref": "http://hyperschema.org/core/base#/definitions/mediaType"
|
||||
},
|
||||
"deprecation": {
|
||||
"$ref": "http://hyperschema.org/core/link#/definitions/isDeprecated"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"href"
|
||||
]
|
||||
},
|
||||
"embedded": {
|
||||
"title": "HAL Embedded Resource",
|
||||
"description": "An embedded HAL resource",
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#"
|
||||
},
|
||||
{
|
||||
"$ref": "#/definitions/embeddedArray"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"embeddedArray": {
|
||||
"title": "HAL Embedded Array",
|
||||
"description": "An array of embedded resources with the same link relation",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
201
src/app/core/dspace-rest-v2/dspace-rest-v2.serializer.spec.ts
Normal file
201
src/app/core/dspace-rest-v2/dspace-rest-v2.serializer.spec.ts
Normal file
@@ -0,0 +1,201 @@
|
||||
import { DSpaceRESTv2Serializer } from "./dspace-rest-v2.serializer";
|
||||
import { autoserialize, autoserializeAs } from "cerialize";
|
||||
|
||||
class TestModel {
|
||||
@autoserialize
|
||||
id: string;
|
||||
|
||||
@autoserialize
|
||||
name: string;
|
||||
|
||||
@autoserializeAs(TestModel)
|
||||
parents?: Array<TestModel>;
|
||||
}
|
||||
|
||||
const testModels = [
|
||||
{
|
||||
"id": "d4466d54-d73b-4d8f-b73f-c702020baa14",
|
||||
"name": "Model 1",
|
||||
},
|
||||
{
|
||||
"id": "752a1250-949a-46ad-9bea-fbc45f0b656d",
|
||||
"name": "Model 2",
|
||||
}
|
||||
];
|
||||
|
||||
const testResponses = [
|
||||
{
|
||||
"_links": {
|
||||
"self": "/testmodels/9e32a2e2-6b91-4236-a361-995ccdc14c60",
|
||||
"parents": [
|
||||
{ "href": "/testmodels/21539b1d-9ef1-4eda-9c77-49565b5bfb78" },
|
||||
{ "href": "/testmodels/be8325f7-243b-49f4-8a4b-df2b793ff3b5" }
|
||||
]
|
||||
},
|
||||
"id": "9e32a2e2-6b91-4236-a361-995ccdc14c60",
|
||||
"type": "testModels",
|
||||
"name": "A Test Model"
|
||||
},
|
||||
{
|
||||
"_links": {
|
||||
"self": "/testmodels/598ce822-c357-46f3-ab70-63724d02d6ad",
|
||||
"parents": [
|
||||
{ "href": "/testmodels/be8325f7-243b-49f4-8a4b-df2b793ff3b5" },
|
||||
{ "href": "/testmodels/21539b1d-9ef1-4eda-9c77-49565b5bfb78" }
|
||||
]
|
||||
},
|
||||
"id": "598ce822-c357-46f3-ab70-63724d02d6ad",
|
||||
"type": "testModels",
|
||||
"name": "Another Test Model"
|
||||
}
|
||||
];
|
||||
|
||||
const parentHrefRegex = /^\/testmodels\/(.+)$/g;
|
||||
|
||||
|
||||
describe("DSpaceRESTv2Serializer", () => {
|
||||
|
||||
describe("serialize", () => {
|
||||
|
||||
it("should turn a model in to a valid document", () => {
|
||||
const serializer = new DSpaceRESTv2Serializer(TestModel);
|
||||
const doc = serializer.serialize(testModels[0]);
|
||||
expect(testModels[0].id).toBe(doc._embedded.id);
|
||||
expect(testModels[0].name).toBe(doc._embedded.name);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("serializeArray", () => {
|
||||
|
||||
it("should turn an array of models in to a valid document", () => {
|
||||
const serializer = new DSpaceRESTv2Serializer(TestModel);
|
||||
const doc = serializer.serializeArray(testModels);
|
||||
|
||||
expect(testModels[0].id).toBe(doc._embedded[0].id);
|
||||
expect(testModels[0].name).toBe(doc._embedded[0].name);
|
||||
expect(testModels[1].id).toBe(doc._embedded[1].id);
|
||||
expect(testModels[1].name).toBe(doc._embedded[1].name);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("deserialize", () => {
|
||||
|
||||
it("should turn a valid document describing a single entity in to a valid model", () => {
|
||||
const serializer = new DSpaceRESTv2Serializer(TestModel);
|
||||
const doc = {
|
||||
"_embedded": testResponses[0],
|
||||
};
|
||||
|
||||
const model = serializer.deserialize(doc);
|
||||
|
||||
expect(model.id).toBe(doc._embedded.id);
|
||||
expect(model.name).toBe(doc._embedded.name);
|
||||
});
|
||||
|
||||
//TODO cant implement/test this yet - depends on how relationships
|
||||
// will be handled in the rest api
|
||||
// it("should retain relationship information", () => {
|
||||
// const serializer = new DSpaceRESTv2Serializer(TestModel);
|
||||
// const doc = {
|
||||
// "_embedded": testResponses[0],
|
||||
// };
|
||||
//
|
||||
// const model = serializer.deserialize(doc);
|
||||
//
|
||||
// console.log(model);
|
||||
//
|
||||
// const modelParentIds = model.parents.map(parent => parent.id).sort();
|
||||
// const responseParentIds = doc._embedded._links.parents
|
||||
// .map(parent => parent.href)
|
||||
// .map(href => href.replace(parentHrefRegex, '$1'))
|
||||
// .sort();
|
||||
//
|
||||
// expect(modelParentIds).toEqual(responseParentIds);
|
||||
// });
|
||||
|
||||
// TODO enable once validation is enabled in the serializer
|
||||
// it("should throw an error when dealing with an invalid document", () => {
|
||||
// const serializer = new DSpaceRESTv2Serializer(TestModel);
|
||||
// const doc = testResponses[0];
|
||||
//
|
||||
// expect(() => {
|
||||
// serializer.deserialize(doc);
|
||||
// }).toThrow();
|
||||
// });
|
||||
|
||||
it("should throw an error when dealing with a document describing an array", () => {
|
||||
const serializer = new DSpaceRESTv2Serializer(TestModel);
|
||||
const doc = {
|
||||
"_embedded": testResponses
|
||||
};
|
||||
|
||||
expect(() => {
|
||||
serializer.deserialize(doc);
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("deserializeArray", () => {
|
||||
|
||||
it("should turn a valid document describing a collection of objects in to an array of valid models", () => {
|
||||
const serializer = new DSpaceRESTv2Serializer(TestModel);
|
||||
const doc = {
|
||||
"_embedded": testResponses
|
||||
};
|
||||
|
||||
const models = serializer.deserializeArray(doc);
|
||||
|
||||
expect(models[0].id).toBe(doc._embedded[0].id);
|
||||
expect(models[0].name).toBe(doc._embedded[0].name);
|
||||
expect(models[1].id).toBe(doc._embedded[1].id);
|
||||
expect(models[1].name).toBe(doc._embedded[1].name);
|
||||
});
|
||||
|
||||
//TODO cant implement/test this yet - depends on how relationships
|
||||
// will be handled in the rest api
|
||||
// it("should retain relationship information", () => {
|
||||
// const serializer = new DSpaceRESTv2Serializer(TestModel);
|
||||
// const doc = {
|
||||
// "_embedded": testResponses,
|
||||
// };
|
||||
//
|
||||
// const models = serializer.deserializeArray(doc);
|
||||
//
|
||||
// models.forEach((model, i) => {
|
||||
// const modelParentIds = model.parents.map(parent => parent.id).sort();
|
||||
// const responseParentIds = doc._embedded[i]._links.parents
|
||||
// .map(parent => parent.href)
|
||||
// .map(href => href.replace(parentHrefRegex, '$1'))
|
||||
// .sort();
|
||||
//
|
||||
// expect(modelParentIds).toEqual(responseParentIds);
|
||||
// });
|
||||
// });
|
||||
|
||||
// TODO enable once validation is enabled in the serializer
|
||||
// it("should throw an error when dealing with an invalid document", () => {
|
||||
// const serializer = new DSpaceRESTv2Serializer(TestModel);
|
||||
// const doc = testResponses[0];
|
||||
//
|
||||
// expect(() => {
|
||||
// serializer.deserializeArray(doc);
|
||||
// }).toThrow();
|
||||
// });
|
||||
|
||||
it("should throw an error when dealing with a document describing a single model", () => {
|
||||
const serializer = new DSpaceRESTv2Serializer(TestModel);
|
||||
const doc = {
|
||||
"_embedded": testResponses[0]
|
||||
};
|
||||
|
||||
expect(() => {
|
||||
serializer.deserializeArray(doc);
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
82
src/app/core/dspace-rest-v2/dspace-rest-v2.serializer.ts
Normal file
82
src/app/core/dspace-rest-v2/dspace-rest-v2.serializer.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import { Serialize, Deserialize } from "cerialize";
|
||||
import { Serializer } from "../serializer";
|
||||
import { DSpaceRESTV2Response } from "./dspace-rest-v2-response.model";
|
||||
import { DSpaceRESTv2Validator } from "./dspace-rest-v2.validator";
|
||||
|
||||
/**
|
||||
* ensures we can use 'typeof T' as a type
|
||||
* more details:
|
||||
* https://github.com/Microsoft/TypeScript/issues/204#issuecomment-257722306
|
||||
*/
|
||||
type Constructor<T> = { new (...args: any[]): T } | ((...args: any[]) => T) | Function;
|
||||
|
||||
/**
|
||||
* This Serializer turns responses from v2 of DSpace's REST API
|
||||
* to models and vice versa
|
||||
*/
|
||||
export class DSpaceRESTv2Serializer<T> implements Serializer<T> {
|
||||
|
||||
/**
|
||||
* Create a new DSpaceRESTv2Serializer instance
|
||||
*
|
||||
* @param modelType a class or interface to indicate
|
||||
* the kind of model this serializer should work with
|
||||
*/
|
||||
constructor(private modelType: Constructor<T>) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a model in to the format expected by the backend
|
||||
*
|
||||
* @param model The model to serialize
|
||||
* @returns An object to send to the backend
|
||||
*/
|
||||
serialize(model: T): DSpaceRESTV2Response {
|
||||
return {
|
||||
"_embedded": Serialize(model, this.modelType)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert an array of models in to the format expected by the backend
|
||||
*
|
||||
* @param models The array of models to serialize
|
||||
* @returns An object to send to the backend
|
||||
*/
|
||||
serializeArray(models: Array<T>): DSpaceRESTV2Response {
|
||||
return {
|
||||
"_embedded": Serialize(models, this.modelType)
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a response from the backend in to a model.
|
||||
*
|
||||
* @param response An object returned by the backend
|
||||
* @returns a model of type T
|
||||
*/
|
||||
deserialize(response: DSpaceRESTV2Response): T {
|
||||
// TODO enable validation, once rest data stabilizes
|
||||
// new DSpaceRESTv2Validator(response).validate();
|
||||
if (Array.isArray(response._embedded)) {
|
||||
throw new Error('Expected a single model, use deserializeArray() instead');
|
||||
}
|
||||
return <T> Deserialize(response._embedded, this.modelType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a response from the backend in to an array of models
|
||||
*
|
||||
* @param response An object returned by the backend
|
||||
* @returns an array of models of type T
|
||||
*/
|
||||
deserializeArray(response: DSpaceRESTV2Response): Array<T> {
|
||||
//TODO enable validation, once rest data stabilizes
|
||||
// new DSpaceRESTv2Validator(response).validate();
|
||||
if (!Array.isArray(response._embedded)) {
|
||||
throw new Error('Expected an Array, use deserialize() instead');
|
||||
}
|
||||
return <Array<T>> Deserialize(response._embedded, this.modelType);
|
||||
}
|
||||
|
||||
}
|
26
src/app/core/dspace-rest-v2/dspace-rest-v2.validator.ts
Normal file
26
src/app/core/dspace-rest-v2/dspace-rest-v2.validator.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import * as schema from './dspace-rest-v2.schema.json'
|
||||
import { Validator } from "jsonschema";
|
||||
|
||||
export class DSpaceRESTv2Validator {
|
||||
|
||||
constructor(private document: any) {
|
||||
|
||||
}
|
||||
|
||||
validate(): void {
|
||||
const validator = new Validator();
|
||||
const result = validator.validate(this.document, schema);
|
||||
if (!result.valid) {
|
||||
if (result.errors && result.errors.length > 0) {
|
||||
const message = result.errors
|
||||
.map((error) => error.message)
|
||||
.join("\n");
|
||||
throw new Error(message);
|
||||
}
|
||||
else {
|
||||
throw new Error("JSON API validation failed for an unknown reason");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
38
src/app/core/serializer.ts
Normal file
38
src/app/core/serializer.ts
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* A Serializer turns responses from the backend to models
|
||||
* and vice versa
|
||||
*/
|
||||
export interface Serializer<T> {
|
||||
|
||||
/**
|
||||
* Convert a model in to the format expected by the backend
|
||||
*
|
||||
* @param model The model to serialize
|
||||
* @returns An object to send to the backend
|
||||
*/
|
||||
serialize(model: T): any;
|
||||
|
||||
/**
|
||||
* Convert an array of models in to the format expected by the backend
|
||||
*
|
||||
* @param models The array of models to serialize
|
||||
* @returns An object to send to the backend
|
||||
*/
|
||||
serializeArray(models: Array<T>): any;
|
||||
|
||||
/**
|
||||
* Convert a response from the backend in to a model.
|
||||
*
|
||||
* @param response An object returned by the backend
|
||||
* @returns a model of type T
|
||||
*/
|
||||
deserialize(response: any): T;
|
||||
|
||||
/**
|
||||
* Convert a response from the backend in to an array of models
|
||||
*
|
||||
* @param response An object returned by the backend
|
||||
* @returns an array of models of type T
|
||||
*/
|
||||
deserializeArray(response: any): Array<T>;
|
||||
}
|
219
src/app/shared/empty.util.spec.ts
Normal file
219
src/app/shared/empty.util.spec.ts
Normal file
@@ -0,0 +1,219 @@
|
||||
import { isEmpty, hasNoValue, hasValue, isNotEmpty } from "./empty.util";
|
||||
|
||||
describe("Empty Utils", () => {
|
||||
const string: string = 'string';
|
||||
const fn: () => void = function () {};
|
||||
const object: any = { length: 0 };
|
||||
const emptyMap: Map<any, any> = new Map();
|
||||
let fullMap: Map<string,string> = new Map();
|
||||
fullMap.set('foo', 'bar');
|
||||
|
||||
describe("hasNoValue", () => {
|
||||
it("should return true for null", () => {
|
||||
expect(hasNoValue(null)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true for undefined", () => {
|
||||
expect(hasNoValue(undefined)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false for an empty String", () => {
|
||||
expect(hasNoValue('')).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false for true", () => {
|
||||
expect(hasNoValue(true)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false for false", () => {
|
||||
expect(hasNoValue(false)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false for a String", () => {
|
||||
expect(hasNoValue(string)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false for a Function", () => {
|
||||
expect(hasNoValue(fn)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false for 0", () => {
|
||||
expect(hasNoValue(0)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false for an empty Array", () => {
|
||||
expect(hasNoValue([])).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false for an empty Object", () => {
|
||||
expect(hasNoValue({})).toBe(false);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("hasValue", () => {
|
||||
|
||||
it("should return false for null", () => {
|
||||
expect(hasValue(null)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false for undefined", () => {
|
||||
expect(hasValue(undefined)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return true for an empty String", () => {
|
||||
expect(hasValue('')).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true for false", () => {
|
||||
expect(hasValue(false)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true for true", () => {
|
||||
expect(hasValue(true)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true for a String", () => {
|
||||
expect(hasValue(string)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true for a Function", () => {
|
||||
expect(hasValue(fn)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true for 0", () => {
|
||||
expect(hasValue(0)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true for an empty Array", () => {
|
||||
expect(hasValue([])).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true for an empty Object", () => {
|
||||
expect(hasValue({})).toBe(true);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("isEmpty", () => {
|
||||
it("should return true for null", () => {
|
||||
expect(isEmpty(null)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true for undefined", () => {
|
||||
expect(isEmpty(undefined)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true for an empty String", () => {
|
||||
expect(isEmpty('')).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false for a whitespace String", () => {
|
||||
expect(isEmpty(' ')).toBe(false);
|
||||
expect(isEmpty('\n\t')).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false for true", () => {
|
||||
expect(isEmpty(true)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false for false", () => {
|
||||
expect(isEmpty(false)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false for a String", () => {
|
||||
expect(isEmpty(string)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false for a Function", () => {
|
||||
expect(isEmpty(fn)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false for 0", () => {
|
||||
expect(isEmpty(0)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return true for an empty Array", () => {
|
||||
expect(isEmpty([])).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false for an empty Object", () => {
|
||||
expect(isEmpty({})).toBe(false);
|
||||
});
|
||||
|
||||
it("should return true for an Object that has zero \'length\'", () => {
|
||||
expect(isEmpty(object)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true for an Empty map", () => {
|
||||
expect(isEmpty(emptyMap)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false for a Map that is not empty", () => {
|
||||
expect(isEmpty(fullMap)).toBe(false);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("isNotEmpty", () => {
|
||||
it("should return false for null", () => {
|
||||
expect(isNotEmpty(null)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false for undefined", () => {
|
||||
expect(isNotEmpty(undefined)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false for an empty String", () => {
|
||||
expect(isNotEmpty('')).toBe(false);
|
||||
});
|
||||
|
||||
it("should return true for a whitespace String", () => {
|
||||
expect(isNotEmpty(' ')).toBe(true);
|
||||
expect(isNotEmpty('\n\t')).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true for false", () => {
|
||||
expect(isNotEmpty(false)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true for true", () => {
|
||||
expect(isNotEmpty(true)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true for a String", () => {
|
||||
expect(isNotEmpty(string)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true for a Function", () => {
|
||||
expect(isNotEmpty(fn)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return true for 0", () => {
|
||||
expect(isNotEmpty(0)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false for an empty Array", () => {
|
||||
expect(isNotEmpty([])).toBe(false);
|
||||
});
|
||||
|
||||
it("should return true for an empty Object", () => {
|
||||
expect(isNotEmpty({})).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false for an Object that has zero length", () => {
|
||||
expect(isNotEmpty(object)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return false for an Empty map", () => {
|
||||
expect(isNotEmpty(emptyMap)).toBe(false);
|
||||
});
|
||||
|
||||
it("should return true for a Map that is not empty", () => {
|
||||
expect(isNotEmpty(fullMap)).toBe(true);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
94
src/app/shared/empty.util.ts
Normal file
94
src/app/shared/empty.util.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
/**
|
||||
Returns true if the passed value is null or undefined.
|
||||
|
||||
hasNoValue(); // true
|
||||
hasNoValue(null); // true
|
||||
hasNoValue(undefined); // true
|
||||
hasNoValue(''); // false
|
||||
hasNoValue([]); // false
|
||||
hasNoValue(function() {}); // false
|
||||
*/
|
||||
export function hasNoValue(obj?: any): boolean {
|
||||
return obj === null || obj === undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
Returns true if the passed value is not null or undefined.
|
||||
|
||||
hasValue(); // false
|
||||
hasValue(null); // false
|
||||
hasValue(undefined); // false
|
||||
hasValue(''); // true
|
||||
hasValue([]); // true
|
||||
hasValue(function() {}); // true
|
||||
*/
|
||||
export function hasValue(obj?: any): boolean {
|
||||
return !hasNoValue(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
Verifies that a value is `null` or an empty string, empty array,
|
||||
or empty function.
|
||||
|
||||
isEmpty(); // true
|
||||
isEmpty(null); // true
|
||||
isEmpty(undefined); // true
|
||||
isEmpty(''); // true
|
||||
isEmpty([]); // true
|
||||
isEmpty({}); // false
|
||||
isEmpty('Adam Hawkins'); // false
|
||||
isEmpty([0,1,2]); // false
|
||||
isEmpty('\n\t'); // false
|
||||
isEmpty(' '); // false
|
||||
*/
|
||||
export function isEmpty(obj?: any): boolean {
|
||||
if (hasNoValue(obj)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (typeof obj.size === 'number') {
|
||||
return !obj.size;
|
||||
}
|
||||
|
||||
let objectType = typeof obj;
|
||||
|
||||
if (objectType === 'object') {
|
||||
let size = obj['size'];
|
||||
if (typeof size === 'number') {
|
||||
return !size;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof obj.length === 'number' && objectType !== 'function') {
|
||||
return !obj.length;
|
||||
}
|
||||
|
||||
if (objectType === 'object') {
|
||||
let length = obj['length'];
|
||||
if (typeof length === 'number') {
|
||||
return !length;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Verifies that a value is not `null`, an empty string, empty array,
|
||||
or empty function.
|
||||
|
||||
isNotEmpty(); // false
|
||||
isNotEmpty(null); // false
|
||||
isNotEmpty(undefined); // false
|
||||
isNotEmpty(''); // false
|
||||
isNotEmpty([]); // false
|
||||
isNotEmpty({}); // true
|
||||
isNotEmpty('Adam Hawkins'); // true
|
||||
isNotEmpty([0,1,2]); // true
|
||||
isNotEmpty('\n\t'); // true
|
||||
isNotEmpty(' '); // true
|
||||
*/
|
||||
export function isNotEmpty(obj?: any): boolean {
|
||||
return !isEmpty(obj);
|
||||
}
|
@@ -11,6 +11,7 @@ import { TranslateLoader, TranslateModule, TranslateStaticLoader } from 'ng2-tra
|
||||
import { AppModule, AppComponent } from './app/app.module';
|
||||
import { SharedModule } from './app/shared/shared.module';
|
||||
import { CacheService } from './app/shared/cache.service';
|
||||
import { CoreModule } from "./app/core/core.module";
|
||||
|
||||
// Will be merged into @angular/platform-browser in a later release
|
||||
// see https://github.com/angular/angular/pull/12322
|
||||
@@ -56,7 +57,8 @@ export const UNIVERSAL_KEY = 'UNIVERSAL_CACHE';
|
||||
RouterModule.forRoot([], { useHash: false, preloadingStrategy: IdlePreload }),
|
||||
|
||||
IdlePreloadModule.forRoot(),
|
||||
SharedModule.forRoot(),
|
||||
CoreModule.forRoot(),
|
||||
SharedModule,
|
||||
AppModule,
|
||||
],
|
||||
providers: [
|
||||
|
@@ -10,6 +10,7 @@ import { TranslateLoader, TranslateModule, TranslateStaticLoader } from 'ng2-tra
|
||||
import { AppModule, AppComponent } from './app/app.module';
|
||||
import { SharedModule } from './app/shared/shared.module';
|
||||
import { CacheService } from './app/shared/cache.service';
|
||||
import { CoreModule } from "./app/core/core.module";
|
||||
|
||||
// Will be merged into @angular/platform-browser in a later release
|
||||
// see https://github.com/angular/angular/pull/12322
|
||||
@@ -47,7 +48,8 @@ export const UNIVERSAL_KEY = 'UNIVERSAL_CACHE';
|
||||
FormsModule,
|
||||
RouterModule.forRoot([], { useHash: false }),
|
||||
|
||||
SharedModule.forRoot(),
|
||||
CoreModule.forRoot(),
|
||||
SharedModule,
|
||||
AppModule,
|
||||
],
|
||||
providers: [
|
||||
|
7
src/typings.d.ts
vendored
7
src/typings.d.ts
vendored
@@ -71,3 +71,10 @@ interface WebpackRequire {
|
||||
interface NodeRequire extends WebpackRequire { }
|
||||
interface NodeModule extends WebpackModule { }
|
||||
interface Global extends GlobalEnvironment { }
|
||||
|
||||
// Allows us to import json files in typescript
|
||||
// See https://hackernoon.com/import-json-into-typescript-8d465beded79#.88tfoy2df
|
||||
declare module "*.json" {
|
||||
const value: any;
|
||||
export default value;
|
||||
}
|
||||
|
Reference in New Issue
Block a user