Skip to content

Commit

Permalink
feat(@ngtools/json-schema): Introduce a separate package for JSON sch…
Browse files Browse the repository at this point in the history
…ema. (#3927)

This is the same code we used before, but:

1. its in a separate package,
2. it also support new serialization to .d.ts,
3. OneOf is now supported entirely (instead of the previous hack).

Also, removed the schema.d.ts file and generate it before building the package. It is not git ignored and changing it will not work (it will be overwritten).
  • Loading branch information
hansl committed Jan 11, 2017
1 parent c6d1c99 commit 74f7cdd
Show file tree
Hide file tree
Showing 29 changed files with 844 additions and 262 deletions.
1 change: 0 additions & 1 deletion package.json
Expand Up @@ -21,7 +21,6 @@
"test:deps": "node scripts/publish/validate_dependencies.js",
"test:inspect": "node --inspect --debug-brk tests/runner",
"test:packages": "node scripts/run-packages-spec.js",
"build-config-interface": "dtsgen packages/angular-cli/lib/config/schema.json --out packages/angular-cli/lib/config/schema.d.ts",
"eslint": "eslint .",
"tslint": "tslint \"**/*.ts\" -c tslint.json -e \"**/blueprints/*/files/**/*.ts\" -e \"node_modules/**\" -e \"tmp/**\" -e \"dist/**\"",
"lint": "npm-run-all -c eslint tslint"
Expand Down
32 changes: 32 additions & 0 deletions packages/@ngtools/json-schema/package.json
@@ -0,0 +1,32 @@
{
"name": "@ngtools/json-schema",
"version": "1.2.1",
"description": "Schema validating and reading for configurations, similar to Angular CLI config.",
"main": "./src/index.js",
"typings": "src/index.d.ts",
"license": "MIT",
"keywords": [
"angular",
"json",
"json-schema",
"schema",
"config"
],
"repository": {
"type": "git",
"url": "https://github.com/angular/angular-cli.git"
},
"author": "angular",
"bugs": {
"url": "https://github.com/angular/angular-cli/issues"
},
"homepage": "https://github.com/angular/angular-cli/tree/master/packages/@ngtools/json-schema",
"engines": {
"node": ">= 4.1.0",
"npm": ">= 3.0.0"
},
"dependencies": {
},
"peerDependencies": {
}
}
12 changes: 12 additions & 0 deletions packages/@ngtools/json-schema/src/error.ts
@@ -0,0 +1,12 @@

export class JsonSchemaErrorBase extends Error {
constructor(message?: string) {
super();

if (message) {
this.message = message;
} else {
this.message = (<any>this.constructor).name;
}
}
}
1 change: 1 addition & 0 deletions packages/@ngtools/json-schema/src/index.ts
@@ -0,0 +1 @@
export {SchemaClass, SchemaClassFactory} from './schema-class-factory';
34 changes: 34 additions & 0 deletions packages/@ngtools/json-schema/src/mimetypes.ts
@@ -0,0 +1,34 @@
import {JsonSchemaErrorBase} from './error';
import {Serializer, WriterFn} from './serializer';
import {JsonSerializer} from './serializers/json';
import {DTsSerializer} from './serializers/dts';


export class UnknownMimetype extends JsonSchemaErrorBase {}


export function createSerializerFromMimetype(mimetype: string,
writer: WriterFn,
...opts: any[]): Serializer {
let Klass: { new (writer: WriterFn, ...args: any[]): Serializer } = null;
switch (mimetype) {
case 'application/json': Klass = JsonSerializer; break;
case 'text/json': Klass = JsonSerializer; break;
case 'text/x.typescript': Klass = DTsSerializer; break;
case 'text/x.dts': Klass = DTsSerializer; break;

default: throw new UnknownMimetype();
}

return new Klass(writer, ...opts);

}


declare module './serializer' {
namespace Serializer {
export let fromMimetype: typeof createSerializerFromMimetype;
}
}

Serializer.fromMimetype = createSerializerFromMimetype;
42 changes: 42 additions & 0 deletions packages/@ngtools/json-schema/src/node.ts
@@ -0,0 +1,42 @@
import {Serializer} from './serializer';


// A TypeScript Type. This can be used to do `new tsType(value)`.
// `null` implies any type; be careful.
export type TypeScriptType = typeof Number
| typeof Boolean
| typeof String
| typeof Object
| typeof Array
| null;


// The most generic interface for a schema node. This is used by the serializers.
export interface SchemaNode {
readonly name: string;
readonly type: string;
readonly tsType: TypeScriptType;
readonly defined: boolean;
readonly dirty: boolean;
readonly frozen: boolean;
readonly readOnly: boolean;
readonly defaultValue: any | null;
readonly required: boolean;
readonly parent: SchemaNode | null;

// Schema related properties.
readonly description: string | null;

// Object-only properties. `null` for everything else.
readonly children: { [key: string]: SchemaNode } | null;

// Array-only properties. `null` for everything else.
readonly items: SchemaNode[] | null;
readonly itemPrototype: SchemaNode | null;

// Mutable properties.
value: any;

// Serialization.
serialize(serializer: Serializer): void;
}
@@ -1,8 +1,11 @@
import {NgToolkitError} from '../error';
import {Serializer} from './serializer';
import {RootSchemaTreeNode, SchemaTreeNode} from './schema-tree';
import {JsonSchemaErrorBase} from './error';

export class InvalidJsonPath extends NgToolkitError {}
import './mimetypes';


export class InvalidJsonPath extends JsonSchemaErrorBase {}


// The schema tree node property of the SchemaClass.
Expand Down Expand Up @@ -66,6 +69,9 @@ export interface SchemaClass<JsonType> extends Object {
$$defined(path: string): boolean;
$$delete(path: string): void;

// Direct access to the schema.
$$schema(): RootSchemaTreeNode;

$$serialize(mimetype?: string): string;
}

Expand Down
34 changes: 34 additions & 0 deletions packages/@ngtools/json-schema/src/schema-tree.spec.ts
@@ -0,0 +1,34 @@
import {readFileSync} from 'fs';
import {join} from 'path';

import {RootSchemaTreeNode} from './schema-tree';


describe('SchemaTreeNode', () => {

});


describe('OneOfSchemaTreeNode', () => {
const schemaJsonFilePath = join(__dirname, '../tests/schema1.json');
const schemaJson = JSON.parse(readFileSync(schemaJsonFilePath, 'utf-8'));
const valueJsonFilePath = join(__dirname, '../tests/value1-1.json');
const valueJson = JSON.parse(readFileSync(valueJsonFilePath, 'utf-8'));


it('works', () => {
const proto: any = Object.create(null);
new RootSchemaTreeNode(proto, {
value: valueJson,
schema: schemaJson
});

expect(proto.oneOfKey2 instanceof Array).toBe(true);
expect(proto.oneOfKey2.length).toBe(2);

// Set it to a string, which is valid.
proto.oneOfKey2 = 'hello';
expect(proto.oneOfKey2 instanceof Array).toBe(false);
});
});

0 comments on commit 74f7cdd

Please sign in to comment.