Milestone 0: import zappier billing, Verae middleware, and Zapier research
Compose-ready workspace: packages/zappier (rate card, portal, Stripe), packages/verae-zapier-middleware (timestamp + NATS), packages/verae-zapier (CLI app), vendor/zapier-platform, and research/zapier vendor corpus. Gate 0 structure checks pass. Product code and research are not yet wired.
This commit is contained in:
commit
b4150c8250
1364 changed files with 6814366 additions and 0 deletions
231
vendor/zapier-platform/packages/schema/lib/utils/buildDocs.js
vendored
Normal file
231
vendor/zapier-platform/packages/schema/lib/utils/buildDocs.js
vendored
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
'use strict';
|
||||
|
||||
const util = require('util');
|
||||
|
||||
const _ = require('lodash');
|
||||
const toc = require('markdown-toc');
|
||||
|
||||
const packageJson = require('../../package.json');
|
||||
const links = require('./links');
|
||||
|
||||
const NO_DESCRIPTION = '_No description given._';
|
||||
const COMBOS = ['anyOf', 'allOf', 'oneOf'];
|
||||
const { SKIP_KEY } = require('../constants');
|
||||
const hiddenRefs = [];
|
||||
|
||||
const walkSchemas = (InitSchema, callback) => {
|
||||
const recurse = (Schema, parents) => {
|
||||
parents = parents || [];
|
||||
callback(Schema, parents);
|
||||
Schema.dependencies.forEach((childSchema) => {
|
||||
const newParents = parents.concat([InitSchema]);
|
||||
recurse(childSchema, newParents);
|
||||
});
|
||||
};
|
||||
recurse(InitSchema);
|
||||
};
|
||||
|
||||
const collectSchemas = (InitSchema) => {
|
||||
const schemas = {};
|
||||
walkSchemas(InitSchema, (Schema) => {
|
||||
if (!_.get(Schema, 'schema.docAnnotation.hide')) {
|
||||
schemas[Schema.id] = Schema;
|
||||
} else {
|
||||
hiddenRefs.push(Schema.id);
|
||||
}
|
||||
});
|
||||
return schemas;
|
||||
};
|
||||
|
||||
const BREAK_LENGTH = 96;
|
||||
const prepQuote = (val) => val.replace('`', '');
|
||||
const quote = (val, triple, indent = '') =>
|
||||
// either ``` with optional indentation or `
|
||||
triple && val.length > BREAK_LENGTH
|
||||
? '```\n' +
|
||||
val
|
||||
.match(/[^\r\n]+/g)
|
||||
.map((line) => indent + line)
|
||||
.join('\n') +
|
||||
'\n' +
|
||||
indent +
|
||||
'```'
|
||||
: `\`${prepQuote(val)}\``;
|
||||
const quoteOrNa = (val, triple = false, indent = '') =>
|
||||
val ? quote(val, triple, indent) : '_n/a_';
|
||||
|
||||
const formatExample = (example) => {
|
||||
const ex = _.isPlainObject(example) ? _.omit(example, SKIP_KEY) : example;
|
||||
return `* ${quoteOrNa(
|
||||
util.inspect(ex, { depth: null, breakLength: BREAK_LENGTH }),
|
||||
true,
|
||||
' ',
|
||||
)}`.replace(/\s+\n/gm, '\n');
|
||||
};
|
||||
|
||||
// Generate a display of the type (or link to a $ref).
|
||||
const typeOrLink = (schema) => {
|
||||
if (schema.type === 'array' && schema.items) {
|
||||
return `${quoteOrNa(schema.type)}[${typeOrLink(schema.items)}]`;
|
||||
}
|
||||
if (schema.$ref) {
|
||||
if (!hiddenRefs.includes(schema.$ref)) {
|
||||
return `[${schema.$ref}](${links.anchor(schema.$ref)})`;
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (let i = 0; i < COMBOS.length; i++) {
|
||||
const key = COMBOS[i];
|
||||
if (schema[key] && schema[key].length) {
|
||||
return `${key}(${schema[key]
|
||||
.map(typeOrLink)
|
||||
.filter(Boolean)
|
||||
.join(', ')})`;
|
||||
}
|
||||
}
|
||||
if (schema.enum && schema.enum.length) {
|
||||
return `${quoteOrNa(schema.type)} in (${schema.enum
|
||||
.map(util.inspect)
|
||||
.map(quoteOrNa)
|
||||
.join(', ')})`;
|
||||
}
|
||||
return quoteOrNa(schema.type);
|
||||
};
|
||||
|
||||
// Properly quote and display examples.
|
||||
const makeExampleSection = (Schema) => {
|
||||
const examples = Schema.schema.examples || [];
|
||||
if (!examples.length) {
|
||||
return '';
|
||||
}
|
||||
return `\
|
||||
#### Examples
|
||||
|
||||
${examples.map(formatExample).join('\n')}
|
||||
`;
|
||||
};
|
||||
|
||||
// Properly quote and display anti-examples.
|
||||
const makeAntiExampleSection = (Schema) => {
|
||||
const antiExamples = Schema.schema.antiExamples || [];
|
||||
if (!antiExamples.length) {
|
||||
return '';
|
||||
}
|
||||
return `\
|
||||
#### Anti-Examples
|
||||
|
||||
${antiExamples
|
||||
.map(({ example, reason }) => {
|
||||
const formattedAntiExample = formatExample(example);
|
||||
// If block quote, newline and indent the reason.
|
||||
// Otherwise, show the reason inline w/ the anti-example and separated by a dash.
|
||||
return formattedAntiExample.endsWith('```')
|
||||
? `${formattedAntiExample}\n _${reason}_`
|
||||
: `${formattedAntiExample} - _${reason}_`;
|
||||
})
|
||||
.join('\n')}
|
||||
`;
|
||||
};
|
||||
|
||||
const processProperty = (key, property, propIsRequired) => {
|
||||
let isRequired = propIsRequired ? '**yes**' : 'no';
|
||||
if (_.get(property, 'docAnnotation.hide')) {
|
||||
return '';
|
||||
} else if (_.get(property, 'docAnnotation.required')) {
|
||||
// can also support keys besides "required"
|
||||
const annotation = property.docAnnotation.required;
|
||||
if (annotation.type === 'replace') {
|
||||
isRequired = annotation.value;
|
||||
} else if (annotation.type === 'append') {
|
||||
isRequired += annotation.value;
|
||||
} else {
|
||||
throw new Error(`unrecognized docAnnotation type: ${annotation.type}`);
|
||||
}
|
||||
}
|
||||
return `${quoteOrNa(key)} | ${isRequired} | ${typeOrLink(property)} | ${
|
||||
property.description || NO_DESCRIPTION
|
||||
}`;
|
||||
};
|
||||
|
||||
// Enumerate the properties as a table.
|
||||
const makePropertiesSection = (Schema) => {
|
||||
const properties =
|
||||
Schema.schema.properties || Schema.schema.patternProperties || {};
|
||||
if (!Object.keys(properties).length) {
|
||||
return '';
|
||||
}
|
||||
const required = Schema.schema.required || [];
|
||||
return `\
|
||||
#### Properties
|
||||
|
||||
Key | Required | Type | Description
|
||||
--- | -------- | ---- | -----------
|
||||
${Object.keys(properties)
|
||||
.map((key) => {
|
||||
const property = properties[key];
|
||||
return processProperty(key, property, required.includes(key));
|
||||
})
|
||||
.join('\n')}
|
||||
`;
|
||||
};
|
||||
|
||||
// Given a "root" schema, create some markdown.
|
||||
const makeMarkdownSection = (Schema) => {
|
||||
return `\
|
||||
## ${Schema.id}
|
||||
|
||||
${Schema.schema.description || NO_DESCRIPTION}
|
||||
|
||||
#### Details
|
||||
|
||||
* **Type** - ${typeOrLink(Schema.schema)}${
|
||||
Schema.schema.pattern
|
||||
? `
|
||||
* **Pattern** - ${quoteOrNa(Schema.schema.pattern)}`
|
||||
: ''
|
||||
}
|
||||
* [**Source Code**](${links.makeCodeLink(Schema.id)})
|
||||
|
||||
${makePropertiesSection(Schema)}
|
||||
${makeExampleSection(Schema)}
|
||||
${makeAntiExampleSection(Schema)}
|
||||
`.trim();
|
||||
};
|
||||
|
||||
// Generate the final markdown.
|
||||
const buildDocs = (InitSchema) => {
|
||||
const schemas = collectSchemas(InitSchema);
|
||||
const markdownSections = _.chain(schemas)
|
||||
.values()
|
||||
.sortBy('id')
|
||||
.map(makeMarkdownSection)
|
||||
.join('\n\n-----\n\n');
|
||||
const docs = `\
|
||||
<!-- {% raw %} -->
|
||||
# \`zapier-platform-schema\` Generated Documentation
|
||||
|
||||
This is automatically generated by the \`npm run docs\` command in \`zapier-platform-schema\` version ${quoteOrNa(
|
||||
packageJson.version,
|
||||
)}.
|
||||
|
||||
To see the docs for a different version, switch to the corresponding version tag in the GitHub repository.
|
||||
|
||||
For example, to view docs for version 17.7.0, switch to the tag 'zapier-platform-schema@17.7.0'.
|
||||
|
||||
Alternatively, modify the URL directly: https://github.com/zapier/zapier-platform/blob/zapier-platform-schema@17.7.0/packages/schema/docs/build/schema.md, replacing 17.7.0 with your desired version.
|
||||
|
||||
|
||||
-----
|
||||
|
||||
## Index
|
||||
<!-- toc -->
|
||||
|
||||
-----
|
||||
|
||||
${markdownSections}
|
||||
<!-- {% endraw %} -->
|
||||
`.trim();
|
||||
return toc.insert(docs, { maxdepth: 2, bullets: '*' });
|
||||
};
|
||||
|
||||
module.exports = buildDocs;
|
||||
Loading…
Add table
Add a link
Reference in a new issue