Skip to content

Commit

Permalink
Absolute path
Browse files Browse the repository at this point in the history
  • Loading branch information
timotheeguerin committed Nov 28, 2023
1 parent da38580 commit eca2fb4
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 11 deletions.
51 changes: 40 additions & 11 deletions packages/compiler/src/core/schema-validator.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import Ajv, { DefinedError, Options } from "ajv";
import Ajv, { ErrorObject, Options } from "ajv";
import { getLocationInYamlScript } from "../yaml/diagnostics.js";
import { YamlScript } from "../yaml/types.js";
import { compilerAssert } from "./diagnostics.js";
import { createDiagnostic } from "./messages.js";
import { isPathAbsolute } from "./path-utils.js";
import { Diagnostic, JSONSchemaType, JSONSchemaValidator, NoTarget, SourceFile } from "./types.js";

export interface JSONSchemaValidatorOptions {
Expand All @@ -13,12 +15,18 @@ export function createJSONSchemaValidator<T>(
schema: JSONSchemaType<T>,
options: JSONSchemaValidatorOptions = { strict: true }
): JSONSchemaValidator {
const ajv = new (Ajv as any)({
const ajv: import("ajv").default = new (Ajv as any)({
strict: options.strict,
coerceTypes: options.coerceTypes,
allErrors: true,
} satisfies Options);

ajv.addFormat("absolute-path", {
type: "string",
validate: (path) => {
return !path.startsWith(".") && isPathAbsolute(path);
},
});
return { validate };

function validate(
Expand All @@ -34,7 +42,7 @@ export function createJSONSchemaValidator<T>(

const diagnostics = [];
for (const error of validate.errors ?? []) {
const diagnostic = ajvErrorToDiagnostic(error, target);
const diagnostic = ajvErrorToDiagnostic(config, error, target);
diagnostics.push(diagnostic);
}

Expand All @@ -45,9 +53,24 @@ export function createJSONSchemaValidator<T>(
const IGNORED_AJV_PARAMS = new Set(["type", "errors"]);

function ajvErrorToDiagnostic(
error: DefinedError,
obj: unknown,
error: ErrorObject<string, Record<string, any>, unknown>,
target: YamlScript | SourceFile | typeof NoTarget
): Diagnostic {
const tspTarget =
target === NoTarget
? target
: "kind" in target
? getLocationInYamlScript(target, getErrorPath(error), "key")
: { file: target, pos: 0, end: 0 };
if (error.params.format === "absolute-path") {
return createDiagnostic({
code: "config-path-absolute",
format: { path: getErrorValue(obj, error) as any },
target: tspTarget,
});
}

const messageLines = [`Schema violation: ${error.message} (${error.instancePath || "/"})`];
for (const [name, value] of Object.entries(error.params).filter(
([name]) => !IGNORED_AJV_PARAMS.has(name)
Expand All @@ -61,16 +84,11 @@ function ajvErrorToDiagnostic(
code: "invalid-schema",
message,
severity: "error",
target:
target === NoTarget
? target
: "kind" in target
? getLocationInYamlScript(target, getErrorPath(error), "key")
: { file: target, pos: 0, end: 0 },
target: tspTarget,
};
}

function getErrorPath(error: DefinedError): string[] {
function getErrorPath(error: ErrorObject<string, Record<string, any>, unknown>): string[] {
const instancePath = parseJsonPointer(error.instancePath);
switch (error.keyword) {
case "additionalProperties":
Expand All @@ -79,6 +97,17 @@ function getErrorPath(error: DefinedError): string[] {
return instancePath;
}
}
function getErrorValue(
obj: any,
error: ErrorObject<string, Record<string, any>, unknown>
): unknown {
const path = getErrorPath(error);
let current = obj;
for (const segment of path) {
current = current[segment];
}
return current;
}

/**
* Converts a json pointer into a array of reference tokens
Expand Down
1 change: 1 addition & 0 deletions packages/openapi3/src/lib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ const EmitterOptionsSchema: JSONSchemaType<OpenAPI3EmitterOptions> = {
"output-file": {
type: "string",
nullable: true,
format: "absolute-path",
description: [
"Name of the output file.",
" Output file will interpolate the following values:",
Expand Down

0 comments on commit eca2fb4

Please sign in to comment.