Skip to content

Commit

Permalink
feat(proxy): generate meta information
Browse files Browse the repository at this point in the history
  • Loading branch information
trieloff committed Dec 6, 2019
1 parent eacbf38 commit ac65ac6
Show file tree
Hide file tree
Showing 6 changed files with 234 additions and 99 deletions.
183 changes: 94 additions & 89 deletions lib/formatInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,115 +17,119 @@ const parse = require('remark-parse');
const inspect = require('unist-util-inspect');
const stringify = require('mdast-util-to-string');
const { formatname } = require('./formatname');
const s = require('./symbols');

function formatInfo({ extension }) {
function plaindescription(schema) {
try {
if (schema.path) {
const filename = path.resolve(
path.dirname(schema.path),
`${path.basename(schema.path, extension)}description.md`,
);
const longdesc = fs.readFileSync(filename);
return longdesc.toString();
}
} catch {}
return schema.schema.description || '';
}

function shorten(str) {
return str.split('\n')[0].split('.')[0];
}
function isabstract(schema) {
return schema.definitions !== undefined &&
(!schema.properties || Object.keys(schema.properties).length === 0);
}

const parser = unified()
.use(parse);
function isextensible(schema) {
return schema.definitions !== undefined || schema['meta:extensible'] === true;
}

function parsedescription(str) {
try {
const markdown = parser.parse(str);
return {
longdescription: markdown,
shortdescription: shorten(stringify(markdown)),
description: str,
};
} catch {
return {
longdescription: {},
shortdescription: '',
description: shorten(str),
};
}
function isidentifiable(schema) {
if (!schema.properties) {
return 'undefined';
}

function isabstract(schema) {
return schema.definitions !== undefined &&
(!schema.properties || Object.keys(schema.properties).length === 0);
if (schema.properties['@id'] && schema.properties['@id'].type === 'string' && schema.properties['@id'].format === 'uri') {
return 'true';
} else {
return 'false';
}
}

function isextensible(schema) {
return schema.definitions !== undefined || schema['meta:extensible'] === true;
}
function iscustom(schema) {
return [...(schema.allOf || [])]
.filter(e => typeof e === 'object')
.filter(e => typeof e.$ref === 'string')
.filter(({ $ref }) => $ref === 'https://ns.adobe.com/xdm/common/extensible.schema.json#/definitions/@context')
.length > 0;
}

function isidentifiable(schema) {
if (!schema.properties) {
return 'undefined';
function getdefined(schema) {
if (schema[s.parent]) {
return {
text: path.basename(schema[s.filename]) + "*",
link: schema[s.filename]
}
if (schema.properties['@id'] && schema.properties['@id'].type === 'string' && schema.properties['@id'].format === 'uri') {
return 'true';
} else {
return 'false';
}
if (schema[s.filename]) {
return {
text: path.basename(schema[s.filename]),
link: schema[s.filename]
}
}
return undefined;
}

function iscustom(schema) {
return [...(schema.allOf || [])]
.filter(e => typeof e === 'object')
.filter(e => typeof e.$ref === 'string')
.filter(({ $ref }) => $ref === 'https://ns.adobe.com/xdm/common/extensible.schema.json#/definitions/@context')
.length > 0;
function gettype(schema) {
if (typeof schema.type === 'string') {
return schema.type;
}

function getdefined(schema) {
if (schema.rootpath) {
return {
text: path.basename(schema.rootpath) + "*",
link: schema.rootpath
}
}
if (schema.path) {
return {
text: path.basename(schema.path),
link: schema.path
}
}
return undefined;
if (Array.isArray(schema.type)) {
return 'multiple';
}
if (isabstract(schema)) {
return gettype(schema.definitions);
}
return undefined;
}

function gettype(schema) {
if (typeof schema.type === 'string') {
return schema.type;
}
if (Array.isArray(schema.type)) {
return 'multiple';
}
if (isabstract(schema)) {
return gettype(schema.definitions);
function plaindescription(schema) {
try {
if (schema[s.filename] && !schema[s.parent]) {
const filename = path.resolve(
path.dirname(schema[s.filename]),
schema[s.filename].replace(/\..*$/, '.description.md')
);
const longdesc = fs.readFileSync(filename);
return longdesc.toString();
}
return undefined;
}
} catch {}
return schema.description || '';
}

function shorten(str) {
return str.split('\n')[0].split('.')[0];
}

function formatmeta(schema) {
const parser = unified()
.use(parse);

function parsedescription(str) {
try {
const markdown = parser.parse(str);
return {
longdescription: markdown,
shortdescription: shorten(stringify(markdown)),
description: str,
};
} catch {
return {
type: gettype(schema.schema),
abstract: isabstract(schema.schema),
extensible: isextensible(schema.schema),
status: schema.schema['meta:status'] || undefined,
identifiable: isidentifiable(schema.schema),
custom: iscustom(schema.schema),
additional: schema.schema.additionalProperties !== false,
definedin: getdefined(schema)
longdescription: {},
shortdescription: '',
description: shorten(str),
};
}
}

function formatmeta(schema) {
return {
type: gettype(schema),
abstract: isabstract(schema),
extensible: isextensible(schema),
status: schema['meta:status'] || undefined,
identifiable: isidentifiable(schema),
custom: iscustom(schema),
additional: schema.additionalProperties !== false,
definedin: getdefined(schema),
...parsedescription(plaindescription(schema))
};
}

function formatInfo({ extension }) {

return schemas => map(schemas, (schema) => {
const newobj = {
Expand All @@ -139,3 +143,4 @@ function formatInfo({ extension }) {
}

module.exports = formatInfo;
module.exports.formatmeta = formatmeta;
16 changes: 7 additions & 9 deletions lib/schemaProxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,8 @@
* governing permissions and limitations under the License.
*/
const ghslugger = require('github-slugger');

const symbols = {
pointer: Symbol('pointer'),
filename: Symbol('filename'),
id: Symbol('id'),
titles: Symbol('titles'),
resolve: Symbol('resolve'),
slug: Symbol('slug'),
};
const formatmeta = require('./formatInfo').formatmeta;
const symbols = require('./symbols');

const myslug = Symbol('myslug');

Expand All @@ -27,6 +20,7 @@ const handler = ({
}) => {
const meta = {};

meta[symbols.parent] = () => parent;
meta[symbols.pointer] = () => root;
meta[symbols.filename] = () => filename;
meta[symbols.id] = (target) => {
Expand Down Expand Up @@ -74,6 +68,10 @@ const handler = ({
return receiver[myslug];
};

meta[symbols.meta] = (target, prop, receiver) => {
return formatmeta(receiver);
}

return {
ownKeys: target => Reflect.ownKeys(target),

Expand Down
12 changes: 12 additions & 0 deletions lib/symbols.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const symbols = {
pointer: Symbol('pointer'),
filename: Symbol('filename'),
id: Symbol('id'),
titles: Symbol('titles'),
resolve: Symbol('resolve'),
slug: Symbol('slug'),
meta: Symbol('meta'),
parent: Symbol('parent'),
};

module.exports = symbols;
24 changes: 24 additions & 0 deletions lib/traverseSchema.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,4 +138,28 @@ function traverse(node) {
return allitems;
}

function sflat(arr) {
return arr.reduce((p, v) => {
if (Array.isArray(v)) {
return [...p, ...v];
}
return [...p, v];
}, []);
}

/**
* Traverses a (proxied) JSON schema. This is a less opinionated
* and tighter traversal.
* @param {*} schema
*/
function traverseSchema(schema) {
if (Array.isArray(schema)) {
return sflat(schema.map(traverseSchema));
} else if (typeof schema === 'object') {
return sflat([schema, ...Object.values(schema).map(traverseSchema)]);
}
return [];
}

module.exports = traverse;
module.exports.traverseSchema = traverseSchema;
12 changes: 11 additions & 1 deletion test/schemaProxy.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@
/* eslint-env mocha */

const assert = require('assert');
const path = require('path');
const {
loader, pointer, filename, id, titles, resolve, slug,
loader, pointer, filename, id, titles, resolve, slug, meta
} = require('../lib/schemaProxy');

const example = {
Expand Down Expand Up @@ -168,4 +169,13 @@ describe('Testing Schema Proxy', () => {
assert.equal(proxied2[slug], 'referencing'); // make sure the slug stays stable
assert.equal(proxied3[slug], 'anotherreference');
});

it('Schema proxy loads actual schemas with meta information', () => {
const myloader = loader();

const examplefile = path.resolve(__dirname, '..', 'examples', 'schemas', 'definitions.schema.json');
const example = myloader(require(examplefile), examplefile);

assert.equal(example[meta].shortdescription, 'This is an example of using a definitions object within a schema');
});
});
Loading

0 comments on commit ac65ac6

Please sign in to comment.