diff --git a/src/ValidatorMain.ts b/src/ValidatorMain.ts index 4eb58977..66f073af 100644 --- a/src/ValidatorMain.ts +++ b/src/ValidatorMain.ts @@ -58,6 +58,16 @@ export class ValidatorMain { config.writeReports, validationOptions ); + } else if (config.tileContentFile) { + const reportFileName = ValidatorMain.obtainReportFileName( + config, + config.tileContentFile + ); + await ValidatorMain.validateTileContentFile( + config.tileContentFile, + reportFileName, + validationOptions + ); } else if (config.metadataSchemaFile) { const reportFileName = ValidatorMain.obtainReportFileName( config, @@ -172,6 +182,26 @@ export class ValidatorMain { console.log(` ${numFilesWithInfos} files with infos`); } + static async validateTileContentFile( + fileName: string, + reportFileName: string | undefined, + options: ValidationOptions | undefined + ): Promise { + console.log("Validating tile content " + fileName); + + const validationResult = await Validators.validateTileContentFile( + fileName, + options + ); + if (defined(reportFileName)) { + await writeUnchecked(reportFileName, validationResult.serialize()); + } else { + console.log("Validation result:"); + console.log(validationResult.serialize()); + } + return validationResult; + } + static async validateSchemaFile( fileName: string, reportFileName: string | undefined diff --git a/src/main.ts b/src/main.ts index 026766b1..d939cd45 100644 --- a/src/main.ts +++ b/src/main.ts @@ -46,6 +46,11 @@ const args = yargs(process.argv.slice(1)) "of the report will be derived from the input file name, " + "and be written into the same directory as the input file.", }, + tileContentFile: { + type: "string", + alias: "f", + describe: "The tile content input file path", + }, optionsFile: { type: "string", alias: "o", diff --git a/src/validation/Validators.ts b/src/validation/Validators.ts index 6825dbb1..d703b72e 100644 --- a/src/validation/Validators.ts +++ b/src/validation/Validators.ts @@ -2,9 +2,10 @@ import path from "path"; import fs from "fs"; import { defined } from "3d-tiles-tools"; +import { LazyContentData } from "3d-tiles-tools"; import { Buffers } from "3d-tiles-tools"; - import { ResourceResolvers } from "3d-tiles-tools"; +import { TileImplicitTiling } from "3d-tiles-tools"; import { Validator } from "./Validator"; import { TilesetValidator } from "./TilesetValidator"; @@ -15,11 +16,10 @@ import { ValidationState } from "./ValidationState"; import { ValidationOptions } from "./ValidationOptions"; import { ExtendedObjectsValidators } from "./ExtendedObjectsValidators"; import { TilesetPackageValidator } from "./TilesetPackageValidator"; +import { ContentDataValidators } from "./ContentDataValidators"; import { SchemaValidator } from "./metadata/SchemaValidator"; -import { TileImplicitTiling } from "3d-tiles-tools"; - import { IoValidationIssues } from "../issues/IoValidationIssue"; import { ContentValidationIssues } from "../issues/ContentValidationIssues"; @@ -175,6 +175,69 @@ export class Validators { return context.getResult(); } + /** + * Performs a default validation of the given tile content file, and + * returns a promise to the `ValidationResult`. + * + * The given file may be of any format. The method will detect + * the format, and decide whether it can perform a sensible + * validation, based on the existing validation functionality. + * + * @param filePath - The file path + * @param validationOptions - The `ValidationOptions`. When this + * is not given (or `undefined`), then default validation options + * will be used. See {@link ValidationOptions}. + * @returns A promise to a `ValidationResult` that is fulfilled when + * the validation finished. + * @beta + */ + static async validateTileContentFile( + filePath: string, + validationOptions?: ValidationOptions + ): Promise { + const directory = path.dirname(filePath); + const fileName = path.basename(filePath); + const resourceResolver = + ResourceResolvers.createFileResourceResolver(directory); + const context = new ValidationContext( + directory, + resourceResolver, + validationOptions + ); + const contentData = new LazyContentData(fileName, resourceResolver); + + // Check if the file exists, and bail out early if it doesn't + const dataExists = await contentData.exists(); + if (!dataExists) { + const message = `Content file ${filePath} could not be resolved`; + const issue = ContentValidationIssues.CONTENT_VALIDATION_ERROR( + filePath, + message + ); + context.addIssue(issue); + return context.getResult(); + } + + // Find the validator for the content data, and bail + // out early if none could be found + const dataValidator = await ContentDataValidators.findContentDataValidator( + contentData + ); + if (!defined(dataValidator)) { + const message = `No valid content type could be determined for ${filePath}`; + const issue = ContentValidationIssues.CONTENT_VALIDATION_WARNING( + filePath, + message + ); + context.addIssue(issue); + return context.getResult(); + } + + // Perform the actual validation + await dataValidator.validateObject(fileName, contentData, context); + return context.getResult(); + } + /** * Creates a `SchemaValidator` with an unspecified default configuration. *