Skip to content

Commit

Permalink
feat: add ability to resolve remote or relative schema $refs (#8293)
Browse files Browse the repository at this point in the history
* bundle schemas when initializing project

* update input type options

* remove extraneous config

* filter out equalExpression before making options
  • Loading branch information
a-b-r-o-w-n committed Jul 8, 2021
1 parent 06897d0 commit 86f05c3
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 37 deletions.
1 change: 1 addition & 0 deletions Composer/packages/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
"ts-node": "^8.4.1"
},
"dependencies": {
"@apidevtools/json-schema-ref-parser": "^9.0.9",
"@azure/cognitiveservices-qnamaker": "^3.2.0",
"@bfc/client": "*",
"@bfc/extension": "*",
Expand Down
24 changes: 24 additions & 0 deletions Composer/packages/server/src/models/bot/botProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { DefaultSettingManager } from '../settings/defaultSettingManager';
import log from '../../logger';
import { BotProjectService } from '../../services/project';
import AssetService from '../../services/asset';
import { bundleSchema } from '../utilities/bundleSchema';

import {
BotStructureFilesPatterns,
Expand Down Expand Up @@ -202,6 +203,8 @@ export class BotProject implements IBotProject {
this.settings = await this.getEnvSettings(false);
this.files = await this._getFiles();
this.readme = await this._getReadme();

await this._bundleSchemas();
};

public getProject = () => {
Expand Down Expand Up @@ -1099,4 +1102,25 @@ export class BotProject implements IBotProject {
}
}
};

private _bundleSchemas = async () => {
const schemas: FileInfo[] = [];
this.files.forEach((file) => {
if (file.name.endsWith('.schema')) {
schemas.push(file);
}
});

debug('Bundling %d schemas.', schemas.length);

await Promise.all(
schemas.map(async (s) => {
const bundled = await bundleSchema(s.path);

if (bundled) {
s.content = bundled;
}
})
);
};
}
19 changes: 19 additions & 0 deletions Composer/packages/server/src/models/utilities/bundleSchema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import $RefParser from '@apidevtools/json-schema-ref-parser';

import logger from '../../logger';

const log = logger.extend('schema');

