Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate 3D Tiles reference #89

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
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
Next Next commit
Refactoring to generate 3D Tiles documentation
  • Loading branch information
javagl committed May 31, 2022
commit 33e16a01b73e3335404f1e778a0a7fda1e074954
264 changes: 185 additions & 79 deletions bin/wetzel.js
Original file line number Diff line number Diff line change
@@ -1,94 +1,200 @@
#!/usr/bin/env node
"use strict";
var fs = require('fs');
var path = require('path');
var argv = require('minimist')(process.argv.slice(2), { boolean : ["w", "suppresswarnings" ]});
var defined = require('../lib/defined');
var defaultValue = require('../lib/defaultValue');
var enums = require('../lib/enums');
var generateMarkdown = require('../lib/generateMarkdown');

if (!defined(argv._[0]) || defined(argv.h) || defined(argv.help)) {
var help = 'Usage: node ' + path.basename(__filename) + ' [path-to-json-schema-file] [OPTIONS]\n' +
' -l, --headerLevel Top-level header. Default: 1\n' +
' -c, --checkmark Symbol for required properties. Default: ✓\n' +
' -k, --keyword Use a particular keyword in place of "must", for example "**MUST**".\n' +
' -p, --schemaPath The path string that should be used when generating the schema reference paths.\n' +
' -s, --searchPath The path string that should be used when loading the schema reference paths.\n' +
' -e, --embedOutput The output path for a document that embeds JSON schemas directly (AsciiDoctor only).\n' +
' -m, --outputMode The output mode, Markdown (the default) or AsciiDoctor (a).\n' +
' -n, --noTOC Skip writing the Table of Contents.\n' +
' -a, --autoLink Aggressively auto-inter-link types referenced in descriptions.\n' +
' Add =cqo to auto-link types that are in code-quotes only.\n' +
' -i An array of schema filenames (no paths) that should not get their own\n' +
' table of contents entry, nor type listing (they are just used for\n' +
' sharing properties across multiple other schemas)\n' +
' -d, --debug Provide a path, and this will save out intermediate processing\n' +
' artifacts useful in debugging wetzel.\n' +
' -w, --suppressWarnings Will not print out WETZEL_WARNING strings indicating identified\n' +
' conversion problems. Default: false\n';
process.stdout.write(help);
return;
const fs = require("fs");
const path = require("path");
const minimist = require("minimist");
const defined = require("../lib/defined");
const defaultValue = require("../lib/defaultValue");
const enums = require("../lib/enums");
const SchemaRepository = require("../lib/SchemaRepository");
const MarkdownGenerator = require("../lib/MarkdownGenerator");

const parsedArguments = minimist(process.argv.slice(2));

/**
* Parse an string that represents an array of file paths, and create
* an array of strings with these file paths, taking different forms
* of single- or double quotes into account.
*
* We're expecting users to pass in an array as a "string", but we aren't expecting them
* to pass it in as a correctly JSON-escaped string. Therefore, we need to replace single
* or double-quotes with a backslash-double-quote, and then we can parse the object.
*
* If the given argument is undefined, then an empty array will be returned.
*
* @param {String} pathsArrayString The string
* @returns The array
*/
function parsePathsArray(pathsArrayString) {
if (!defined(pathsArrayString)) {
return [];
}
let escapedPathsArrayString = pathsArrayString.replace(/'/g, '"');
escapedPathsArrayString = escapedPathsArrayString.replace(/"/g, '\"');
const pathsArray = JSON.parse(escapedPathsArrayString);
return pathsArray;
}

var filepath = argv._[0];
var schema = JSON.parse(fs.readFileSync(filepath));
function printHelp() {
const help =
"Usage: node wetzel.js [path-to-json-schema-file] [OPTIONS]\n" +
" -l, --headerLevel Top-level header. Default: 1\n" +
" -o, --outputFile The output file\n" +
" -c, --checkmark Symbol for required properties. Default: ✓\n" +
' -k, --keyword Use a particular keyword in place of "must", for example "**MUST**".\n' +
" -s, --searchPath The path string that should be used when loading the schema reference paths.\n" +
" -S, --searchPaths An array of path strings that should be used when loading the schema reference paths.\n" +
" -e, --embedOutput The output path for a document that embeds JSON schemas directly (AsciiDoctor only).\n" +
" -E, --EmbedOutput The same as 'e', but inlining the file contents instead of using include statements\n" +
" -m, --outputMode The output mode, Markdown (the default) or AsciiDoctor (a).\n" +
" -n, --noTOC Skip writing the Table of Contents.\n" +
" -a, --autoLink Aggressively auto-inter-link types referenced in descriptions.\n" +
" Add =cqo to auto-link types that are in code-quotes only.\n" +
" -i An array of type names that should not get their own\n" +
" table of contents entry, nor type listing (they are just used for\n" +
" sharing properties across multiple other schemas)\n" +
" -f, --fragmentPrefix A prefix for the fragments and anchors that are created for internal links.\n";
console.log(help);
}

function parseOptions(args) {
if (!defined(args._[0]) || defined(args.h) || defined(args.help)) {
printHelp();
return undefined;
}

// Somewhat hacky: Handle a single input file (i.e. a string),
// or an array of input files....
let inputFilePaths;
const inputFilesArgument = args._[0].trim();
if (inputFilesArgument.startsWith("[")) {
inputFilePaths = parsePathsArray(inputFilesArgument);
} else {
inputFilePaths = [inputFilesArgument];
}

var autoLink = enums.autoLinkOption.off;
switch (defaultValue(argv.a, argv.autoLink)) {
let autoLink = enums.autoLinkOption.off;
switch (defaultValue(args.a, args.autoLink)) {
case true:
autoLink = enums.autoLinkOption.aggressive;
break;
autoLink = enums.autoLinkOption.aggressive;
break;
case "=cqo":
case "cqo":
autoLink = enums.autoLinkOption.codeQuoteOnly;
break;
}
autoLink = enums.autoLinkOption.codeQuoteOnly;
break;
}

var styleModeArgument = defaultValue(argv.m, argv.outputMode);
if (styleModeArgument === 'a' || styleModeArgument === '=a') {
styleModeArgument = enums.styleModeOption.AsciiDoctor;
}
let styleMode = enums.styleModeOption.Markdown;
let styleModeArgument = defaultValue(args.m, args.outputMode);
if (styleModeArgument === "a" || styleModeArgument === "=a") {
styleMode = enums.styleModeOption.AsciiDoctor;
}

// We're expecting users to pass in an array as a "string", but we aren't expecting them
// to pass it in as a correctly JSON-escaped string. Therefore, we need to replace single
// or double-quotes with a backslash-double-quote, and then we can parse the object.
var ignorableTypesString = defaultValue(argv.i, '[]');
ignorableTypesString = ignorableTypesString.replace(/'/g, '\"');
ignorableTypesString = ignorableTypesString.replace(/"/g, '\"');
var ignorableTypes = JSON.parse(ignorableTypesString);

var searchPath = ['', path.dirname(filepath)];
if (defined(argv.s) || defined(argv.searchPath)) {
searchPath.push(defaultValue(argv.s, argv.searchPath));
}
const ignorableTypeNames = parsePathsArray(args.i);

let searchPaths = [""];
if (defined(args.s) || defined(args.searchPath)) {
searchPaths.push(defaultValue(args.s, args.searchPath));
}
for (let i = 0; i < inputFilePaths.length; i++) {
searchPaths.push(path.dirname(inputFilePaths[i]));
}
if (defined(args.S) || defined(args.searchPaths)) {
const additionalSearchPathsString = defaultValue(args.S, args.searchPaths);
const additionalSearchPaths = parsePathsArray(additionalSearchPathsString);
searchPaths = searchPaths.concat(additionalSearchPaths);
}

let embedOutputFile;
let inlineEmbeddedOutput = false;
if (defined(args.e) || defined(args.embedOutput)) {
embedOutputFile = defaultValue(
defaultValue(args.e, args.embedOutput),
null
);
}
if (defined(args.E) || defined(args.EmbedOutput)) {
embedOutputFile = defaultValue(
defaultValue(args.E, args.EmbedOutput),
null
);
inlineEmbeddedOutput = true;
}

var embedOutput = defaultValue(defaultValue(argv.e, argv.embedOutput), null);

var options = {
schema: schema,
filePath: filepath,
fileName: path.basename(filepath),
searchPath: searchPath,
styleMode: styleModeArgument,
writeTOC: !defaultValue(defaultValue(argv.n, argv.noTOC), false),
headerLevel: defaultValue(defaultValue(argv.l, argv.headerLevel), 1),
checkmark: defaultValue(defaultValue(argv.c, argv.checkmark), null),
mustKeyword: defaultValue(defaultValue(argv.k, argv.keyword), null),
schemaRelativeBasePath: defaultValue(defaultValue(argv.p, argv.schemaPath), null),
let outputFilePath;
if (defined(args.o) || defined(args.outputFile)) {
outputFilePath = defaultValue(defaultValue(args.o, args.outputFile), null);
} else {
console.warn("No output file specified");
printHelp();
return undefined;
}

let fragmentPrefix;
if (defined(args.f) || defined(args.fragmentPrefix)) {
fragmentPrefix = defaultValue(args.f, args.fragmentPrefix);
}

const options = {
inputFilePaths: inputFilePaths,
outputFilePath: outputFilePath,
searchPaths: searchPaths,
styleMode: styleMode,
writeTOC: !defaultValue(defaultValue(args.n, args.noTOC), false),
headerLevel: defaultValue(defaultValue(args.l, args.headerLevel), 1),
checkmark: defaultValue(defaultValue(args.c, args.checkmark), null),
mustKeyword: defaultValue(defaultValue(args.k, args.keyword), null),
embedMode: enums.embedMode.none,
debug: defaultValue(defaultValue(argv.d, argv.debug), null),
suppressWarnings: defaultValue(defaultValue(argv.w, argv.suppressWarnings), false),
autoLink: autoLink,
ignorableTypes: ignorableTypes
};

if (defined(embedOutput)) {
options.embedMode = enums.embedMode.writeIncludeStatements;
options.ignorableTypes = [];
fs.writeFileSync(embedOutput, generateMarkdown(options));
options.embedMode = enums.embedMode.referenceIncludeDocument;
options.ignorableTypes = ignorableTypes;
fragmentPrefix: fragmentPrefix,
ignorableTypeNames: ignorableTypeNames,
embedOutputFile: embedOutputFile,
inlineEmbeddedOutput: inlineEmbeddedOutput,
};
return options;
}

function run() {
const options = parseOptions(parsedArguments);
if (!defined(options)) {
return;
}

// Create the SchemaRepository and populate it with all
// input file paths
const schemaRepository = new SchemaRepository(options.searchPaths);
for (let i = 0; i < options.inputFilePaths.length; i++) {
schemaRepository.addRootSchema(options.inputFilePaths[i]);
}

// Create the markdown generator
const markdownGenerator = new MarkdownGenerator(schemaRepository, options);

// Create the JSON Schema reference markdown, if requested,
// which contains the actual JSON schema files
let embedMode = enums.embedMode.none;
if (defined(options.embedOutputFile)) {
if (options.inlineEmbeddedOutput) {
embedMode = enums.embedMode.inlineFileContents;
} else {
embedMode = enums.embedMode.writeIncludeStatements;
}
const schemaReferenceMarkdown =
markdownGenerator.generateFullJsonSchemaReferenceMarkdown(options.headerLevel, embedMode);
fs.writeFileSync(options.embedOutputFile, schemaReferenceMarkdown);
}

// Generate the main property reference, including all property
// references for the types that have been found from the input
// file paths
let propertyReferenceMarkdown = '';
if (options.writeTOC) {
propertyReferenceMarkdown += markdownGenerator.generateTableOfContentsMarkdown(options.headerLevel);
}
propertyReferenceMarkdown +=
markdownGenerator.generateFullPropertyReferenceMarkdown(options.headerLevel, embedMode);
fs.writeFileSync(options.outputFilePath, propertyReferenceMarkdown);

}

process.stdout.write(generateMarkdown(options));
run(); // wetzel, run!
Loading