Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions implementations/js-jetio/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
FROM node:22-alpine
WORKDIR /usr/src/myapp
COPY package.json ./
RUN npm install --omit=dev
COPY meta-schemas/ ./meta-schemas/
COPY bowtie_jetio.mjs ./
CMD ["node", "bowtie_jetio.mjs"]
108 changes: 108 additions & 0 deletions implementations/js-jetio/bowtie_jetio.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { createInterface } from "node:readline";
import { readFileSync } from "node:fs";
import { JetValidator } from "@jetio/validator";
import { loadAllMetaSchemas } from "./meta-schemas/loader.mjs";

const pkg = JSON.parse(
readFileSync(
new URL("./node_modules/@jetio/validator/package.json", import.meta.url),
),
);

let started = false;
let implicitDialect = null;

function draftOptionFor(dialect) {
if (!dialect) return {};
if (dialect.includes("draft-06")) return { draft: "draft6" };
if (dialect.includes("draft-07")) return { draft: "draft7" };
if (dialect.includes("2019-09")) return { draft: "draft2019-09" };
return { draft: "draft2020-12" };
}

const handlers = {
start(req) {
if (req.version !== 1)
throw new Error(`unsupported IHOP version ${req.version}`);
started = true;
return {
version: 1,
implementation: {
language: "javascript",
name: "jetio-validator",
version: pkg.version,
homepage: "https://github.com/official-jetio/validator",
issues: "https://github.com/official-jetio/validator/issues",
source: "https://github.com/official-jetio/validator",
dialects: [
"https://json-schema.org/draft/2020-12/schema",
"https://json-schema.org/draft/2019-09/schema",
"http://json-schema.org/draft-07/schema#",
"http://json-schema.org/draft-06/schema#",
],
},
};
},

dialect(req) {
if (!started) throw new Error("not started");
implicitDialect = req.dialect;
return { ok: true };
},

run(req) {
if (!started) throw new Error("not started");
const { seq, case: kase } = req;
try {
const schema = kase.schema;
const isBool = typeof schema === "boolean";
const hasSchema =
!isBool && schema && typeof schema === "object" && "$schema" in schema;

const base = { strict: false, validateFormats: false };
const jet = new JetValidator(
hasSchema ? base : { ...base, ...draftOptionFor(implicitDialect) },
);
loadAllMetaSchemas(jet);

for (const [uri, s] of Object.entries(kase.registry ?? {}))
if (typeof s !== "boolean") jet.addSchema(s, uri);

if (!isBool) {
const rootId = schema.$id || schema.id;
if (rootId) jet.addSchema(schema, rootId);
}

const validate = jet.compile(schema);
const results = kase.tests.map((t) => ({
valid: Boolean(validate(t.instance)),
}));
return { seq, results };
} catch (err) {
console.error(
`[jet] ${kase.schema?.$id ?? kase.schema?.$schema ?? "?"} :: ${err?.stack ?? err}`,
);
return {
seq,
errored: true,
context: {
message: String(err?.message ?? err),
traceback: err?.stack,
},
};
}
},

stop() {
if (!started) throw new Error("not started");
process.exit(0);
},
};

const rl = createInterface({ input: process.stdin });
rl.on("line", (line) => {
if (!line.trim()) return;
const req = JSON.parse(line);
const res = handlers[req.cmd](req);
if (res) process.stdout.write(JSON.stringify(res) + "\n");
});
218 changes: 218 additions & 0 deletions implementations/js-jetio/meta-schemas/draft-06/schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
{
"$schema": "http://json-schema.org/draft-06/schema#",
"$id": "http://json-schema.org/draft-06/schema#",
"title": "Core schema meta-schema",
"definitions": {
"schemaArray": {
"type": "array",
"minItems": 1,
"items": {
"$ref": "#"
}
},
"nonNegativeInteger": {
"type": "integer",
"minimum": 0
},
"nonNegativeIntegerDefault0": {
"allOf": [
{
"$ref": "#/definitions/nonNegativeInteger"
},
{
"default": 0
}
]
},
"simpleTypes": {
"enum": [
"array",
"boolean",
"integer",
"null",
"number",
"object",
"string"
]
},
"stringArray": {
"type": "array",
"items": {
"type": "string"
},
"uniqueItems": true,
"default": []
}
},
"type": [
"object",
"boolean"
],
"properties": {
"$id": {
"type": "string",
"format": "uri-reference"
},
"$schema": {
"type": "string",
"format": "uri"
},
"$ref": {
"type": "string",
"format": "uri-reference"
},
"title": {
"type": "string"
},
"description": {
"type": "string"
},
"default": {},
"examples": {
"type": "array",
"items": {}
},
"multipleOf": {
"type": "number",
"exclusiveMinimum": 0
},
"maximum": {
"type": "number"
},
"exclusiveMaximum": {
"type": "number"
},
"minimum": {
"type": "number"
},
"exclusiveMinimum": {
"type": "number"
},
"maxLength": {
"$ref": "#/definitions/nonNegativeInteger"
},
"minLength": {
"$ref": "#/definitions/nonNegativeIntegerDefault0"
},
"pattern": {
"type": "string",
"format": "regex"
},
"additionalItems": {
"$ref": "#"
},
"items": {
"anyOf": [
{
"$ref": "#"
},
{
"$ref": "#/definitions/schemaArray"
}
],
"default": {}
},
"maxItems": {
"$ref": "#/definitions/nonNegativeInteger"
},
"minItems": {
"$ref": "#/definitions/nonNegativeIntegerDefault0"
},
"uniqueItems": {
"type": "boolean",
"default": false
},
"contains": {
"$ref": "#"
},
"maxProperties": {
"$ref": "#/definitions/nonNegativeInteger"
},
"minProperties": {
"$ref": "#/definitions/nonNegativeIntegerDefault0"
},
"required": {
"$ref": "#/definitions/stringArray"
},
"additionalProperties": {
"$ref": "#"
},
"definitions": {
"type": "object",
"additionalProperties": {
"$ref": "#"
},
"default": {}
},
"properties": {
"type": "object",
"additionalProperties": {
"$ref": "#"
},
"default": {}
},
"patternProperties": {
"type": "object",
"additionalProperties": {
"$ref": "#"
},
"propertyNames": {
"format": "regex"
},
"default": {}
},
"dependencies": {
"type": "object",
"additionalProperties": {
"anyOf": [
{
"$ref": "#"
},
{
"$ref": "#/definitions/stringArray"
}
]
}
},
"propertyNames": {
"$ref": "#"
},
"const": {},
"enum": {
"type": "array",
"minItems": 1,
"uniqueItems": true
},
"type": {
"anyOf": [
{
"$ref": "#/definitions/simpleTypes"
},
{
"type": "array",
"items": {
"$ref": "#/definitions/simpleTypes"
},
"minItems": 1,
"uniqueItems": true
}
]
},
"format": {
"type": "string"
},
"allOf": {
"$ref": "#/definitions/schemaArray"
},
"anyOf": {
"$ref": "#/definitions/schemaArray"
},
"oneOf": {
"$ref": "#/definitions/schemaArray"
},
"not": {
"$ref": "#"
}
},
"default": {}
}
Loading
Loading