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

Added flag link-title to remove titles from markdown links #470

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
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
12 changes: 12 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export function jsonschema2md(schema, options) {
metadata,
schemaOut,
includeReadme,
linkTitles,
links,
i18n,
language,
Expand Down Expand Up @@ -159,6 +160,7 @@ export function jsonschema2md(schema, options) {
// build readme
readme({
readme: true,
linkTitles,
}),

writereadme({
Expand Down Expand Up @@ -195,6 +197,7 @@ export function jsonschema2md(schema, options) {
).split(nodepath.sep).join(nodepath.posix.sep);
return target;
},
linkTitles
}),

// write to files
Expand Down Expand Up @@ -260,6 +263,11 @@ export async function main(args) {
.alias('n', 'no-readme')
.describe('n', 'Do not generate a README.md file in the output directory')

.alias('t', 'link-titles')
.describe('t', 'Set this to false to disable rendering titles in markdown links')
.boolean('t')
.default('t', true)

.describe('link-*', 'Add this file as a link the explain the * attribute, e.g. --link-abstract=abstract.md')

.alias('i', 'i18n')
Expand Down Expand Up @@ -297,12 +305,15 @@ export async function main(args) {
map(([key, value]) => [key.substr(5), value]),
obj,
);
console.log("links", links);
console.log("t", argv.t);

const schemaPath = argv.d;
const outDir = argv.o;
const metadata = argv.m;
const schemaOut = argv.x !== '-' ? argv.x : null;
const includeReadme = !argv.n;
const linkTitles = argv.t;
const i18n = argv.i;
const language = argv.l;
const exampleFormat = argv.f;
Expand Down Expand Up @@ -331,6 +342,7 @@ export async function main(args) {
metadata,
schemaOut,
includeReadme,
linkTitles,
links,
i18n,
language,
Expand Down
40 changes: 24 additions & 16 deletions lib/markdownBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export default function build({
links = {},
includeProperties = [],
rewritelinks = (x) => x,
linkTitles = true,
exampleFormat = 'json',
skipProperties = [],
} = {}) {
Expand Down Expand Up @@ -246,6 +247,13 @@ export default function build({
}
return [];
}
function makelink(url, title, description) {
if (linkTitles) {
return link(url, title, description);
} else {
return link(url, '', description);
}
}

/**
* Generates the overall header for the schema documentation
Expand All @@ -266,7 +274,7 @@ export default function build({
headerprops,
({ name, title }) => {
if (links[name]) {
return tableCell(link(links[name], i18n`What does ${title} mean?`, text(title)));
return tableCell(makelink(links[name], i18n`What does ${title} mean?`, text(title)));
}
return tableCell(text(title));
},
Expand All @@ -281,7 +289,7 @@ export default function build({
&& typeof schema[s.meta][prop.name] === 'object'
&& schema[s.meta][prop.name].link
&& schema[s.meta][prop.name].text) {
return tableCell(link(rewritelinks(schema[s.meta][prop.name].link), i18n`open original schema`, [text(schema[s.meta][prop.name].text)]));
return tableCell(makelink(rewritelinks(schema[s.meta][prop.name].link), i18n`open original schema`, [text(schema[s.meta][prop.name].text)]));
}
const value = schema[s.meta] ? schema[s.meta][prop.name] : undefined;
return tableCell(text(prop[`${String(value)}label`] || i18n`Unknown`));
Expand Down Expand Up @@ -323,11 +331,11 @@ export default function build({
*/
function makepropheader(required = [], ispattern = false, slugger) {
return ([name, definition]) => tableRow([
tableCell(ispattern ? inlineCode(name) : link(`#${slugger.slug(name)}`, '', text(name))), // Property
tableCell(ispattern ? inlineCode(name) : makelink(`#${slugger.slug(name)}`, '', text(name))), // Property
tableCell(type(definition)),
tableCell(text(required.indexOf(name) > -1 ? i18n`Required` : i18n`Optional`)),
tableCell(nullable(definition)),
tableCell(link(
tableCell(makelink(
`${definition[s.slug]}.md`,
`${definition[s.id]}#${definition[s.pointer]}`,
text(definition[s.titles] && definition[s.titles][0] ? definition[s.titles][0] : i18n`Untitled schema`),
Expand Down Expand Up @@ -358,7 +366,7 @@ export default function build({
tableCell(any ? text('Any') : type(additionalProps)),
tableCell(text(i18n`Optional`)),
tableCell(any ? text('can be null') : nullable(additionalProps)),
tableCell(any ? text('') : link(`${additionalProps[s.slug]}.md`, `${additionalProps[s.id]}#${additionalProps[s.pointer]}`, text(additionalProps[s.titles][0] || i18n`Untitled schema`))),
tableCell(any ? text('') : makelink(`${additionalProps[s.slug]}.md`, `${additionalProps[s.id]}#${additionalProps[s.pointer]}`, text(additionalProps[s.titles][0] || i18n`Untitled schema`))),
])];
}
return [];
Expand Down Expand Up @@ -388,7 +396,7 @@ export default function build({
paragraph([text(i18n`Type: `), text(i18n`an array where each item follows the corresponding schema in the following list:`)]),
list(
'ordered',
[...items.map((schema) => listItem(paragraph(link(
[...items.map((schema) => listItem(paragraph(makelink(
`${schema[s.slug]}.md`,
i18n`check type definition`,
text(gentitle(schema[s.titles], schema[keyword`type`])),
Expand All @@ -398,7 +406,7 @@ export default function build({
return [listItem(paragraph(text(i18n`and all following items may follow any schema`)))];
} else if (typeof additional === 'object') {
return [listItem(paragraph([text(i18n`and all following items must follow the schema: `),
link(
makelink(
`${additional[s.slug]}.md`,
i18n`check type definition`,
text(gentitle(additional[s.titles], additional[keyword`type`])),
Expand Down Expand Up @@ -448,9 +456,9 @@ export default function build({
const typelink = (() => {
if (definition[keyword`title`] && typeof definition[keyword`title`] === 'string') {
// if the type has a title, always create a link to the schema
return [text(' ('), link(`${definition[s.slug]}.md`, '', text(definition[keyword`title`])), text(')')];
return [text(' ('), makelink(`${definition[s.slug]}.md`, '', text(definition[keyword`title`])), text(')')];
} else if (!singletype || firsttype === keyword`object` || merged) {
return [text(' ('), link(`${definition[s.slug]}.md`, '', text(i18n`Details`)), text(')')];
return [text(' ('), makelink(`${definition[s.slug]}.md`, '', text(i18n`Details`)), text(')')];
}
return [];
})();
Expand All @@ -473,7 +481,7 @@ export default function build({
function makedefinedinfact(definition) {
return listItem(paragraph([
text(i18n`defined in: `),
link(`${definition[s.slug]}.md`, `${definition[s.id]}#${definition[s.pointer]}`, text(definition[s.titles] && definition[s.titles][0] ? definition[s.titles][0] : i18n`Untitled schema`)),
makelink(`${definition[s.slug]}.md`, `${definition[s.id]}#${definition[s.pointer]}`, text(definition[s.titles] && definition[s.titles][0] ? definition[s.titles][0] : i18n`Untitled schema`)),
]));
}

Expand Down Expand Up @@ -544,7 +552,7 @@ export default function build({
];
} else if (depth > 0) {
return [
link(`${schema[s.slug]}.md`, i18n`check type definition`, text(gentitle(schema[s.titles], schema[keyword`type`]))),
makelink(`${schema[s.slug]}.md`, i18n`check type definition`, text(gentitle(schema[s.titles], schema[keyword`type`]))),
];
} else {
return [];
Expand Down Expand Up @@ -621,15 +629,15 @@ export default function build({
// console.log('pattern!', schema[s.filename], schema[s.pointer]);
constraints.push(paragraph([strong(text(i18n`pattern`)), text(': '), text(i18n`the string must match the following regular expression: `)]));
constraints.push(code('regexp', schema[keyword`pattern`]));
constraints.push(paragraph([link(`https://regexr.com/?expression=${encodeURIComponent(schema[keyword`pattern`])}`, i18n`try regular expression with regexr.com`, text(i18n`try pattern`))]));
constraints.push(paragraph([makelink(`https://regexr.com/?expression=${encodeURIComponent(schema[keyword`pattern`])}`, i18n`try regular expression with regexr.com`, text(i18n`try pattern`))]));
}
// https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.7.3
if (schema.format && typeof schema.format === 'string' && formats[schema.format]) {
constraints.push(paragraph([
strong(text(formats[keyword([schema.format])].label)),
text(': '),
text(formats[schema.format].text),
link(formats[schema.format].speclink, i18n`check the specification`, text(formats[schema.format].specname)),
makelink(formats[schema.format].speclink, i18n`check the specification`, text(formats[schema.format].specname)),
]));
} else if (schema.format && typeof schema.format === 'string') {
constraints.push(paragraph([strong(text(i18n`unknown format`)), text(': '), text(i18n`the value of this string must follow the format: `), inlineCode(String(schema.format))]));
Expand All @@ -645,7 +653,7 @@ export default function build({
constraints.push(paragraph([
strong(text(i18n`schema`)), text(': '),
text(i18n`the contents of this string should follow this schema: `),
link(`${schema[keyword`contentSchema`][s.slug]}.md`, i18n`check type definition`, text(gentitle(schema[keyword`contentSchema`][s.titles], schema[keyword`contentSchema`][keyword`type`])))]));
makelink(`${schema[keyword`contentSchema`][s.slug]}.md`, i18n`check type definition`, text(gentitle(schema[keyword`contentSchema`][s.titles], schema[keyword`contentSchema`][keyword`type`])))]));
}

// https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.6.4
Expand All @@ -664,12 +672,12 @@ export default function build({
if (schema[keyword`minContains`] !== undefined && schema[keyword`contains`]) {
// console.log('minContains!', schema[s.filename], schema[s.pointer]);
constraints.push(paragraph([strong(text(i18n`minimum number of contained items`)), text(': '), text(`${i18n`this array may not contain fewer than ${String(schema[keyword`minContains`])} items that validate against the schema:`} `),
link(`${schema[keyword`contains`][s.slug]}.md`, i18n`check type definition`, text(gentitle(schema[keyword`contains`][s.titles], schema[keyword`contains`][keyword`type`])))]));
makelink(`${schema[keyword`contains`][s.slug]}.md`, i18n`check type definition`, text(gentitle(schema[keyword`contains`][s.titles], schema[keyword`contains`][keyword`type`])))]));
}
if (schema[keyword`maxContains`] !== undefined && schema[keyword`contains`]) {
// console.log('maxContains!', schema[s.filename], schema[s.pointer]);
constraints.push(paragraph([strong(text(i18n`maximum number of contained items`)), text(': '), text(`${i18n`this array may not contain more than ${String(schema[keyword`maxContains`])} items that validate against the schema:`} `),
link(`${schema[keyword`contains`][s.slug]}.md`, i18n`check type definition`, text(gentitle(schema[keyword`contains`][s.titles], schema[keyword`contains`][keyword`type`])))]));
makelink(`${schema[keyword`contains`][s.slug]}.md`, i18n`check type definition`, text(gentitle(schema[keyword`contains`][s.titles], schema[keyword`contains`][keyword`type`])))]));
}

// https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.6.5
Expand Down
13 changes: 10 additions & 3 deletions lib/readmeBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,23 @@ function makeversionnote(schemas) {
* Generate the README.md
* @param {object} opts
*/
export default function build({ readme = true }) {
export default function build({ readme = true, linkTitles = true }) {
return (schemas) => {
function makelink(url, title, description) {
if (linkTitles) {
return link(url, title, description);
} else {
return link(url, '', description);
}
}
if (readme) {
console.log('building readme');
const toplevel = flist(pipe(
schemas,
filter((schema) => !schema[s.parent]), // remove schemas with a parent
mapSort((schema) => gentitle(schema[s.titles], schema[keyword`type`])),
map((schema) => listItem(paragraph([
link(`./${schema[s.slug]}.md`, gendescription(schema), [text(gentitle(schema[s.titles], schema[keyword`type`]))]),
makelink(`./${schema[s.slug]}.md`, gendescription(schema), [text(gentitle(schema[s.titles], schema[keyword`type`]))]),
text(' – '),
inlineCode(schema[keyword`$id`] || '-'),
]))),
Expand All @@ -65,7 +72,7 @@ export default function build({ readme = true }) {
filter((schema) => !schema.$ref), // it is not a reference
mapSort((schema) => gentitle(schema[s.titles], schema[keyword`type`])),
map((schema) => listItem(paragraph([
link(`./${schema[s.slug]}.md`, gendescription(schema), [text(gentitle(schema[s.titles], schema[keyword`type`]))]),
makelink(`./${schema[s.slug]}.md`, gendescription(schema), [text(gentitle(schema[s.titles], schema[keyword`type`]))]),
text(' – '),
inlineCode(`${schema[s.id]}#${schema[s.pointer]}`),
]))),
Expand Down
11 changes: 11 additions & 0 deletions test/fixtures/skiptitles/complete.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Complete JSON Schema",
"description": "Testing for skipped props",
"type": "object",
"properties": {
"foo": {
"type": "string"
}
}
}
17 changes: 17 additions & 0 deletions test/markdownBuilder.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,23 @@ value: Maximum
});
});

describe('Testing Markdown Builder: Skip titles', () => {
let results;

before(async () => {
const schemas = await traverseSchemas('skiptitles');
const builder = build({ header: false, linkTitles: false });
results = builder(schemas);
});

it('Format Schema has JSON examples', () => {
console.log(results.complete)
assertMarkdown(results.complete)
.contains('[Complete JSON Schema](complete-properties-foo.md)')
.doesNotContain('[Complete JSON Schema](complete-properties-foo.md "undefined#/properties/foo")');
});
});

describe('Testing Markdown Builder: enums', () => {
let results;

Expand Down
31 changes: 31 additions & 0 deletions test/readmeBuilder.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ describe('Testing Readme Builder', () => {
assertMarkdown(result)
.contains('# README')
.matches(/Top-level Schemas/)
.contains('[Test Schema](./example.md "Not much")')
.has('heading > text')
.equals('heading > text', {
type: 'text',
Expand All @@ -103,4 +104,34 @@ describe('Testing Readme Builder', () => {

### Arrays`;
});
it('Readme Builder should skip titles in links if flag is set', () => {
const builder = build({ readme: true, linkTitles: false });
const schemaloader = loader();
const schemas = [
schemaloader('example.schema.json', {
type: 'object',
title: 'Test Schema',
description: 'Not much',
properties: {
foo: {
const: 1,
},
obj: {
type: 'object',
title: 'An Object',
},
arr: {
type: 'array',
title: 'An Array',
},
},
}),
];

const result = builder(schemas);
// eslint-disable-next-line no-unused-expressions
assertMarkdown(result)
.contains('[Test Schema](./example.md)')
.doesNotContain('[Test Schema](./example.md "Not much")');
});
});