export async function bundleSchema(schemaPath: string) {
try {
const parser = new $RefParser();
const bundled = await parser.bundle(schemaPath);
return JSON.stringify(bundled);
} catch (err) {
log('Error while bundling schema at %s', schemaPath);
log('%O', err);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ import { valueTypeDefinitions } from '../schema';

export const ValueRefField: React.FC<FieldProps> = ({ description, id, label, value, required, onChange }) => {
const options = useMemo<IDropdownOption[]>(() => {
return Object.entries(valueTypeDefinitions || {}).map(([key, value]) => ({
key: `#/definitions/${key}`,
text: value?.title || startCase(key),
}));
return Object.entries(valueTypeDefinitions || {})
.filter(([key]) => key !== 'equalsExpression') // a value must be a type, not just an expression
.map(([key, value]) => ({
key: `#/definitions/${key}`,
text: value?.title || startCase(key),
}));
}, []);

const handleChange = (_: React.FormEvent<HTMLDivElement>, option?: IDropdownOption) => {
Expand Down
39 changes: 7 additions & 32 deletions Composer/packages/ui-plugins/schema-editor/src/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,6 @@ export const schema = (): JSONSchema7 => ({
});

export const valueTypeDefinitions: { [key: string]: JSONSchema7 } = {
expression: {
$role: 'expression',
type: 'string',
title: formatMessage('Expression'),
description: formatMessage('Expression to evaluate.'),
pattern: '^.*\\S.*',
examples: ['user.age > 13'],
},
equalsExpression: {
$role: 'expression',
type: 'string',
Expand All @@ -68,26 +60,9 @@ export const valueTypeDefinitions: { [key: string]: JSONSchema7 } = {
pattern: '^=.*\\S.*',
examples: ['=user.name'],
},
condition: {
$role: 'expression',
title: formatMessage('Boolean condition'),
description: formatMessage('Boolean constant or expression to evaluate.'),
oneOf: [
{
$ref: '#/definitions/expression',
},
{
type: 'boolean',
title: formatMessage('Boolean'),
description: formatMessage('Boolean value.'),
default: true,
examples: [false],
},
],
},
booleanExpression: {
$role: 'expression',
title: formatMessage('Boolean or expression'),
title: formatMessage('Boolean'),
description: formatMessage('Boolean constant or expression to evaluate.'),
oneOf: [
{
Expand All @@ -105,7 +80,7 @@ export const valueTypeDefinitions: { [key: string]: JSONSchema7 } = {
},
numberExpression: {
$role: 'expression',
title: formatMessage('Number or expression'),
title: formatMessage('Number'),
description: formatMessage('Number constant or expression to evaluate.'),
oneOf: [
{
Expand All @@ -123,7 +98,7 @@ export const valueTypeDefinitions: { [key: string]: JSONSchema7 } = {
},
integerExpression: {
$role: 'expression',
title: formatMessage('Integer or expression'),
title: formatMessage('Integer'),
description: formatMessage('Integer constant or expression to evaluate.'),
oneOf: [
{
Expand All @@ -141,7 +116,7 @@ export const valueTypeDefinitions: { [key: string]: JSONSchema7 } = {
},
stringExpression: {
$role: 'expression',
title: formatMessage('String or expression'),
title: formatMessage('String'),
description: formatMessage('Interpolated string or expression to evaluate.'),
oneOf: [
{
Expand All @@ -159,7 +134,7 @@ export const valueTypeDefinitions: { [key: string]: JSONSchema7 } = {
},
arrayExpression: {
$role: 'expression',
title: formatMessage('Array or expression'),
title: formatMessage('Array'),
description: formatMessage('Array or expression to evaluate.'),
oneOf: [
{
Expand All @@ -174,7 +149,7 @@ export const valueTypeDefinitions: { [key: string]: JSONSchema7 } = {
},
objectExpression: {
$role: 'expression',
title: formatMessage('Object or expression'),
title: formatMessage('Object'),
description: formatMessage('Object or expression to evaluate.'),
oneOf: [
{
Expand All @@ -189,7 +164,7 @@ export const valueTypeDefinitions: { [key: string]: JSONSchema7 } = {
},
valueExpression: {
$role: 'expression',
title: formatMessage('Any or expression'),
title: formatMessage('Any'),
description: formatMessage('Any constant or expression to evaluate.'),
oneOf: [
{
Expand Down
19 changes: 18 additions & 1 deletion Composer/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,16 @@
call-me-maybe "^1.0.1"
js-yaml "^3.13.1"

"@apidevtools/json-schema-ref-parser@^9.0.9":
version "9.0.9"
resolved "https://registry.yarnpkg.com/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-9.0.9.tgz#d720f9256e3609621280584f2b47ae165359268b"
integrity sha512-GBD2Le9w2+lVFoc4vswGI/TjkNIZSVp7+9xPf+X3uidBfWnAeUWmquteSyt0+VCrhNMWj/FTABISQrD3Z/YA+w==
dependencies:
"@jsdevtools/ono" "^7.1.3"
"@types/json-schema" "^7.0.6"
call-me-maybe "^1.0.1"
js-yaml "^4.1.0"

"@apidevtools/openapi-schemas@^2.0.4":
version "2.1.0"
resolved "https://botbuilder.myget.org/F/botframework-cli/npm/@apidevtools/openapi-schemas/-/@apidevtools/openapi-schemas-2.1.0.tgz#9fa08017fb59d80538812f03fc7cac5992caaa17"
Expand Down Expand Up @@ -5214,7 +5224,7 @@
jest-diff "^26.0.0"
pretty-format "^26.0.0"

"@types/json-schema@*":
"@types/json-schema@*", "@types/json-schema@^7.0.6":
version "7.0.7"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad"
integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==
Expand Down Expand Up @@ -15455,6 +15465,13 @@ js-yaml@^3.13.1:
argparse "^1.0.7"
esprima "^4.0.0"

js-yaml@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602"
integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==
dependencies:
argparse "^2.0.1"

jsbn@~0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
Expand Down

0 comments on commit 86f05c3

Please sign in to comment.