Skip to content

Commit

Permalink
Extract class for resolving schema. Fix return values.
Browse files Browse the repository at this point in the history
  • Loading branch information
javagl committed Sep 25, 2023
1 parent 256bc9d commit 7cbacb5
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 80 deletions.
95 changes: 95 additions & 0 deletions src/validation/SchemaResolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { defined } from "3d-tiles-tools";
import { Buffers } from "3d-tiles-tools";
import { Schema } from "3d-tiles-tools";
import { ValidationContext } from "./ValidationContext";
import { IoValidationIssues } from "../issues/IoValidationIssue";

/**
* Internal utility class for resolving a metadata `Schema` object.
*
* This receives the `schema` and `schemaUri` (for example,
* from a `tileset` object), and returns the resulting
* schema, resolving the `schemaUri` if necessary.
*
* @internal
*/
export class SchemaResolver {
/**
* Resolves the schema for the given object.
*
* The result will be an object with the following properties:
*
* `hasSchemaDefinition`: This is `true` if there either was a
* `schema` or a `schemaUri`
*
* `schema`: This is either the `schema`, or the schema that was
* read from the `schemaUri`. If the latter could not be resolved,
* then `schema` will be `undefined`.
*
* @param path - The path for validation issues
* @param schema - The schema
* @param schemaUri - The schema URI
* @param context - The `ValidationContext`
* @returns A promise that resolves with the result object
*/
static async resolveSchema(
path: string,
schema: any,
schemaUri: any,
context: ValidationContext
): Promise<{ hasSchemaDefinition: boolean; schema?: Schema }> {
if (defined(schema) && typeof schema === "object") {
return {
hasSchemaDefinition: true,
schema: schema,
};
}
if (defined(schemaUri) && typeof schemaUri === "string") {
const resourceResolver = context.getResourceResolver();
const schemaBuffer = await resourceResolver.resolveData(schemaUri);
if (!defined(schemaBuffer)) {
const schemaUriPath = path + "/schemaUri";
const message = `The 'schemaUri' is '${schemaUri}' and could not be resolved`;
const issue = IoValidationIssues.IO_ERROR(schemaUriPath, message);
context.addIssue(issue);
return {
hasSchemaDefinition: true,
schema: undefined,
};
}

const bom = Buffers.getUnicodeBOMDescription(schemaBuffer);
if (defined(bom)) {
const message = `Unexpected BOM in schema JSON buffer: ${bom}`;
const issue = IoValidationIssues.IO_ERROR(schemaUri, message);
context.addIssue(issue);
return {
hasSchemaDefinition: true,
schema: undefined,
};
}

const schemaString = schemaBuffer.toString();
try {
const resolvedSchema = JSON.parse(schemaString);
return {
hasSchemaDefinition: true,
schema: resolvedSchema,
};
} catch (error) {
//console.log(error);
const issue = IoValidationIssues.JSON_PARSE_ERROR(path, "" + error);
context.addIssue(issue);
return {
hasSchemaDefinition: true,
schema: undefined,
};
}
}
return {
hasSchemaDefinition: false,
schema: undefined,
};
}

}
93 changes: 13 additions & 80 deletions src/validation/TilesetValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { IoValidationIssues } from "../issues/IoValidationIssue";
import { StructureValidationIssues } from "../issues/StructureValidationIssues";
import { JsonValidationIssues } from "../issues/JsonValidationIssues";
import { SemanticValidationIssues } from "../issues/SemanticValidationIssues";
import { SchemaResolver } from "./SchemaResolver";

/**
* A class that can validate a 3D Tiles tileset.
Expand Down Expand Up @@ -173,8 +174,10 @@ export class TilesetValidator implements Validator<Tileset> {
validatedGroups: undefined,
hasGroupsDefinition: false,
};
const schemaResult = await TilesetValidator.resolveTilesetSchema(
tileset,
const schemaResult = await SchemaResolver.resolveSchema(
"",
tileset.schema,
tileset.schemaUri,
context
);
validationState.hasSchemaDefinition = schemaResult.hasSchemaDefinition;
Expand Down Expand Up @@ -359,12 +362,15 @@ export class TilesetValidator implements Validator<Tileset> {
extensionsUsed.forEach((e) => actualExtensionsUsed.add(e));

// The elements in extensionsUsed MUST be unique
BasicValidator.validateArrayElementsUnique(
const elementsUnique = BasicValidator.validateArrayElementsUnique(
extensionsUsedPath,
"extensionsUsed",
extensionsUsed,
context
);
if (!elementsUnique) {
result = false;
}
}
}
// Validate the extensionsRequired
Expand All @@ -389,12 +395,15 @@ export class TilesetValidator implements Validator<Tileset> {
extensionsRequired.forEach((e) => actualExtensionsRequired.add(e));

// The elements in extensionsRequired MUST be unique
BasicValidator.validateArrayElementsUnique(
const elementsUnique = BasicValidator.validateArrayElementsUnique(
extensionsRequiredPath,
"extensionsRequired",
extensionsRequired,
context
);
if (!elementsUnique) {
result = false;
}
}
}

Expand Down Expand Up @@ -449,82 +458,6 @@ export class TilesetValidator implements Validator<Tileset> {
return result;
}

/**
* Resolves the schema for the given tileset.
*
* The result will be an object with the following properties:
*
* `hasSchemaDefinition`: This is `true` if there either was a
* `tileset.schema` or a `tileset.schemaUri`
*
* `schema`: This is either the `tileset.schema`, or the
* schema that was read from the `tileset.schemaUri`. If
* the latter could not be resolved, `schema` will be
* `undefined`.
*
* @param tileset - The `Tileset` object
* @param context - The `ValidationContext`
* @returns A promise that resolves with the result object
*/
static async resolveTilesetSchema(
tileset: Tileset,
context: ValidationContext
): Promise<{ hasSchemaDefinition: boolean; schema?: Schema }> {
const schema = tileset.schema;
const schemaUri = tileset.schemaUri;
if (defined(schema) && typeof schema === "object") {
return {
hasSchemaDefinition: true,
schema: schema,
};
}
if (defined(schemaUri) && typeof schemaUri === "string") {
const resourceResolver = context.getResourceResolver();
const schemaBuffer = await resourceResolver.resolveData(schemaUri);
if (!defined(schemaBuffer)) {
const path = "/schemaUri";
const message = `The 'schemaUri' is '${schemaUri}' and could not be resolved`;
const issue = IoValidationIssues.IO_ERROR(path, message);
context.addIssue(issue);
return {
hasSchemaDefinition: true,
schema: undefined,
};
}

const bom = Buffers.getUnicodeBOMDescription(schemaBuffer);
if (defined(bom)) {
const message = `Unexpected BOM in schema JSON buffer: ${bom}`;
const issue = IoValidationIssues.IO_ERROR(schemaUri, message);
context.addIssue(issue);
return {
hasSchemaDefinition: true,
schema: undefined,
};
}

const schemaString = schemaBuffer.toString();
try {
const resolvedSchema = JSON.parse(schemaString);
return {
hasSchemaDefinition: true,
schema: resolvedSchema,
};
} catch (error) {
//console.log(error);
const issue = IoValidationIssues.JSON_PARSE_ERROR("", "" + error);
context.addIssue(issue);
return {
hasSchemaDefinition: true,
schema: undefined,
};
}
}
return {
hasSchemaDefinition: false,
schema: undefined,
};
}

/**
* Validates the given `tileset.groups`
Expand Down

0 comments on commit 7cbacb5

Please sign in to comment.