inspector.ts 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. /*-----------------------------------------------------------------------------
  2. | Copyright (c) Jupyter Development Team.
  3. | Distributed under the terms of the Modified BSD License.
  4. |----------------------------------------------------------------------------*/
  5. import {
  6. DataConnector, ISchemaValidator
  7. } from '@jupyterlab/coreutils';
  8. import {
  9. InspectionHandler, InspectorPanel
  10. } from '@jupyterlab/inspector';
  11. import {
  12. RenderMimeRegistry, standardRendererFactories
  13. } from '@jupyterlab/rendermime';
  14. import {
  15. ReadonlyJSONObject
  16. } from '@phosphor/coreutils';
  17. import {
  18. RawEditor
  19. } from './raweditor';
  20. /**
  21. * Create a raw editor inspector.
  22. */
  23. export
  24. function createInspector(editor: RawEditor, rendermime?: RenderMimeRegistry): InspectorPanel {
  25. const connector = new InspectorConnector(editor);
  26. const inspector = new InspectorPanel();
  27. const handler = new InspectionHandler({
  28. connector,
  29. rendermime: rendermime || new RenderMimeRegistry({
  30. initialFactories: standardRendererFactories
  31. })
  32. });
  33. inspector.add({
  34. className: 'jp-SettingsDebug',
  35. name: 'Debug',
  36. rank: 0,
  37. type: 'hints'
  38. });
  39. inspector.source = handler;
  40. handler.editor = editor.source;
  41. return inspector;
  42. }
  43. /**
  44. * The data connector used to populate a code inspector.
  45. *
  46. * #### Notes
  47. * This data connector debounces fetch requests to throttle them at no more than
  48. * one request per 100ms. This means that using the connector to populate
  49. * multiple client objects can lead to missed fetch responses.
  50. */
  51. class InspectorConnector extends DataConnector<InspectionHandler.IReply, void, InspectionHandler.IRequest> {
  52. constructor(editor: RawEditor) {
  53. super();
  54. this._editor = editor;
  55. }
  56. /**
  57. * Fetch inspection requests.
  58. */
  59. fetch(request: InspectionHandler.IRequest): Promise<InspectionHandler.IReply> {
  60. return new Promise<InspectionHandler.IReply>(resolve => {
  61. // Debounce requests at a rate of 100ms.
  62. const current = this._current = window.setTimeout(() => {
  63. if (current !== this._current) {
  64. return resolve(null);
  65. }
  66. const errors = this._validate(request.text);
  67. if (!errors) {
  68. return resolve(null);
  69. }
  70. resolve({ data: Private.render(errors), metadata: { } });
  71. }, 100);
  72. });
  73. }
  74. private _validate(raw: string): ISchemaValidator.IError[] | null {
  75. const editor = this._editor;
  76. const data = { composite: { }, user: { } };
  77. const id = editor.settings.plugin;
  78. const schema = editor.settings.schema;
  79. const validator = editor.registry.validator;
  80. return validator.validateData({ data, id, raw, schema }, false);
  81. }
  82. private _current = 0;
  83. private _editor: RawEditor;
  84. }
  85. /**
  86. * A namespace for private module data.
  87. */
  88. namespace Private {
  89. /**
  90. * Render validation errors as an HTML string.
  91. */
  92. export
  93. function render(errors: ISchemaValidator.IError[]): ReadonlyJSONObject {
  94. return { 'text/markdown': errors.map(renderError).join('') };
  95. }
  96. /**
  97. * Render an individual validation error as a markdown string.
  98. */
  99. function renderError(error: ISchemaValidator.IError): string {
  100. switch (error.keyword) {
  101. case 'additionalProperties':
  102. return `**\`[additional property error]\`**
  103. \`${error.params.additionalProperty}\` is not a valid property`;
  104. case 'syntax':
  105. return `**\`[syntax error]\`** *${error.message}*`;
  106. case 'type':
  107. return `**\`[type error]\`**
  108. \`${error.dataPath}\` ${error.message}`;
  109. default:
  110. return `**\`[error]\`** *${error.message}*`;
  111. }
  112. }
  113. }