ckeditorerror.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /**
  2. * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
  3. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
  4. */
  5. /**
  6. * @module utils/ckeditorerror
  7. */
  8. /* globals console */
  9. /**
  10. * URL to the documentation with error codes.
  11. */
  12. export const DOCUMENTATION_URL =
  13. 'https://ckeditor.com/docs/ckeditor5/latest/framework/guides/support/error-codes.html';
  14. /**
  15. * The CKEditor error class.
  16. *
  17. * You should throw `CKEditorError` when:
  18. *
  19. * * An unexpected situation occurred and the editor (most probably) will not work properly. Such exception will be handled
  20. * by the {@link module:watchdog/watchdog~Watchdog watchdog} (if it is integrated),
  21. * * If the editor is incorrectly integrated or the editor API is used in the wrong way. This way you will give
  22. * feedback to the developer as soon as possible. Keep in mind that for common integration issues which should not
  23. * stop editor initialization (like missing upload adapter, wrong name of a toolbar component) we use
  24. * {@link module:utils/ckeditorerror~logWarning `logWarning()`} and
  25. * {@link module:utils/ckeditorerror~logError `logError()`}
  26. * to improve developers experience and let them see the a working editor as soon as possible.
  27. *
  28. * /**
  29. * * Error thrown when a plugin cannot be loaded due to JavaScript errors, lack of plugins with a given name, etc.
  30. * *
  31. * * @error plugin-load
  32. * * @param pluginName The name of the plugin that could not be loaded.
  33. * * @param moduleName The name of the module which tried to load this plugin.
  34. * * /
  35. * throw new CKEditorError( 'plugin-load', {
  36. * pluginName: 'foo',
  37. * moduleName: 'bar'
  38. * } );
  39. *
  40. * @extends Error
  41. */
  42. export default class CKEditorError extends Error {
  43. /**
  44. * Creates an instance of the CKEditorError class.
  45. *
  46. * @param {String} errorName The error id in an `error-name` format. A link to this error documentation page will be added
  47. * to the thrown error's `message`.
  48. * @param {Object|null} context A context of the error by which the {@link module:watchdog/watchdog~Watchdog watchdog}
  49. * is able to determine which editor crashed. It should be an editor instance or a property connected to it. It can be also
  50. * a `null` value if the editor should not be restarted in case of the error (e.g. during the editor initialization).
  51. * The error context should be checked using the `areConnectedThroughProperties( editor, context )` utility
  52. * to check if the object works as the context.
  53. * @param {Object} [data] Additional data describing the error. A stringified version of this object
  54. * will be appended to the error message, so the data are quickly visible in the console. The original
  55. * data object will also be later available under the {@link #data} property.
  56. */
  57. constructor( errorName, context, data ) {
  58. const message = `${ errorName }${ ( data ? ` ${ JSON.stringify( data ) }` : '' ) }${ getLinkToDocumentationMessage( errorName ) }`;
  59. super( message );
  60. /**
  61. * @type {String}
  62. */
  63. this.name = 'CKEditorError';
  64. /**
  65. * A context of the error by which the Watchdog is able to determine which editor crashed.
  66. *
  67. * @type {Object|null}
  68. */
  69. this.context = context;
  70. /**
  71. * The additional error data passed to the constructor. Undefined if none was passed.
  72. *
  73. * @type {Object|undefined}
  74. */
  75. this.data = data;
  76. }
  77. /**
  78. * Checks if the error is of the `CKEditorError` type.
  79. */
  80. is( type ) {
  81. return type === 'CKEditorError';
  82. }
  83. /**
  84. * A utility that ensures that the thrown error is a {@link module:utils/ckeditorerror~CKEditorError} one.
  85. * It is useful when combined with the {@link module:watchdog/watchdog~Watchdog} feature, which can restart the editor in case
  86. * of a {@link module:utils/ckeditorerror~CKEditorError} error.
  87. *
  88. * @static
  89. * @param {Error} err The error to rethrow.
  90. * @param {Object} context An object connected through properties with the editor instance. This context will be used
  91. * by the watchdog to verify which editor should be restarted.
  92. */
  93. static rethrowUnexpectedError( err, context ) {
  94. if ( err.is && err.is( 'CKEditorError' ) ) {
  95. throw err;
  96. }
  97. /**
  98. * An unexpected error occurred inside the CKEditor 5 codebase. This error will look like the original one
  99. * to make the debugging easier.
  100. *
  101. * This error is only useful when the editor is initialized using the {@link module:watchdog/watchdog~Watchdog} feature.
  102. * In case of such error (or any {@link module:utils/ckeditorerror~CKEditorError} error) the watchdog should restart the editor.
  103. *
  104. * @error unexpected-error
  105. */
  106. const error = new CKEditorError( err.message, context );
  107. // Restore the original stack trace to make the error look like the original one.
  108. // See https://github.com/ckeditor/ckeditor5/issues/5595 for more details.
  109. error.stack = err.stack;
  110. throw error;
  111. }
  112. }
  113. /**
  114. * Logs a warning to the console with a properly formatted message and adds a link to the documentation.
  115. * Use whenever you want to log a warning to the console.
  116. *
  117. * /**
  118. * * There was a problem processing the configuration of the toolbar. The item with the given
  119. * * name does not exist, so it was omitted when rendering the toolbar.
  120. * *
  121. * * @error toolbarview-item-unavailable
  122. * * @param {String} name The name of the component.
  123. * * /
  124. * logWarning( 'toolbarview-item-unavailable', { name } );
  125. *
  126. * See also {@link module:utils/ckeditorerror~CKEditorError} for an explanation when to throw an error and when to log
  127. * a warning or an error to the console.
  128. *
  129. * @param {String} errorName Error name to be logged.
  130. * @param {Object} [data] Additional data to be logged.
  131. * @returns {String}
  132. */
  133. export function logWarning( errorName, data ) {
  134. console.warn( ...formatConsoleArguments( errorName, data ) );
  135. }
  136. /**
  137. * Logs an error to the console with properly formatted message and adds a link to the documentation.
  138. * Use whenever you want to log a error to the console.
  139. *
  140. * /**
  141. * * There was a problem processing the configuration of the toolbar. The item with the given
  142. * * name does not exist, so it was omitted when rendering the toolbar.
  143. * *
  144. * * @error toolbarview-item-unavailable
  145. * * @param {String} name The name of the component.
  146. * * /
  147. * logError( 'toolbarview-item-unavailable', { name } );
  148. *
  149. * **Note**: In most cases logging a warning using {@link module:utils/ckeditorerror~logWarning} is enough.
  150. *
  151. * See also {@link module:utils/ckeditorerror~CKEditorError} for an explanation when to use each method.
  152. *
  153. * @param {String} errorName Error name to be logged.
  154. * @param {Object} [data] Additional data to be logged.
  155. * @returns {String}
  156. */
  157. export function logError( errorName, data ) {
  158. console.error( ...formatConsoleArguments( errorName, data ) );
  159. }
  160. function getLinkToDocumentationMessage( errorName ) {
  161. return `\nRead more: ${ DOCUMENTATION_URL }#error-${ errorName }`;
  162. }
  163. function formatConsoleArguments( errorName, data ) {
  164. const documentationMessage = getLinkToDocumentationMessage( errorName );
  165. return data ? [ errorName, data, documentationMessage ] : [ errorName, documentationMessage ];
  166. }