Merge pull request #97 from remcohaszing/schemastore-example

Let demo users select a schema from schema store
This commit is contained in:
Remco Haszing 2021-08-29 12:53:08 +02:00 committed by GitHub
commit b4ffefc00f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 159 additions and 71 deletions

View file

@ -8,6 +8,7 @@
},
"dependencies": {
"@fortawesome/fontawesome-free": "^5.15.4",
"@schemastore/schema-catalog": "^0.0.5",
"css-loader": "^6.2.0",
"css-minimizer-webpack-plugin": "^3.0.2",
"html-webpack-plugin": "^5.3.2",

View file

@ -59,6 +59,14 @@ nav {
margin: 1.5rem;
}
#schema-selection {
background-color: var(--editor-background);
border: none;
border-bottom: 1px solid var(--shadow-color);
color: var(--foreground-color);
width: 100%;
}
#breadcrumbs {
border-bottom: 1px solid var(--shadow-color);
color: var(--foreground-color);

View file

@ -24,6 +24,11 @@
</div>
</nav>
<div class="editor-wrapper">
<div>
<select id="schema-selection">
<option value="monaco-yaml.yaml">Monaco YAML example</option>
</select>
</div>
<div id="breadcrumbs"></div>
<div id="editor"></div>
<div id="problems"></div>

View file

