Commit 38736642 authored by nanahira's avatar nanahira

unit test and remove deprecated things

parent 2e67ff05
Pipeline #7356 failed with stages
in 1 minute and 30 seconds
...@@ -2,4 +2,4 @@ webpack.config.js ...@@ -2,4 +2,4 @@ webpack.config.js
dist/* dist/*
build/* build/*
*.js *.js
/src/schemastery /src/schemastery
\ No newline at end of file
stages: stages:
- install
- build - build
- deploy - deploy
variables: variables:
GIT_DEPTH: "1" GIT_DEPTH: "1"
build: npm_ci:
stage: build stage: install
tags: tags:
- linux - linux
script: script:
- npm ci - npm ci
artifacts:
paths:
- node_modules
.build_base:
stage: build
tags:
- linux
dependencies:
- npm_ci
build:
extends:
- .build_base
script:
- npm run build - npm run build
artifacts: artifacts:
paths: paths:
- dist/ - dist/
unit-test:
extends:
- .build_base
script:
- npm run test
deploy_npm: deploy_npm:
stage: deploy stage: deploy
dependencies: dependencies:
......
...@@ -16,7 +16,7 @@ The decorator `@RegisterSchema` for class is used to register schema from a clas ...@@ -16,7 +16,7 @@ The decorator `@RegisterSchema` for class is used to register schema from a clas
// Don't forget this decorator. // Don't forget this decorator.
@RegisterSchema({ @RegisterSchema({
desc: 'my desc', description: 'my desc',
}) })
export class Config { export class Config {
// add this constructor to make sure the class has one parameter on constructor // add this constructor to make sure the class has one parameter on constructor
...@@ -41,7 +41,7 @@ export class Config { ...@@ -41,7 +41,7 @@ export class Config {
ant: string[]; ant: string[];
// You may also specify schema manually. // You may also specify schema manually.
@DefineSchema({ schema: Schema.string() }) @DefineSchema({ type: Schema.string() })
dream: string; dream: string;
// Nested schema. // Nested schema.
......
This diff is collapsed.
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
"scripts": { "scripts": {
"lint": "eslint --fix .", "lint": "eslint --fix .",
"build": "rm -rf dist && tsc", "build": "rm -rf dist && tsc",
"test": "jest --passWithNoTests",
"start": "node dist/index.js" "start": "node dist/index.js"
}, },
"repository": { "repository": {
...@@ -21,6 +22,7 @@ ...@@ -21,6 +22,7 @@
}, },
"homepage": "https://code.mycard.moe/3rdeye/schemastery-gen", "homepage": "https://code.mycard.moe/3rdeye/schemastery-gen",
"devDependencies": { "devDependencies": {
"@types/jest": "^27.0.3",
"@types/lodash": "^4.14.176", "@types/lodash": "^4.14.176",
"@types/node": "^16.11.9", "@types/node": "^16.11.9",
"@typescript-eslint/eslint-plugin": "^4.33.0", "@typescript-eslint/eslint-plugin": "^4.33.0",
...@@ -28,8 +30,10 @@ ...@@ -28,8 +30,10 @@
"eslint": "^7.32.0", "eslint": "^7.32.0",
"eslint-config-prettier": "^8.3.0", "eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^3.4.1", "eslint-plugin-prettier": "^3.4.1",
"jest": "^27.4.3",
"prettier": "^2.4.1", "prettier": "^2.4.1",
"schemastery": "^2.1.0", "schemastery": "^2.1.0",
"ts-jest": "^27.0.7",
"typescript": "^4.5.2" "typescript": "^4.5.2"
}, },
"peerDependencies": { "peerDependencies": {
...@@ -39,5 +43,22 @@ ...@@ -39,5 +43,22 @@
"lodash": "^4.17.21", "lodash": "^4.17.21",
"reflect-metadata": "^0.1.13", "reflect-metadata": "^0.1.13",
"typed-reflector": "^1.0.5" "typed-reflector": "^1.0.5"
},
"jest": {
"moduleFileExtensions": [
"js",
"json",
"ts"
],
"rootDir": "tests",
"testRegex": ".*\\.spec\\.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
"collectCoverageFrom": [
"**/*.(t|j)s"
],
"coverageDirectory": "../coverage",
"testEnvironment": "node"
} }
} }
...@@ -21,7 +21,7 @@ export function SchemaProperty(options: SchemaOptions = {}): PropertyDecorator { ...@@ -21,7 +21,7 @@ export function SchemaProperty(options: SchemaOptions = {}): PropertyDecorator {
options.type = 'any'; options.type = 'any';
} }
} }
const typeInSchema = options.schema?.type; const typeInSchema = (options.type as Schema)?.type;
if ( if (
nativeType === Array && nativeType === Array &&
options.array !== false && options.array !== false &&
......
...@@ -33,21 +33,17 @@ function getBasePropertySchemaFromOptions(options: SchemaOptions) { ...@@ -33,21 +33,17 @@ function getBasePropertySchemaFromOptions(options: SchemaOptions) {
} }
function applyOptionsToSchema(schema: Schema, options: SchemaClassOptions) { function applyOptionsToSchema(schema: Schema, options: SchemaClassOptions) {
if (options.desc) {
schema.meta.description = options.desc;
}
Object.assign(schema.meta, options); Object.assign(schema.meta, options);
} }
function getPropertySchemaFromOptions<PT>(options: SchemaOptions): Schema<PT> { function getPropertySchemaFromOptions<PT>(options: SchemaOptions): Schema<PT> {
let schema = getBasePropertySchemaFromOptions(options); let schema = getBasePropertySchemaFromOptions(options);
if (options.dict) { if (options.dict) {
const skeySchema = (options.dict === true const skeySchema = (
? Schema.string() options.dict === true
: ((Schema.from(options.dict) as unknown) as Schema< ? Schema.string()
any, : (Schema.from(options.dict) as unknown as Schema<any, string>)
string ) as Schema<any, string>;
>)) as Schema<any, string>;
schema = Schema.dict(schema, skeySchema).default({}); schema = Schema.dict(schema, skeySchema).default({});
} }
if (options.array) { if (options.array) {
...@@ -140,11 +136,11 @@ function applySchemaForClass<T>( ...@@ -140,11 +136,11 @@ function applySchemaForClass<T>(
export function SchemaClass<T>(originalClass: ClassType<T>) { export function SchemaClass<T>(originalClass: ClassType<T>) {
const schema = schemaFromClass(originalClass); const schema = schemaFromClass(originalClass);
const newClass = (function (...args: any[]): T { const newClass = function (...args: any[]): T {
const instance = new originalClass(...args); const instance = new originalClass(...args);
const originalObject = args[0]; const originalObject = args[0];
return applySchemaForClass(originalClass, instance, originalObject); return applySchemaForClass(originalClass, instance, originalObject);
} as unknown) as ClassType<T> & Schema<Partial<T>, T>; } as unknown as ClassType<T> & Schema<Partial<T>, T>;
Object.defineProperty(newClass, 'name', { Object.defineProperty(newClass, 'name', {
value: originalClass.name, value: originalClass.name,
}); });
......
...@@ -23,10 +23,7 @@ export type SchemaSource = ...@@ -23,10 +23,7 @@ export type SchemaSource =
export type SchemaType = SchemaNativeType | SchemaSource; export type SchemaType = SchemaNativeType | SchemaSource;
export interface SchemaClassOptions extends Schema.Meta<any> { export type SchemaClassOptions = Schema.Meta<any>;
desc?: string;
allowUnknown?: boolean; // for backward compatibility
}
export interface SchemaOptions extends SchemaClassOptions { export interface SchemaOptions extends SchemaClassOptions {
schema?: Schema<any>; schema?: Schema<any>;
......
import { RegisterSchema, SchemaProperty } from '../src/decorators';
import Schema from 'schemastery';
describe('Circular schema', () => {
@RegisterSchema()
class MyProperty {
@SchemaProperty({ default: 'bar' })
foo: string;
getFoo() {
return this.foo;
}
}
@RegisterSchema()
class MyConfig {
constructor(_: any) {}
@SchemaProperty({ type: MyProperty })
myProperty: MyProperty;
}
it('Should be object type', () => {
const schema = MyConfig as Schema<MyConfig>;
expect(schema.type).toBe('object');
expect(schema.dict.myProperty.type).toBe('object');
});
it('Should be instance', () => {
const config = new MyConfig({ myProperty: {} });
expect(config.myProperty.foo).toBe('bar');
expect(config.myProperty.getFoo()).toBe('bar');
});
it('Should throw if invalid', () => {
expect(() => new MyConfig({ myProperty: 'boo' })).toThrow();
});
});
import { RegisterSchema, SchemaProperty } from '../src/decorators';
describe('schema of class extend', () => {
class MyConfigBase {
@SchemaProperty({ default: 'bar' })
foo: string;
}
@RegisterSchema()
class MyConfig extends MyConfigBase {
constructor(_: any) {
super();
}
@SchemaProperty({ default: 'baz' })
bar: string;
}
it('should have foo and bar', () => {
const config = new MyConfig({});
expect(config.foo).toBe('bar');
expect(config.bar).toBe('baz');
});
});
import { kSchema } from '../src/utility/kschema';
describe('Testing of kSchema', () => {
it('kSchema should be a symbol', () => {
expect(typeof kSchema).toEqual('symbol');
});
});
import { RegisterSchema, SchemaProperty } from '../src/decorators';
import { kSchema } from '../src/utility/kschema';
import Schema from 'schemastery';
describe('Schema registration', () => {
@RegisterSchema()
class Config {
constructor(_config: any) {}
@SchemaProperty({ default: 'bar' })
foo: string;
}
@RegisterSchema()
class ConfigWithRequiredFields {
constructor(_config: any) {}
@SchemaProperty({ required: true })
foo: string;
}
it('should be a schema', () => {
expect(Config[kSchema]).toBeDefined();
});
it('should be schema object type', () => {
const schema = Config as Schema<Config>;
expect(schema.type).toBe('object');
expect(schema.dict.foo.type).toBe('string');
});
it('should put default value', () => {
expect(new Config({}).foo).toBe('bar');
expect(new Config({ foo: 'baz' }).foo).toBe('baz');
});
it('should throw if no default value', () => {
expect(() => new Config({ foo: 111 })).toThrow();
});
it('should throw if required field is missing', () => {
expect(() => new ConfigWithRequiredFields({})).toThrow();
});
});
import { RegisterSchema, SchemaProperty } from '../src/decorators';
import Schema from 'schemastery';
describe('Schema arrays', () => {
@RegisterSchema()
class MyProperty {
@SchemaProperty({ default: 'default' })
name: string;
getName() {
return this.name;
}
}
@RegisterSchema()
class MyConfig {
constructor(_: any) {}
@SchemaProperty({ type: Schema.array(Schema.string()) })
foo: string[];
@SchemaProperty({ type: Number })
bar: number[];
@SchemaProperty({ type: MyProperty })
myProperties: MyProperty[];
@SchemaProperty()
notArray: string;
@SchemaProperty({ type: Schema.tuple([Number, String]) })
myTup: [number, string];
@SchemaProperty({ type: Schema.tuple([Number, String]), array: true })
myTupArr: [number, string][];
}
const schema = MyConfig as Schema<MyConfig>;
it('should be correct type', () => {
expect(schema.dict.foo.type).toEqual('array');
expect(schema.dict.bar.type).toEqual('array');
expect(schema.dict.myProperties.type).toEqual('array');
expect(schema.dict.notArray.type).toEqual('string');
expect(schema.dict.myTup.type).toEqual('tuple');
expect(schema.dict.myTupArr.type).toEqual('array');
});
it('should be instance of property', () => {
const config = new MyConfig({ myProperties: [{ name: 'foo' }] });
expect(config.myProperties[0].getName()).toEqual('foo');
});
});
import { RegisterSchema, SchemaProperty } from '../src/decorators';
import Schema from 'schemastery';
describe('Schema dict', () => {
@RegisterSchema()
class MyProperty {
@SchemaProperty({ default: 'default' })
name: string;
getName() {
return this.name;
}
}
interface FooAndBar {
foo: number;
bar: number;
}
const sym = Symbol();
@RegisterSchema()
class MyConfig {
constructor(_: any) {}
@SchemaProperty({ type: String, dict: true })
foo: Record<string, string>;
@SchemaProperty({ type: Number, dict: Schema.union(['foo', 'bar']) })
fooAndBar: FooAndBar;
@SchemaProperty({ dict: true, type: MyProperty, default: {} })
myProperties: Record<string, MyProperty>;
@SchemaProperty({ dict: true, type: MyProperty, default: {} })
myPropertiesArr: Record<string, MyProperty>[];
}
const schema = MyConfig as Schema<MyConfig>;
it('should be correct type', () => {
expect(schema.dict.foo.type).toEqual('dict');
expect(schema.dict.fooAndBar.type).toEqual('dict');
expect(schema.dict.myProperties.type).toEqual('dict');
expect(schema.dict.myPropertiesArr.type).toEqual('array');
});
it('should check dict', () => {
const config = new MyConfig({
foo: {
bar: 'baz',
},
fooAndBar: {
foo: 1,
bar: 2,
},
});
expect(config.foo).toEqual({ bar: 'baz' });
expect(config.fooAndBar).toEqual({ foo: 1, bar: 2 });
});
it('should throw on invalid', () => {
expect(() => new MyConfig({ foo: 1 })).toThrow();
expect(() => new MyConfig({ foo: { bar: 1 } })).toThrow();
expect(() => new MyConfig({ [sym]: { bar: 'baz' } })).toThrow();
expect(() => new MyConfig({ fooAndBar: { foo: 'not number' } })).toThrow();
expect(() => new MyConfig({ fooAndBar: { somethingElse: 4 } })).toThrow();
});
it('should be instance of MyProperty', () => {
const config = new MyConfig({
myProperties: {
foo: {
name: 'foo',
},
},
myPropertiesArr: [
{
bar: {
name: 'bar',
},
},
],
});
expect(config.myProperties.foo.getName()).toEqual('foo');
expect(config.myPropertiesArr[0].bar.getName()).toEqual('bar');
});
});
...@@ -10,14 +10,11 @@ ...@@ -10,14 +10,11 @@
"sourceMap": true "sourceMap": true
}, },
"compileOnSave": true, "compileOnSave": true,
"allowJs": true,
"include": [ "include": [
"./src/**/*.ts", "*.ts",
"./test/**/*.ts", "src/**/*.ts",
"./index.ts", "test/**/*.ts",
"!*.d.ts" "tests/**/*.ts"
],
"exclude": [
"node_modules",
"dist"
] ]
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment