From 9cc010e8c44c4f25b7d0b107751e385f7e0ec356 Mon Sep 17 00:00:00 2001 From: Ed Mackey <elm19087@gmail.com> Date: Mon, 16 Aug 2021 14:27:23 -0400 Subject: [PATCH] Add a commandline option for the **MUST** keyword. --- README.md | 1 + bin/wetzel.js | 6 +- lib/generateMarkdown.js | 20 +- lib/style.js | 24 +- test/test-golden/example-keyword.md | 43 +++ test/test-golden/nested-keyword.md | 417 ++++++++++++++++++++++++++++ test/test-schemas/index.json | 3 +- 7 files changed, 502 insertions(+), 12 deletions(-) create mode 100644 test/test-golden/example-keyword.md create mode 100644 test/test-golden/nested-keyword.md diff --git a/README.md b/README.md index c0c2682..8ba1da6 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,7 @@ There's also a version [published on npm](https://www.npmjs.com/package/wetzel). * The `-l` option specifies the starting header level. * The `-c` option lets you specify a custom symbol to place in front of required properties. +* The `-k` option replaces the word `must` with a specified keyword, such as `**MUST**`. * 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). diff --git a/bin/wetzel.js b/bin/wetzel.js index 801b797..0f8fc30 100755 --- a/bin/wetzel.js +++ b/bin/wetzel.js @@ -12,11 +12,12 @@ 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, --noTOC Skip writing the Table of Contents.' + + ' -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' + @@ -73,6 +74,7 @@ var options = { 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), embedMode: enums.embedMode.none, debug: defaultValue(defaultValue(argv.d, argv.debug), null), diff --git a/lib/generateMarkdown.js b/lib/generateMarkdown.js index 6cc1728..9303e8c 100644 --- a/lib/generateMarkdown.js +++ b/lib/generateMarkdown.js @@ -30,6 +30,10 @@ function generateMarkdown(options) { style.setCheckmark(options.checkmark); } + if (defined(options.mustKeyword)) { + style.setMustKeyword(options.mustKeyword); + } + // Verify JSON Schema version var schemaRef = schema.$schema; var resolved = null; @@ -278,9 +282,11 @@ function createPropertiesDetails(schema, title, headerLevel, knownTypes, autoLin md += style.bulletItem(style.propertyDetails('Type') + ': ' + summary.formattedType, 0); + var eachElementInTheArrayMust = 'Each element in the array' + style.mustKeyword; + var uniqueItems = property.uniqueItems; if (defined(uniqueItems) && uniqueItems) { - md += style.bulletItem('Each element in the array must be unique.', 1); + md += style.bulletItem(eachElementInTheArrayMust + 'be unique.', 1); } // TODO: items is a full schema @@ -293,21 +299,21 @@ function createPropertiesDetails(schema, title, headerLevel, knownTypes, autoLin var maxString = itemsExclusiveMaximum ? 'less than' : 'less than or equal to'; if (defined(items.minimum) && defined(items.maximum)) { - md += style.bulletItem('Each element in the array must be ' + minString + ' ' + + md += style.bulletItem(eachElementInTheArrayMust + 'be ' + minString + ' ' + style.minMax(items.minimum) + ' and ' + maxString + ' ' + style.minMax(items.maximum) + '.', 1); } else if (defined(items.minimum)) { - md += style.bulletItem('Each element in the array must be ' + minString + ' ' + style.minMax(items.minimum) + '.', 1); + md += style.bulletItem(eachElementInTheArrayMust + 'be ' + minString + ' ' + style.minMax(items.minimum) + '.', 1); } else if (defined(items.maximum)) { - md += style.bulletItem('Each element in the array must be ' + maxString + ' ' + style.minMax(items.maximum) + '.', 1); + md += style.bulletItem(eachElementInTheArrayMust + 'be ' + maxString + ' ' + style.minMax(items.maximum) + '.', 1); } if (defined(items.minLength) && defined(items.maxLength)) { - md += style.bulletItem('Each element in the array must have length between ' + style.minMax(items.minLength) + + md += style.bulletItem(eachElementInTheArrayMust + 'have length between ' + style.minMax(items.minLength) + ' and ' + style.minMax(items.maxLength) + '.', 1); } else if (defined(items.minLength)) { - md += style.bulletItem('Each element in the array must have length greater than or equal to ' + style.minMax(items.minLength) + '.', 1); + md += style.bulletItem(eachElementInTheArrayMust + 'have length greater than or equal to ' + style.minMax(items.minLength) + '.', 1); } else if (defined(items.maxLength)) { - md += style.bulletItem('Each element in the array must have length less than or equal to ' + style.minMax(items.maxLength) + '.', 1); + md += style.bulletItem(eachElementInTheArrayMust + 'have length less than or equal to ' + style.minMax(items.maxLength) + '.', 1); } var itemsString = getEnumString(items, type, 2); diff --git a/lib/style.js b/lib/style.js index a51837b..b98eef1 100644 --- a/lib/style.js +++ b/lib/style.js @@ -10,6 +10,8 @@ module.exports = { setCheckmark: setCheckmark, + setMustKeyword: setMustKeyword, + getHeaderMarkdown: getHeaderMarkdown, getSectionMarkdown: getSectionMarkdown, @@ -123,9 +125,14 @@ module.exports = { embedJsonSchema: embedJsonSchema, /** - * @property {string} The markdown string used for displaying the icon used to indicate a value is required. + * @property {string} requiredIcon - The markdown string used for displaying the icon used to indicate a value is required. */ - requiredIcon: ' ✓ ' + requiredIcon: ' ✓ ', + + /** + * @property {string} mustKeyword - The keyword used when a condition must be true. + */ + mustKeyword: ' must ', }; const REFERENCE = "reference-"; @@ -160,6 +167,19 @@ function setCheckmark(checkmark) { } } +/** + * @function setMustKeyword + * Set the keyword used in place of the word "must". + * @param {string} mustKeyword The keyword used when a condition must be true. + */ +function setMustKeyword(mustKeyword) { + if (mustKeyword.length > 0) { + module.exports.mustKeyword = ' ' + mustKeyword + ' '; + } else { + module.exports.mustKeyword = ' must '; + } +} + /** * @function getHeaderMarkdown * Gets the markdown syntax for the start of a header. diff --git a/test/test-golden/example-keyword.md b/test/test-golden/example-keyword.md new file mode 100644 index 0000000..e9114dc --- /dev/null +++ b/test/test-golden/example-keyword.md @@ -0,0 +1,43 @@ +# Objects +* [`example`](#reference-example) (root object) + + +--------------------------------------- +<a name="reference-example"></a> +## 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.| ✓ Yes| + +Additional properties are not allowed. + +### example.byteOffset + +The offset relative to the start of the buffer in bytes. + +* **Type**: `integer` +* **Required**: No, default: `0` +* **Minimum**: ` >= 0` + +### example.type + +Specifies if the elements are scalars, vectors, or matrices. + +* **Type**: `string` +* **Required**: ✓ Yes +* **Allowed values**: + * `"SCALAR"` + * `"VEC2"` + * `"VEC3"` + * `"VEC4"` + * `"MAT2"` + * `"MAT3"` + * `"MAT4"` + + diff --git a/test/test-golden/nested-keyword.md b/test/test-golden/nested-keyword.md new file mode 100644 index 0000000..1480ac8 --- /dev/null +++ b/test/test-golden/nested-keyword.md @@ -0,0 +1,417 @@ +# Objects +* [`Buffer View`](#reference-bufferview) +* [`Extension`](#reference-extension) +* [`Extras`](#reference-extras) +* [`Image`](#reference-image) +* [`Material`](#reference-material) + * [`PBR Metallic Roughness`](#reference-material-pbrmetallicroughness) +* [`nestedTest`](#reference-nestedtest) (root object) + + +--------------------------------------- +<a name="reference-bufferview"></a> +## Buffer View + +A view into a buffer. + +**`Buffer View` Properties** + +| |Type|Description|Required| +|---|---|---|---| +|**byteOffset**|`integer`|The offset into the buffer in bytes.|No, default: `0`| +|**byteLength**|`integer`|The length of the bufferView in bytes.| ✓ Yes| +|**byteStride**|`integer`|The stride, in bytes.|No| +|**target**|`integer`|This is a test of some enums.|No| +|**name**|`string`|The user-defined name of this object.|No| +|**extensions**|`extension`|Dictionary object with extension-specific objects.|No| +|**extras**|`extras`|Application-specific data.|No| + +Additional properties are allowed. + +### bufferView.byteOffset + +The offset into the buffer in bytes. + +* **Type**: `integer` +* **Required**: No, default: `0` +* **Minimum**: ` >= 0` + +### bufferView.byteLength + +The length of the bufferView in bytes. + +* **Type**: `integer` +* **Required**: ✓ Yes +* **Minimum**: ` >= 1` + +### bufferView.byteStride + +The stride, in bytes, between vertex attributes. This is the detailed description of the property. + +* **Type**: `integer` +* **Required**: No +* **Minimum**: ` >= 4` +* **Maximum**: ` <= 252` +* **Related WebGL functions**: `vertexAttribPointer()` stride parameter + +### bufferView.target + +This is a test of some enums. + +* **Type**: `integer` +* **Required**: No +* **Allowed values**: + * `34962` ARRAY_BUFFER + * `34963` ELEMENT_ARRAY_BUFFER +* **Related WebGL functions**: `bindBuffer()` + +### bufferView.name + +The user-defined name of this object. This is the detailed description of the property. + +* **Type**: `string` +* **Required**: No + +### bufferView.extensions + +Dictionary object with extension-specific objects. + +* **Type**: `extension` +* **Required**: No +* **Type of each property**: Extension + +### bufferView.extras + +Application-specific data. + +* **Type**: `extras` +* **Required**: No + + + + +--------------------------------------- +<a name="reference-extension"></a> +## Extension + +Dictionary object with extension-specific objects. + +Additional properties are allowed. + + + + +--------------------------------------- +<a name="reference-extras"></a> +## Extras + +Application-specific data. + +**Implementation Note:** Although extras may have any type, it is common for applications to store and access custom data as key/value pairs. As best practice, extras should be an Object rather than a primitive value for best portability. + + + +--------------------------------------- +<a name="reference-image"></a> +## Image + +Image data used to create a texture. Image can be referenced by URI or `bufferView` index. `mimeType` is required in the latter case. + +**`Image` Properties** + +| |Type|Description|Required| +|---|---|---|---| +|**uri**|`string`|The uri of the image.|No| +|**mimeType**|`string`|The image's MIME type. Required if `bufferView` is defined.|No| +|**bufferView**|`integer`|The index of the bufferView that contains the image. Use this instead of the image's uri property.|No| +|**fraction**|`number`|A number that must be between zero and one.|No| +|**name**|`string`|The user-defined name of this object.|No| +|**extensions**|`extension`|Dictionary object with extension-specific objects.|No| +|**extras**|`extras`|Application-specific data.|No| + +Additional properties are allowed. + +### image.uri + +The uri of the image. This is the detailed description of the property. + +* **Type**: `string` +* **Required**: No +* **Format**: uriref + +### image.mimeType + +The image's MIME type. Required if `bufferView` is defined. + +* **Type**: `string` +* **Required**: No +* **Allowed values**: + * `"image/jpeg"` + * `"image/png"` + +### image.bufferView + +The index of the bufferView that contains the image. Use this instead of the image's uri property. + +* **Type**: `integer` +* **Required**: No +* **Minimum**: ` >= 0` + +### image.fraction + +A number that must be between zero and one. + +* **Type**: `number` +* **Required**: No +* **Minimum**: ` > 0` +* **Maximum**: ` < 1` + +### image.name + +The user-defined name of this object. This is the detailed description of the property. + +* **Type**: `string` +* **Required**: No + +### image.extensions + +Dictionary object with extension-specific objects. + +* **Type**: `extension` +* **Required**: No +* **Type of each property**: Extension + +### image.extras + +Application-specific data. + +* **Type**: `extras` +* **Required**: No + + + + +--------------------------------------- +<a name="reference-material"></a> +## Material + +The material appearance of a primitive. + +**`Material` Properties** + +| |Type|Description|Required| +|---|---|---|---| +|**name**|`string`|The user-defined name of this object.|No| +|**extensions**|`extension`|Dictionary object with extension-specific objects.|No| +|**extras**|`extras`|Application-specific data.|No| +|**pbrMetallicRoughness**|`material.pbrMetallicRoughness`|A set of parameter values that are used to define the metallic-roughness material model from Physically-Based Rendering (PBR) methodology. When not specified, all the default values of `pbrMetallicRoughness` apply.|No| +|**emissiveFactor**|`number` `[3]`|The emissive color of the material.|No, default: `[0,0,0]`| +|**alphaMode**|`string`|The alpha rendering mode of the material.|No, default: `"OPAQUE"`| +|**alphaCutoff**|`number`|The alpha cutoff value of the material.|No, default: `0.5`| +|**doubleSided**|`boolean`|Specifies whether the material is double sided.|No, default: `false`| + +Additional properties are allowed. + +### material.name + +The user-defined name of this object. This is the detailed description of the property. + +* **Type**: `string` +* **Required**: No + +### material.extensions + +Dictionary object with extension-specific objects. + +* **Type**: `extension` +* **Required**: No +* **Type of each property**: Extension + +### material.extras + +Application-specific data. + +* **Type**: `extras` +* **Required**: No + +### material.pbrMetallicRoughness + +A set of parameter values that are used to define the metallic-roughness material model from Physically-Based Rendering (PBR) methodology. When not specified, all the default values of `pbrMetallicRoughness` apply. + +* **Type**: `material.pbrMetallicRoughness` +* **Required**: No + +### material.emissiveFactor + +The RGB components of the emissive color of the material. This is the detailed description of the property. + +* **Type**: `number` `[3]` + * Each element in the array **MUST** be greater than or equal to `0` and less than or equal to `1`. +* **Required**: No, default: `[0,0,0]` + +### material.alphaMode + +The material's alpha rendering mode enumeration specifying the interpretation of the alpha value of the main factor and texture. + +* **Type**: `string` +* **Required**: No, default: `"OPAQUE"` +* **Allowed values**: + * `"OPAQUE"` The alpha value is ignored and the rendered output is fully opaque. + * `"MASK"` The rendered output is either fully opaque or fully transparent depending on the alpha value and the specified alpha cutoff value. + * `"BLEND"` The alpha value is used to composite the source and destination areas. + +### material.alphaCutoff + +Specifies the cutoff threshold when in `MASK` mode. This is the detailed description of the property. + +* **Type**: `number` +* **Required**: No, default: `0.5` +* **Minimum**: ` >= 0` + +### material.doubleSided + +Specifies whether the material is double sided. This is the detailed description of the property. + +* **Type**: `boolean` +* **Required**: No, default: `false` + + + + +--------------------------------------- +<a name="reference-material-pbrmetallicroughness"></a> +## Material PBR Metallic Roughness + +A set of parameter values that are used to define the metallic-roughness material model from Physically-Based Rendering (PBR) methodology. + +**`Material PBR Metallic Roughness` Properties** + +| |Type|Description|Required| +|---|---|---|---| +|**baseColorFactor**|`number` `[4]`|The material's base color factor.|No, default: `[1,1,1,1]`| +|**metallicFactor**|`number`|The metalness of the material.|No, default: `1`| +|**roughnessFactor**|`number`|The roughness of the material.|No, default: `1`| +|**extensions**|`extension`|Dictionary object with extension-specific objects.|No| +|**extras**|`extras`|Application-specific data.|No| + +Additional properties are allowed. + +### material.pbrMetallicRoughness.baseColorFactor + +The RGBA components of the base color of the material. This is the detailed description of the property. + +* **Type**: `number` `[4]` + * Each element in the array **MUST** be greater than or equal to `0` and less than or equal to `1`. +* **Required**: No, default: `[1,1,1,1]` + +### material.pbrMetallicRoughness.metallicFactor + +The metalness of the material. This is the detailed description of the property. + +* **Type**: `number` +* **Required**: No, default: `1` +* **Minimum**: ` >= 0` +* **Maximum**: ` <= 1` + +### material.pbrMetallicRoughness.roughnessFactor + +The roughness of the material. This is the detailed description of the property. + +* **Type**: `number` +* **Required**: No, default: `1` +* **Minimum**: ` >= 0` +* **Maximum**: ` <= 1` + +### material.pbrMetallicRoughness.extensions + +Dictionary object with extension-specific objects. + +* **Type**: `extension` +* **Required**: No +* **Type of each property**: Extension + +### material.pbrMetallicRoughness.extras + +Application-specific data. + +* **Type**: `extras` +* **Required**: No + + + + +--------------------------------------- +<a name="reference-nestedtest"></a> +## nestedTest + +The root object for a nestedTest asset. + +**`nestedTest` Properties** + +| |Type|Description|Required| +|---|---|---|---| +|**bufferViews**|`bufferView` `[1-*]`|An array of bufferViews.| ✓ Yes| +|**materials**|`material` `[1-*]`|An array of materials.|No| +|**images**|`image` `[1-*]`|An array of images.|No| +|**version**|`string`|A version string with a specific pattern.|No| +|**uri**|`string`|A string that should reference a URI.|No| +|**extensions**|`extension`|Dictionary object with extension-specific objects.|No| +|**extras**|`extras`|Application-specific data.|No| + +Additional properties are allowed. + +### nestedTest.bufferViews + +An array of bufferViews. This is the detailed description of the property. + +* **Type**: `bufferView` `[1-*]` +* **Required**: ✓ Yes + +### nestedTest.materials + +An array of materials. This is the detailed description of the property. + +* **Type**: `material` `[1-*]` +* **Required**: No + +### nestedTest.images + +An array of images. This is the detailed description of the property. + +* **Type**: `image` `[1-*]` +* **Required**: No + +### nestedTest.version + +A version string with a specific pattern. + +* **Type**: `string` +* **Required**: No +* **Pattern**: `^[0-9]+\.[0-9]+$` + +### nestedTest.uri + +A string that should reference a URI. This is the detailed description of the property. + +* **Type**: `string` +* **Required**: No +* **Format**: uriref + +### nestedTest.extensions + +Dictionary object with extension-specific objects. + +* **Type**: `extension` +* **Required**: No +* **Type of each property**: Extension + +### nestedTest.extras + +Application-specific data. + +* **Type**: `extras` +* **Required**: No + + + + diff --git a/test/test-schemas/index.json b/test/test-schemas/index.json index 0382a30..9636bd4 100644 --- a/test/test-schemas/index.json +++ b/test/test-schemas/index.json @@ -6,7 +6,8 @@ "linked.adoc": "-l2 -a=cqo -m=a -p schema --checkmark \"icon:check[]\"", "remote.md": "-n -a=cqo -p \"https://www.khronos.org/wetzel/just/testing/schema\"", "remote.adoc": "-n -a=cqo -m=a -p \"https://www.khronos.org/wetzel/just/testing/schema\"", - "embed.adoc,embedJSON.adoc": "-n -a=cqo -m=a -p schema -e {EMBED}" + "embed.adoc,embedJSON.adoc": "-n -a=cqo -m=a -p schema -e {EMBED}", + "keyword.md": "-k \"**MUST**\"" }, "schemas": [{ "name": "example",