123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 |
- /*-----------------------------------------------------------------------------
- | Copyright (c) Jupyter Development Team.
- | Distributed under the terms of the Modified BSD License.
- |----------------------------------------------------------------------------*/
- import { DataConnector, ISchemaValidator } from '@jupyterlab/coreutils';
- import { InspectionHandler, InspectorPanel } from '@jupyterlab/inspector';
- import {
- IRenderMimeRegistry,
- RenderMimeRegistry,
- standardRendererFactories
- } from '@jupyterlab/rendermime';
- import { ReadonlyJSONObject } from '@phosphor/coreutils';
- import { RawEditor } from './raweditor';
- /**
- * Create a raw editor inspector.
- */
- export function createInspector(
- editor: RawEditor,
- rendermime?: IRenderMimeRegistry
- ): InspectorPanel {
- const connector = new InspectorConnector(editor);
- const inspector = new InspectorPanel({
- initialContent: 'Any errors will be listed here'
- });
- const handler = new InspectionHandler({
- connector,
- rendermime:
- rendermime ||
- new RenderMimeRegistry({
- initialFactories: standardRendererFactories
- })
- });
- inspector.addClass('jp-SettingsDebug');
- inspector.source = handler;
- handler.editor = editor.source;
- return inspector;
- }
- /**
- * The data connector used to populate a code inspector.
- *
- * #### Notes
- * This data connector debounces fetch requests to throttle them at no more than
- * one request per 100ms. This means that using the connector to populate
- * multiple client objects can lead to missed fetch responses.
- */
- class InspectorConnector extends DataConnector<
- InspectionHandler.IReply,
- void,
- InspectionHandler.IRequest
- > {
- constructor(editor: RawEditor) {
- super();
- this._editor = editor;
- }
- /**
- * Fetch inspection requests.
- */
- fetch(
- request: InspectionHandler.IRequest
- ): Promise<InspectionHandler.IReply> {
- return new Promise<InspectionHandler.IReply>(resolve => {
- // Debounce requests at a rate of 100ms.
- const current = (this._current = window.setTimeout(() => {
- if (current !== this._current) {
- return resolve(null);
- }
- const errors = this._validate(request.text);
- if (!errors) {
- return resolve({
- data: { 'text/markdown': 'No errors found' },
- metadata: {}
- });
- }
- resolve({ data: Private.render(errors), metadata: {} });
- }, 100));
- });
- }
- private _validate(raw: string): ISchemaValidator.IError[] | null {
- const editor = this._editor;
- if (!editor.settings) {
- return null;
- }
- const { id, schema, version } = editor.settings;
- const data = { composite: {}, user: {} };
- const validator = editor.registry.validator;
- return validator.validateData({ data, id, raw, schema, version }, false);
- }
- private _current = 0;
- private _editor: RawEditor;
- }
- /**
- * A namespace for private module data.
- */
- namespace Private {
- /**
- * Render validation errors as an HTML string.
- */
- export function render(
- errors: ISchemaValidator.IError[]
- ): ReadonlyJSONObject {
- return { 'text/markdown': errors.map(renderError).join('') };
- }
- /**
- * Render an individual validation error as a markdown string.
- */
- function renderError(error: ISchemaValidator.IError): string {
- switch (error.keyword) {
- case 'additionalProperties':
- return `**\`[additional property error]\`**
- \`${error.params.additionalProperty}\` is not a valid property`;
- case 'syntax':
- return `**\`[syntax error]\`** *${error.message}*`;
- case 'type':
- return `**\`[type error]\`**
- \`${error.dataPath}\` ${error.message}`;
- default:
- return `**\`[error]\`** *${error.message}*`;
- }
- }
- }
|