forked from jupyterlab/jupyterlab
-
Notifications
You must be signed in to change notification settings - Fork 0
/
inspector.ts
135 lines (117 loc) · 3.56 KB
/
inspector.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/*-----------------------------------------------------------------------------
| 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 {
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?: RenderMimeRegistry
): InspectorPanel {
const connector = new InspectorConnector(editor);
const inspector = new InspectorPanel();
const handler = new InspectionHandler({
connector,
rendermime:
rendermime ||
new RenderMimeRegistry({
initialFactories: standardRendererFactories
})
});
inspector.add({
className: 'jp-SettingsDebug',
name: 'Debug',
rank: 0,
type: 'hints'
});
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(null);
}
resolve({ data: Private.render(errors), metadata: {} });
}, 100));
});
}
private _validate(raw: string): ISchemaValidator.IError[] | null {
const editor = this._editor;
const data = { composite: {}, user: {} };
const id = editor.settings.plugin;
const schema = editor.settings.schema;
const validator = editor.registry.validator;
return validator.validateData({ data, id, raw, schema }, 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}*`;
}
}
}