Giter Club home page Giter Club logo

create-validator-ts's Introduction

create-validator-ts

Create JSON Schema validator from TypeScript.

Motivation

  • Generate JSON Schema Validator functions from TypeScript code
  • Make TypeScript a single source of truth

Structure

.
└── src/
    ├── hello/
    │   ├── api-types.ts
    │   ├── api-types.validator.ts <- Generated
    │   └── index.ts
    └── status/
        ├── api-types.ts
        ├── api-types.validator.ts <- Generated
        └── index.ts

Install

Install with npm:

npm install create-validator-ts

Usage

Usage
  $ create-validator-ts [file|glob*]

Options
  --watch               [Boolean] If set the flag, start watch mode
  --check               [Boolean] If set the flag, start test mode
  --cwd                 [Path:String] current working directory
  --tsconfigFilePath    [Path:String] path to tsconfig.json
  --generatorScript     [Path:String] A JavaScript file path that customize validator code generator
  --verbose             [Boolean] If set the flag, show progressing logs
 
  ts-json-schema-generator options
  --sortProps               [Boolean] Enable sortProps
  --no-sortProps            
  --strictTuples            [Boolean] Enable strictTuples
  --no-strictTuples         
  --encodeRefs              [Boolean] Enable encodeRefs
  --no-encodeRefs           
  --skipTypeCheck           [Boolean] Enable skipTypeCheck. true by default
  --no-skipTypeCheck
  --additionalProperties    [Boolean] Enable additionalProperties. false by default
  --no-additionalProperties 


Examples
  $ create-validator-ts "src/**/api-types.ts"
  # use cache
  $ create-validator-ts --cache "src/**/api-types.ts"
  # custom tsconfig.json
  $ create-validator-ts "src/**/api-types.ts" --tsconfigFilePath ./tsconfig.app.json
  # custom validator code
  $ create-validator-ts "src/**/api-types.ts" --generatorScript ./custom.js

Example

You can generate validator code via following command

$ create-validator-ts "src/**/api-types.ts"

Default validator require ajv, and you need to install ajv into your project.

$ npm install ajv

Structure:

.
├ tsconfig.json
└── src/
    └─── api/
        ├──  api-types.ts
        └─── api-types.validator.ts <- Generated

api-types.ts:

// Example api-types
// GET /api
export type GetAPIRequestQuery = {
    id: string;
};
export type GetAPIResponseBody = {
    ok: boolean;
};

api-types.validator.ts (generated):

// @ts-nocheck
// eslint-disable
// This file is generated by create-validator-ts
import Ajv from 'ajv';
import * as apiTypes from './api-types';

const SCHEMA = {
    "$schema": "http://json-schema.org/draft-07/schema#",
    "definitions": {
        "GetAPIRequestQuery": {
            "type": "object",
            "properties": {
                "id": {
                    "type": "string"
                }
            },
            "required": [
                "id"
            ],
            "additionalProperties": false
        },
        "GetAPIResponseBody": {
            "type": "object",
            "properties": {
                "ok": {
                    "type": "boolean"
                }
            },
            "required": [
                "ok"
            ],
            "additionalProperties": false
        }
    }
};
const ajv = new Ajv({ removeAdditional: true }).addSchema(SCHEMA, "SCHEMA");
export function validateGetAPIRequestQuery(payload: unknown): apiTypes.GetAPIRequestQuery {
  if (!isGetAPIRequestQuery(payload)) {
    const error = new Error('invalid payload: GetAPIRequestQuery');
    error.name = "ValidatorError";
    throw error;
  }
  return payload;
}

export function isGetAPIRequestQuery(payload: unknown): payload is apiTypes.GetAPIRequestQuery {
  /** Schema is defined in {@link SCHEMA.definitions.GetAPIRequestQuery } **/
  const ajvValidate = ajv.compile({ "$ref": "SCHEMA#/definitions/GetAPIRequestQuery" });
  return ajvValidate(payload);
}

export function validateGetAPIResponseBody(payload: unknown): apiTypes.GetAPIResponseBody {
  if (!isGetAPIResponseBody(payload)) {
    const error = new Error('invalid payload: GetAPIResponseBody');
    error.name = "ValidatorError";
    throw error;
  }
  return payload;
}

export function isGetAPIResponseBody(payload: unknown): payload is apiTypes.GetAPIResponseBody {
  /** Schema is defined in {@link SCHEMA.definitions.GetAPIResponseBody } **/
  const ajvValidate = ajv.compile({ "$ref": "SCHEMA#/definitions/GetAPIResponseBody" });
  return ajvValidate(payload);
}

Check generated code

When You can check if your generated codes are match with api-types.ts, you can run it via --check flag.

$ create-validator-ts "src/**/api-types.ts"
# $? → 0 or 1

It is useful for testing on CI.

Custom Validator

You can create custom validator using --generatorScript flag.

$ create-validator-ts "src/**/api-types.ts" --generatorScript ./custom.js

custom.js

"use strict";
const path = require("path");
const generator = ({ apiFilePath, apiFileCode, schema }) => {
    const apiFileName = path.basename(apiFilePath, ".ts");
    const isExportedTypeInApiTypes = (apiName) => {
        return (apiFileCode.includes(`export type ${apiName} =`) ||
            apiFileCode.includes(`export interface ${apiName} {`));
    };
    const banner = `// @ts-nocheck
// eslint-disable
// This file is generated by create-validator-ts
import Ajv from 'ajv';
import logger from 'logger';
import * as apiTypes from './${apiFileName}';
`;
    // define SCHEMA to top, and we can refer it as "SCHEMA".
    // Note: { "$ref": "SCHEMA#/definitions/${apiName}" }
    const schemaDefinition = `const SCHEMA = ${JSON.stringify(schema, null, 4)};
const ajv = new Ajv({ removeAdditional: true }).addSchema(SCHEMA, "SCHEMA");`;
    const code = Object.entries(schema.definitions || {})
        .filter(([apiName]) => {
        return isExportedTypeInApiTypes(apiName);
    })
        .map(([apiName, _schema]) => {
        return `export function validate${apiName}(payload: unknown): apiTypes.${apiName} {
  if (!is${apiName}(payload)) {
    const error = new Error('invalid payload: ${apiName}');
    error.name = "ValidatorError";
    throw error;
  }
  return payload;
}

export function is${apiName}(payload: unknown): payload is apiTypes.${apiName} {
  /** Schema is defined in {@link SCHEMA.definitions.${apiName} } **/
  const ajvValidate = ajv.compile({ "$ref": "SCHEMA#/definitions/${apiName}" });
  return ajvValidate(payload);
}`;
    })
        .join("\n\n");
    return `${banner}
${schemaDefinition}
${code}
`;
};
exports.generator = generator;
exports.generatorOptions = {
  extraTags: ["<ajv-plugin-extra-tag>"] // optional
};

Ignore generated Code

If you used Prettier, you should add *.validator.ts to .prettierignore

*.validator.ts

Changelog

See Releases page.

Running tests

Install devDependencies and Run npm test:

npm test

Contributing

Pull requests and stars are always welcome.

For bugs and feature requests, please create an issue.

  1. Fork it!
  2. Create your feature branch: git checkout -b my-new-feature
  3. Commit your changes: git commit -am 'Add some feature'
  4. Push to the branch: git push origin my-new-feature
  5. Submit a pull request :D

Author

License

MIT © azu

Prior art

Differences:

create-validator-ts's People

Contributors

azu avatar otolab avatar renovate-bot avatar renovate[bot] avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.