Skip to content
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
7 changes: 6 additions & 1 deletion src/cli.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import sdk from './sdk/index.mjs'
import docs from './docs/index.mjs'
import openrpc from './openrpc/index.mjs'
import validate from './validate/index.mjs'
import update from './update/index.mjs'

import nopt from 'nopt'
import path from 'path'
Expand Down Expand Up @@ -62,6 +63,10 @@ else if (task === 'validate') {
}
else if (task === 'openrpc') {
openrpc(parsedArgs).then(signOff)
} else {
}
else if (task === 'update') {
update(parsedArgs).then(signOff)
}
else {
console.log("Invalid build type")
}
21 changes: 13 additions & 8 deletions src/openrpc/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ const run = async ({
}) => {

let openrpc = await readJson(template)
const sharedSchemaList = schemas ? (await Promise.all(schemas.map(d => readDir(d, { recursive: true })))).flat() : []
const sharedSchemas = await readFiles(sharedSchemaList)
const sharedSchemaList = schemas ? (await Promise.all(schemas.map(d => readDir(d, { recursive: true, base: path.resolve('.') })))).flat() : []
const sharedSchemas = await readFiles(sharedSchemaList, path.resolve('.'))

try {
const packageJson = await readJson(path.join(input, '..', 'package.json'))
Expand All @@ -45,14 +45,19 @@ const run = async ({
Object.entries(sharedSchemas).forEach(([path, schema]) => {
const json = JSON.parse(schema)
const id = json.$id
sharedSchemas[id] = json
delete sharedSchemas[path]
if (id) {
sharedSchemas[id] = json
delete sharedSchemas[path]
}
else {
sharedSchemas[path] = json
}
})

const moduleList = input ? await readDir(path.join(input, 'openrpc'), { recursive: true }) : []
const modules = await readFiles(moduleList, path.join(input, 'openrpc'))
const moduleList = input ? await readDir(path.join(input, 'openrpc'), { recursive: true, base: path.resolve('.') }) : []
const modules = await readFiles(moduleList, path.resolve('..'))

const descriptionsList = input ? await readDir(path.join(input, 'descriptions'), { recursive: true }) : []
const descriptionsList = input ? await readDir(path.join(input, 'descriptions'), { recursive: true, base: path.resolve('.') }) : []
const markdown = await readFiles(descriptionsList, path.join(input, 'descriptions'))

Object.keys(modules).forEach(key => {
Expand Down Expand Up @@ -94,7 +99,7 @@ const run = async ({
json.components && Object.assign(openrpc.components.schemas, json.components.schemas)

// add externally referenced schemas that are in our shared schemas path
openrpc = addExternalSchemas(openrpc, sharedSchemas)
openrpc = addExternalSchemas(openrpc, sharedSchemas, path.dirname(key))

modules[key] = JSON.stringify(json, null, '\t')

Expand Down
11 changes: 6 additions & 5 deletions src/shared/filesystem.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,18 @@ const readJson = ref => readFile(ref)
const writeJson = (ref, json) => writeText(ref, JSON.stringify(json, null, '\t'))

const readDir = async (ref, options) => {

if (!options.base) {
options.base = path.join(ref, '..')
}

let i = 0
const isJustAFile = lstatSync(ref).isFile()
const files = isJustAFile ? [ { name:'', isDirectory: _ => false } ] : await readdir(ref, { withFileTypes: true })
const results = files.filter(file => !file.isDirectory()).map(file => path.join(ref, file.name))
const results = files.filter(file => !file.isDirectory()).map(file => path.relative(options.base, path.join(ref, file.name)))

if (!options.base) {
options.base = path.join(ref, '..')
}
if (options.recursive) {
for (var index=files.length-1; index>=0; index--) {

if (files[index].isDirectory()) {
results.push(...((await readDir(path.join(ref, files[index].name), options))))
}
Expand Down
8 changes: 5 additions & 3 deletions src/shared/json-schema.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

import deepmerge from 'deepmerge'
import crocks from 'crocks'
import path from 'path'

const { setPath, getPathOr } = crocks

const isNull = schema => {
Expand Down Expand Up @@ -103,16 +105,16 @@ const replaceUri = (existing, replacement, schema) => {
}
}

const replaceRef = (existing, replacement, schema) => {
const replaceRef = (existing, replacement, schema, dir = '') => {
if (schema) {
if (schema.hasOwnProperty('$ref') && (typeof schema['$ref'] === 'string')) {
if (schema['$ref'] === existing) {
if (path.join(dir, schema['$ref']) === existing) {
schema['$ref'] = replacement
}
}
else if (typeof schema === 'object') {
Object.keys(schema).forEach(key => {
replaceRef(existing, replacement, schema[key])
replaceRef(existing, replacement, schema[key], dir)
})
}
}
Expand Down
6 changes: 6 additions & 0 deletions src/shared/methods.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const tag = (method, name) => method.tags.find(tag => tag.name === name)
export const capabilities = method => tag(method, 'capabilities')
export const provides = method => capabilities(method)['x-provides']
export const pusher = method => capabilities(method)['x-push']
export const notifier = method => method.tags.find(t => t.name === 'notifier')
export const event = method => tag(method, 'event')
70 changes: 57 additions & 13 deletions src/shared/modules.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import predicates from 'crocks/predicates/index.js'
import { getExternalSchemaPaths, isDefinitionReferencedBySchema, isNull, localizeDependencies, isSchema, getLocalSchemaPaths, replaceRef } from './json-schema.mjs'
import { getPath as getRefDefinition } from './json-schema.mjs'
const { isObject, isArray, propEq, pathSatisfies, hasProp, propSatisfies } = predicates
import path from 'path'

// util for visually debugging crocks ADTs
const inspector = obj => {
Expand Down Expand Up @@ -630,7 +631,8 @@ const createResponseFromProvider = (provider, type, json) => {
schema: {
allOf: [
{
"$ref": "https://meta.comcast.com/firebolt/types#/definitions/ProviderResponse" // use this schema for both Errors and Results
"$ref": "#/x-schemas/Types/ProviderResponse" // use this schema for both Errors and Results
// "$ref": "https://meta.comcast.com/firebolt/types#/definitions/ProviderResponse" // use this schema for both Errors and Results
},
{
"type": "object",
Expand Down Expand Up @@ -843,7 +845,8 @@ const generateEventListenResponse = json => {
// only want or and xor here (might even remove xor)
const anyOf = event.result.schema.oneOf || event.result.schema.anyOf
const ref = {
"$ref": "https://meta.comcast.com/firebolt/types#/definitions/ListenResponse"
"$ref": "#/x-schemas/Types/ListenResponse"
// "$ref": "https://meta.comcast.com/firebolt/types#/definitions/ListenResponse"
}

if (anyOf) {
Expand Down Expand Up @@ -1051,7 +1054,7 @@ const getExternalPath = (uri = '', schemas = {}) => {

const [mainPath, subPath] = uri.split('#')
const json = schemas[mainPath] || schemas[mainPath + '/']

// copy to avoid side effects
let result

Expand All @@ -1067,7 +1070,7 @@ const getExternalPath = (uri = '', schemas = {}) => {
return result
}

const getExternalSchemas = (json = {}, schemas = {}) => {
const getExternalSchemas = (json = {}, schemas = {}, dir = '') => {
// make a copy for safety!
json = JSON.parse(JSON.stringify(json))

Expand All @@ -1077,20 +1080,58 @@ const getExternalSchemas = (json = {}, schemas = {}) => {

while (refs.length > 0) {
for (let i=0; i<refs.length; i++) {
let path = refs[i]
const ref = getPathOr(null, path, json)
path.pop() // drop ref
let refPath = refs[i]
let ref = getPathOr(null, refPath, json)
if (['.', '/'].includes(ref.charAt(0))) {
ref = path.join(dir, ref)
}
refPath.pop() // drop ref
let resolvedSchema = getExternalPath(ref, schemas)

if (!resolvedSchema) {
// rename it so the while loop ends
throw "Unresolved schema: " + ref
}

// adjust relative paths
const rels = getExternalSchemaPaths(resolvedSchema)
rels.forEach(external => {
external.pop()
const node = getPathOr(null, external, resolvedSchema)
const target = path.join(path.dirname(ref.split('#')[0]), node.$ref.split('#')[0])
// console.log(target)
const modified = path.relative(dir, target)
// console.log('old: ' + node.$ref)
// console.log('rel: ' + dir)
// console.log('tar: ' + target)
// console.log('mod: ' + modified)
const hash = node.$ref.split('#')[1]
node.$ref = modified + '#' + hash//[modified].concat(node.$ref.split('#')).slice(1).join('#')
console.log('fin: ' + node.$ref)
})

const locals = getLocalSchemaPaths(resolvedSchema)
locals.forEach(local => {
local.pop()
const node = getPathOr(null, local, resolvedSchema)
console.log('loc0: ' + ref.split('#')[0])
console.log('loc1: ' + node.$ref)
const target = path.join(path.dirname(ref.split('#')[0]), node.$ref.split('#')[0])
const modified = path.relative(dir, ref.split('#')[0])
console.log('loc2: ' + node.$ref)
console.log('loc3: ' + dir)
console.log('loc4: ' + target)
console.log('loc5: ' + modified)
const hash = node.$ref.split('#')[1]
node.$ref = modified + '#' + hash//[modified].concat(node.$ref.split('#')).slice(1).join('#')
console.log('loc!: ' + node.$ref)
})

// replace the ref so we can recursively grab more refs if needed...
else if (path.length) {
if (refPath.length) {
returnedSchemas[ref] = JSON.parse(JSON.stringify(resolvedSchema))
// use a copy, so we don't pollute the returned schemas
json = setPath(path, JSON.parse(JSON.stringify(resolvedSchema)), json)
json = setPath(refPath, JSON.parse(JSON.stringify(resolvedSchema)), json)
}
else {
delete json['$ref']
Expand All @@ -1103,17 +1144,18 @@ const getExternalSchemas = (json = {}, schemas = {}) => {
return returnedSchemas
}

const addExternalSchemas = (json, sharedSchemas) => {
const addExternalSchemas = (json, sharedSchemas, dir) => {
console.log('addExternalSchemas')
json = JSON.parse(JSON.stringify(json))

let searching = true

while (searching) {
searching = false
const externalSchemas = getExternalSchemas(json, sharedSchemas)
const externalSchemas = getExternalSchemas(json, sharedSchemas, dir)
Object.entries(externalSchemas).forEach( ([name, schema]) => {
const group = sharedSchemas[name.split('#')[0]].title
const id = sharedSchemas[name.split('#')[0]].$id
const id = sharedSchemas[name.split('#')[0]].$id || name.split('#')[0]
const refs = getLocalSchemaPaths(schema)
refs.forEach(ref => {
ref.pop() // drop the actual '$ref' so we can modify it
Expand All @@ -1127,15 +1169,17 @@ const addExternalSchemas = (json, sharedSchemas) => {
return
}
searching = true

json['x-schemas'] = json['x-schemas'] || {}
json['x-schemas'][group] = json['x-schemas'][group] || { uri: name.split("#")[0]}
json['x-schemas'][group][name.split("/").pop()] = schema
})

//update references to external schemas to be local
Object.keys(externalSchemas).forEach(ref => {
console.log('localizing: ' + ref)
const group = sharedSchemas[ref.split('#')[0]].title
replaceRef(ref, `#/x-schemas/${group}/${ref.split("#").pop().substring('/definitions/'.length)}`, json)
replaceRef(ref, `#/x-schemas/${group}/${ref.split("#").pop().substring('/definitions/'.length)}`, json, dir)
})
}

Expand Down
Loading