diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 6b3ebc7..59e96c6 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -2,9 +2,9 @@ name: CI on: push: - branches: [ main ] + branches: [main] pull_request: - branches: [ main ] + branches: [main] workflow_dispatch: @@ -21,4 +21,6 @@ jobs: run: yarn install - name: Build - run: yarn build + run: | + yarn build + yarn validate diff --git a/.gitignore b/.gitignore index 3161163..4b3630b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ node_modules -index.js +**.js **.d.ts diff --git a/.travis.yml b/.travis.yml index 772835c..1b7f3ac 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,3 +9,4 @@ cache: - node_modules script: - yarn build + - yarn validate diff --git a/index.ts b/index.ts index 6aef7e3..2217f0d 100644 --- a/index.ts +++ b/index.ts @@ -21,6 +21,8 @@ export type Company = { }; }; -export const data: { +export type JobsData = { [name: string]: Company; -} = rawData; +}; + +export const data: JobsData = rawData; diff --git a/package.json b/package.json index 8487bbf..8110b41 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,18 @@ { "name": "tech-jobs", "version": "1.0.0", + "type": "module", "main": "index.js", "types": "index.d.ts", "repository": "git@github.com:techcareerio/tech-jobs.git", "author": "Cat Chen ", "license": "MIT", "devDependencies": { + "ajv": "^7.0.3", "typescript": "^4.1.3" }, "scripts": { - "build": "npx tsc" + "build": "npx tsc", + "validate": "node --experimental-json-modules validate.js" } } diff --git a/validate.ts b/validate.ts new file mode 100644 index 0000000..7ffe3ab --- /dev/null +++ b/validate.ts @@ -0,0 +1,60 @@ +import Ajv, { JSONSchemaType, DefinedError } from "ajv"; +import type { Opening, Job, Company, JobsData } from "./index"; +import data from "./data.json"; + +const openingSchema: JSONSchemaType = { + type: "object", + required: ["available"], + properties: { + available: { type: "boolean" }, + url: { type: "string", nullable: true }, + }, + additionalProperties: false, +}; + +const jobSchema: JSONSchemaType = { + type: "object", + required: [], + properties: { + intern: { ...openingSchema, nullable: true }, + newGrad: { ...openingSchema, nullable: true }, + senior: { ...openingSchema, nullable: true }, + manager: { ...openingSchema, nullable: true }, + }, + additionalProperties: false, +}; + +const companySchema: JSONSchemaType = { + type: "object", + required: ["jobs"], + properties: { + url: { type: "string", nullable: true }, + jobs: { + type: "object", + required: [], + properties: { + softwareEngineer: { ...jobSchema, nullable: true }, + dataScientist: { ...jobSchema, nullable: true }, + productManager: { ...jobSchema, nullable: true }, + }, + additionalProperties: false, + }, + }, + additionalProperties: false, +}; + +const schema: JSONSchemaType = { + type: "object", + required: [], + additionalProperties: companySchema, +}; + +// @ts-ignore +const ajv: Ajv = new Ajv.default(); +const validate = ajv.compile(schema); +if (!validate(data)) { + for (const error of validate.errors as DefinedError[]) { + console.error(error); + } + throw new Error("Validation failure"); +} diff --git a/yarn.lock b/yarn.lock index 3986214..c581095 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,7 +2,44 @@ # yarn lockfile v1 +ajv@^7.0.3: + version "7.0.3" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-7.0.3.tgz#13ae747eff125cafb230ac504b2406cf371eece2" + integrity sha512-R50QRlXSxqXcQP5SvKUrw8VZeypvo12i2IX0EeR5PiZ7bEKeHWgzgo264LDadUsCU42lTJVhFikTqJwNeH34gQ== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + +fast-deep-equal@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +punycode@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + typescript@^4.1.3: version "4.1.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.3.tgz#519d582bd94cba0cf8934c7d8e8467e473f53bb7" integrity sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg== + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0"