@ -1,5 +1,6 @@
import './index.css';
import { JSONSchemaForSchemaStoreOrgCatalogFiles } from '@schemastore/schema-catalog';
import { CancellationToken } from 'monaco-editor/esm/vs/base/common/cancellation';
import { getDocumentSymbols } from 'monaco-editor/esm/vs/editor/contrib/documentSymbols/documentSymbols';
import {
@ -8,13 +9,16 @@ import {
languages,
Position,
Range,
Uri,
} from 'monaco-editor/esm/vs/editor/editor.api';
import { setDiagnosticsOptions } from 'monaco-yaml';
import { SchemasSettings, setDiagnosticsOptions } from 'monaco-yaml';
// NOTE: This will give you all editor featues. If you would prefer to limit to only the editor
// features you want to use, import them each individually. See this example: (https://github.com/microsoft/monaco-editor-samples/blob/main/browser-esm-webpack-small/index.js#L1-L91)
import 'monaco-editor';
import defaultSchemaUri from './schema.json';
declare global {
interface Window {
MonacoEnvironment: Environment;
@ -34,63 +38,18 @@ window.MonacoEnvironment = {
},
};
const defaultSchema: SchemasSettings = {
uri: defaultSchemaUri,
fileMatch: ['monaco-yaml.yaml'],
};
setDiagnosticsOptions({
validate: true,
enableSchemaRequest: true,
format: true,
hover: true,
completion: true,
schemas: [
{
// Id of the first schema
uri: 'https://example.com/example-schema.json',
// Associate with our model
fileMatch: ['*'],
schema: {
// Id of the first schema
id: 'https://example.com/example-schema.json',
type: 'object',
properties: {
property: {
description: 'I have a description',
},
titledProperty: {
title: 'I have a title',
description: 'I also have a description',
},
markdown: {
markdownDescription: 'Even **markdown** _descriptions_ `are` ~~not~~ supported!',
},
enum: {
description: 'Pick your starter',
enum: ['Bulbasaur', 'Squirtle', 'Charmander', 'Pikachu'],
},
number: {
description: 'Numbers work!',
minimum: 42,
maximum: 1337,
},
boolean: {
description: 'Are boolean supported?',
type: 'boolean',
},
string: {
type: 'string',
},
reference: {
description: 'JSON schemas can be referenced, even recursively',
$ref: 'https://example.com/example-schema.json',
},
array: {
description: 'It also works in arrays',
items: {
$ref: 'https://example.com/example-schema.json',
},
},
},
},
},
],
schemas: [defaultSchema],
});
const value = `
@ -152,11 +111,50 @@ formatting: Formatting is supported too! Under the hood this is powered by
const ed = editor.create(document.getElementById('editor'), {
automaticLayout: true,
value,
language: 'yaml',
model: editor.createModel(value, 'yaml', Uri.parse('monaco-yaml.yaml')),
theme: window.matchMedia('(prefers-color-scheme: dark)').matches ? 'vs-dark' : 'vs-light',
});
const select = document.getElementById('schema-selection') as HTMLSelectElement;
fetch('https://www.schemastore.org/api/json/catalog.json').then(async (response) => {
if (!response.ok) {
return;
}
const catalog: JSONSchemaForSchemaStoreOrgCatalogFiles = await response.json();
const schemas = [defaultSchema];
catalog.schemas.sort((a, b) => a.name.localeCompare(b.name));
for (const { fileMatch, name, url } of catalog.schemas) {
const match =
typeof name === 'string' && fileMatch?.find((filename) => /\.ya?ml$/i.test(filename));
if (!match) {
continue;
}
const option = document.createElement('option');
option.value = match;
option.textContent = name;
select.append(option);
schemas.push({
fileMatch: [match],
uri: url,
});
}
setDiagnosticsOptions({
validate: true,
enableSchemaRequest: true,
format: true,
hover: true,
completion: true,
schemas,
});
});
select.addEventListener('change', () => {
ed.setModel(editor.createModel(ed.getValue(), 'yaml', Uri.parse(select.value)));
});
function* iterateSymbols(
symbols: languages.DocumentSymbol[],
position: Position,

View file

@ -0,0 +1,41 @@
{
"type": "object",
"properties": {
"property": {
"description": "I have a description"
},
"titledProperty": {
"title": "I have a title",
"description": "I also have a description"
},
"markdown": {
"markdownDescription": "Even **markdown** _descriptions_ `are` ~~not~~ supported!"
},
"enum": {
"description": "Pick your starter",
"enum": ["Bulbasaur", "Squirtle", "Charmander", "Pikachu"]
},
"number": {
"description": "Numbers work!",
"minimum": 42,
"maximum": 1337
},
"boolean": {
"description": "Are boolean supported?",
"type": "boolean"
},
"string": {
"type": "string"
},
"reference": {
"description": "JSON schemas can be referenced, even recursively",
"$ref": "#"
},
"array": {
"description": "It also works in arrays",
"items": {
"$ref": "#"
}
}
}
}

4
examples/demo/src/types.d.ts vendored Normal file
View file

@ -0,0 +1,4 @@
declare module '*.json' {
declare const uri;
export default uri;
}

View file

@ -22,7 +22,11 @@ module.exports = {
{
// Monaco editor uses .ttf icons.
test: /\.(svg|ttf)$/,
type: 'asset',
type: 'asset/resource',
},
{
test: /schema\.json$/,
type: 'asset/resource',
},
{
test: /\.ts$/,

39
index.d.ts vendored
View file

@ -1,6 +1,29 @@
import { JSONSchema4, JSONSchema6, JSONSchema7 } from 'json-schema';
import { IEvent, languages } from 'monaco-editor/esm/vs/editor/editor.api';
export interface SchemasSettings {
/**
* A `Uri` file match which will trigger the schema validation. This may be a glob or an exact
* path.
*
* @example '.gitlab-ci.yml'
* @example 'file://**\/.github/actions/*.yaml'
*/
fileMatch: string[];
/**
* The JSON schema which will be used for validation. If not specified, it will be downloaded from
* `uri`.
*/
schema?: JSONSchema4 | JSONSchema6 | JSONSchema7;
/**
* The source URI of the JSON schema. The JSON schema will be downloaded from here if no schema
* was supplied. It will also be displayed as the source in hover tooltips.
*/
uri: string;
}
declare module 'monaco-editor/esm/vs/editor/editor.api' {
namespace languages.yaml {
export interface DiagnosticsOptions {
@ -23,21 +46,7 @@ declare module 'monaco-editor/esm/vs/editor/editor.api' {
/**
* A list of known schemas and/or associations of schemas to file names.
*/
readonly schemas?: {
/**
* The URI of the schema, which is also the identifier of the schema.
*/
readonly uri: string;
/**
* A list of file names that are associated to the schema. The '*' wildcard can be used.
* For example '*.schema.json', 'package.json'
*/
readonly fileMatch?: string[];
/**
* The schema for the given URI.
*/
readonly schema?: JSONSchema4 | JSONSchema6 | JSONSchema7;
}[];
readonly schemas?: SchemasSettings[];
/**
* If set, the schema service would load schema content on-demand with 'fetch' if available

20
package-lock.json generated
View file

@ -42,6 +42,7 @@
"version": "1.0.0",
"dependencies": {
"@fortawesome/fontawesome-free": "^5.15.4",
"@schemastore/schema-catalog": "^0.0.5",
"css-loader": "^6.2.0",
"css-minimizer-webpack-plugin": "^3.0.2",
"html-webpack-plugin": "^5.3.2",
@ -690,6 +691,11 @@
"node": ">= 8"
}
},
"node_modules/@schemastore/schema-catalog": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/@schemastore/schema-catalog/-/schema-catalog-0.0.5.tgz",
"integrity": "sha512-5+Xo5tNdgdQ6Q2otY3XSs1WZR8J1cYHAmGDDHbCk0C3Qx/ycD6r2Fpzz0X9UFjm/hsbZDBd9fh/xLqdIKzREew=="
},
"node_modules/@trysound/sax": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.1.1.tgz",
@ -11590,6 +11596,11 @@
"fastq": "^1.6.0"
}
},
"@schemastore/schema-catalog": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/@schemastore/schema-catalog/-/schema-catalog-0.0.5.tgz",
"integrity": "sha512-5+Xo5tNdgdQ6Q2otY3XSs1WZR8J1cYHAmGDDHbCk0C3Qx/ycD6r2Fpzz0X9UFjm/hsbZDBd9fh/xLqdIKzREew=="
},
"@trysound/sax": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.1.1.tgz",
@ -13368,6 +13379,7 @@
"version": "file:examples/demo",
"requires": {
"@fortawesome/fontawesome-free": "^5.15.4",
"@schemastore/schema-catalog": "*",
"css-loader": "^6.2.0",
"css-minimizer-webpack-plugin": "^3.0.2",
"html-webpack-plugin": "^5.3.2",
@ -16139,7 +16151,7 @@
"monaco-editor": "^0.27.0",
"path-browserify": "^1.0.1",
"prettier": "2.0.5",
"type-fest": "*",
"type-fest": "^2.1.0",
"typescript": "^4.3.5",
"vscode-languageserver-textdocument": "^1.0.1",
"vscode-languageserver-types": "^3.16.0",
@ -16649,6 +16661,11 @@
"fastq": "^1.6.0"
}
},
"@schemastore/schema-catalog": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/@schemastore/schema-catalog/-/schema-catalog-0.0.5.tgz",
"integrity": "sha512-5+Xo5tNdgdQ6Q2otY3XSs1WZR8J1cYHAmGDDHbCk0C3Qx/ycD6r2Fpzz0X9UFjm/hsbZDBd9fh/xLqdIKzREew=="
},
"@trysound/sax": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.1.1.tgz",
@ -18427,6 +18444,7 @@
"version": "file:examples/demo",
"requires": {
"@fortawesome/fontawesome-free": "^5.15.4",
"@schemastore/schema-catalog": "*",
"css-loader": "^6.2.0",
"css-minimizer-webpack-plugin": "^3.0.2",
"html-webpack-plugin": "^5.3.2",