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

Add option to embed whole JSON schemas in AsciiDoctor #51

Merged
merged 4 commits into from
Nov 24, 2020
Merged
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ There's also a version [published on npm](https://www.npmjs.com/package/wetzel).
* The `-l` option specifies the starting header level.
* The `-p` option lets you specify the relative path that should be used when referencing the schema, relative to where you store the documentation.
* The `-s` option lets you specify the path string that should be used when loading the schema reference paths.
* The `-e` option writes an additional output file that embeds the full text of JSON schemas (AsciiDoctor mode only).
* The `-m` option controls the output style mode. The default is `Markdown`, use `-m=a` for `AsciiDoctor` mode.
* The `-n` option will skip writing a Table of Contents.
* The `-w` option will suppress any warnings about potential documentation problems that wetzel normally prints by default.
Expand Down
18 changes: 16 additions & 2 deletions bin/wetzel.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ if (!defined(argv._[0]) || defined(argv.h) || defined(argv.help)) {
' -l, --headerLevel Top-level header. Default: 1\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, --noTOC Skip writing the Table of Contents.' +
' -a, --autoLink Aggressively auto-inter-link types referenced in descriptions.\n' +
Expand Down Expand Up @@ -60,7 +61,9 @@ if (defined(argv.s) || defined(argv.searchPath)) {
searchPath.push(defaultValue(argv.s, argv.searchPath));
}

process.stdout.write(generateMarkdown({
var embedOutput = defaultValue(defaultValue(argv.e, argv.embedOutput), null);

var options = {
schema: schema,
filePath: filepath,
fileName: path.basename(filepath),
Expand All @@ -69,8 +72,19 @@ process.stdout.write(generateMarkdown({
writeTOC: !defaultValue(defaultValue(argv.n, argv.noTOC), false),
headerLevel: defaultValue(defaultValue(argv.l, argv.headerLevel), 1),
schemaRelativeBasePath: defaultValue(defaultValue(argv.p, argv.schemaPath), 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;
}

process.stdout.write(generateMarkdown(options));
13 changes: 12 additions & 1 deletion lib/enums.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ var styleModeOption = {
'AsciiDoctor' : 'AsciiDoctor'
};

var embedMode = {
'none': 'none',
'writeIncludeStatements': 'writeIncludeStatements',
'referenceIncludeDocument': 'referenceIncludeDocument'
};

module.exports = {
/**
* Indicates the possible resulting values for the autoLink commandline parameter
Expand All @@ -20,5 +26,10 @@ module.exports = {
/**
* Indicates the output style mode, Markdown or AsciiDoctor.
*/
styleModeOption: styleModeOption
styleModeOption: styleModeOption,

/**
* Indicates if we're writing a JSON schema include document, or referencing one.
*/
embedMode: embedMode
};
18 changes: 14 additions & 4 deletions lib/generateMarkdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ function generateMarkdown(options) {
options.suppressWarnings,
options.schemaRelativeBasePath,
orderedTypesDescending,
options.autoLink);
options.autoLink,
options.embedMode);
}

return md;
Expand Down Expand Up @@ -142,17 +143,24 @@ function getRecursiveTOC(orderedTypes, parentTitle, depth) {
* Leave as null if you don't want the documentation to link to the schema files.
* @param {object} knownTypes The dictionary of types and their schema information.
* @param {string} autoLink Enum value indicating how the auto-linking should be handled.
* @param {string} embedMode Emum value indicating if we are embedding JSON schema include directives.
* @return {string} The markdown for the schema.
*/
function getSchemaMarkdown(schema, fileName, headerLevel, suppressWarnings, schemaRelativeBasePath, knownTypes, autoLink) {
function getSchemaMarkdown(schema, fileName, headerLevel, suppressWarnings, schemaRelativeBasePath, knownTypes, autoLink, embedMode) {
var md = '';

if (schema === undefined) {
return md;
}

// Render section header
md += style.getSectionMarkdown(schema, headerLevel, suppressWarnings);
md += style.getSectionMarkdown(schema, headerLevel, suppressWarnings, embedMode);

// Check if we're generating an abbreviated document with JSON schema include directives.
if (embedMode === enums.embedMode.writeIncludeStatements) {
md += style.embedJsonSchema(fileName, schemaRelativeBasePath);
return md;
}

// Render description
var value = autoLinkDescription(schema.description, knownTypes, autoLink);
Expand Down Expand Up @@ -192,7 +200,9 @@ function getSchemaMarkdown(schema, fileName, headerLevel, suppressWarnings, sche
}

// Schema reference
if (defined(schemaRelativeBasePath)) {
if (embedMode === enums.embedMode.referenceIncludeDocument) {
md += style.bulletItem(style.bold('JSON schema') + ': ' + style.getSchemaEmbedLink(fileName, schema)) + '\n';
} else if (defined(schemaRelativeBasePath)) {
if (!schemaRelativeBasePath.endsWith('/')) {
schemaRelativeBasePath += '/';
}
Expand Down
2 changes: 1 addition & 1 deletion lib/schema4Resolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ function mergeProperties(derived, base) {
}
}
}
} else {
} else if (name !== 'typeName' || derived.title === base.title) {
let cloned = clone(baseProperty, true);
if (!defined(derived[name])) {
derived[name] = cloned;
Expand Down
59 changes: 56 additions & 3 deletions lib/style.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,13 +116,18 @@ module.exports = {

getTOCLink: getTOCLink,

getSchemaEmbedLink: getSchemaEmbedLink,

embedJsonSchema: embedJsonSchema,

/**
* @property {string} The markdown string used for displaying the icon used to indicate a value is required.
*/
requiredIcon: ' ✅ '
};

const REFERENCE = "reference-";
const SCHEMA_REFERENCE = "schema-reference-";

/**
* @private
Expand Down Expand Up @@ -162,9 +167,10 @@ function getHeaderMarkdown(level) {
* @param {object} schema - The schema for which this section is created
* @param {int} level - The header lever that is being requested
* @param {boolean} suppressWarnings Indicates if wetzel warnings should be printed in the documentation.
* @param {string} embedMode Emum value indicating if we are embedding JSON schema include directives.
* @return {string} The markdown string that should be placed as the start of the section
*/
function getSectionMarkdown(schema, level, suppressWarnings) {
function getSectionMarkdown(schema, level, suppressWarnings, embedMode) {
var md = '';

if (isADoc()) {
Expand All @@ -179,10 +185,16 @@ function getSectionMarkdown(schema, level, suppressWarnings) {
typeName = title.toLowerCase().replace(/ /g, ".");
}

var reference = REFERENCE;
if (embedMode === enums.embedMode.writeIncludeStatements) {
reference = SCHEMA_REFERENCE;
title = 'JSON Schema for ' + title;
}

if (isADoc()) {
md += '[#' + REFERENCE + createAnchorName(typeName) + ']\n';
md += '[#' + reference + createAnchorName(typeName) + ']\n';
} else {
md += '<a name="' + REFERENCE + createAnchorName(typeName) + '"></a>\n';
md += '<a name="' + reference + createAnchorName(typeName) + '"></a>\n';
}
md += getHeaderMarkdown(level) + ' ' + title + '\n\n';

Expand Down Expand Up @@ -401,3 +413,44 @@ function getTOCLink(displayString, type) {
var typeLink = '#' + REFERENCE + createAnchorName(type);
return getLinkMarkdown(styleCode(displayString), typeLink);
}

/**
* @function getSchemaEmbedLink
* @param {string} displayString The text to display in the link.
* @param {object} schema - The schema for which this section is created
* @return {string} The markdown for a link with displayString text targeted at type.
*/
function getSchemaEmbedLink(displayString, schema) {
if ((!defined(displayString) || displayString.length === 0)) {
return displayString;
} else if (!defined(schema)) {
return displayString;
}

var typeName = schema.typeName;
if (!defined(typeName)) {
typeName = schema.title.toLowerCase().replace(/ /g, ".");
}

var typeLink = '#' + SCHEMA_REFERENCE + createAnchorName(typeName);
return getLinkMarkdown(styleCode(displayString), typeLink);
}

function embedJsonSchema(fileName, schemaRelativeBasePath) {
var md = '';
if (!defined(schemaRelativeBasePath)) {
schemaRelativeBasePath = '';
} else if (!schemaRelativeBasePath.endsWith('/')) {
schemaRelativeBasePath += '/';
}

if (isADoc()) {
md += '[source,json]\n';
md += '----\n';
md += 'include::' + schemaRelativeBasePath + fileName + '[]\n';
md += '----\n';
} else {
md += getLinkMarkdown(fileName, schemaRelativeBasePath + fileName) + '\n';
}
return md;
}
52 changes: 52 additions & 0 deletions test/test-golden/example-embed.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@


'''
[#reference-example]
== example

Example description.

.`example` Properties
|===
| |Type|Description|Required

|**byteOffset**
|`integer`
|The offset relative to the start of the buffer in bytes.
|No, default: `0`

|**type**
|`string`
|Specifies if the elements are scalars, vectors, or matrices.
| &#x2705; Yes

|===

Additional properties are not allowed.

* **JSON schema**: <<schema-reference-example,`example.schema.json`>>

=== example.byteOffset

The offset relative to the start of the buffer in bytes.

* **Type**: `integer`
* **Required**: No, default: `0`
* **Minimum**: `&gt;= 0`

=== example.type &#x2705;

Specifies if the elements are scalars, vectors, or matrices.

* **Type**: `string`
* **Required**: Yes
* **Allowed values**:
** `"SCALAR"`
** `"VEC2"`
** `"VEC3"`
** `"VEC4"`
** `"MAT2"`
** `"MAT3"`
** `"MAT4"`


10 changes: 10 additions & 0 deletions test/test-golden/example-embedJSON.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@


'''
[#schema-reference-example]
== JSON Schema for example

[source,json]
----
include::schema/example.schema.json[]
----
Loading