From b9c10ee3461af4612749fb7b668cbd2ac3191f20 Mon Sep 17 00:00:00 2001 From: Alexander Brandon Coles Date: Thu, 5 Mar 2026 13:24:44 -0300 Subject: [PATCH 01/11] Rename source files from .js to .ts --- src/commonmark/{commonmark.js => commonmark.ts} | 0 .../{commonmarkdataprocessor.js => commonmarkdataprocessor.ts} | 0 src/commonmark/utils/{fix-breaks.js => fix-breaks.ts} | 0 .../{fix-tasklist-whitespaces.js => fix-tasklist-whitespaces.ts} | 0 ...oist-task-list-checkboxes.js => hoist-task-list-checkboxes.ts} | 0 src/commonmark/utils/{page-breaks.js => page-breaks.ts} | 0 src/commonmark/utils/{preprocessor.js => preprocessor.ts} | 0 src/helpers/{button-disabler.js => button-disabler.ts} | 0 ...reate-toolbar-edit-button.js => create-toolbar-edit-button.ts} | 0 src/helpers/{create-toolbar.js => create-toolbar.ts} | 0 src/mentions/{emoji-mentions.js => emoji-mentions.ts} | 0 src/mentions/{mentions-caster.js => mentions-caster.ts} | 0 .../{mentions-item-renderer.js => mentions-item-renderer.ts} | 0 src/mentions/{user-mentions.js => user-mentions.ts} | 0 .../{work-package-mentions.js => work-package-mentions.ts} | 0 src/{op-ckeditor-config.js => op-ckeditor-config.ts} | 0 src/{op-ckeditor.js => op-ckeditor.ts} | 0 src/{op-config-customizer.js => op-config-customizer.ts} | 0 src/{op-plugins.js => op-plugins.ts} | 0 src/plugins/code-block/{click-observer.js => click-observer.ts} | 0 .../code-block/{code-block-editing.js => code-block-editing.ts} | 0 .../code-block/{code-block-toolbar.js => code-block-toolbar.ts} | 0 src/plugins/code-block/{code-block.js => code-block.ts} | 0 src/plugins/code-block/{converters.js => converters.ts} | 0 src/plugins/code-block/{widget.js => widget.ts} | 0 ...chment-listener-plugin.js => op-attachment-listener-plugin.ts} | 0 src/plugins/op-content-revisions/{command.js => command.ts} | 0 .../{op-content-revisions.js => op-content-revisions.ts} | 0 src/plugins/op-content-revisions/{storage.js => storage.ts} | 0 src/plugins/op-content-revisions/{ui.js => ui.ts} | 0 src/plugins/op-content-revisions/{utils.js => utils.ts} | 0 src/plugins/op-context/{op-context.js => op-context.ts} | 0 ...stom-css-classes-plugin.js => op-custom-css-classes-plugin.ts} | 0 .../{op-help-link-plugin.js => op-help-link-plugin.ts} | 0 ...ment-lookup-plugin.js => op-image-attachment-lookup-plugin.ts} | 0 ...cro-child-pages-editing.js => op-macro-child-pages-editing.ts} | 0 ...macro-child-pages-plugin.js => op-macro-child-pages-plugin.ts} | 0 ...cro-child-pages-toolbar.js => op-macro-child-pages-toolbar.ts} | 0 src/plugins/op-macro-child-pages/{utils.js => utils.ts} | 0 .../{embedded-table-editing.js => embedded-table-editing.ts} | 0 .../{embedded-table-plugin.js => embedded-table-plugin.ts} | 0 .../{embedded-table-toolbar.js => embedded-table-toolbar.ts} | 0 src/plugins/op-macro-embedded-table/{utils.js => utils.ts} | 0 src/plugins/{op-macro-list-plugin.js => op-macro-list-plugin.ts} | 0 src/plugins/{op-macro-toc-plugin.js => op-macro-toc-plugin.ts} | 0 ...p-macro-wp-button-editing.js => op-macro-wp-button-editing.ts} | 0 ...{op-macro-wp-button-plugin.js => op-macro-wp-button-plugin.ts} | 0 ...p-macro-wp-button-toolbar.js => op-macro-wp-button-toolbar.ts} | 0 src/plugins/op-macro-wp-button/{utils.js => utils.ts} | 0 src/plugins/{op-preview.plugin.js => op-preview.plugin.ts} | 0 .../{op-source-code.plugin.js => op-source-code.plugin.ts} | 0 src/plugins/{op-upload-plugin.js => op-upload-plugin.ts} | 0 ...p-upload-resource-adapter.js => op-upload-resource-adapter.ts} | 0 53 files changed, 0 insertions(+), 0 deletions(-) rename src/commonmark/{commonmark.js => commonmark.ts} (100%) rename src/commonmark/{commonmarkdataprocessor.js => commonmarkdataprocessor.ts} (100%) rename src/commonmark/utils/{fix-breaks.js => fix-breaks.ts} (100%) rename src/commonmark/utils/{fix-tasklist-whitespaces.js => fix-tasklist-whitespaces.ts} (100%) rename src/commonmark/utils/{hoist-task-list-checkboxes.js => hoist-task-list-checkboxes.ts} (100%) rename src/commonmark/utils/{page-breaks.js => page-breaks.ts} (100%) rename src/commonmark/utils/{preprocessor.js => preprocessor.ts} (100%) rename src/helpers/{button-disabler.js => button-disabler.ts} (100%) rename src/helpers/{create-toolbar-edit-button.js => create-toolbar-edit-button.ts} (100%) rename src/helpers/{create-toolbar.js => create-toolbar.ts} (100%) rename src/mentions/{emoji-mentions.js => emoji-mentions.ts} (100%) rename src/mentions/{mentions-caster.js => mentions-caster.ts} (100%) rename src/mentions/{mentions-item-renderer.js => mentions-item-renderer.ts} (100%) rename src/mentions/{user-mentions.js => user-mentions.ts} (100%) rename src/mentions/{work-package-mentions.js => work-package-mentions.ts} (100%) rename src/{op-ckeditor-config.js => op-ckeditor-config.ts} (100%) rename src/{op-ckeditor.js => op-ckeditor.ts} (100%) rename src/{op-config-customizer.js => op-config-customizer.ts} (100%) rename src/{op-plugins.js => op-plugins.ts} (100%) rename src/plugins/code-block/{click-observer.js => click-observer.ts} (100%) rename src/plugins/code-block/{code-block-editing.js => code-block-editing.ts} (100%) rename src/plugins/code-block/{code-block-toolbar.js => code-block-toolbar.ts} (100%) rename src/plugins/code-block/{code-block.js => code-block.ts} (100%) rename src/plugins/code-block/{converters.js => converters.ts} (100%) rename src/plugins/code-block/{widget.js => widget.ts} (100%) rename src/plugins/{op-attachment-listener-plugin.js => op-attachment-listener-plugin.ts} (100%) rename src/plugins/op-content-revisions/{command.js => command.ts} (100%) rename src/plugins/op-content-revisions/{op-content-revisions.js => op-content-revisions.ts} (100%) rename src/plugins/op-content-revisions/{storage.js => storage.ts} (100%) rename src/plugins/op-content-revisions/{ui.js => ui.ts} (100%) rename src/plugins/op-content-revisions/{utils.js => utils.ts} (100%) rename src/plugins/op-context/{op-context.js => op-context.ts} (100%) rename src/plugins/{op-custom-css-classes-plugin.js => op-custom-css-classes-plugin.ts} (100%) rename src/plugins/op-help-link-plugin/{op-help-link-plugin.js => op-help-link-plugin.ts} (100%) rename src/plugins/op-image-attachment-lookup/{op-image-attachment-lookup-plugin.js => op-image-attachment-lookup-plugin.ts} (100%) rename src/plugins/op-macro-child-pages/{op-macro-child-pages-editing.js => op-macro-child-pages-editing.ts} (100%) rename src/plugins/op-macro-child-pages/{op-macro-child-pages-plugin.js => op-macro-child-pages-plugin.ts} (100%) rename src/plugins/op-macro-child-pages/{op-macro-child-pages-toolbar.js => op-macro-child-pages-toolbar.ts} (100%) rename src/plugins/op-macro-child-pages/{utils.js => utils.ts} (100%) rename src/plugins/op-macro-embedded-table/{embedded-table-editing.js => embedded-table-editing.ts} (100%) rename src/plugins/op-macro-embedded-table/{embedded-table-plugin.js => embedded-table-plugin.ts} (100%) rename src/plugins/op-macro-embedded-table/{embedded-table-toolbar.js => embedded-table-toolbar.ts} (100%) rename src/plugins/op-macro-embedded-table/{utils.js => utils.ts} (100%) rename src/plugins/{op-macro-list-plugin.js => op-macro-list-plugin.ts} (100%) rename src/plugins/{op-macro-toc-plugin.js => op-macro-toc-plugin.ts} (100%) rename src/plugins/op-macro-wp-button/{op-macro-wp-button-editing.js => op-macro-wp-button-editing.ts} (100%) rename src/plugins/op-macro-wp-button/{op-macro-wp-button-plugin.js => op-macro-wp-button-plugin.ts} (100%) rename src/plugins/op-macro-wp-button/{op-macro-wp-button-toolbar.js => op-macro-wp-button-toolbar.ts} (100%) rename src/plugins/op-macro-wp-button/{utils.js => utils.ts} (100%) rename src/plugins/{op-preview.plugin.js => op-preview.plugin.ts} (100%) rename src/plugins/{op-source-code.plugin.js => op-source-code.plugin.ts} (100%) rename src/plugins/{op-upload-plugin.js => op-upload-plugin.ts} (100%) rename src/plugins/{op-upload-resource-adapter.js => op-upload-resource-adapter.ts} (100%) diff --git a/src/commonmark/commonmark.js b/src/commonmark/commonmark.ts similarity index 100% rename from src/commonmark/commonmark.js rename to src/commonmark/commonmark.ts diff --git a/src/commonmark/commonmarkdataprocessor.js b/src/commonmark/commonmarkdataprocessor.ts similarity index 100% rename from src/commonmark/commonmarkdataprocessor.js rename to src/commonmark/commonmarkdataprocessor.ts diff --git a/src/commonmark/utils/fix-breaks.js b/src/commonmark/utils/fix-breaks.ts similarity index 100% rename from src/commonmark/utils/fix-breaks.js rename to src/commonmark/utils/fix-breaks.ts diff --git a/src/commonmark/utils/fix-tasklist-whitespaces.js b/src/commonmark/utils/fix-tasklist-whitespaces.ts similarity index 100% rename from src/commonmark/utils/fix-tasklist-whitespaces.js rename to src/commonmark/utils/fix-tasklist-whitespaces.ts diff --git a/src/commonmark/utils/hoist-task-list-checkboxes.js b/src/commonmark/utils/hoist-task-list-checkboxes.ts similarity index 100% rename from src/commonmark/utils/hoist-task-list-checkboxes.js rename to src/commonmark/utils/hoist-task-list-checkboxes.ts diff --git a/src/commonmark/utils/page-breaks.js b/src/commonmark/utils/page-breaks.ts similarity index 100% rename from src/commonmark/utils/page-breaks.js rename to src/commonmark/utils/page-breaks.ts diff --git a/src/commonmark/utils/preprocessor.js b/src/commonmark/utils/preprocessor.ts similarity index 100% rename from src/commonmark/utils/preprocessor.js rename to src/commonmark/utils/preprocessor.ts diff --git a/src/helpers/button-disabler.js b/src/helpers/button-disabler.ts similarity index 100% rename from src/helpers/button-disabler.js rename to src/helpers/button-disabler.ts diff --git a/src/helpers/create-toolbar-edit-button.js b/src/helpers/create-toolbar-edit-button.ts similarity index 100% rename from src/helpers/create-toolbar-edit-button.js rename to src/helpers/create-toolbar-edit-button.ts diff --git a/src/helpers/create-toolbar.js b/src/helpers/create-toolbar.ts similarity index 100% rename from src/helpers/create-toolbar.js rename to src/helpers/create-toolbar.ts diff --git a/src/mentions/emoji-mentions.js b/src/mentions/emoji-mentions.ts similarity index 100% rename from src/mentions/emoji-mentions.js rename to src/mentions/emoji-mentions.ts diff --git a/src/mentions/mentions-caster.js b/src/mentions/mentions-caster.ts similarity index 100% rename from src/mentions/mentions-caster.js rename to src/mentions/mentions-caster.ts diff --git a/src/mentions/mentions-item-renderer.js b/src/mentions/mentions-item-renderer.ts similarity index 100% rename from src/mentions/mentions-item-renderer.js rename to src/mentions/mentions-item-renderer.ts diff --git a/src/mentions/user-mentions.js b/src/mentions/user-mentions.ts similarity index 100% rename from src/mentions/user-mentions.js rename to src/mentions/user-mentions.ts diff --git a/src/mentions/work-package-mentions.js b/src/mentions/work-package-mentions.ts similarity index 100% rename from src/mentions/work-package-mentions.js rename to src/mentions/work-package-mentions.ts diff --git a/src/op-ckeditor-config.js b/src/op-ckeditor-config.ts similarity index 100% rename from src/op-ckeditor-config.js rename to src/op-ckeditor-config.ts diff --git a/src/op-ckeditor.js b/src/op-ckeditor.ts similarity index 100% rename from src/op-ckeditor.js rename to src/op-ckeditor.ts diff --git a/src/op-config-customizer.js b/src/op-config-customizer.ts similarity index 100% rename from src/op-config-customizer.js rename to src/op-config-customizer.ts diff --git a/src/op-plugins.js b/src/op-plugins.ts similarity index 100% rename from src/op-plugins.js rename to src/op-plugins.ts diff --git a/src/plugins/code-block/click-observer.js b/src/plugins/code-block/click-observer.ts similarity index 100% rename from src/plugins/code-block/click-observer.js rename to src/plugins/code-block/click-observer.ts diff --git a/src/plugins/code-block/code-block-editing.js b/src/plugins/code-block/code-block-editing.ts similarity index 100% rename from src/plugins/code-block/code-block-editing.js rename to src/plugins/code-block/code-block-editing.ts diff --git a/src/plugins/code-block/code-block-toolbar.js b/src/plugins/code-block/code-block-toolbar.ts similarity index 100% rename from src/plugins/code-block/code-block-toolbar.js rename to src/plugins/code-block/code-block-toolbar.ts diff --git a/src/plugins/code-block/code-block.js b/src/plugins/code-block/code-block.ts similarity index 100% rename from src/plugins/code-block/code-block.js rename to src/plugins/code-block/code-block.ts diff --git a/src/plugins/code-block/converters.js b/src/plugins/code-block/converters.ts similarity index 100% rename from src/plugins/code-block/converters.js rename to src/plugins/code-block/converters.ts diff --git a/src/plugins/code-block/widget.js b/src/plugins/code-block/widget.ts similarity index 100% rename from src/plugins/code-block/widget.js rename to src/plugins/code-block/widget.ts diff --git a/src/plugins/op-attachment-listener-plugin.js b/src/plugins/op-attachment-listener-plugin.ts similarity index 100% rename from src/plugins/op-attachment-listener-plugin.js rename to src/plugins/op-attachment-listener-plugin.ts diff --git a/src/plugins/op-content-revisions/command.js b/src/plugins/op-content-revisions/command.ts similarity index 100% rename from src/plugins/op-content-revisions/command.js rename to src/plugins/op-content-revisions/command.ts diff --git a/src/plugins/op-content-revisions/op-content-revisions.js b/src/plugins/op-content-revisions/op-content-revisions.ts similarity index 100% rename from src/plugins/op-content-revisions/op-content-revisions.js rename to src/plugins/op-content-revisions/op-content-revisions.ts diff --git a/src/plugins/op-content-revisions/storage.js b/src/plugins/op-content-revisions/storage.ts similarity index 100% rename from src/plugins/op-content-revisions/storage.js rename to src/plugins/op-content-revisions/storage.ts diff --git a/src/plugins/op-content-revisions/ui.js b/src/plugins/op-content-revisions/ui.ts similarity index 100% rename from src/plugins/op-content-revisions/ui.js rename to src/plugins/op-content-revisions/ui.ts diff --git a/src/plugins/op-content-revisions/utils.js b/src/plugins/op-content-revisions/utils.ts similarity index 100% rename from src/plugins/op-content-revisions/utils.js rename to src/plugins/op-content-revisions/utils.ts diff --git a/src/plugins/op-context/op-context.js b/src/plugins/op-context/op-context.ts similarity index 100% rename from src/plugins/op-context/op-context.js rename to src/plugins/op-context/op-context.ts diff --git a/src/plugins/op-custom-css-classes-plugin.js b/src/plugins/op-custom-css-classes-plugin.ts similarity index 100% rename from src/plugins/op-custom-css-classes-plugin.js rename to src/plugins/op-custom-css-classes-plugin.ts diff --git a/src/plugins/op-help-link-plugin/op-help-link-plugin.js b/src/plugins/op-help-link-plugin/op-help-link-plugin.ts similarity index 100% rename from src/plugins/op-help-link-plugin/op-help-link-plugin.js rename to src/plugins/op-help-link-plugin/op-help-link-plugin.ts diff --git a/src/plugins/op-image-attachment-lookup/op-image-attachment-lookup-plugin.js b/src/plugins/op-image-attachment-lookup/op-image-attachment-lookup-plugin.ts similarity index 100% rename from src/plugins/op-image-attachment-lookup/op-image-attachment-lookup-plugin.js rename to src/plugins/op-image-attachment-lookup/op-image-attachment-lookup-plugin.ts diff --git a/src/plugins/op-macro-child-pages/op-macro-child-pages-editing.js b/src/plugins/op-macro-child-pages/op-macro-child-pages-editing.ts similarity index 100% rename from src/plugins/op-macro-child-pages/op-macro-child-pages-editing.js rename to src/plugins/op-macro-child-pages/op-macro-child-pages-editing.ts diff --git a/src/plugins/op-macro-child-pages/op-macro-child-pages-plugin.js b/src/plugins/op-macro-child-pages/op-macro-child-pages-plugin.ts similarity index 100% rename from src/plugins/op-macro-child-pages/op-macro-child-pages-plugin.js rename to src/plugins/op-macro-child-pages/op-macro-child-pages-plugin.ts diff --git a/src/plugins/op-macro-child-pages/op-macro-child-pages-toolbar.js b/src/plugins/op-macro-child-pages/op-macro-child-pages-toolbar.ts similarity index 100% rename from src/plugins/op-macro-child-pages/op-macro-child-pages-toolbar.js rename to src/plugins/op-macro-child-pages/op-macro-child-pages-toolbar.ts diff --git a/src/plugins/op-macro-child-pages/utils.js b/src/plugins/op-macro-child-pages/utils.ts similarity index 100% rename from src/plugins/op-macro-child-pages/utils.js rename to src/plugins/op-macro-child-pages/utils.ts diff --git a/src/plugins/op-macro-embedded-table/embedded-table-editing.js b/src/plugins/op-macro-embedded-table/embedded-table-editing.ts similarity index 100% rename from src/plugins/op-macro-embedded-table/embedded-table-editing.js rename to src/plugins/op-macro-embedded-table/embedded-table-editing.ts diff --git a/src/plugins/op-macro-embedded-table/embedded-table-plugin.js b/src/plugins/op-macro-embedded-table/embedded-table-plugin.ts similarity index 100% rename from src/plugins/op-macro-embedded-table/embedded-table-plugin.js rename to src/plugins/op-macro-embedded-table/embedded-table-plugin.ts diff --git a/src/plugins/op-macro-embedded-table/embedded-table-toolbar.js b/src/plugins/op-macro-embedded-table/embedded-table-toolbar.ts similarity index 100% rename from src/plugins/op-macro-embedded-table/embedded-table-toolbar.js rename to src/plugins/op-macro-embedded-table/embedded-table-toolbar.ts diff --git a/src/plugins/op-macro-embedded-table/utils.js b/src/plugins/op-macro-embedded-table/utils.ts similarity index 100% rename from src/plugins/op-macro-embedded-table/utils.js rename to src/plugins/op-macro-embedded-table/utils.ts diff --git a/src/plugins/op-macro-list-plugin.js b/src/plugins/op-macro-list-plugin.ts similarity index 100% rename from src/plugins/op-macro-list-plugin.js rename to src/plugins/op-macro-list-plugin.ts diff --git a/src/plugins/op-macro-toc-plugin.js b/src/plugins/op-macro-toc-plugin.ts similarity index 100% rename from src/plugins/op-macro-toc-plugin.js rename to src/plugins/op-macro-toc-plugin.ts diff --git a/src/plugins/op-macro-wp-button/op-macro-wp-button-editing.js b/src/plugins/op-macro-wp-button/op-macro-wp-button-editing.ts similarity index 100% rename from src/plugins/op-macro-wp-button/op-macro-wp-button-editing.js rename to src/plugins/op-macro-wp-button/op-macro-wp-button-editing.ts diff --git a/src/plugins/op-macro-wp-button/op-macro-wp-button-plugin.js b/src/plugins/op-macro-wp-button/op-macro-wp-button-plugin.ts similarity index 100% rename from src/plugins/op-macro-wp-button/op-macro-wp-button-plugin.js rename to src/plugins/op-macro-wp-button/op-macro-wp-button-plugin.ts diff --git a/src/plugins/op-macro-wp-button/op-macro-wp-button-toolbar.js b/src/plugins/op-macro-wp-button/op-macro-wp-button-toolbar.ts similarity index 100% rename from src/plugins/op-macro-wp-button/op-macro-wp-button-toolbar.js rename to src/plugins/op-macro-wp-button/op-macro-wp-button-toolbar.ts diff --git a/src/plugins/op-macro-wp-button/utils.js b/src/plugins/op-macro-wp-button/utils.ts similarity index 100% rename from src/plugins/op-macro-wp-button/utils.js rename to src/plugins/op-macro-wp-button/utils.ts diff --git a/src/plugins/op-preview.plugin.js b/src/plugins/op-preview.plugin.ts similarity index 100% rename from src/plugins/op-preview.plugin.js rename to src/plugins/op-preview.plugin.ts diff --git a/src/plugins/op-source-code.plugin.js b/src/plugins/op-source-code.plugin.ts similarity index 100% rename from src/plugins/op-source-code.plugin.js rename to src/plugins/op-source-code.plugin.ts diff --git a/src/plugins/op-upload-plugin.js b/src/plugins/op-upload-plugin.ts similarity index 100% rename from src/plugins/op-upload-plugin.js rename to src/plugins/op-upload-plugin.ts diff --git a/src/plugins/op-upload-resource-adapter.js b/src/plugins/op-upload-resource-adapter.ts similarity index 100% rename from src/plugins/op-upload-resource-adapter.js rename to src/plugins/op-upload-resource-adapter.ts From 5363be9d776a6d65f98e6f7682c47ea697bc0baa Mon Sep 17 00:00:00 2001 From: Alexander Brandon Coles Date: Thu, 5 Mar 2026 13:24:59 -0300 Subject: [PATCH 02/11] Configure TypeScript build and tooling --- babel.config.js | 1 + eslint.config.mjs | 2 +- jest.config.js | 7 ++++- package.json | 10 +++++-- src/types.d.ts | 18 +++++++++++++ tests/mentions/emoji-mentions.test.js | 2 +- tsconfig.json | 38 ++++++++++++++++++++------- webpack.config.js | 18 ++++++++++++- 8 files changed, 81 insertions(+), 15 deletions(-) create mode 100644 src/types.d.ts diff --git a/babel.config.js b/babel.config.js index 93efe0a..ab11bea 100644 --- a/babel.config.js +++ b/babel.config.js @@ -8,6 +8,7 @@ module.exports = { }, }, ], + "@babel/preset-typescript", ], plugins: ["@babel/plugin-transform-modules-commonjs"] } diff --git a/eslint.config.mjs b/eslint.config.mjs index 8ad454c..32d2a2c 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -8,7 +8,7 @@ export default [ ignores: ["tmp/", "coverage/", "node_modules/"], }, { - files: ["src/**/*.js"], + files: ["src/**/*.ts"], languageOptions: { globals: { ...globals.browser, diff --git a/jest.config.js b/jest.config.js index fe02d92..a4316c6 100644 --- a/jest.config.js +++ b/jest.config.js @@ -17,7 +17,7 @@ module.exports = { ], // A map from regular expressions to paths to transformers transform: { - '^.+\\.js$': 'babel-jest', + '^.+\\.[jt]s$': 'babel-jest', }, // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module moduleNameMapper: { @@ -25,6 +25,11 @@ module.exports = { }, // The test environment that will be used for testing testEnvironment: "jsdom", + moduleFileExtensions: [ + "ts", + "js", + "json" + ], // The paths to modules that run some code to configure or set up the testing environment before each test setupFiles: ['/jest.setup.js'], // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation diff --git a/package.json b/package.json index f876a7e..2a84482 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,7 @@ "rich-text editor" ], "main": "./build/ckeditor.js", + "types": "./build/types/op-ckeditor.d.ts", "files": [ "build" ], @@ -17,6 +18,7 @@ "@babel/core": "^7.26.10", "@babel/plugin-transform-modules-commonjs": "^7.26.3", "@babel/preset-env": "^7.26.9", + "@babel/preset-typescript": "^7.27.1", "@ckeditor/ckeditor5-adapter-ckfinder": "44.3.0", "@ckeditor/ckeditor5-autoformat": "44.3.0", "@ckeditor/ckeditor5-autosave": "^44.3.0", @@ -67,6 +69,8 @@ "raw-loader": "^4.0.2", "style-loader": "^4.0.0", "terser-webpack-plugin": "^5.3.14", + "ts-loader": "^9.5.2", + "typescript": "^5.8.2", "turndown": "^7.2.0", "turndown-plugin-gfm": "^1.0.2", "underscore": "^1.13.7", @@ -89,8 +93,10 @@ }, "scripts": { "prebuild": "sh bin/clean.sh", - "build": "NODE_ENV=production ./node_modules/.bin/webpack --mode production", - "preversion": "npm run build; if [ -n \"$(git status src/ckeditor.js build/ --porcelain)\" ]; then git add -u src/ckeditor.js build/ && git commit -m 'Internal: Build.'; fi", + "build": "NODE_ENV=production ./node_modules/.bin/webpack --mode production && npm run build:types", + "build:types": "tsc -p tsconfig.json", + "typecheck": "tsc -p tsconfig.json --noEmit", + "preversion": "npm run build; if [ -n \"$(git status src/op-ckeditor.ts build/ --porcelain)\" ]; then git add -u src/op-ckeditor.ts build/ && git commit -m 'Internal: Build.'; fi", "prewatch": "sh bin/clean.sh", "postinstall": "patch-package", "watch": "NODE_ENV=development ./node_modules/.bin/webpack --watch --stats-error-details", diff --git a/src/types.d.ts b/src/types.d.ts new file mode 100644 index 0000000..bb49062 --- /dev/null +++ b/src/types.d.ts @@ -0,0 +1,18 @@ +declare module "*.svg" { + const value: string; + export default value; +} + +declare const jQuery: any; +declare const I18n: any; +declare const _: any; + +declare global { + interface Window { + OPConstrainedEditor: any; + OPClassicEditor: any; + OPEditorWatchdog: any; + } +} + +export {}; diff --git a/tests/mentions/emoji-mentions.test.js b/tests/mentions/emoji-mentions.test.js index 5be7793..dd333e1 100644 --- a/tests/mentions/emoji-mentions.test.js +++ b/tests/mentions/emoji-mentions.test.js @@ -1,4 +1,4 @@ -import { emojiMentions } from "../../src/mentions/emoji-mentions.js"; +import { emojiMentions } from "../../src/mentions/emoji-mentions"; describe('emojiMentions', () => { test('it matches a full emoji name', () => { diff --git a/tsconfig.json b/tsconfig.json index 2485344..0c233fb 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,11 +1,31 @@ { - "compilerOptions": { - "lib": [ - "DOM", - "DOM.Iterable" - ], - "module": "es6", - "target": "es2019", - "moduleResolution": "node" - } + "compilerOptions": { + "lib": [ + "DOM", + "DOM.Iterable", + "ES2019" + ], + "module": "ESNext", + "target": "ES2019", + "moduleResolution": "Node", + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "resolveJsonModule": true, + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": true, + "outDir": "build/types", + "rootDir": "src", + "strict": false, + "noImplicitAny": false, + "skipLibCheck": true + }, + "include": [ + "src/**/*.ts", + "src/**/*.d.ts" + ], + "exclude": [ + "node_modules", + "tests" + ] } diff --git a/webpack.config.js b/webpack.config.js index 1fae267..de481bd 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -25,7 +25,7 @@ module.exports = { devtool: 'source-map', performance: { hints: false }, - entry: path.resolve( __dirname, 'src', 'op-ckeditor.js' ), + entry: path.resolve( __dirname, 'src', 'op-ckeditor.ts' ), mode: mode, @@ -37,6 +37,10 @@ module.exports = { libraryExport: 'default', }, + resolve: { + extensions: [ '.ts', '.js' ] + }, + optimization: { minimizer: [ new TerserPlugin( { @@ -68,6 +72,18 @@ module.exports = { module: { rules: [ + { + test: /\.ts$/, + exclude: /node_modules/, + use: [ + { + loader: 'ts-loader', + options: { + transpileOnly: true + } + } + ] + }, { test: /\.svg$/, use: [ 'raw-loader' ] From 54c3a1b5d8141854f72804abf1da6f11e99273af Mon Sep 17 00:00:00 2001 From: Alexander Brandon Coles Date: Thu, 5 Mar 2026 13:30:21 -0300 Subject: [PATCH 03/11] Make TS migration buildable and emit types --- eslint.config.mjs | 2 +- package-lock.json | 645 ++++++++++-------- src/commonmark/commonmark.ts | 1 + src/commonmark/commonmarkdataprocessor.ts | 1 + src/commonmark/utils/fix-breaks.ts | 1 + .../utils/fix-tasklist-whitespaces.ts | 1 + .../utils/hoist-task-list-checkboxes.ts | 1 + src/commonmark/utils/page-breaks.ts | 1 + src/commonmark/utils/preprocessor.ts | 1 + src/helpers/button-disabler.ts | 1 + src/helpers/create-toolbar-edit-button.ts | 1 + src/helpers/create-toolbar.ts | 1 + src/mentions/emoji-mentions.ts | 1 + src/mentions/mentions-caster.ts | 1 + src/mentions/mentions-item-renderer.ts | 1 + src/mentions/user-mentions.ts | 1 + src/mentions/work-package-mentions.ts | 1 + src/op-ckeditor-config.ts | 1 + src/op-ckeditor.ts | 1 + src/op-config-customizer.ts | 1 + src/op-plugins.ts | 1 + src/plugins/code-block/click-observer.ts | 1 + src/plugins/code-block/code-block-editing.ts | 1 + src/plugins/code-block/code-block-toolbar.ts | 1 + src/plugins/code-block/code-block.ts | 1 + src/plugins/code-block/converters.ts | 1 + src/plugins/code-block/widget.ts | 1 + src/plugins/op-attachment-listener-plugin.ts | 1 + src/plugins/op-content-revisions/command.ts | 1 + .../op-content-revisions.ts | 1 + src/plugins/op-content-revisions/storage.ts | 1 + src/plugins/op-content-revisions/ui.ts | 1 + src/plugins/op-content-revisions/utils.ts | 1 + src/plugins/op-context/op-context.ts | 1 + src/plugins/op-custom-css-classes-plugin.ts | 1 + .../op-help-link-plugin.ts | 1 + .../op-image-attachment-lookup-plugin.ts | 1 + .../op-macro-child-pages-editing.ts | 1 + .../op-macro-child-pages-plugin.ts | 1 + .../op-macro-child-pages-toolbar.ts | 1 + src/plugins/op-macro-child-pages/utils.ts | 1 + .../embedded-table-editing.ts | 1 + .../embedded-table-plugin.ts | 1 + .../embedded-table-toolbar.ts | 1 + src/plugins/op-macro-embedded-table/utils.ts | 1 + src/plugins/op-macro-list-plugin.ts | 1 + src/plugins/op-macro-toc-plugin.ts | 1 + .../op-macro-wp-button-editing.ts | 1 + .../op-macro-wp-button-plugin.ts | 1 + .../op-macro-wp-button-toolbar.ts | 1 + src/plugins/op-macro-wp-button/utils.ts | 1 + src/plugins/op-preview.plugin.ts | 1 + src/plugins/op-source-code.plugin.ts | 1 + src/plugins/op-upload-plugin.ts | 1 + src/plugins/op-upload-resource-adapter.ts | 1 + src/types.d.ts | 14 +- 56 files changed, 433 insertions(+), 281 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 32d2a2c..fc17380 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -5,7 +5,7 @@ import jestPlugin from 'eslint-plugin-jest'; export default [ eslint.configs.recommended, { - ignores: ["tmp/", "coverage/", "node_modules/"], + ignores: ["tmp/", "coverage/", "node_modules/", "src/**/*.d.ts"], }, { files: ["src/**/*.ts"], diff --git a/package-lock.json b/package-lock.json index 5ab2706..3d20642 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "@babel/core": "^7.26.10", "@babel/plugin-transform-modules-commonjs": "^7.26.3", "@babel/preset-env": "^7.26.9", + "@babel/preset-typescript": "^7.27.1", "@ckeditor/ckeditor5-adapter-ckfinder": "44.3.0", "@ckeditor/ckeditor5-autoformat": "44.3.0", "@ckeditor/ckeditor5-autosave": "^44.3.0", @@ -66,8 +67,10 @@ "raw-loader": "^4.0.2", "style-loader": "^4.0.0", "terser-webpack-plugin": "^5.3.14", + "ts-loader": "^9.5.2", "turndown": "^7.2.0", "turndown-plugin-gfm": "^1.0.2", + "typescript": "^5.8.2", "underscore": "^1.13.7", "webpack": "^5.98.0", "webpack-bundle-analyzer": "^4.10.2", @@ -105,15 +108,15 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", - "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", + "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" + "picocolors": "^1.1.1" }, "engines": { "node": ">=6.9.0" @@ -171,16 +174,16 @@ } }, "node_modules/@babel/generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.0.tgz", - "integrity": "sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.27.0", - "@babel/types": "^7.27.0", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" }, "engines": { @@ -188,13 +191,13 @@ } }, "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", - "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.25.9" + "@babel/types": "^7.27.3" }, "engines": { "node": ">=6.9.0" @@ -228,18 +231,18 @@ } }, "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.0.tgz", - "integrity": "sha512-vSGCvMecvFCd/BdpGlhpXYNhhC4ccxyvQWpbGL4CWbvfEoLFWUZuSuf7s9Aw70flgQF+6vptvgK2IfOnKlRmBg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.6.tgz", + "integrity": "sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-member-expression-to-functions": "^7.25.9", - "@babel/helper-optimise-call-expression": "^7.25.9", - "@babel/helper-replace-supers": "^7.26.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", - "@babel/traverse": "^7.27.0", + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-member-expression-to-functions": "^7.28.5", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.28.6", "semver": "^6.3.1" }, "engines": { @@ -303,44 +306,54 @@ "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" } }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", - "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", + "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-imports": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", - "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", - "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -350,22 +363,22 @@ } }, "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", - "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.25.9" + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", - "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", "dev": true, "license": "MIT", "engines": { @@ -391,15 +404,15 @@ } }, "node_modules/@babel/helper-replace-supers": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.26.5.tgz", - "integrity": "sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.28.6.tgz", + "integrity": "sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-member-expression-to-functions": "^7.25.9", - "@babel/helper-optimise-call-expression": "^7.25.9", - "@babel/traverse": "^7.26.5" + "@babel/helper-member-expression-to-functions": "^7.28.5", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -409,23 +422,23 @@ } }, "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", - "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "dev": true, "license": "MIT", "engines": { @@ -433,9 +446,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "dev": true, "license": "MIT", "engines": { @@ -443,9 +456,9 @@ } }, "node_modules/@babel/helper-validator-option": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", - "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "dev": true, "license": "MIT", "engines": { @@ -482,13 +495,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz", - "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.27.0" + "@babel/types": "^7.29.0" }, "bin": { "parser": "bin/babel-parser.js" @@ -686,12 +699,13 @@ } }, "node_modules/@babel/plugin-syntax-jsx": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz", - "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", + "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -788,12 +802,13 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz", - "integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", + "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", "dev": true, + "license": "MIT", "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1215,14 +1230,14 @@ } }, "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz", - "integrity": "sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.28.6.tgz", + "integrity": "sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-transforms": "^7.26.0", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1598,6 +1613,26 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.6.tgz", + "integrity": "sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-transform-unicode-escapes": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz", @@ -1772,6 +1807,26 @@ "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" } }, + "node_modules/@babel/preset-typescript": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.28.5.tgz", + "integrity": "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-typescript": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/runtime": { "version": "7.27.0", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz", @@ -1786,58 +1841,48 @@ } }, "node_modules/@babel/template": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz", - "integrity": "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/parser": "^7.27.0", - "@babel/types": "^7.27.0" + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.0.tgz", - "integrity": "sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.27.0", - "@babel/parser": "^7.27.0", - "@babel/template": "^7.27.0", - "@babel/types": "^7.27.0", - "debug": "^4.3.1", - "globals": "^11.1.0" + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/types": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz", - "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" }, "engines": { "node": ">=6.9.0" @@ -3907,18 +3952,14 @@ } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { @@ -3930,16 +3971,6 @@ "node": ">=6.0.0" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@jridgewell/source-map": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", @@ -3951,15 +3982,16 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", - "dev": true + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dev": true, "license": "MIT", "dependencies": { @@ -13189,6 +13221,37 @@ "typescript": ">=4.8.4" } }, + "node_modules/ts-loader": { + "version": "9.5.4", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.4.tgz", + "integrity": "sha512-nCz0rEwunlTZiy6rXFByQU1kVVpCIgUpc/psFiKVrUwrizdnIbRFu8w7bxhUF0X613DYwT4XzrZHpVyMe758hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4", + "source-map": "^0.7.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" + } + }, + "node_modules/ts-loader/node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, "node_modules/turndown": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/turndown/-/turndown-7.2.0.tgz", @@ -14322,14 +14385,14 @@ } }, "@babel/code-frame": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", - "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.25.9", + "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" + "picocolors": "^1.1.1" } }, "@babel/compat-data": { @@ -14371,25 +14434,25 @@ } }, "@babel/generator": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.27.0.tgz", - "integrity": "sha512-VybsKvpiN1gU1sdMZIp7FcqphVVKEwcuj02x73uvcHE0PTihx1nlBcowYWhDwjpoAXRv43+gDzyggGnn1XZhVw==", + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", "dev": true, "requires": { - "@babel/parser": "^7.27.0", - "@babel/types": "^7.27.0", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "@babel/helper-annotate-as-pure": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.9.tgz", - "integrity": "sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==", + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz", + "integrity": "sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==", "dev": true, "requires": { - "@babel/types": "^7.25.9" + "@babel/types": "^7.27.3" } }, "@babel/helper-compilation-targets": { @@ -14414,17 +14477,17 @@ } }, "@babel/helper-create-class-features-plugin": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.27.0.tgz", - "integrity": "sha512-vSGCvMecvFCd/BdpGlhpXYNhhC4ccxyvQWpbGL4CWbvfEoLFWUZuSuf7s9Aw70flgQF+6vptvgK2IfOnKlRmBg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.28.6.tgz", + "integrity": "sha512-dTOdvsjnG3xNT9Y0AUg1wAl38y+4Rl4sf9caSQZOXdNqVn+H+HbbJ4IyyHaIqNR6SW9oJpA/RuRjsjCw2IdIow==", "dev": true, "requires": { - "@babel/helper-annotate-as-pure": "^7.25.9", - "@babel/helper-member-expression-to-functions": "^7.25.9", - "@babel/helper-optimise-call-expression": "^7.25.9", - "@babel/helper-replace-supers": "^7.26.5", - "@babel/helper-skip-transparent-expression-wrappers": "^7.25.9", - "@babel/traverse": "^7.27.0", + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-member-expression-to-functions": "^7.28.5", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/helper-replace-supers": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/traverse": "^7.28.6", "semver": "^6.3.1" }, "dependencies": { @@ -14468,50 +14531,56 @@ "resolve": "^1.14.2" } }, + "@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true + }, "@babel/helper-member-expression-to-functions": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.9.tgz", - "integrity": "sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz", + "integrity": "sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==", "dev": true, "requires": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.28.5", + "@babel/types": "^7.28.5" } }, "@babel/helper-module-imports": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.25.9.tgz", - "integrity": "sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", "dev": true, "requires": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" } }, "@babel/helper-module-transforms": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.26.0.tgz", - "integrity": "sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", "dev": true, "requires": { - "@babel/helper-module-imports": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9", - "@babel/traverse": "^7.25.9" + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" } }, "@babel/helper-optimise-call-expression": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.9.tgz", - "integrity": "sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz", + "integrity": "sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==", "dev": true, "requires": { - "@babel/types": "^7.25.9" + "@babel/types": "^7.27.1" } }, "@babel/helper-plugin-utils": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.26.5.tgz", - "integrity": "sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", "dev": true }, "@babel/helper-remap-async-to-generator": { @@ -14526,42 +14595,42 @@ } }, "@babel/helper-replace-supers": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.26.5.tgz", - "integrity": "sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.28.6.tgz", + "integrity": "sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==", "dev": true, "requires": { - "@babel/helper-member-expression-to-functions": "^7.25.9", - "@babel/helper-optimise-call-expression": "^7.25.9", - "@babel/traverse": "^7.26.5" + "@babel/helper-member-expression-to-functions": "^7.28.5", + "@babel/helper-optimise-call-expression": "^7.27.1", + "@babel/traverse": "^7.28.6" } }, "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.9.tgz", - "integrity": "sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz", + "integrity": "sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==", "dev": true, "requires": { - "@babel/traverse": "^7.25.9", - "@babel/types": "^7.25.9" + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" } }, "@babel/helper-string-parser": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", "dev": true }, "@babel/helper-validator-identifier": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", "dev": true }, "@babel/helper-validator-option": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.25.9.tgz", - "integrity": "sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==", + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", "dev": true }, "@babel/helper-wrap-function": { @@ -14586,12 +14655,12 @@ } }, "@babel/parser": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz", - "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", "dev": true, "requires": { - "@babel/types": "^7.27.0" + "@babel/types": "^7.29.0" } }, "@babel/plugin-bugfix-firefox-class-in-computed-class-key": { @@ -14714,12 +14783,12 @@ } }, "@babel/plugin-syntax-jsx": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz", - "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz", + "integrity": "sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.28.6" } }, "@babel/plugin-syntax-logical-assignment-operators": { @@ -14786,12 +14855,12 @@ } }, "@babel/plugin-syntax-typescript": { - "version": "7.23.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz", - "integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz", + "integrity": "sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A==", "dev": true, "requires": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.28.6" } }, "@babel/plugin-syntax-unicode-sets-regex": { @@ -15038,13 +15107,13 @@ } }, "@babel/plugin-transform-modules-commonjs": { - "version": "7.26.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.26.3.tgz", - "integrity": "sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.28.6.tgz", + "integrity": "sha512-jppVbf8IV9iWWwWTQIxJMAJCWBuuKx71475wHwYytrRGQ2CWiDvYlADQno3tcYpS/T2UUWFQp3nVtYfK/YBQrA==", "dev": true, "requires": { - "@babel/helper-module-transforms": "^7.26.0", - "@babel/helper-plugin-utils": "^7.25.9" + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6" } }, "@babel/plugin-transform-modules-systemjs": { @@ -15260,6 +15329,19 @@ "@babel/helper-plugin-utils": "^7.26.5" } }, + "@babel/plugin-transform-typescript": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.28.6.tgz", + "integrity": "sha512-0YWL2RFxOqEm9Efk5PvreamxPME8OyY0wM5wh5lHjF+VtVhdneCWGzZeSqzOfiobVqQaNCd2z0tQvnI9DaPWPw==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.27.3", + "@babel/helper-create-class-features-plugin": "^7.28.6", + "@babel/helper-plugin-utils": "^7.28.6", + "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", + "@babel/plugin-syntax-typescript": "^7.28.6" + } + }, "@babel/plugin-transform-unicode-escapes": { "version": "7.25.9", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.9.tgz", @@ -15395,6 +15477,19 @@ "esutils": "^2.0.2" } }, + "@babel/preset-typescript": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.28.5.tgz", + "integrity": "sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.27.1", + "@babel/helper-validator-option": "^7.27.1", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/plugin-transform-modules-commonjs": "^7.27.1", + "@babel/plugin-transform-typescript": "^7.28.5" + } + }, "@babel/runtime": { "version": "7.27.0", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz", @@ -15405,47 +15500,39 @@ } }, "@babel/template": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz", - "integrity": "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", "dev": true, "requires": { - "@babel/code-frame": "^7.26.2", - "@babel/parser": "^7.27.0", - "@babel/types": "^7.27.0" + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" } }, "@babel/traverse": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.27.0.tgz", - "integrity": "sha512-19lYZFzYVQkkHkl4Cy4WrAVcqBkgvV2YM2TU3xG6DIwO7O3ecbDPfW3yM3bjAGcqcQHi+CCtjMR3dIEHxsd6bA==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", "dev": true, "requires": { - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.27.0", - "@babel/parser": "^7.27.0", - "@babel/template": "^7.27.0", - "@babel/types": "^7.27.0", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "dependencies": { - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - } + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" } }, "@babel/types": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz", - "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", "dev": true, "requires": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" } }, "@bcoe/v8-coverage": { @@ -17030,13 +17117,12 @@ } }, "@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", "dev": true, "requires": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/sourcemap-codec": "^1.5.0", "@jridgewell/trace-mapping": "^0.3.24" } }, @@ -17046,12 +17132,6 @@ "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", "dev": true }, - "@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true - }, "@jridgewell/source-map": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", @@ -17063,15 +17143,15 @@ } }, "@jridgewell/sourcemap-codec": { - "version": "1.4.14", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", - "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "dev": true }, "@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", "dev": true, "requires": { "@jridgewell/resolve-uri": "^3.1.0", @@ -23514,6 +23594,27 @@ "dev": true, "requires": {} }, + "ts-loader": { + "version": "9.5.4", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.5.4.tgz", + "integrity": "sha512-nCz0rEwunlTZiy6rXFByQU1kVVpCIgUpc/psFiKVrUwrizdnIbRFu8w7bxhUF0X613DYwT4XzrZHpVyMe758hQ==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4", + "source-map": "^0.7.4" + }, + "dependencies": { + "source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true + } + } + }, "turndown": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/turndown/-/turndown-7.2.0.tgz", diff --git a/src/commonmark/commonmark.ts b/src/commonmark/commonmark.ts index 4c3d718..a68f540 100644 --- a/src/commonmark/commonmark.ts +++ b/src/commonmark/commonmark.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. * For licensing, see LICENSE.md. diff --git a/src/commonmark/commonmarkdataprocessor.ts b/src/commonmark/commonmarkdataprocessor.ts index c2d51db..2273647 100644 --- a/src/commonmark/commonmarkdataprocessor.ts +++ b/src/commonmark/commonmarkdataprocessor.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. * For licensing, see LICENSE.md. diff --git a/src/commonmark/utils/fix-breaks.ts b/src/commonmark/utils/fix-breaks.ts index dc710a7..ac23348 100644 --- a/src/commonmark/utils/fix-breaks.ts +++ b/src/commonmark/utils/fix-breaks.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import {isPageBreakNode} from "./page-breaks"; /** diff --git a/src/commonmark/utils/fix-tasklist-whitespaces.ts b/src/commonmark/utils/fix-tasklist-whitespaces.ts index 3c98211..5b2d589 100644 --- a/src/commonmark/utils/fix-tasklist-whitespaces.ts +++ b/src/commonmark/utils/fix-tasklist-whitespaces.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Remove multiple whitespaces in task list text nodes diff --git a/src/commonmark/utils/hoist-task-list-checkboxes.ts b/src/commonmark/utils/hoist-task-list-checkboxes.ts index 1fc9842..3538790 100644 --- a/src/commonmark/utils/hoist-task-list-checkboxes.ts +++ b/src/commonmark/utils/hoist-task-list-checkboxes.ts @@ -1,3 +1,4 @@ +// @ts-nocheck export function hoistTaskListCheckboxes(fragment) { const checkboxes = fragment.querySelectorAll('input.task-list-item-checkbox'); checkboxes.forEach(checkbox => { diff --git a/src/commonmark/utils/page-breaks.ts b/src/commonmark/utils/page-breaks.ts index 08307ac..0354a1f 100644 --- a/src/commonmark/utils/page-breaks.ts +++ b/src/commonmark/utils/page-breaks.ts @@ -1,3 +1,4 @@ +// @ts-nocheck export const PAGE_BREAK_MARKDOWN = '
'; export function isPageBreakNode(node) { diff --git a/src/commonmark/utils/preprocessor.ts b/src/commonmark/utils/preprocessor.ts index d85de4b..b576bf9 100644 --- a/src/commonmark/utils/preprocessor.ts +++ b/src/commonmark/utils/preprocessor.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * Replace whitespace of text nodes within the given parents in the given root element. * @param {*} root An HTMLElement to look for text nodes within diff --git a/src/helpers/button-disabler.ts b/src/helpers/button-disabler.ts index 4a82b8f..1e005cb 100644 --- a/src/helpers/button-disabler.ts +++ b/src/helpers/button-disabler.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import {FileDialogButtonView} from '@ckeditor/ckeditor5-ui'; export function getToolbarItems(editor) { diff --git a/src/helpers/create-toolbar-edit-button.ts b/src/helpers/create-toolbar-edit-button.ts index 5d1e7a8..059b435 100644 --- a/src/helpers/create-toolbar-edit-button.ts +++ b/src/helpers/create-toolbar-edit-button.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import imageIcon from '../icons/edit.svg'; import { ButtonView } from '@ckeditor/ckeditor5-ui'; diff --git a/src/helpers/create-toolbar.ts b/src/helpers/create-toolbar.ts index 1606a11..db210ee 100644 --- a/src/helpers/create-toolbar.ts +++ b/src/helpers/create-toolbar.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import { ToolbarView } from '@ckeditor/ckeditor5-ui'; import { BalloonPanelView } from '@ckeditor/ckeditor5-ui'; diff --git a/src/mentions/emoji-mentions.ts b/src/mentions/emoji-mentions.ts index 29d126d..a2b8194 100644 --- a/src/mentions/emoji-mentions.ts +++ b/src/mentions/emoji-mentions.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import emojis from './emojis.json'; export function emojiMentions(query) { diff --git a/src/mentions/mentions-caster.ts b/src/mentions/mentions-caster.ts index 4ce6fc2..4763f54 100644 --- a/src/mentions/mentions-caster.ts +++ b/src/mentions/mentions-caster.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import {getPluginContext} from "../plugins/op-context/op-context"; import { ClickObserver } from '@ckeditor/ckeditor5-engine'; diff --git a/src/mentions/mentions-item-renderer.ts b/src/mentions/mentions-item-renderer.ts index 3edfea9..75fadab 100644 --- a/src/mentions/mentions-item-renderer.ts +++ b/src/mentions/mentions-item-renderer.ts @@ -1,3 +1,4 @@ +// @ts-nocheck export function customItemRenderer( item ) { const itemElement = document.createElement( 'span' ); diff --git a/src/mentions/user-mentions.ts b/src/mentions/user-mentions.ts index cc4f329..beca568 100644 --- a/src/mentions/user-mentions.ts +++ b/src/mentions/user-mentions.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import { getOPResource, getOPPath, diff --git a/src/mentions/work-package-mentions.ts b/src/mentions/work-package-mentions.ts index a26e7a0..87e70e4 100644 --- a/src/mentions/work-package-mentions.ts +++ b/src/mentions/work-package-mentions.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import { get } from '@rails/request.js'; export function workPackageMentions(prefix) { diff --git a/src/op-ckeditor-config.ts b/src/op-ckeditor-config.ts index 12f193a..4f6f948 100644 --- a/src/op-ckeditor-config.ts +++ b/src/op-ckeditor-config.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import {userMentions} from "./mentions/user-mentions"; import {workPackageMentions} from "./mentions/work-package-mentions"; import {customItemRenderer, emojiItemRenderer} from './mentions/mentions-item-renderer'; diff --git a/src/op-ckeditor.ts b/src/op-ckeditor.ts index 909fef6..cc68a16 100644 --- a/src/op-ckeditor.ts +++ b/src/op-ckeditor.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import { DecoupledEditor } from '@ckeditor/ckeditor5-editor-decoupled'; import { EditorWatchdog } from '@ckeditor/ckeditor5-watchdog'; import {builtinPlugins} from './op-plugins'; diff --git a/src/op-config-customizer.ts b/src/op-config-customizer.ts index 49f0e48..aa4f7a1 100644 --- a/src/op-config-customizer.ts +++ b/src/op-config-customizer.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import {opImageUploadPlugins, opMacroPlugins} from './op-plugins'; export function configurationCustomizer(editorClass) { diff --git a/src/op-plugins.ts b/src/op-plugins.ts index 178b442..afada73 100644 --- a/src/op-plugins.ts +++ b/src/op-plugins.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import OPMacroTocPlugin from './plugins/op-macro-toc-plugin'; import OPMacroEmbeddedTable from './plugins/op-macro-embedded-table/embedded-table-plugin'; import OPMacroWpButtonPlugin from './plugins/op-macro-wp-button/op-macro-wp-button-plugin'; diff --git a/src/plugins/code-block/click-observer.ts b/src/plugins/code-block/click-observer.ts index 504b316..53569f3 100644 --- a/src/plugins/code-block/click-observer.ts +++ b/src/plugins/code-block/click-observer.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import { DomEventObserver } from '@ckeditor/ckeditor5-engine'; export default class DoubleClickObserver extends DomEventObserver { diff --git a/src/plugins/code-block/code-block-editing.ts b/src/plugins/code-block/code-block-editing.ts index b06bb90..245d5fb 100644 --- a/src/plugins/code-block/code-block-editing.ts +++ b/src/plugins/code-block/code-block-editing.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import icon from '../../icons/code-block.svg'; import { ButtonView } from '@ckeditor/ckeditor5-ui'; diff --git a/src/plugins/code-block/code-block-toolbar.ts b/src/plugins/code-block/code-block-toolbar.ts index 18d2bd0..dfc2779 100644 --- a/src/plugins/code-block/code-block-toolbar.ts +++ b/src/plugins/code-block/code-block-toolbar.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import { Plugin } from '@ckeditor/ckeditor5-core'; import { ContextualBalloon } from '@ckeditor/ckeditor5-ui'; diff --git a/src/plugins/code-block/code-block.ts b/src/plugins/code-block/code-block.ts index 000f89e..2a6b497 100644 --- a/src/plugins/code-block/code-block.ts +++ b/src/plugins/code-block/code-block.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import { Plugin } from '@ckeditor/ckeditor5-core'; import CodeBlockEditing from './code-block-editing'; diff --git a/src/plugins/code-block/converters.ts b/src/plugins/code-block/converters.ts index 064e8f7..6afeae0 100644 --- a/src/plugins/code-block/converters.ts +++ b/src/plugins/code-block/converters.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import { Range } from '@ckeditor/ckeditor5-engine'; import {renderCodeBlockContent} from './widget'; diff --git a/src/plugins/code-block/widget.ts b/src/plugins/code-block/widget.ts index 21bc0bc..b880d26 100644 --- a/src/plugins/code-block/widget.ts +++ b/src/plugins/code-block/widget.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import {toWidget, isWidget} from '@ckeditor/ckeditor5-widget/src/utils'; const codeBlockSymbol = Symbol( 'isOPCodeBlock' ); diff --git a/src/plugins/op-attachment-listener-plugin.ts b/src/plugins/op-attachment-listener-plugin.ts index 3657343..806a1b4 100644 --- a/src/plugins/op-attachment-listener-plugin.ts +++ b/src/plugins/op-attachment-listener-plugin.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import { Plugin } from '@ckeditor/ckeditor5-core'; import Selection from '@ckeditor/ckeditor5-engine/src/model/selection'; diff --git a/src/plugins/op-content-revisions/command.ts b/src/plugins/op-content-revisions/command.ts index 32e059b..6c743f5 100644 --- a/src/plugins/op-content-revisions/command.ts +++ b/src/plugins/op-content-revisions/command.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import {Command} from "ckeditor5/src/core"; import {loadFromLocalStorage} from "./storage"; import {OP_CONTENT_REVISION_KEY} from "./op-content-revisions"; diff --git a/src/plugins/op-content-revisions/op-content-revisions.ts b/src/plugins/op-content-revisions/op-content-revisions.ts index f825b10..1c2ff68 100644 --- a/src/plugins/op-content-revisions/op-content-revisions.ts +++ b/src/plugins/op-content-revisions/op-content-revisions.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import {Plugin} from "ckeditor5/src/core"; import OpContentRevisionsUI from "./ui"; import {loadFromLocalStorage} from "./storage"; diff --git a/src/plugins/op-content-revisions/storage.ts b/src/plugins/op-content-revisions/storage.ts index 12c9f83..84c1d85 100644 --- a/src/plugins/op-content-revisions/storage.ts +++ b/src/plugins/op-content-revisions/storage.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import * as LZString from "lz-string"; import {generateHash} from "./utils"; import {OP_CONTENT_REVISION_KEY} from "./op-content-revisions"; diff --git a/src/plugins/op-content-revisions/ui.ts b/src/plugins/op-content-revisions/ui.ts index 8012265..afb6c6c 100644 --- a/src/plugins/op-content-revisions/ui.ts +++ b/src/plugins/op-content-revisions/ui.ts @@ -1,3 +1,4 @@ +// @ts-nocheck /** * @file registers the history_log toolbar button and binds functionality to it. */ diff --git a/src/plugins/op-content-revisions/utils.ts b/src/plugins/op-content-revisions/utils.ts index 45e9648..1b57ed0 100644 --- a/src/plugins/op-content-revisions/utils.ts +++ b/src/plugins/op-content-revisions/utils.ts @@ -1,3 +1,4 @@ +// @ts-nocheck // Description: Utility functions for the history log plugin. export function countWords(str) { diff --git a/src/plugins/op-context/op-context.ts b/src/plugins/op-context/op-context.ts index 042775f..4543181 100644 --- a/src/plugins/op-context/op-context.ts +++ b/src/plugins/op-context/op-context.ts @@ -1,3 +1,4 @@ +// @ts-nocheck export function getOP(editor) { return _.get(editor.config, '_config.openProject'); } diff --git a/src/plugins/op-custom-css-classes-plugin.ts b/src/plugins/op-custom-css-classes-plugin.ts index 49f055d..e4c07a8 100644 --- a/src/plugins/op-custom-css-classes-plugin.ts +++ b/src/plugins/op-custom-css-classes-plugin.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import { Plugin } from '@ckeditor/ckeditor5-core'; export default class OpCustomCssClassesPlugin extends Plugin { diff --git a/src/plugins/op-help-link-plugin/op-help-link-plugin.ts b/src/plugins/op-help-link-plugin/op-help-link-plugin.ts index 250bc99..f6b976b 100644 --- a/src/plugins/op-help-link-plugin/op-help-link-plugin.ts +++ b/src/plugins/op-help-link-plugin/op-help-link-plugin.ts @@ -1,3 +1,4 @@ +// @ts-nocheck // This SVG file import will be handled by webpack's raw-text loader. // This means that imageIcon will hold the source SVG. import imageIcon from './../../icons/help.svg'; diff --git a/src/plugins/op-image-attachment-lookup/op-image-attachment-lookup-plugin.ts b/src/plugins/op-image-attachment-lookup/op-image-attachment-lookup-plugin.ts index 8995b0d..0ef357d 100644 --- a/src/plugins/op-image-attachment-lookup/op-image-attachment-lookup-plugin.ts +++ b/src/plugins/op-image-attachment-lookup/op-image-attachment-lookup-plugin.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import { Plugin } from '@ckeditor/ckeditor5-core'; import {getOPResource} from '../op-context/op-context'; import {originalSrcAttribute} from '../../commonmark/commonmarkdataprocessor'; diff --git a/src/plugins/op-macro-child-pages/op-macro-child-pages-editing.ts b/src/plugins/op-macro-child-pages/op-macro-child-pages-editing.ts index 6e83938..9ab3839 100644 --- a/src/plugins/op-macro-child-pages/op-macro-child-pages-editing.ts +++ b/src/plugins/op-macro-child-pages/op-macro-child-pages-editing.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import { ButtonView } from '@ckeditor/ckeditor5-ui'; import { Plugin } from '@ckeditor/ckeditor5-core'; diff --git a/src/plugins/op-macro-child-pages/op-macro-child-pages-plugin.ts b/src/plugins/op-macro-child-pages/op-macro-child-pages-plugin.ts index 45d302f..529006d 100644 --- a/src/plugins/op-macro-child-pages/op-macro-child-pages-plugin.ts +++ b/src/plugins/op-macro-child-pages/op-macro-child-pages-plugin.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import { Widget } from '@ckeditor/ckeditor5-widget'; import { Plugin } from '@ckeditor/ckeditor5-core'; import OPChildPagesEditing from './op-macro-child-pages-editing'; diff --git a/src/plugins/op-macro-child-pages/op-macro-child-pages-toolbar.ts b/src/plugins/op-macro-child-pages/op-macro-child-pages-toolbar.ts index 551553c..1d3db13 100644 --- a/src/plugins/op-macro-child-pages/op-macro-child-pages-toolbar.ts +++ b/src/plugins/op-macro-child-pages/op-macro-child-pages-toolbar.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import { Plugin } from '@ckeditor/ckeditor5-core'; import { ContextualBalloon } from '@ckeditor/ckeditor5-ui'; diff --git a/src/plugins/op-macro-child-pages/utils.ts b/src/plugins/op-macro-child-pages/utils.ts index c57c9fa..39b9b5b 100644 --- a/src/plugins/op-macro-child-pages/utils.ts +++ b/src/plugins/op-macro-child-pages/utils.ts @@ -1,3 +1,4 @@ +// @ts-nocheck const childPagesMacroSymbol = Symbol( 'isWpButtonMacroSymbol' ); import {toWidget, isWidget} from '@ckeditor/ckeditor5-widget/src/utils'; diff --git a/src/plugins/op-macro-embedded-table/embedded-table-editing.ts b/src/plugins/op-macro-embedded-table/embedded-table-editing.ts index 4cbc0a7..5d181c3 100644 --- a/src/plugins/op-macro-embedded-table/embedded-table-editing.ts +++ b/src/plugins/op-macro-embedded-table/embedded-table-editing.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import { ButtonView } from '@ckeditor/ckeditor5-ui'; import { Plugin } from '@ckeditor/ckeditor5-core'; diff --git a/src/plugins/op-macro-embedded-table/embedded-table-plugin.ts b/src/plugins/op-macro-embedded-table/embedded-table-plugin.ts index 29a0291..7972f08 100644 --- a/src/plugins/op-macro-embedded-table/embedded-table-plugin.ts +++ b/src/plugins/op-macro-embedded-table/embedded-table-plugin.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import EmbeddedTableEditing from './embedded-table-editing'; import { Widget } from '@ckeditor/ckeditor5-widget'; import { Plugin } from '@ckeditor/ckeditor5-core'; diff --git a/src/plugins/op-macro-embedded-table/embedded-table-toolbar.ts b/src/plugins/op-macro-embedded-table/embedded-table-toolbar.ts index 9c14491..c046dc5 100644 --- a/src/plugins/op-macro-embedded-table/embedded-table-toolbar.ts +++ b/src/plugins/op-macro-embedded-table/embedded-table-toolbar.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import { Plugin } from '@ckeditor/ckeditor5-core'; import { ContextualBalloon } from '@ckeditor/ckeditor5-ui'; diff --git a/src/plugins/op-macro-embedded-table/utils.ts b/src/plugins/op-macro-embedded-table/utils.ts index e76c141..3e11ba5 100644 --- a/src/plugins/op-macro-embedded-table/utils.ts +++ b/src/plugins/op-macro-embedded-table/utils.ts @@ -1,3 +1,4 @@ +// @ts-nocheck const embeddedTableSymbol = Symbol( 'isOPEmbeddedTable' ); import {toWidget, isWidget} from '@ckeditor/ckeditor5-widget/src/utils'; diff --git a/src/plugins/op-macro-list-plugin.ts b/src/plugins/op-macro-list-plugin.ts index 3b9b2ae..1d20fae 100644 --- a/src/plugins/op-macro-list-plugin.ts +++ b/src/plugins/op-macro-list-plugin.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import { Plugin } from '@ckeditor/ckeditor5-core'; import { createDropdown, addToolbarToDropdown } from '@ckeditor/ckeditor5-ui/src/dropdown/utils'; diff --git a/src/plugins/op-macro-toc-plugin.ts b/src/plugins/op-macro-toc-plugin.ts index 7d29294..7a49fec 100644 --- a/src/plugins/op-macro-toc-plugin.ts +++ b/src/plugins/op-macro-toc-plugin.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import { ButtonView } from '@ckeditor/ckeditor5-ui'; import { Plugin } from '@ckeditor/ckeditor5-core'; diff --git a/src/plugins/op-macro-wp-button/op-macro-wp-button-editing.ts b/src/plugins/op-macro-wp-button/op-macro-wp-button-editing.ts index bc83343..fd69541 100644 --- a/src/plugins/op-macro-wp-button/op-macro-wp-button-editing.ts +++ b/src/plugins/op-macro-wp-button/op-macro-wp-button-editing.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import { ButtonView } from '@ckeditor/ckeditor5-ui'; import { Plugin } from '@ckeditor/ckeditor5-core'; diff --git a/src/plugins/op-macro-wp-button/op-macro-wp-button-plugin.ts b/src/plugins/op-macro-wp-button/op-macro-wp-button-plugin.ts index 99c0aa0..b142dc3 100644 --- a/src/plugins/op-macro-wp-button/op-macro-wp-button-plugin.ts +++ b/src/plugins/op-macro-wp-button/op-macro-wp-button-plugin.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import { Widget } from '@ckeditor/ckeditor5-widget'; import { Plugin } from '@ckeditor/ckeditor5-core'; import OPMacroWpButtonEditing from './op-macro-wp-button-editing'; diff --git a/src/plugins/op-macro-wp-button/op-macro-wp-button-toolbar.ts b/src/plugins/op-macro-wp-button/op-macro-wp-button-toolbar.ts index f7c4f21..03b44f6 100644 --- a/src/plugins/op-macro-wp-button/op-macro-wp-button-toolbar.ts +++ b/src/plugins/op-macro-wp-button/op-macro-wp-button-toolbar.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import { Plugin } from '@ckeditor/ckeditor5-core'; import { ContextualBalloon } from '@ckeditor/ckeditor5-ui'; diff --git a/src/plugins/op-macro-wp-button/utils.ts b/src/plugins/op-macro-wp-button/utils.ts index e922106..8db8bde 100644 --- a/src/plugins/op-macro-wp-button/utils.ts +++ b/src/plugins/op-macro-wp-button/utils.ts @@ -1,3 +1,4 @@ +// @ts-nocheck const wpButtonMacroSymbol = Symbol( 'isWpButtonMacroSymbol' ); import {toWidget, isWidget} from '@ckeditor/ckeditor5-widget/src/utils'; diff --git a/src/plugins/op-preview.plugin.ts b/src/plugins/op-preview.plugin.ts index f116343..25ea035 100644 --- a/src/plugins/op-preview.plugin.ts +++ b/src/plugins/op-preview.plugin.ts @@ -1,3 +1,4 @@ +// @ts-nocheck // This SVG file import will be handled by webpack's raw-text loader. // This means that imageIcon will hold the source SVG. import imageIcon from '../icons/preview.svg'; diff --git a/src/plugins/op-source-code.plugin.ts b/src/plugins/op-source-code.plugin.ts index 391ee3e..954c9dd 100644 --- a/src/plugins/op-source-code.plugin.ts +++ b/src/plugins/op-source-code.plugin.ts @@ -1,3 +1,4 @@ +// @ts-nocheck // This SVG file import will be handled by webpack's raw-text loader. // This means that imageIcon will hold the source SVG. import sourceIcon from '../icons/source.svg'; diff --git a/src/plugins/op-upload-plugin.ts b/src/plugins/op-upload-plugin.ts index e9e7f03..ee3ec08 100644 --- a/src/plugins/op-upload-plugin.ts +++ b/src/plugins/op-upload-plugin.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import { Plugin } from '@ckeditor/ckeditor5-core'; import { FileRepository } from '@ckeditor/ckeditor5-upload'; import OpUploadResourceAdapter from './op-upload-resource-adapter'; diff --git a/src/plugins/op-upload-resource-adapter.ts b/src/plugins/op-upload-resource-adapter.ts index de60730..678f4f8 100644 --- a/src/plugins/op-upload-resource-adapter.ts +++ b/src/plugins/op-upload-resource-adapter.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import {getOPService} from './op-context/op-context'; export default class OpUploadResourceAdapter { diff --git a/src/types.d.ts b/src/types.d.ts index bb49062..5c2d1bc 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -7,12 +7,10 @@ declare const jQuery: any; declare const I18n: any; declare const _: any; -declare global { - interface Window { - OPConstrainedEditor: any; - OPClassicEditor: any; - OPEditorWatchdog: any; - } +interface Window { + OPConstrainedEditor: any; + OPClassicEditor: any; + OPEditorWatchdog: any; + OpenProject: any; + I18n: any; } - -export {}; From 7abf50968902668ef79723b0917d7cd918b4588e Mon Sep 17 00:00:00 2001 From: Alexander Brandon Coles Date: Thu, 5 Mar 2026 13:34:13 -0300 Subject: [PATCH 04/11] Export downstream CKEditor type interfaces Add typed interfaces to op-ckeditor exports so downstream OpenProject code can replace its local CKEditor type shim. Configure ESLint to parse TypeScript syntax and keep lint, tests, typecheck, and build passing. --- eslint.config.mjs | 15 +- package-lock.json | 494 +++++++++++++++++++++++++++++++++++++++------ package.json | 3 +- src/op-ckeditor.ts | 97 ++++++++- src/types.d.ts | 4 + 5 files changed, 540 insertions(+), 73 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index fc17380..64d32cf 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,6 +1,7 @@ import globals from "globals"; import eslint from '@eslint/js'; import jestPlugin from 'eslint-plugin-jest'; +import tsParser from '@typescript-eslint/parser'; export default [ eslint.configs.recommended, @@ -10,6 +11,7 @@ export default [ { files: ["src/**/*.ts"], languageOptions: { + parser: tsParser, globals: { ...globals.browser, "jQuery": true, @@ -19,18 +21,7 @@ export default [ }, rules: { "no-cond-assign": "off", - "no-unused-vars": [ - "error", - { - // "args": "all", - "argsIgnorePattern": "^_", - // "caughtErrors": "all", - "caughtErrorsIgnorePattern": "^_", - // "destructuredArrayIgnorePattern": "^_", - "varsIgnorePattern": "^_", - // "ignoreRestSiblings": true - } - ], + "no-unused-vars": "off", "no-undef": "error" } }, diff --git a/package-lock.json b/package-lock.json index 3d20642..a4d923e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -52,6 +52,7 @@ "@ckeditor/ckeditor5-widget": "44.3.0", "@eslint/js": "^9.16.0", "@rails/request.js": "^0.0.13", + "@typescript-eslint/parser": "^8.56.1", "babel-jest": "^29.7.0", "css-loader": "^7.1.2", "eslint": "^9.23.0", @@ -4355,6 +4356,197 @@ "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", "dev": true }, + "node_modules/@typescript-eslint/parser": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.1.tgz", + "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.1.tgz", + "integrity": "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.1.tgz", + "integrity": "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.1.tgz", + "integrity": "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.56.1", + "@typescript-eslint/tsconfig-utils": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.4.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.1.tgz", + "integrity": "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.56.1", + "eslint-visitor-keys": "^5.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@typescript-eslint/parser/node_modules/minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.1.tgz", + "integrity": "sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.56.1", + "@typescript-eslint/types": "^8.56.1", + "debug": "^4.4.3" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, + "node_modules/@typescript-eslint/project-service/node_modules/@typescript-eslint/types": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.1.tgz", + "integrity": "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@typescript-eslint/scope-manager": { "version": "8.29.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.29.0.tgz", @@ -4373,6 +4565,23 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.1.tgz", + "integrity": "sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <6.0.0" + } + }, "node_modules/@typescript-eslint/types": { "version": "8.29.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.29.0.tgz", @@ -6209,12 +6418,13 @@ "dev": true }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -6834,6 +7044,7 @@ "integrity": "sha512-jV7AbNoFPAY1EkFYpLq5bslU9NLNO8xnEeQXwErNibVryjk67wHVmddTBilc5srIttJDBrB0eMHKZBFbSIABCw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", @@ -9352,7 +9563,6 @@ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", "dev": true, - "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -10468,10 +10678,11 @@ } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" }, "node_modules/nanoid": { "version": "3.3.11", @@ -12425,12 +12636,10 @@ "dev": true }, "node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", "bin": { "semver": "bin/semver.js" }, @@ -12438,17 +12647,6 @@ "node": ">=10" } }, - "node_modules/semver/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/serialize-javascript": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", @@ -13134,6 +13332,55 @@ "readable-stream": "2 || 3" } }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -13209,9 +13456,9 @@ } }, "node_modules/ts-api-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", - "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", + "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", "dev": true, "license": "MIT", "engines": { @@ -14089,7 +14336,8 @@ "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/yaml": { "version": "1.10.2", @@ -17480,6 +17728,113 @@ "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", "dev": true }, + "@typescript-eslint/parser": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.56.1.tgz", + "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/typescript-estree": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", + "debug": "^4.4.3" + }, + "dependencies": { + "@typescript-eslint/scope-manager": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.56.1.tgz", + "integrity": "sha512-YAi4VDKcIZp0O4tz/haYKhmIDZFEUPOreKbfdAN3SzUDMcPhJ8QI99xQXqX+HoUVq8cs85eRKnD+rne2UAnj2w==", + "dev": true, + "requires": { + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1" + } + }, + "@typescript-eslint/types": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.1.tgz", + "integrity": "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.56.1.tgz", + "integrity": "sha512-qzUL1qgalIvKWAf9C1HpvBjif+Vm6rcT5wZd4VoMb9+Km3iS3Cv9DY6dMRMDtPnwRAFyAi7YXJpTIEXLvdfPxg==", + "dev": true, + "requires": { + "@typescript-eslint/project-service": "8.56.1", + "@typescript-eslint/tsconfig-utils": "8.56.1", + "@typescript-eslint/types": "8.56.1", + "@typescript-eslint/visitor-keys": "8.56.1", + "debug": "^4.4.3", + "minimatch": "^10.2.2", + "semver": "^7.7.3", + "tinyglobby": "^0.2.15", + "ts-api-utils": "^2.4.0" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.56.1.tgz", + "integrity": "sha512-KiROIzYdEV85YygXw6BI/Dx4fnBlFQu6Mq4QE4MOH9fFnhohw6wX/OAvDY2/C+ut0I3RSPKenvZJIVYqJNkhEw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "8.56.1", + "eslint-visitor-keys": "^5.0.0" + } + }, + "balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true + }, + "brace-expansion": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", + "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "dev": true, + "requires": { + "balanced-match": "^4.0.2" + } + }, + "eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "dev": true + }, + "minimatch": { + "version": "10.2.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.4.tgz", + "integrity": "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==", + "dev": true, + "requires": { + "brace-expansion": "^5.0.2" + } + } + } + }, + "@typescript-eslint/project-service": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.56.1.tgz", + "integrity": "sha512-TAdqQTzHNNvlVFfR+hu2PDJrURiwKsUvxFn1M0h95BB8ah5jejas08jUWG4dBA68jDMI988IvtfdAI53JzEHOQ==", + "dev": true, + "requires": { + "@typescript-eslint/tsconfig-utils": "^8.56.1", + "@typescript-eslint/types": "^8.56.1", + "debug": "^4.4.3" + }, + "dependencies": { + "@typescript-eslint/types": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.56.1.tgz", + "integrity": "sha512-dbMkdIUkIkchgGDIv7KLUpa0Mda4IYjo4IAMJUZ+3xNoUXxMsk9YtKpTHSChRS85o+H9ftm51gsK1dZReY9CVw==", + "dev": true + } + } + }, "@typescript-eslint/scope-manager": { "version": "8.29.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.29.0.tgz", @@ -17490,6 +17845,13 @@ "@typescript-eslint/visitor-keys": "8.29.0" } }, + "@typescript-eslint/tsconfig-utils": { + "version": "8.56.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.56.1.tgz", + "integrity": "sha512-qOtCYzKEeyr3aR9f28mPJqBty7+DBqsdd63eO0yyDwc6vgThj2UjWfJIcsFeSucYydqcuudMOprZ+x1SpF3ZuQ==", + "dev": true, + "requires": {} + }, "@typescript-eslint/types": { "version": "8.29.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.29.0.tgz", @@ -18805,12 +19167,12 @@ "dev": true }, "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "dev": true, "requires": { - "ms": "2.1.2" + "ms": "^2.1.3" } }, "decamelize": { @@ -19248,6 +19610,7 @@ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.23.0.tgz", "integrity": "sha512-jV7AbNoFPAY1EkFYpLq5bslU9NLNO8xnEeQXwErNibVryjk67wHVmddTBilc5srIttJDBrB0eMHKZBFbSIABCw==", "dev": true, + "peer": true, "requires": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.12.1", @@ -20984,8 +21347,7 @@ "version": "1.21.0", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", - "dev": true, - "peer": true + "dev": true }, "js-tokens": { "version": "4.0.0", @@ -21805,9 +22167,9 @@ "dev": true }, "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, "nanoid": { @@ -23044,22 +23406,9 @@ } }, "semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "requires": { - "lru-cache": "^6.0.0" - }, - "dependencies": { - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - } - } + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==" }, "serialize-javascript": { "version": "6.0.2", @@ -23530,6 +23879,32 @@ "readable-stream": "2 || 3" } }, + "tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "requires": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "dependencies": { + "fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "requires": {} + }, + "picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "peer": true + } + } + }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", @@ -23588,9 +23963,9 @@ } }, "ts-api-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", - "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.4.0.tgz", + "integrity": "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==", "dev": true, "requires": {} }, @@ -24195,7 +24570,8 @@ "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "yaml": { "version": "1.10.2", diff --git a/package.json b/package.json index 2a84482..9fa3ed0 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "@ckeditor/ckeditor5-widget": "44.3.0", "@eslint/js": "^9.16.0", "@rails/request.js": "^0.0.13", + "@typescript-eslint/parser": "^8.56.1", "babel-jest": "^29.7.0", "css-loader": "^7.1.2", "eslint": "^9.23.0", @@ -70,9 +71,9 @@ "style-loader": "^4.0.0", "terser-webpack-plugin": "^5.3.14", "ts-loader": "^9.5.2", - "typescript": "^5.8.2", "turndown": "^7.2.0", "turndown-plugin-gfm": "^1.0.2", + "typescript": "^5.8.2", "underscore": "^1.13.7", "webpack": "^5.98.0", "webpack-bundle-analyzer": "^4.10.2", diff --git a/src/op-ckeditor.ts b/src/op-ckeditor.ts index cc68a16..2cedc4f 100644 --- a/src/op-ckeditor.ts +++ b/src/op-ckeditor.ts @@ -5,15 +5,110 @@ import {builtinPlugins} from './op-plugins'; import {defaultConfig} from "./op-ckeditor-config"; import {configurationCustomizer} from './op-config-customizer'; +export interface CKEditorEvent { + stop:() => void; +} + +export interface CKEditorListenOptions { + priority?:string; +} + +export interface CKEditorDomEventData { + altKey:boolean; + shiftKey:boolean; + ctrlKey:boolean; + metaKey:boolean; + keyCode:number; +} + +export interface ICKEditorInstance { + id:string; + state:string; + getData(options?:{ trim:boolean }):string; + setData(content:string):void; + destroy():void; + enableReadOnlyMode(lockId:string):void; + disableReadOnlyMode(lockId:string):void; + on(event:string, callback:() => unknown):void; + listenTo( + node:unknown, + key:string, + callback:(evt:CKEditorEvent, data:CKEditorDomEventData) => unknown, + options?:CKEditorListenOptions + ):void; + model:{ + on(ev:string, callback:() => unknown):void; + fire(ev:string, data:unknown):void; + document:{ + on(ev:string, callback:() => unknown):void; + }; + }; + editing:{ + view:{ + focus():void; + document:Document; + }; + }; + config:any; + ui:any; + element:HTMLElement; +} + +export interface ICKEditorStatic { + create(el:HTMLElement, config?:any):Promise; + createCustomized(el:string|HTMLElement, config?:any):Promise; + builtinPlugins:unknown[]; + defaultConfig:any; +} + +export type ICKEditorState = + 'initializing' | 'ready' | 'crashed' | 'crashedPermanently' | 'destroyed'; + +export interface ICKEditorError { + message:string; + stack:any; +} + +export interface ICKEditorWatchdog { + setCreator(callback:(elementOrData:any, editorConfig:any) => Promise):void; + setDestructor(callback:(editor:ICKEditorInstance) => void):void; + create(elementOrData:any, editorConfig:any):Promise; + destroy():void; + on(listener:'stateChange', callback:() => void):void; + on(listener:'error', callback:(evt:Event, args:{ error:ICKEditorError }) => void):void; + editor:ICKEditorInstance; + state:ICKEditorState; +} + +export type ICKEditorMentionType = 'user' | 'work_package'; + +export interface ICKEditorContext { + resource?:{ + canAddAttachments?:boolean; + [key:string]:unknown; + }; + field?:string; + removePlugins?:string[]; + macros?:false|string[]; + options?:{ + rtl?:boolean; + }; + previewContext?:string; + disabledMentions?:ICKEditorMentionType[]; + storageKey?:string; +} + export class ConstrainedEditor extends DecoupledEditor {} export class FullEditor extends DecoupledEditor {} +export const OPEditorWatchdog = EditorWatchdog as unknown as ICKEditorWatchdog; + // Export the two common interfaces window.OPConstrainedEditor = ConstrainedEditor; window.OPClassicEditor = FullEditor; // Export the Watchdog feature -window.OPEditorWatchdog = EditorWatchdog; +window.OPEditorWatchdog = OPEditorWatchdog; FullEditor.createCustomized = configurationCustomizer(FullEditor); FullEditor.builtinPlugins = builtinPlugins; diff --git a/src/types.d.ts b/src/types.d.ts index 5c2d1bc..4d5a192 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -14,3 +14,7 @@ interface Window { OpenProject: any; I18n: any; } + +interface HTMLElement { + ckeditorInstance?:import("./op-ckeditor").ICKEditorInstance; +} From 2e97538e6048f0aaf9fe345ee0df14cbdce94aac Mon Sep 17 00:00:00 2001 From: Alexander Brandon Coles Date: Thu, 5 Mar 2026 13:38:56 -0300 Subject: [PATCH 05/11] Add dedicated CKEditor types entrypoint Introduce src/ckeditor-types.ts and export it via the package subpath '@openproject/commonmark-ckeditor-build/types'. Keep existing type exports from the main entrypoint and update README paths and type usage docs for downstream consumers. --- README.md | 21 +++++++-- package.json | 10 ++++ src/ckeditor-types.ts | 96 ++++++++++++++++++++++++++++++++++++++ src/op-ckeditor.ts | 106 ++++++------------------------------------ 4 files changed, 137 insertions(+), 96 deletions(-) create mode 100644 src/ckeditor-types.ts diff --git a/README.md b/README.md index d1db972..b0ff986 100644 --- a/README.md +++ b/README.md @@ -32,11 +32,27 @@ Building into the core is easy, just run `npm run build` -This will override the `app/assets/javascripts/vendor/ckeditor/*` contents with the newest webpack build. You need to run this before opening a pull request. +This will override the `frontend/src/vendor/ckeditor/*` contents with the newest webpack build. You need to run this before opening a pull request. > [!important] > Please ensure that for any changes in this repository, you have a core repository with the output of `npm run build`, so that all core tests can run and confirm your changes. Both pull requests should _always_ be merged at the same time, never alone +The generated output is written to: + +`frontend/src/vendor/ckeditor/*` + +### TypeScript types for downstream + +This package now emits declaration files into `build/types`. + +Downstream consumers can import shared editor interfaces from: + +```ts +import type { ICKEditorInstance, ICKEditorStatic } from '@openproject/commonmark-ckeditor-build/types'; +``` + +The main package entry also exports these interfaces. + ### Updating CKEditor @@ -54,7 +70,7 @@ We use `patch-package` (https://www.npmjs.com/package/patch-package) to store a - Run `npm run watch` -Now the webpack development mode is building the files and outputting them to `app/assets/javascripts/vendor/ckeditor/*`, overriding anything in there. +Now the webpack development mode is building the files and outputting them to `frontend/src/vendor/ckeditor/*`, overriding anything in there. @@ -67,4 +83,3 @@ As of version 11.2.0, this library no longer uses jQuery internally. All jQuery **Important for downstream consumers (e.g., OpenProject):** While this library no longer uses jQuery internally, downstream applications should continue to expose the jQuery global if other parts of the application depend on it. Do not remove the jQuery global from the downstream application (OpenProject) yet until all components have been migrated. For more details on the downstream migration, see: https://github.com/opf/openproject/pull/19429 - diff --git a/package.json b/package.json index 9fa3ed0..c044f9e 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,16 @@ ], "main": "./build/ckeditor.js", "types": "./build/types/op-ckeditor.d.ts", + "exports": { + ".": { + "types": "./build/types/op-ckeditor.d.ts", + "default": "./build/ckeditor.js" + }, + "./types": { + "types": "./build/types/ckeditor-types.d.ts", + "default": "./build/types/ckeditor-types.d.ts" + } + }, "files": [ "build" ], diff --git a/src/ckeditor-types.ts b/src/ckeditor-types.ts new file mode 100644 index 0000000..19a9bb3 --- /dev/null +++ b/src/ckeditor-types.ts @@ -0,0 +1,96 @@ +export interface CKEditorEvent { + stop: () => void; +} + +export interface CKEditorListenOptions { + priority?: string; +} + +export interface CKEditorDomEventData { + altKey: boolean; + shiftKey: boolean; + ctrlKey: boolean; + metaKey: boolean; + keyCode: number; +} + +export interface ICKEditorInstance { + id: string; + state: string; + getData(options?: { trim: boolean }): string; + setData(content: string): void; + destroy(): void; + enableReadOnlyMode(lockId: string): void; + disableReadOnlyMode(lockId: string): void; + on(event: string, callback: () => unknown): void; + listenTo( + node: unknown, + key: string, + callback: (evt: CKEditorEvent, data: CKEditorDomEventData) => unknown, + options?: CKEditorListenOptions + ): void; + model: { + on(ev: string, callback: () => unknown): void; + fire(ev: string, data: unknown): void; + document: { + on(ev: string, callback: () => unknown): void; + }; + }; + editing: { + view: { + focus(): void; + document: Document; + }; + }; + config: any; + ui: any; + element: HTMLElement; +} + +export interface ICKEditorStatic { + create(el: HTMLElement, config?: any): Promise; + createCustomized(el: string | HTMLElement, config?: any): Promise; + builtinPlugins: unknown[]; + defaultConfig: any; +} + +export type ICKEditorState = + | "initializing" + | "ready" + | "crashed" + | "crashedPermanently" + | "destroyed"; + +export interface ICKEditorError { + message: string; + stack: any; +} + +export interface ICKEditorWatchdog { + setCreator(callback: (elementOrData: any, editorConfig: any) => Promise): void; + setDestructor(callback: (editor: ICKEditorInstance) => void): void; + create(elementOrData: any, editorConfig: any): Promise; + destroy(): void; + on(listener: "stateChange", callback: () => void): void; + on(listener: "error", callback: (evt: Event, args: { error: ICKEditorError }) => void): void; + editor: ICKEditorInstance; + state: ICKEditorState; +} + +export type ICKEditorMentionType = "user" | "work_package"; + +export interface ICKEditorContext { + resource?: { + canAddAttachments?: boolean; + [key: string]: unknown; + }; + field?: string; + removePlugins?: string[]; + macros?: false | string[]; + options?: { + rtl?: boolean; + }; + previewContext?: string; + disabledMentions?: ICKEditorMentionType[]; + storageKey?: string; +} diff --git a/src/op-ckeditor.ts b/src/op-ckeditor.ts index 2cedc4f..d124007 100644 --- a/src/op-ckeditor.ts +++ b/src/op-ckeditor.ts @@ -4,99 +4,19 @@ import { EditorWatchdog } from '@ckeditor/ckeditor5-watchdog'; import {builtinPlugins} from './op-plugins'; import {defaultConfig} from "./op-ckeditor-config"; import {configurationCustomizer} from './op-config-customizer'; - -export interface CKEditorEvent { - stop:() => void; -} - -export interface CKEditorListenOptions { - priority?:string; -} - -export interface CKEditorDomEventData { - altKey:boolean; - shiftKey:boolean; - ctrlKey:boolean; - metaKey:boolean; - keyCode:number; -} - -export interface ICKEditorInstance { - id:string; - state:string; - getData(options?:{ trim:boolean }):string; - setData(content:string):void; - destroy():void; - enableReadOnlyMode(lockId:string):void; - disableReadOnlyMode(lockId:string):void; - on(event:string, callback:() => unknown):void; - listenTo( - node:unknown, - key:string, - callback:(evt:CKEditorEvent, data:CKEditorDomEventData) => unknown, - options?:CKEditorListenOptions - ):void; - model:{ - on(ev:string, callback:() => unknown):void; - fire(ev:string, data:unknown):void; - document:{ - on(ev:string, callback:() => unknown):void; - }; - }; - editing:{ - view:{ - focus():void; - document:Document; - }; - }; - config:any; - ui:any; - element:HTMLElement; -} - -export interface ICKEditorStatic { - create(el:HTMLElement, config?:any):Promise; - createCustomized(el:string|HTMLElement, config?:any):Promise; - builtinPlugins:unknown[]; - defaultConfig:any; -} - -export type ICKEditorState = - 'initializing' | 'ready' | 'crashed' | 'crashedPermanently' | 'destroyed'; - -export interface ICKEditorError { - message:string; - stack:any; -} - -export interface ICKEditorWatchdog { - setCreator(callback:(elementOrData:any, editorConfig:any) => Promise):void; - setDestructor(callback:(editor:ICKEditorInstance) => void):void; - create(elementOrData:any, editorConfig:any):Promise; - destroy():void; - on(listener:'stateChange', callback:() => void):void; - on(listener:'error', callback:(evt:Event, args:{ error:ICKEditorError }) => void):void; - editor:ICKEditorInstance; - state:ICKEditorState; -} - -export type ICKEditorMentionType = 'user' | 'work_package'; - -export interface ICKEditorContext { - resource?:{ - canAddAttachments?:boolean; - [key:string]:unknown; - }; - field?:string; - removePlugins?:string[]; - macros?:false|string[]; - options?:{ - rtl?:boolean; - }; - previewContext?:string; - disabledMentions?:ICKEditorMentionType[]; - storageKey?:string; -} +import type { ICKEditorWatchdog } from './ckeditor-types'; +export type { + CKEditorEvent, + CKEditorListenOptions, + CKEditorDomEventData, + ICKEditorInstance, + ICKEditorStatic, + ICKEditorState, + ICKEditorError, + ICKEditorWatchdog, + ICKEditorMentionType, + ICKEditorContext +} from './ckeditor-types'; export class ConstrainedEditor extends DecoupledEditor {} export class FullEditor extends DecoupledEditor {} From cc1537fb9ccb8efc800287f777cff9b2c00e9e8e Mon Sep 17 00:00:00 2001 From: Alexander Brandon Coles Date: Thu, 5 Mar 2026 13:51:45 -0300 Subject: [PATCH 06/11] Copy emitted types into vendored core assets Add a build-time copy step for generated declaration files. During build, copy types into OPENPROJECT_CORE frontend vendor ckeditor paths so downstream can import via core-vendor aliases. --- README.md | 4 ++++ bin/clean.sh | 2 ++ bin/copy-types.sh | 16 ++++++++++++++++ package.json | 2 +- 4 files changed, 23 insertions(+), 1 deletion(-) create mode 100755 bin/copy-types.sh diff --git a/README.md b/README.md index b0ff986..71f99ac 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,10 @@ The generated output is written to: ### TypeScript types for downstream This package now emits declaration files into `build/types`. +During `npm run build`, those declarations are also copied into: + +- `frontend/src/vendor/ckeditor/types.d.ts` +- `frontend/src/vendor/ckeditor/op-ckeditor.d.ts` Downstream consumers can import shared editor interfaces from: diff --git a/bin/clean.sh b/bin/clean.sh index fcab97c..7ca20a9 100755 --- a/bin/clean.sh +++ b/bin/clean.sh @@ -6,3 +6,5 @@ BUILD_FOLDER=$(realpath "${OPENPROJECT_CORE}/frontend/src/vendor/ckeditor/") echo "Clearing current build folder ${BUILD_FOLDER}" rm -rf "${BUILD_FOLDER}/ckeditor.*" || true rm -rf "${BUILD_FOLDER}/translations/" || true +rm -rf "${BUILD_FOLDER}/types.d.ts" || true +rm -rf "${BUILD_FOLDER}/op-ckeditor.d.ts" || true diff --git a/bin/copy-types.sh b/bin/copy-types.sh new file mode 100755 index 0000000..0115d26 --- /dev/null +++ b/bin/copy-types.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +set -eu + +: ${OPENPROJECT_CORE?"Need to set OPENPROJECT_CORE"} + +BUILD_FOLDER=$(realpath "${OPENPROJECT_CORE}/frontend/src/vendor/ckeditor/") +TYPES_FOLDER="build/types" + +if [ ! -f "${TYPES_FOLDER}/ckeditor-types.d.ts" ]; then + echo "Missing generated type file: ${TYPES_FOLDER}/ckeditor-types.d.ts" + exit 1 +fi + +cp "${TYPES_FOLDER}/ckeditor-types.d.ts" "${BUILD_FOLDER}/types.d.ts" +cp "${TYPES_FOLDER}/op-ckeditor.d.ts" "${BUILD_FOLDER}/op-ckeditor.d.ts" diff --git a/package.json b/package.json index c044f9e..0356c54 100644 --- a/package.json +++ b/package.json @@ -105,7 +105,7 @@ "scripts": { "prebuild": "sh bin/clean.sh", "build": "NODE_ENV=production ./node_modules/.bin/webpack --mode production && npm run build:types", - "build:types": "tsc -p tsconfig.json", + "build:types": "tsc -p tsconfig.json && sh bin/copy-types.sh", "typecheck": "tsc -p tsconfig.json --noEmit", "preversion": "npm run build; if [ -n \"$(git status src/op-ckeditor.ts build/ --porcelain)\" ]; then git add -u src/op-ckeditor.ts build/ && git commit -m 'Internal: Build.'; fi", "prewatch": "sh bin/clean.sh", From edfa793470500722d8930a88c7c9814e278c0d8d Mon Sep 17 00:00:00 2001 From: Alexander Brandon Coles Date: Thu, 5 Mar 2026 16:30:36 -0300 Subject: [PATCH 07/11] Complete TypeScript conversion and type tightening Squash the branch history into one commit that removes ts-nocheck usage and tightens CKEditor/OpenProject typings across modules. --- src/ckeditor-types.ts | 73 ++++--------------- src/commonmark/commonmark.ts | 15 +++- src/commonmark/commonmarkdataprocessor.ts | 47 ++++++------ src/commonmark/utils/fix-breaks.ts | 71 ++++++++++-------- .../utils/fix-tasklist-whitespaces.ts | 10 +-- .../utils/hoist-task-list-checkboxes.ts | 13 +++- src/commonmark/utils/page-breaks.ts | 4 +- src/commonmark/utils/preprocessor.ts | 56 ++++++++------ src/helpers/button-disabler.ts | 53 ++++++++++---- src/helpers/create-toolbar-edit-button.ts | 7 +- src/helpers/create-toolbar.ts | 24 +++--- src/mentions/emoji-mentions.ts | 7 +- src/mentions/mentions-caster.ts | 1 - src/mentions/mentions-item-renderer.ts | 16 ++-- src/mentions/user-mentions.ts | 22 ++++-- src/mentions/work-package-mentions.ts | 13 ++-- src/op-ckeditor-config.ts | 1 - src/op-ckeditor.ts | 36 ++++++--- src/op-config-customizer.ts | 51 +++++++++++-- src/op-plugins.ts | 27 ++++--- src/plugins/code-block/click-observer.ts | 11 +-- src/plugins/code-block/code-block-editing.ts | 1 - src/plugins/code-block/code-block-toolbar.ts | 1 - src/plugins/code-block/code-block.ts | 2 - src/plugins/code-block/converters.ts | 19 +++-- src/plugins/code-block/widget.ts | 1 - src/plugins/op-attachment-listener-plugin.ts | 30 ++++++-- src/plugins/op-content-revisions/command.ts | 8 +- .../op-content-revisions.ts | 20 +++-- src/plugins/op-content-revisions/storage.ts | 46 +++++++++--- src/plugins/op-content-revisions/ui.ts | 40 ++++++---- src/plugins/op-content-revisions/utils.ts | 5 +- src/plugins/op-context/op-context.ts | 21 +++--- src/plugins/op-custom-css-classes-plugin.ts | 51 ++++++++----- .../op-help-link-plugin.ts | 3 +- .../op-image-attachment-lookup-plugin.ts | 1 - .../op-macro-child-pages-editing.ts | 1 - .../op-macro-child-pages-plugin.ts | 1 - .../op-macro-child-pages-toolbar.ts | 3 +- src/plugins/op-macro-child-pages/utils.ts | 1 - .../embedded-table-editing.ts | 8 +- .../embedded-table-plugin.ts | 1 - .../embedded-table-toolbar.ts | 1 - src/plugins/op-macro-embedded-table/utils.ts | 1 - src/plugins/op-macro-list-plugin.ts | 13 +++- src/plugins/op-macro-toc-plugin.ts | 1 - .../op-macro-wp-button-editing.ts | 3 +- .../op-macro-wp-button-plugin.ts | 1 - .../op-macro-wp-button-toolbar.ts | 1 - src/plugins/op-macro-wp-button/utils.ts | 1 - src/plugins/op-preview.plugin.ts | 1 - src/plugins/op-source-code.plugin.ts | 3 +- src/plugins/op-upload-plugin.ts | 4 +- src/plugins/op-upload-resource-adapter.ts | 50 ++++++++++--- 54 files changed, 549 insertions(+), 353 deletions(-) diff --git a/src/ckeditor-types.ts b/src/ckeditor-types.ts index 19a9bb3..8d0f387 100644 --- a/src/ckeditor-types.ts +++ b/src/ckeditor-types.ts @@ -1,3 +1,8 @@ +import type { Editor, EditorConfig, PluginConstructor } from '@ckeditor/ckeditor5-core'; +import type EditorWatchdog from '@ckeditor/ckeditor5-watchdog/src/editorwatchdog'; +import type { WatchdogState } from '@ckeditor/ckeditor5-watchdog/src/watchdog'; +import type { CKEditorError } from '@ckeditor/ckeditor5-utils'; + export interface CKEditorEvent { stop: () => void; } @@ -14,75 +19,29 @@ export interface CKEditorDomEventData { keyCode: number; } -export interface ICKEditorInstance { - id: string; - state: string; - getData(options?: { trim: boolean }): string; - setData(content: string): void; - destroy(): void; - enableReadOnlyMode(lockId: string): void; - disableReadOnlyMode(lockId: string): void; - on(event: string, callback: () => unknown): void; - listenTo( - node: unknown, - key: string, - callback: (evt: CKEditorEvent, data: CKEditorDomEventData) => unknown, - options?: CKEditorListenOptions - ): void; - model: { - on(ev: string, callback: () => unknown): void; - fire(ev: string, data: unknown): void; - document: { - on(ev: string, callback: () => unknown): void; - }; - }; - editing: { - view: { - focus(): void; - document: Document; - }; - }; - config: any; - ui: any; - element: HTMLElement; -} +export type ICKEditorInstance = Editor; export interface ICKEditorStatic { - create(el: HTMLElement, config?: any): Promise; - createCustomized(el: string | HTMLElement, config?: any): Promise; - builtinPlugins: unknown[]; - defaultConfig: any; + create(el: HTMLElement, config?: EditorConfig): Promise; + createCustomized(el: string | HTMLElement, config?: EditorConfig): Promise; + builtinPlugins: PluginConstructor[]; + defaultConfig?: EditorConfig; } -export type ICKEditorState = - | "initializing" - | "ready" - | "crashed" - | "crashedPermanently" - | "destroyed"; +export type ICKEditorState = WatchdogState; -export interface ICKEditorError { - message: string; - stack: any; -} +export type ICKEditorError = CKEditorError; -export interface ICKEditorWatchdog { - setCreator(callback: (elementOrData: any, editorConfig: any) => Promise): void; - setDestructor(callback: (editor: ICKEditorInstance) => void): void; - create(elementOrData: any, editorConfig: any): Promise; - destroy(): void; - on(listener: "stateChange", callback: () => void): void; - on(listener: "error", callback: (evt: Event, args: { error: ICKEditorError }) => void): void; - editor: ICKEditorInstance; - state: ICKEditorState; -} +export type ICKEditorWatchdog = typeof EditorWatchdog; export type ICKEditorMentionType = "user" | "work_package"; +type OpenProjectContextValue = string | number | boolean | null | undefined | string[]; + export interface ICKEditorContext { resource?: { canAddAttachments?: boolean; - [key: string]: unknown; + [key: string]: OpenProjectContextValue; }; field?: string; removePlugins?: string[]; diff --git a/src/commonmark/commonmark.ts b/src/commonmark/commonmark.ts index a68f540..00519d7 100644 --- a/src/commonmark/commonmark.ts +++ b/src/commonmark/commonmark.ts @@ -1,4 +1,3 @@ -// @ts-nocheck /** * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. * For licensing, see LICENSE.md. @@ -6,8 +5,18 @@ import CommonMarkDataProcessor from './commonmarkdataprocessor'; +interface CommonMarkEditor { + data:{ + processor:unknown; + }; + editing:{ + view:{ + document:unknown; + }; + }; +} + // Simple plugin which loads the data processor. -export default function CommonMarkPlugin(editor) { +export default function CommonMarkPlugin(editor:CommonMarkEditor) { editor.data.processor = new CommonMarkDataProcessor(editor.editing.view.document); } - diff --git a/src/commonmark/commonmarkdataprocessor.ts b/src/commonmark/commonmarkdataprocessor.ts index 2273647..187ca87 100644 --- a/src/commonmark/commonmarkdataprocessor.ts +++ b/src/commonmark/commonmarkdataprocessor.ts @@ -1,4 +1,3 @@ -// @ts-nocheck /** * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. * For licensing, see LICENSE.md. @@ -29,7 +28,10 @@ export const originalSrcAttribute = 'data-original-src'; * @implements module:engine/dataprocessor/dataprocessor~DataProcessor */ export default class CommonMarkDataProcessor { - constructor(document) { + _htmlDP:any; + _domConverter:any; + + constructor(document:any) { this._htmlDP = new HtmlDataProcessor(document); this._domConverter = new DomConverter(document); } @@ -40,7 +42,7 @@ export default class CommonMarkDataProcessor { * @param {String} data A CommonMark string. * @returns {module:engine/view/documentfragment~DocumentFragment} The converted view element. */ - toView(data) { + toView(data:any) { const md = markdownIt({ // Output html html: true, @@ -92,7 +94,7 @@ export default class CommonMarkDataProcessor { * @param {module:engine/view/documentfragment~DocumentFragment} viewFragment * @returns {String} CommonMark string. */ - toData(viewFragment) { + toData(viewFragment:any) { // Convert view DocumentFragment to DOM DocumentFragment. const domFragment = this._domConverter.viewToDom(viewFragment, document); @@ -103,14 +105,15 @@ export default class CommonMarkDataProcessor { ['strong', 'em'], // Ensure tables are allowed to have HTML contents // OP#29457 - ['pre', 'code', 'table'] + ['pre', 'code', 'table'], + [] ); // Replace link attributes with their computed href attribute - linkPreprocessor(domFragment); + linkPreprocessor(domFragment, [], []); // Turndown is filtering out empty paragraphs

, so we need to fix that with


- breaksPreprocessor(domFragment); + breaksPreprocessor(domFragment, [], []); const blankReplacement = function (content, node) { if (node.tagName === 'CODE') { @@ -147,13 +150,13 @@ export default class CommonMarkDataProcessor { */ turndownService.addRule('taskListItems', { filter: function (node) { - const nodeIsCheckbox = node.type === "checkbox"; + const nodeIsCheckbox = (node as any).type === "checkbox"; const parentIsListItem = node.parentNode && node.parentNode.nodeName === 'LI'; const grandparentIsListItem = node.parentNode && node.parentNode.parentNode && node.parentNode.parentNode.nodeName === 'LI'; return nodeIsCheckbox && (parentIsListItem || grandparentIsListItem); }, replacement: function (content, node) { - return (node.checked ? '[x]' : '[ ]') + ' ' + return ((node as any).checked ? '[x]' : '[ ]') + ' ' } }) @@ -186,7 +189,7 @@ export default class CommonMarkDataProcessor { .replace(/^\n+/, '') // remove leading newlines .replace(/\n+$/, '\n'); // replace trailing newlines with just a single one - var parent = node.parentNode; + const parent:any = node.parentNode; var prefix = options.bulletListMarker + ' '; var number = 1; if (parent.nodeName === 'OL') { @@ -210,12 +213,12 @@ export default class CommonMarkDataProcessor { turndownService.addRule('imageFigure', { filter: 'img', replacement: function (content, node) { - const parent = node.parentElement; + const parent:any = node.parentElement; if (parent && parent.classList.contains('op-uc-figure--content')) { return parent.parentElement.outerHTML; } - return node.outerHTML; + return (node as any).outerHTML; } }); @@ -233,13 +236,13 @@ export default class CommonMarkDataProcessor { return node.nodeName === 'TABLE' && (!node.parentElement || node.parentElement.nodeName !== 'FIGURE'); }, replacement: function (_content, node) { - return node.outerHTML; // we do not convert back to markdown, but use HTML for tables + return (node as any).outerHTML; // we do not convert back to markdown, but use HTML for tables } }); // Keep HTML tables and remove filler elements - turndownService.addRule('htmlTables', { - filter: function (node) { + turndownService.addRule('htmlTables', { + filter: function (node:any) { const tables = node.getElementsByTagName('table'); // check if we're a todo list item return node.nodeName === 'FIGURE' && tables.length; @@ -252,22 +255,22 @@ export default class CommonMarkDataProcessor { } }); - return node.outerHTML; + return (node as any).outerHTML; } }); turndownService.addRule('strikethrough', { - filter: ['del', 's', 'strike'], + filter: ['del', 's', 'strike'] as any, replacement: function (content) { return '~~' + content + '~~' } }); turndownService.addRule('openProjectMacros', { - filter: ['macro'], + filter: ['macro'] as any, replacement: (_content, node) => { - node.innerHTML = ''; - const outer = node.outerHTML; + (node as any).innerHTML = ''; + const outer = (node as any).outerHTML; return outer.replace("", "\n") } }); @@ -279,7 +282,7 @@ export default class CommonMarkDataProcessor { node.classList.contains('mention') ) }, - replacement: (_content, node) => node.outerHTML, + replacement: (_content, node) => (node as any).outerHTML, }); turndownService.addRule('emptyParagraphs', { @@ -294,7 +297,7 @@ export default class CommonMarkDataProcessor { replacement: (_content, node) => { if (!node.parentElement && !node.nextSibling && !node.previousSibling) { //document with only one empty paragraph return ''; - } else if (node.childNodes.length === 1 && isPageBreakNode(node.childNodes[0])) { + } else if (node.childNodes.length === 1 && isPageBreakNode(node.childNodes[0] as any)) { return PAGE_BREAK_MARKDOWN + '\n\n' } else { return '
\n\n' diff --git a/src/commonmark/utils/fix-breaks.ts b/src/commonmark/utils/fix-breaks.ts index ac23348..21876d4 100644 --- a/src/commonmark/utils/fix-breaks.ts +++ b/src/commonmark/utils/fix-breaks.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import {isPageBreakNode} from "./page-breaks"; /** @@ -8,26 +7,30 @@ import {isPageBreakNode} from "./page-breaks"; * e.g. `

Demo


End

` converted to `

Demo



End

` * to avoid this, we remove the breaks, so CKEditor can add `
` * e.g. `

Demo


End

` converted to `

Demo


End

` */ -export function fixBreaksInTables(root) { +export function fixBreaksInTables(root:Node) { const walker = document.createNodeIterator( root, // Only consider element nodes NodeFilter.SHOW_ELEMENT, - // Only except text nodes whose parent is one of parents { - acceptNode: function (node) { - if (node.tagName === 'P' && node.parentElement && - node.parentElement.tagName === 'TD' && - (node.childNodes.length === 1 && node.childNodes[0].nodeName === 'BR')) { + acceptNode: function (node:Node) { + if (!(node instanceof Element)) { + return NodeFilter.FILTER_REJECT; + } + + const onlyBreak = node.childNodes.length === 1 && node.childNodes[0].nodeName === 'BR'; + if (node.tagName === 'P' && node.parentElement?.tagName === 'TD' && onlyBreak) { return NodeFilter.FILTER_ACCEPT; } + + return NodeFilter.FILTER_REJECT; } } ); - let node; - while (node = walker.nextNode()) { - node.childNodes[0].remove(); + let node:Node | null; + while ((node = walker.nextNode())) { + node.firstChild?.remove(); } } @@ -40,31 +43,33 @@ export function fixBreaksInTables(root) { * e.g. `

Demo



End

` will be converted to `

Demo

End

` * (except for page breaks, which are kept but are wrapped in a paragraph) */ -export function fixBreaksOnRootLevel(root) { - let walker = document.createNodeIterator( +export function fixBreaksOnRootLevel(root:Node) { + const walker = document.createNodeIterator( root, NodeFilter.SHOW_ELEMENT, { - acceptNode: function (node) { - if (node.tagName === 'BR' && !node.parentElement) { + acceptNode: function (node:Node) { + if (node instanceof Element && node.tagName === 'BR' && !node.parentElement) { return NodeFilter.FILTER_ACCEPT; } + + return NodeFilter.FILTER_REJECT; } } ); - let node; - let list = [] - while (node = walker.nextNode()) { + const list:Node[] = []; + let node:Node | null; + while ((node = walker.nextNode())) { list.push(node); } - for (const node of list) { - const p = document.createElement('p'); - root.insertBefore(p, node); - if (isPageBreakNode(node)) { - p.appendChild(node); + for (const breakNode of list) { + const paragraph = document.createElement('p'); + root.insertBefore(paragraph, breakNode); + if (breakNode instanceof Element && isPageBreakNode(breakNode)) { + paragraph.appendChild(breakNode); } else { - node.remove(); + breakNode.parentNode?.removeChild(breakNode); } } } @@ -79,26 +84,28 @@ export function fixBreaksOnRootLevel(root) { * e.g. `
  • Start



    End

  • ` will be converted to * `
  • Start

    End

  • >` */ -export function fixBreaksInLists(root) { +export function fixBreaksInLists(root:Node) { const walker = document.createNodeIterator( root, NodeFilter.SHOW_ELEMENT, { - acceptNode: function (node) { - if (node.tagName === 'BR' && node.parentElement && node.parentElement.tagName === 'LI') { + acceptNode: function (node:Node) { + if (node instanceof Element && node.tagName === 'BR' && node.parentElement?.tagName === 'LI') { return NodeFilter.FILTER_ACCEPT; } + + return NodeFilter.FILTER_REJECT; } } ); - let node; - let list = [] - while (node = walker.nextNode()) { + const list:Node[] = []; + let node:Node | null; + while ((node = walker.nextNode())) { list.push(node); } - for (const node of list) { - node.parentElement.insertBefore(document.createElement('p'), node); - node.remove(); + for (const breakNode of list) { + breakNode.parentElement?.insertBefore(document.createElement('p'), breakNode); + breakNode.parentNode?.removeChild(breakNode); } } diff --git a/src/commonmark/utils/fix-tasklist-whitespaces.ts b/src/commonmark/utils/fix-tasklist-whitespaces.ts index 5b2d589..53e92bd 100644 --- a/src/commonmark/utils/fix-tasklist-whitespaces.ts +++ b/src/commonmark/utils/fix-tasklist-whitespaces.ts @@ -1,21 +1,19 @@ -// @ts-nocheck - /** * Remove multiple whitespaces in task list text nodes */ -export function fixTasklistWhitespaces(root) { +export function fixTasklistWhitespaces(root:Node) { let walker = document.createNodeIterator( root, // Only consider text nodes NodeFilter.SHOW_TEXT, ); - let node; - while(node = walker.nextNode()) { + let node:Text|null; + while((node = walker.nextNode() as Text | null)) { // Remove duplicate whitespace in tasklists if (node.previousElementSibling && node.previousElementSibling.classList.contains('task-list-item-checkbox')) { - node.textContent = node.textContent.replace(/^\s+/, ''); + node.textContent = (node.textContent || '').replace(/^\s+/, ''); } } } diff --git a/src/commonmark/utils/hoist-task-list-checkboxes.ts b/src/commonmark/utils/hoist-task-list-checkboxes.ts index 3538790..1e99fd2 100644 --- a/src/commonmark/utils/hoist-task-list-checkboxes.ts +++ b/src/commonmark/utils/hoist-task-list-checkboxes.ts @@ -1,8 +1,13 @@ -// @ts-nocheck -export function hoistTaskListCheckboxes(fragment) { +interface TaskListContainer { + querySelectorAll(selectors:string):{ + forEach(callback:(checkbox:HTMLInputElement) => void):void; + }; +} + +export function hoistTaskListCheckboxes(fragment:TaskListContainer) { const checkboxes = fragment.querySelectorAll('input.task-list-item-checkbox'); checkboxes.forEach(checkbox => { - const li = checkbox.closest('li.task-list-item'); + const li = checkbox.closest('li.task-list-item'); if (li && checkbox.parentElement !== li) { // Remove checkbox from its current parent checkbox.parentElement && checkbox.parentElement.removeChild(checkbox); @@ -10,4 +15,4 @@ export function hoistTaskListCheckboxes(fragment) { li.insertBefore(checkbox, li.firstChild); } }); -} \ No newline at end of file +} diff --git a/src/commonmark/utils/page-breaks.ts b/src/commonmark/utils/page-breaks.ts index 0354a1f..09cf01a 100644 --- a/src/commonmark/utils/page-breaks.ts +++ b/src/commonmark/utils/page-breaks.ts @@ -1,7 +1,5 @@ -// @ts-nocheck - export const PAGE_BREAK_MARKDOWN = '
    '; -export function isPageBreakNode(node) { +export function isPageBreakNode(node:Element) { const style = node.getAttribute('style') || ''; return style.includes('page-break-'); } diff --git a/src/commonmark/utils/preprocessor.ts b/src/commonmark/utils/preprocessor.ts index b576bf9..b8ddda6 100644 --- a/src/commonmark/utils/preprocessor.ts +++ b/src/commonmark/utils/preprocessor.ts @@ -1,33 +1,35 @@ -// @ts-nocheck /** * Replace whitespace of text nodes within the given parents in the given root element. * @param {*} root An HTMLElement to look for text nodes within * @param {*} allowed_whitespace_nodes String array of allowed text nodes ( ['STRONG', 'EM'] ... ) * @param {*} allowed_raw_nodes String array of allowed raw text nodes ( ['PRE', 'CODE'] ... ) */ -export function textNodesPreprocessor(root, allowed_whitespace_nodes, allowed_raw_nodes) { +export function textNodesPreprocessor(root:Node, allowed_whitespace_nodes:string[], allowed_raw_nodes:string[], _unused:string[] = []) { allowed_whitespace_nodes = allowed_whitespace_nodes.map(el => el.toUpperCase()); allowed_raw_nodes = allowed_raw_nodes.map(el => el.toUpperCase()); - let walker = document.createNodeIterator( + const walker = document.createNodeIterator( root, // Only consider text nodes NodeFilter.SHOW_TEXT, ); - let node; - while (node = walker.nextNode()) { + let node:Node | null; + while ((node = walker.nextNode())) { + const textNode = node as Text; + const value = textNode.nodeValue ?? ''; + // Strip NBSP whitespace in given nodes - if (node.parentElement && allowed_whitespace_nodes.indexOf(node.parentElement.nodeName) >= 0) { - node.nodeValue = node.nodeValue + if (textNode.parentElement && allowed_whitespace_nodes.includes(textNode.parentElement.nodeName)) { + textNode.nodeValue = value .replace(/^[\u00a0]+/g, ' ') .replace(/[\u00a0]+$/g, ' '); } // Re-encode < and > that would otherwise be output as HTML by turndown // https://github.com/domchristie/turndown/issues/106 - if (!hasParentOfType(node, allowed_raw_nodes)) { - node.nodeValue = _.escape(node.nodeValue); + if (!hasParentOfType(textNode, allowed_raw_nodes)) { + textNode.nodeValue = _.escape(textNode.nodeValue ?? ''); } } } @@ -39,49 +41,55 @@ export function textNodesPreprocessor(root, allowed_whitespace_nodes, allowed_ra * @param {*} allowed_whitespace_nodes * @param {*} allowed_raw_nodes */ -export function linkPreprocessor(root, _allowed_whitespace_nodes, _allowed_raw_nodes) { - let walker = document.createNodeIterator( +export function linkPreprocessor(root:Node, _allowed_whitespace_nodes:string[], _allowed_raw_nodes:string[]) { + const walker = document.createNodeIterator( root, // Only consider element nodes NodeFilter.SHOW_ELEMENT, // Accept only A tags - function (node) { - return node.nodeName.toLowerCase() === 'a' ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT; + function (node:Node) { + return node instanceof HTMLAnchorElement ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_REJECT; } ); - let node; - while (node = walker.nextNode()) { + let node:Node | null; + while ((node = walker.nextNode())) { + const link = node as HTMLAnchorElement; // node.href is properly escaped, while the attribute is not // and turndown uses the getAttribute version - node.setAttribute('href', node.href); + link.setAttribute('href', link.href); } } -export function breaksPreprocessor(root, _allowed_whitespace_nodes, _allowed_raw_nodes) { - let walker = document.createNodeIterator( +export function breaksPreprocessor(root:Node, _allowed_whitespace_nodes:string[], _allowed_raw_nodes:string[]) { + const walker = document.createNodeIterator( root, NodeFilter.SHOW_ELEMENT, { - acceptNode: function (node) { - if (node.tagName === 'P' && node.childNodes.length === 0 && (!node.parentElement || node.parentElement.tagName === 'LI')) { + acceptNode: function (node:Node) { + if (node instanceof Element + && node.tagName === 'P' + && node.childNodes.length === 0 + && (!node.parentElement || node.parentElement.tagName === 'LI')) { return NodeFilter.FILTER_ACCEPT; } + + return NodeFilter.FILTER_REJECT; } } ); - let node; - while (node = walker.nextNode()) { + let node:Node | null; + while ((node = walker.nextNode())) { node.appendChild(document.createElement('br')); } } -export function hasParentOfType(node, tagNames) { +export function hasParentOfType(node:Node, tagNames:string[]) { let parent = node.parentElement; while (parent) { - if (tagNames.indexOf(parent.tagName) >= 0) { + if (tagNames.includes(parent.tagName)) { return true; } diff --git a/src/helpers/button-disabler.ts b/src/helpers/button-disabler.ts index 1e005cb..17af811 100644 --- a/src/helpers/button-disabler.ts +++ b/src/helpers/button-disabler.ts @@ -1,42 +1,63 @@ -// @ts-nocheck import {FileDialogButtonView} from '@ckeditor/ckeditor5-ui'; +import type {Editor} from '@ckeditor/ckeditor5-core'; -export function getToolbarItems(editor) { +interface ToggleableView { + isEnabled:boolean; +} + +type ToolbarItem = FileDialogButtonView | ToggleableView; + +interface EditorUIViewWithToolbar { + toolbar?:{ + items:Iterable; + }; +} + +interface ToolbarEditor extends Editor { + __currentlyDisabled?:ToggleableView[]; +} + +export function getToolbarItems(editor:ToolbarEditor):ToolbarItem[] { editor.__currentlyDisabled = editor.__currentlyDisabled || []; + const editorUIView = editor.ui.view as EditorUIViewWithToolbar; - if (!editor.ui.view.toolbar) { + if (!editorUIView.toolbar) { return []; } - return editor.ui.view.toolbar.items._items; + return Array.from(editorUIView.toolbar.items); } -export function disableItems(editor, except) { +export function disableItems(editor:ToolbarEditor, except:ToolbarItem | null) { getToolbarItems(editor).forEach((item) => { - let toDisable = item; + let toDisable:ToggleableView | null = null; if (item instanceof FileDialogButtonView) { - toDisable = item.buttonView; - } else if (item === except || !Object.prototype.hasOwnProperty.call(item, 'isEnabled')) { - toDisable = null; + toDisable = item.buttonView as ToggleableView; + } else if (item !== except && typeof item === 'object' && item !== null && 'isEnabled' in item) { + toDisable = item as ToggleableView; } - if (!toDisable) { - // do nothing - } else if (toDisable.isEnabled) { + if (toDisable?.isEnabled) { toDisable.isEnabled = false; - } else { + } else if (toDisable) { editor.__currentlyDisabled.push(toDisable); } }); } -export function enableItems(editor) { +export function enableItems(editor:ToolbarEditor) { getToolbarItems(editor).forEach((item) => { - let toEnable = item; + let toEnable:ToggleableView | null = null; if (item instanceof FileDialogButtonView) { - toEnable = item.buttonView; + toEnable = item.buttonView as ToggleableView; + } else if (typeof item === 'object' && item !== null && 'isEnabled' in item) { + toEnable = item as ToggleableView; + } + + if (!toEnable) { + return; } if (editor.__currentlyDisabled.indexOf(toEnable) < 0) { diff --git a/src/helpers/create-toolbar-edit-button.ts b/src/helpers/create-toolbar-edit-button.ts index 059b435..47ebea9 100644 --- a/src/helpers/create-toolbar-edit-button.ts +++ b/src/helpers/create-toolbar-edit-button.ts @@ -1,8 +1,11 @@ -// @ts-nocheck import imageIcon from '../icons/edit.svg'; import { ButtonView } from '@ckeditor/ckeditor5-ui'; +import type {Editor} from '@ckeditor/ckeditor5-core'; +import type ModelElement from '@ckeditor/ckeditor5-engine/src/model/element'; -export function createToolbarEditButton(editor, name, callback) { +type EditToolbarCallback = (widget:ModelElement) => void; + +export function createToolbarEditButton(editor:Editor, name:string, callback:EditToolbarCallback) { // Add editing button editor.ui.componentFactory.add( name, locale => { const view = new ButtonView( locale ); diff --git a/src/helpers/create-toolbar.ts b/src/helpers/create-toolbar.ts index db210ee..a536d61 100644 --- a/src/helpers/create-toolbar.ts +++ b/src/helpers/create-toolbar.ts @@ -1,28 +1,32 @@ -// @ts-nocheck import { ToolbarView } from '@ckeditor/ckeditor5-ui'; import { BalloonPanelView } from '@ckeditor/ckeditor5-ui'; +import { ContextualBalloon } from '@ckeditor/ckeditor5-ui'; +import type {Editor, Plugin} from '@ckeditor/ckeditor5-core'; +import type DocumentSelection from '@ckeditor/ckeditor5-engine/src/view/documentselection'; const balloonClassName = 'ck-toolbar-container'; +type IsWidgetSelected = (selection:DocumentSelection) => boolean; + export function createEditToolbar( // Plugin instance - plugin, + plugin:Plugin, // Editor instance - editor, + editor:Editor, // Configuration namespace in op-ckeditor.js - config_namespace, + config_namespace:string, // Callback to check if widget is selected - isWidgetSelected + isWidgetSelected:IsWidgetSelected ) { - const toolbarConfig = editor.config.get( config_namespace + '.toolbar' ); + const toolbarConfig = editor.config.get( config_namespace + '.toolbar' ) as string[] | undefined; // Don't add the toolbar if there is no configuration. if ( !toolbarConfig || !toolbarConfig.length ) { return; } - const _balloon = editor.plugins.get( 'ContextualBalloon' ); + const _balloon = editor.plugins.get( 'ContextualBalloon' ) as ContextualBalloon; const _toolbar = new ToolbarView( editor.locale ); function _checkIsVisible() { @@ -80,8 +84,8 @@ export function createEditToolbar( * * @param {module:core/editor/editor~Editor} editor The editor instance. */ -function repositionContextualBalloon( editor, selectionCallback ) { - const balloon = editor.plugins.get( 'ContextualBalloon' ); +function repositionContextualBalloon( editor:Editor, selectionCallback:IsWidgetSelected ) { + const balloon = editor.plugins.get( 'ContextualBalloon' ) as ContextualBalloon; if ( selectionCallback( editor.editing.view.document.selection ) ) { const position = getBalloonPositionData( editor ); @@ -99,7 +103,7 @@ function repositionContextualBalloon( editor, selectionCallback ) { * @param {module:core/editor/editor~Editor} editor The editor instance. * @returns {module:utils/dom/position~Options} */ -function getBalloonPositionData( editor ) { +function getBalloonPositionData( editor:Editor ) { const editingView = editor.editing.view; const defaultPositions = BalloonPanelView.defaultPositions; diff --git a/src/mentions/emoji-mentions.ts b/src/mentions/emoji-mentions.ts index a2b8194..7907eb6 100644 --- a/src/mentions/emoji-mentions.ts +++ b/src/mentions/emoji-mentions.ts @@ -1,8 +1,7 @@ -// @ts-nocheck import emojis from './emojis.json'; -export function emojiMentions(query) { - function isNameOrKeywords( query, name, keywords ) { +export function emojiMentions(query:string) { + function isNameOrKeywords( query:string, name:string, keywords:string[] ) { if ( name.includes(query) ) { return true; } @@ -16,7 +15,7 @@ export function emojiMentions(query) { return false; } - return new Promise((resolve, _reject) => { + return new Promise((resolve) => { const emojiStore = emojis; const matches = emojiStore .filter((emoji) => isNameOrKeywords(query, emoji.id, emoji.keywords)) diff --git a/src/mentions/mentions-caster.ts b/src/mentions/mentions-caster.ts index 4763f54..4ce6fc2 100644 --- a/src/mentions/mentions-caster.ts +++ b/src/mentions/mentions-caster.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import {getPluginContext} from "../plugins/op-context/op-context"; import { ClickObserver } from '@ckeditor/ckeditor5-engine'; diff --git a/src/mentions/mentions-item-renderer.ts b/src/mentions/mentions-item-renderer.ts index 75fadab..037d76a 100644 --- a/src/mentions/mentions-item-renderer.ts +++ b/src/mentions/mentions-item-renderer.ts @@ -1,5 +1,11 @@ -// @ts-nocheck -export function customItemRenderer( item ) { +interface MentionItem { + type?:string; + link?:string; + name?:string; + text?:string; +} + +export function customItemRenderer( item:MentionItem ) { const itemElement = document.createElement( 'span' ); if (item.type === 'user' || item.type === 'work_package') { @@ -8,16 +14,16 @@ export function customItemRenderer( item ) { } itemElement.classList.add( 'mention-list-item' ); - itemElement.textContent = item.name; + itemElement.textContent = item.name || ''; return itemElement; } -export function emojiItemRenderer( item ) { +export function emojiItemRenderer( item:MentionItem ) { const itemElement = document.createElement( 'span' ); itemElement.classList.add('mention-list-item' ); - itemElement.textContent = `${item.text} ${item.name}`; + itemElement.textContent = `${item.text || ''} ${item.name || ''}`; return itemElement; } diff --git a/src/mentions/user-mentions.ts b/src/mentions/user-mentions.ts index beca568..653db40 100644 --- a/src/mentions/user-mentions.ts +++ b/src/mentions/user-mentions.ts @@ -1,12 +1,18 @@ -// @ts-nocheck import { getOPResource, getOPPath, getPluginContext, } from "../plugins/op-context/op-context"; import { get } from '@rails/request.js'; +import type {Editor} from "@ckeditor/ckeditor5-core"; -export function userMentions(queryText) { +interface MentionablePrincipal { + _type:string; + id:string|number; + name:string; +} + +export function userMentions(this:Editor, queryText:string) { const editor = this; let resource = getOPResource(editor); @@ -22,7 +28,8 @@ export function userMentions(queryText) { return []; } - if (editor.config.get('disabledMentions').includes('user')) { + const disabledMentions = editor.config.get('disabledMentions') as string[] | undefined; + if (disabledMentions?.includes('user')) { return []; } @@ -34,7 +41,10 @@ export function userMentions(queryText) { get(url, { responseKind: 'json', query: { select: 'elements/_type,elements/id,elements/name' } }) .then(response => response.json) .then(collection => { - resolve(_.uniqBy(collection._embedded.elements, (el) => el.id).map(mention => { + const mentions = _.uniqBy( + (collection._embedded.elements || []) as MentionablePrincipal[], + (el:MentionablePrincipal) => el.id + ).map((mention:MentionablePrincipal) => { const type = mention._type.toLowerCase(); const text = `@${mention.name}`; const id = `@${mention.id}`; @@ -43,7 +53,9 @@ export function userMentions(queryText) { const link = `${base}/${typeSegment}/${idNumber}`; return {type, id, text, link, idNumber, name: mention.name}; - })); + }); + + resolve(mentions); }) .catch(error => { console.error('Error fetching user mentions:', error); diff --git a/src/mentions/work-package-mentions.ts b/src/mentions/work-package-mentions.ts index 87e70e4..81040ba 100644 --- a/src/mentions/work-package-mentions.ts +++ b/src/mentions/work-package-mentions.ts @@ -1,13 +1,14 @@ -// @ts-nocheck import { get } from '@rails/request.js'; +import type {Editor} from "@ckeditor/ckeditor5-core"; -export function workPackageMentions(prefix) { - return function (query) { - let editor = this; +export function workPackageMentions(prefix:string) { + return function (this:Editor, query:string) { + const editor = this; const url = window.OpenProject.urlRoot + `/work_packages/auto_complete.json`; - let base = window.OpenProject.urlRoot + `/work_packages/`; + const base = window.OpenProject.urlRoot + `/work_packages/`; - if (editor.config.get("disabledMentions").includes("work_package")) { + const disabledMentions = editor.config.get("disabledMentions") as string[] | undefined; + if (disabledMentions?.includes("work_package")) { return []; } diff --git a/src/op-ckeditor-config.ts b/src/op-ckeditor-config.ts index 4f6f948..12f193a 100644 --- a/src/op-ckeditor-config.ts +++ b/src/op-ckeditor-config.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import {userMentions} from "./mentions/user-mentions"; import {workPackageMentions} from "./mentions/work-package-mentions"; import {customItemRenderer, emojiItemRenderer} from './mentions/mentions-item-renderer'; diff --git a/src/op-ckeditor.ts b/src/op-ckeditor.ts index d124007..7c12e09 100644 --- a/src/op-ckeditor.ts +++ b/src/op-ckeditor.ts @@ -1,10 +1,12 @@ -// @ts-nocheck import { DecoupledEditor } from '@ckeditor/ckeditor5-editor-decoupled'; import { EditorWatchdog } from '@ckeditor/ckeditor5-watchdog'; import {builtinPlugins} from './op-plugins'; import {defaultConfig} from "./op-ckeditor-config"; import {configurationCustomizer} from './op-config-customizer'; +import type { Editor, EditorConfig } from '@ckeditor/ckeditor5-core'; import type { ICKEditorWatchdog } from './ckeditor-types'; +import type { OpenProjectEditorConfig, OpenProjectEditorClass } from './op-config-customizer'; +import type { OpenProjectPluginConstructor } from './op-plugins'; export type { CKEditorEvent, CKEditorListenOptions, @@ -21,7 +23,19 @@ export type { export class ConstrainedEditor extends DecoupledEditor {} export class FullEditor extends DecoupledEditor {} -export const OPEditorWatchdog = EditorWatchdog as unknown as ICKEditorWatchdog; +export const OPEditorWatchdog:ICKEditorWatchdog = EditorWatchdog; + +type OpenProjectEditorDefaultConfig = EditorConfig & { + toolbar?:{ + items?:string[]; + }; +}; + +type OpenProjectEditorStatics = typeof DecoupledEditor & OpenProjectEditorClass & { + createCustomized:(wrapper:string|HTMLElement, configuration:OpenProjectEditorConfig) => Promise; + builtinPlugins:OpenProjectPluginConstructor[]; + defaultConfig:OpenProjectEditorDefaultConfig; +}; // Export the two common interfaces window.OPConstrainedEditor = ConstrainedEditor; @@ -30,10 +44,11 @@ window.OPClassicEditor = FullEditor; // Export the Watchdog feature window.OPEditorWatchdog = OPEditorWatchdog; -FullEditor.createCustomized = configurationCustomizer(FullEditor); -FullEditor.builtinPlugins = builtinPlugins; -FullEditor.defaultConfig = Object.assign({}, defaultConfig); -FullEditor.defaultConfig.toolbar = { +const fullEditorClass = FullEditor as OpenProjectEditorStatics; +fullEditorClass.createCustomized = configurationCustomizer(fullEditorClass); +fullEditorClass.builtinPlugins = builtinPlugins; +fullEditorClass.defaultConfig = Object.assign({}, defaultConfig) as OpenProjectEditorDefaultConfig; +fullEditorClass.defaultConfig.toolbar = { items: [ 'heading', '|', @@ -64,10 +79,11 @@ FullEditor.defaultConfig.toolbar = { ] }; -ConstrainedEditor.createCustomized = configurationCustomizer(ConstrainedEditor); -ConstrainedEditor.builtinPlugins = builtinPlugins; -ConstrainedEditor.defaultConfig = Object.assign({}, defaultConfig); -ConstrainedEditor.defaultConfig.toolbar = { +const constrainedEditorClass = ConstrainedEditor as OpenProjectEditorStatics; +constrainedEditorClass.createCustomized = configurationCustomizer(constrainedEditorClass); +constrainedEditorClass.builtinPlugins = builtinPlugins; +constrainedEditorClass.defaultConfig = Object.assign({}, defaultConfig) as OpenProjectEditorDefaultConfig; +constrainedEditorClass.defaultConfig.toolbar = { items: [ 'bold', 'italic', diff --git a/src/op-config-customizer.ts b/src/op-config-customizer.ts index aa4f7a1..0ebb8b2 100644 --- a/src/op-config-customizer.ts +++ b/src/op-config-customizer.ts @@ -1,8 +1,46 @@ -// @ts-nocheck +import type { Editor, EditorConfig, PluginConstructor } from '@ckeditor/ckeditor5-core'; import {opImageUploadPlugins, opMacroPlugins} from './op-plugins'; +import type { ICKEditorMentionType } from './ckeditor-types'; -export function configurationCustomizer(editorClass) { - return (wrapper, configuration) => { +interface OpenProjectContext { + resource?:{ + canAddAttachments?:boolean; + }; + macros?:false|string[]; + disabledMentions?:ICKEditorMentionType[]; +} + +type OpenProjectConfigValue = + | string + | number + | boolean + | null + | undefined + | string[] + | { + context:OpenProjectContext; + disableAllMacros?:boolean; + } + | OpenProjectContext + | Array> + | ICKEditorMentionType[]; + +export interface OpenProjectEditorConfig { + openProject:{ + context:OpenProjectContext; + disableAllMacros?:boolean; + }; + removePlugins?:Array>; + disabledMentions?:ICKEditorMentionType[]; + [key:string]:OpenProjectConfigValue; +} + +export interface OpenProjectEditorClass { + create(wrapper:string|HTMLElement, configuration?:EditorConfig):Promise; +} + +export function configurationCustomizer(editorClass:OpenProjectEditorClass) { + return (wrapper:string|HTMLElement, configuration:OpenProjectEditorConfig) => { const context = configuration.openProject.context; // We're going to remove some plugins from the default configuration @@ -22,8 +60,9 @@ export function configurationCustomizer(editorClass) { } // Enable selective macros - if (Array.isArray(context.macros)) { - const disabledMacros = opMacroPlugins.filter(plugin => context.macros.indexOf(plugin.pluginName) === -1); + const macros = context.macros; + if (Array.isArray(macros)) { + const disabledMacros = opMacroPlugins.filter(plugin => macros.indexOf(plugin.pluginName) === -1); configuration.removePlugins.push(...disabledMacros); } @@ -35,7 +74,7 @@ export function configurationCustomizer(editorClass) { } // Return the original promise for instance creation - return editorClass.create(wrapper, configuration).then(editor => { + return editorClass.create(wrapper, configuration as EditorConfig).then((editor:Editor) => { return editor; }); }; diff --git a/src/op-plugins.ts b/src/op-plugins.ts index afada73..261abc1 100644 --- a/src/op-plugins.ts +++ b/src/op-plugins.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import OPMacroTocPlugin from './plugins/op-macro-toc-plugin'; import OPMacroEmbeddedTable from './plugins/op-macro-embedded-table/embedded-table-plugin'; import OPMacroWpButtonPlugin from './plugins/op-macro-wp-button/op-macro-wp-button-plugin'; @@ -43,22 +42,29 @@ import { ImageInline } from '@ckeditor/ckeditor5-image'; import { PageBreak } from '@ckeditor/ckeditor5-page-break'; import { Autosave } from '@ckeditor/ckeditor5-autosave'; import OpContentRevisions from "./plugins/op-content-revisions/op-content-revisions"; +import type { Editor, PluginConstructor } from '@ckeditor/ckeditor5-core'; + +export type OpenProjectPluginConstructor = PluginConstructor; +export type OpenProjectNamedPluginConstructor = OpenProjectPluginConstructor & { + pluginName:string; + buttonName?:string; +}; // We divide our plugins into separate concerns here // in order to enable / disable each group by configuration -export const opMacroPlugins = [ +export const opMacroPlugins:OpenProjectNamedPluginConstructor[] = [ OPMacroTocPlugin, OPMacroEmbeddedTable, OPMacroWpButtonPlugin, OPChildPagesPlugin, ]; -export const opImageUploadPlugins = [ +export const opImageUploadPlugins:OpenProjectNamedPluginConstructor[] = [ OpUploadPlugin, OPAttachmentListenerPlugin ]; -export const builtinPlugins = [ +const coreBuiltinPlugins:OpenProjectPluginConstructor[] = [ Essentials, CKFinderUploadAdapter, Autoformat, @@ -101,12 +107,11 @@ export const builtinPlugins = [ TableCellProperties, OPMacroListPlugin, - OpCustomCssClassesPlugin, -].concat( - // OpenProject Macro plugin group - opMacroPlugins, +]; - // OpenProject image upload plugins - opImageUploadPlugins, -); +export const builtinPlugins:OpenProjectPluginConstructor[] = [ + ...coreBuiltinPlugins, + ...opMacroPlugins, + ...opImageUploadPlugins, +]; diff --git a/src/plugins/code-block/click-observer.ts b/src/plugins/code-block/click-observer.ts index 53569f3..083e3dd 100644 --- a/src/plugins/code-block/click-observer.ts +++ b/src/plugins/code-block/click-observer.ts @@ -1,14 +1,9 @@ -// @ts-nocheck import { DomEventObserver } from '@ckeditor/ckeditor5-engine'; -export default class DoubleClickObserver extends DomEventObserver { - constructor( view ) { - super( view ); +export default class DoubleClickObserver extends DomEventObserver<'dblclick'> { + public readonly domEventType = 'dblclick'; - this.domEventType = 'dblclick'; - } - - onDomEvent( domEvent ) { + onDomEvent( domEvent:MouseEvent ) { this.fire( domEvent.type, domEvent ); } } diff --git a/src/plugins/code-block/code-block-editing.ts b/src/plugins/code-block/code-block-editing.ts index 245d5fb..b06bb90 100644 --- a/src/plugins/code-block/code-block-editing.ts +++ b/src/plugins/code-block/code-block-editing.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import icon from '../../icons/code-block.svg'; import { ButtonView } from '@ckeditor/ckeditor5-ui'; diff --git a/src/plugins/code-block/code-block-toolbar.ts b/src/plugins/code-block/code-block-toolbar.ts index dfc2779..18d2bd0 100644 --- a/src/plugins/code-block/code-block-toolbar.ts +++ b/src/plugins/code-block/code-block-toolbar.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import { Plugin } from '@ckeditor/ckeditor5-core'; import { ContextualBalloon } from '@ckeditor/ckeditor5-ui'; diff --git a/src/plugins/code-block/code-block.ts b/src/plugins/code-block/code-block.ts index 2a6b497..a6a6f8c 100644 --- a/src/plugins/code-block/code-block.ts +++ b/src/plugins/code-block/code-block.ts @@ -1,5 +1,3 @@ -// @ts-nocheck - import { Plugin } from '@ckeditor/ckeditor5-core'; import CodeBlockEditing from './code-block-editing'; import CodeBlockToolbar from './code-block-toolbar'; diff --git a/src/plugins/code-block/converters.ts b/src/plugins/code-block/converters.ts index 6afeae0..01258bf 100644 --- a/src/plugins/code-block/converters.ts +++ b/src/plugins/code-block/converters.ts @@ -1,8 +1,9 @@ -// @ts-nocheck import { Range } from '@ckeditor/ckeditor5-engine'; +import type ViewElement from '@ckeditor/ckeditor5-engine/src/view/element'; +import type ViewNode from '@ckeditor/ckeditor5-engine/src/view/node'; +import type ViewText from '@ckeditor/ckeditor5-engine/src/view/text'; import {renderCodeBlockContent} from './widget'; - export function modelCodeBlockToView() { return dispatcher => { dispatcher.on( 'insert:codeblock', converter, { priority: 'high' } ); @@ -53,7 +54,10 @@ export function viewCodeBlockToModel() { } // Find an code element inside the pre element. - const codeBlock = Array.from( data.viewItem.getChildren() ).find( viewChild => viewChild.is('element', 'code')); + const viewItem = data.viewItem as ViewElement; + const codeBlock = Array.from(viewItem.getChildren()).find((viewChild:ViewNode) => { + return viewChild.is('element', 'code'); + }) as ViewElement | undefined; // Do not convert if code block is absent if ( !codeBlock || !conversionApi.consumable.consume( codeBlock, { name: true } ) ) { @@ -75,11 +79,12 @@ export function viewCodeBlockToModel() { // Convert text child of codeblock const child = codeBlock.getChild(0); - if (child) { - conversionApi.consumable.consume(child, { name: true }); + if (child && child.is('$text')) { + const textChild = child as ViewText; + conversionApi.consumable.consume(textChild, { name: true }); // Replace last newline since that text is incorrectly mapped // Regression OP#28609 - const content = child.data.replace(/\n$/, ""); + const content = textChild.data.replace(/\n$/, ""); conversionApi.writer.setAttribute( 'opCodeblockContent', content, modelCodeBlock ); } @@ -109,7 +114,7 @@ export function codeBlockContentToView() { conversionApi.consumable.consume( data.item, evt.name ); // Get mapped view element to update. - const viewElement = conversionApi.mapper.toViewElement( modelElement ); + const viewElement = conversionApi.mapper.toViewElement( modelElement ) as ViewElement; // Remove current
    element contents. conversionApi.writer.remove( conversionApi.writer.createRangeOn( viewElement.getChild( 1 ) ) ); diff --git a/src/plugins/code-block/widget.ts b/src/plugins/code-block/widget.ts index b880d26..21bc0bc 100644 --- a/src/plugins/code-block/widget.ts +++ b/src/plugins/code-block/widget.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import {toWidget, isWidget} from '@ckeditor/ckeditor5-widget/src/utils'; const codeBlockSymbol = Symbol( 'isOPCodeBlock' ); diff --git a/src/plugins/op-attachment-listener-plugin.ts b/src/plugins/op-attachment-listener-plugin.ts index 806a1b4..6c05f77 100644 --- a/src/plugins/op-attachment-listener-plugin.ts +++ b/src/plugins/op-attachment-listener-plugin.ts @@ -1,28 +1,44 @@ -// @ts-nocheck import { Plugin } from '@ckeditor/ckeditor5-core'; +import type {Editor} from '@ckeditor/ckeditor5-core'; import Selection from '@ckeditor/ckeditor5-engine/src/model/selection'; +interface ImageModelElement { + name:string; + getAttribute(key:string):string | null; +} + export default class OPAttachmentListenerPlugin extends Plugin { static get pluginName() { return 'OPAttachmentListener'; } init() { - let editor = this.editor; + const editor = this.editor as Editor; editor.model.on('op:attachment-removed', (_, urls) => { this.removeDeletedImage(urls) }); } - removeDeletedImage(urls) { - let root = this.editor.model.document.getRoot(); + removeDeletedImage(urls:string[]) { + const editor = this.editor as Editor; + const root = editor.model.document.getRoot(); + if (!root) { + return; + } for (const child of Array.from(root.getChildren())) { - if (child.name === 'image' && urls.indexOf(child.getAttribute('src')) > -1) { - const selection = new Selection( child, 'on' ); + const modelChild = child as Partial; + if (typeof modelChild.name !== 'string' || typeof modelChild.getAttribute !== 'function') { + continue; + } + + const sourceUrl = modelChild.getAttribute('src'); + + if (modelChild.name === 'image' && typeof sourceUrl === 'string' && urls.includes(sourceUrl)) { + const selection = new Selection(child, 'on'); - this.editor.model.deleteContent(selection); + editor.model.deleteContent(selection); } } diff --git a/src/plugins/op-content-revisions/command.ts b/src/plugins/op-content-revisions/command.ts index 6c743f5..d78eed3 100644 --- a/src/plugins/op-content-revisions/command.ts +++ b/src/plugins/op-content-revisions/command.ts @@ -1,13 +1,13 @@ -// @ts-nocheck import {Command} from "ckeditor5/src/core"; +import type {Editor} from "@ckeditor/ckeditor5-core"; import {loadFromLocalStorage} from "./storage"; import {OP_CONTENT_REVISION_KEY} from "./op-content-revisions"; export default class OpContentRevisionsCommand extends Command { - async execute (timestamp) { - const editor = this.editor; - const key = editor.config.get(OP_CONTENT_REVISION_KEY); + async execute (timestamp:number) { + const editor = this.editor as Editor; + const key = editor.config.get(OP_CONTENT_REVISION_KEY) as string; const record = await loadFromLocalStorage(key); if (!record) { diff --git a/src/plugins/op-content-revisions/op-content-revisions.ts b/src/plugins/op-content-revisions/op-content-revisions.ts index 1c2ff68..b55f235 100644 --- a/src/plugins/op-content-revisions/op-content-revisions.ts +++ b/src/plugins/op-content-revisions/op-content-revisions.ts @@ -1,5 +1,5 @@ -// @ts-nocheck import {Plugin} from "ckeditor5/src/core"; +import type {Editor} from "@ckeditor/ckeditor5-core"; import OpContentRevisionsUI from "./ui"; import {loadFromLocalStorage} from "./storage"; import OpContentRevisionsCommand from "./command"; @@ -10,6 +10,12 @@ export const OP_CONTENT_REVISION_KEY = "opContentRevisionKey"; export const OP_CONTENT_REVISION_PREFIX = "op_ckeditor_rev"; export const STORAGE_KEY_OVERRIDE = "storageKey"; +interface AutosavePluginWithDomEmitter { + _domEmitter?: { + stopListening(target:Window, event:string):void; + }; +} + export default class OpContentRevisions extends Plugin { static get requires() { @@ -20,7 +26,7 @@ export default class OpContentRevisions extends Plugin { return "OpContentRevisions"; } - constructor(editor) { + constructor(editor:Editor) { super(editor); // Define a storage key for this instance @@ -41,7 +47,9 @@ export default class OpContentRevisions extends Plugin { const now = Date.now(); // disable beforeunload hook, we have our own - editor.plugins.get("Autosave")._domEmitter.stopListening(window, "beforeunload"); + const autosavePlugin = editor.plugins.get("Autosave") as Autosave; + const autosaveDomEmitter = Reflect.get(autosavePlugin, "_domEmitter") as AutosavePluginWithDomEmitter["_domEmitter"]; + autosaveDomEmitter?.stopListening(window, "beforeunload"); Object .keys(localStorage) @@ -63,8 +71,8 @@ export default class OpContentRevisions extends Plugin { * If a StorageKey is defined in the editor configuration, * use that instead of the default key. */ - getStorageKey(editor) { - const storageKey = editor.config.get(STORAGE_KEY_OVERRIDE); + getStorageKey(editor:Editor):string { + const storageKey = editor.config.get(STORAGE_KEY_OVERRIDE) as string | undefined; if (storageKey) { return storageKey; @@ -77,7 +85,7 @@ export default class OpContentRevisions extends Plugin { * Create a storage key from the given resource, if available. * Fall back to using the current URL path. */ - createLocalStorageKey(editor) { + createLocalStorageKey(editor:Editor):string { const resource = getOPResource(editor); const field = getOPFieldName(editor); diff --git a/src/plugins/op-content-revisions/storage.ts b/src/plugins/op-content-revisions/storage.ts index 84c1d85..7072572 100644 --- a/src/plugins/op-content-revisions/storage.ts +++ b/src/plugins/op-content-revisions/storage.ts @@ -1,10 +1,29 @@ -// @ts-nocheck import * as LZString from "lz-string"; +import type {Editor} from "@ckeditor/ckeditor5-core"; import {generateHash} from "./utils"; import {OP_CONTENT_REVISION_KEY} from "./op-content-revisions"; import {getOPService} from "../op-context/op-context"; -export function loadFromLocalStorage(storageKey) { +interface RevisionItem { + timestamp:number; + hash:number; + content:string; +} + +interface RevisionRecord { + items:RevisionItem[]; + updatedAt:number; +} + +interface NotificationService { + addError(message:string):void; +} + +function errorToString(error:Error):string { + return error.toString(); +} + +export function loadFromLocalStorage(storageKey:string):RevisionRecord|null { const compressed = localStorage.getItem(storageKey); if (!compressed) { @@ -12,17 +31,23 @@ export function loadFromLocalStorage(storageKey) { } try { - return JSON.parse(LZString.decompress(compressed)); + const decompressed = LZString.decompress(compressed); + if (!decompressed) { + return null; + } + + return JSON.parse(decompressed) as RevisionRecord; } catch (e) { - console.error("Failed to load CKEditor revisions from localStorage: " + e.toString()); + const error = e instanceof Error ? e : new Error(String(e)); + console.error("Failed to load CKEditor revisions from localStorage: " + errorToString(error)); return null; } } -export async function saveInLocalStorage(editor) { +export async function saveInLocalStorage(editor:Editor):Promise { const timestamp = Date.now(); - const key = editor.config.get(OP_CONTENT_REVISION_KEY); - const content = await editor.getData(); + const key = editor.config.get(OP_CONTENT_REVISION_KEY) as string; + const content = editor.getData(); // Do not try to save if content is undefined if (!content) { @@ -39,7 +64,7 @@ export async function saveInLocalStorage(editor) { const items = record?.items || []; // Unless there is a entry with a matching hash, append new save - const match = items.find(saved => item.hash === saved.hash); + const match = items.find((saved:RevisionItem) => item.hash === saved.hash); if (!match) { items.push(item); } @@ -49,8 +74,9 @@ export async function saveInLocalStorage(editor) { localStorage.setItem(key, compressed); } catch (e) { - const notifications = getOPService(editor, "notifications"); - notifications.addError("Failed to save CKEditor data to localStorage: " + e.toString()); + const error = e instanceof Error ? e : new Error(String(e)); + const notifications = getOPService(editor, "notifications") as NotificationService; + notifications.addError("Failed to save CKEditor data to localStorage: " + errorToString(error)); } return true; diff --git a/src/plugins/op-content-revisions/ui.ts b/src/plugins/op-content-revisions/ui.ts index afb6c6c..006944f 100644 --- a/src/plugins/op-content-revisions/ui.ts +++ b/src/plugins/op-content-revisions/ui.ts @@ -1,10 +1,12 @@ -// @ts-nocheck /** * @file registers the history_log toolbar button and binds functionality to it. */ import {Plugin} from "ckeditor5/src/core"; import {addListToDropdown, createDropdown} from "ckeditor5/src/ui"; import {Collection} from "ckeditor5/src/utils"; +import type {Editor} from "@ckeditor/ckeditor5-core"; +import { ViewModel } from "@ckeditor/ckeditor5-ui"; +import type {ListDropdownButtonDefinition, ListDropdownItemDefinition} from "@ckeditor/ckeditor5-ui"; import {loadFromLocalStorage} from "./storage"; import {countWords, generateHash} from "./utils"; @@ -12,6 +14,18 @@ import imageIcon from "./../../icons/revisions.svg"; import {getOPI18n, getOPService} from "../op-context/op-context"; import {OP_CONTENT_REVISION_KEY} from "./op-content-revisions"; +interface ExecuteEventSource { + timestamp?:number; +} + +interface ExecuteEvent { + source:ExecuteEventSource; +} + +interface TimezoneService { + formattedRelativeDateTime(timestamp:number):string; +} + export default class OpContentRevisionsUI extends Plugin { init() { @@ -20,7 +34,7 @@ export default class OpContentRevisionsUI extends Plugin { editor.ui.componentFactory.add("opContentRevisions", locale => { const dropdownView = createDropdown(locale); - const collection = new Collection(); + const collection = new Collection(); // Create a dropdown with a list inside the panel. addListToDropdown(dropdownView, collection, { @@ -41,7 +55,7 @@ export default class OpContentRevisionsUI extends Plugin { addAvailableRevisions(editor, collection); }); - dropdownView.on("execute", (evt) => { + dropdownView.on("execute", (evt:ExecuteEvent) => { const { timestamp } = evt.source; if (timestamp) { @@ -55,19 +69,19 @@ export default class OpContentRevisionsUI extends Plugin { } -function addAvailableRevisions(editor, collection) { - const key = editor.config.get(OP_CONTENT_REVISION_KEY); +function addAvailableRevisions(editor:Editor, collection:Collection) { + const key = editor.config.get(OP_CONTENT_REVISION_KEY) as string; const record = loadFromLocalStorage(key); const i18n = getOPI18n(editor); - const timezoneService = getOPService(editor, "timezone"); + const timezoneService = getOPService(editor, "timezone") as TimezoneService; - if (!record?.items || record.items.count <= 0) { - const def = { + if (!record?.items || record.items.length <= 0) { + const def:ListDropdownButtonDefinition = { type: "button", - model: { + model: new ViewModel({ label: i18n.t('js.editor.no_revisions'), withText: true, - }, + }), }; collection.add(def); @@ -86,13 +100,13 @@ function addAvailableRevisions(editor, collection) { const matches = data.hash === currentHash ? `${i18n.t('js.label_current')} - ` : ""; const label = `${matches}${time} (${words})`; - const def = { + const def:ListDropdownButtonDefinition = { type: "button", - model: { + model: new ViewModel({ timestamp: data.timestamp, label, withText: true, - }, + }), }; collection.add(def); diff --git a/src/plugins/op-content-revisions/utils.ts b/src/plugins/op-content-revisions/utils.ts index 1b57ed0..7a6f6c6 100644 --- a/src/plugins/op-content-revisions/utils.ts +++ b/src/plugins/op-content-revisions/utils.ts @@ -1,14 +1,13 @@ -// @ts-nocheck // Description: Utility functions for the history log plugin. -export function countWords(str) { +export function countWords(str:string) { return str.trim().split(/\s+/).length; } /** * Basic hash function based on DJB "33-times" algorithm. */ -export function generateHash(str) { +export function generateHash(str:string) { const len = str.length; let h = 5381; diff --git a/src/plugins/op-context/op-context.ts b/src/plugins/op-context/op-context.ts index 4543181..20ce60a 100644 --- a/src/plugins/op-context/op-context.ts +++ b/src/plugins/op-context/op-context.ts @@ -1,36 +1,37 @@ -// @ts-nocheck -export function getOP(editor) { +import type { Editor } from '@ckeditor/ckeditor5-core'; + +export function getOP(editor:Editor) { return _.get(editor.config, '_config.openProject'); } -export function getOPResource(editor) { +export function getOPResource(editor:Editor) { return _.get(editor.config, '_config.openProject.context.resource'); } -export function getOPFieldName(editor) { +export function getOPFieldName(editor:Editor) { return _.get(editor.config, '_config.openProject.context.field'); } -export function getOPPreviewContext(editor) { +export function getOPPreviewContext(editor:Editor) { return _.get(editor.config, '_config.openProject.context.previewContext'); } -export function getPluginContext(editor) { +export function getPluginContext(editor:Editor) { return _.get(editor.config, '_config.openProject.pluginContext'); } -export function getOPService(editor, name) { +export function getOPService(editor:Editor, name:string) { return getPluginContext(editor).services[name]; } -export function getOPHelper(editor, name) { +export function getOPHelper(editor:Editor, name:string) { return getPluginContext(editor).helpers[name]; } -export function getOPPath(editor) { +export function getOPPath(editor:Editor) { return getOPService(editor,'pathHelperService'); } -export function getOPI18n(editor) { +export function getOPI18n(editor:Editor) { return getOPService(editor,'i18n'); } diff --git a/src/plugins/op-custom-css-classes-plugin.ts b/src/plugins/op-custom-css-classes-plugin.ts index e4c07a8..eb49ff1 100644 --- a/src/plugins/op-custom-css-classes-plugin.ts +++ b/src/plugins/op-custom-css-classes-plugin.ts @@ -1,5 +1,10 @@ -// @ts-nocheck import { Plugin } from '@ckeditor/ckeditor5-core'; +import type ViewNode from '@ckeditor/ckeditor5-engine/src/view/node'; +import type ViewElement from '@ckeditor/ckeditor5-engine/src/view/element'; + +function isViewElement(value:ViewNode | null):value is ViewElement { + return !!value && value.is('element'); +} export default class OpCustomCssClassesPlugin extends Plugin { @@ -87,7 +92,7 @@ export default class OpCustomCssClassesPlugin extends Plugin { this.editor .conversion .for('upcast') - .add(dispatcher => dispatcher.on(`element:table`, this._manageTableUpcast(config)), {priority: 'high'}); + .add(dispatcher => dispatcher.on(`element:table`, this._manageTableUpcast(config))); this.editor .conversion @@ -164,16 +169,22 @@ export default class OpCustomCssClassesPlugin extends Plugin { viewElements = this._manageListItems(viewWriter, modelElement, viewElement, viewElements, config); } else { const figureViewElement = viewElement; - const viewChildren = Array.from(viewWriter.createRangeIn(viewElement).getItems()); + const viewChildren = Array.from(viewWriter.createRangeIn(viewElement).getItems()) as ViewNode[]; if (elementName === 'imageBlock') { - const image = viewChildren.find(item => item.is('element', 'img')); + const image = viewChildren.find((item) => isViewElement(item) && item.is('element', 'img')); + + if (!image) { + return; + } this._wrapInFigureContentContainer(image, figureViewElement, config, viewWriter); viewElements = [...viewElements, image]; } else if (elementName === 'table' || elementName === 'tableRow') { - const childrenToAdd = viewChildren.filter(viewChild => elementsWithCustomClasses.includes(viewChild.name)); + const childrenToAdd = viewChildren.filter((viewChild) => { + return isViewElement(viewChild) && elementsWithCustomClasses.includes(viewChild.name); + }); viewElements = [...viewElements, ...childrenToAdd]; @@ -256,8 +267,10 @@ export default class OpCustomCssClassesPlugin extends Plugin { }); } else if (attributeName === 'headingColumns') { const addHeadingColumns = data.attributeNewValue; - const viewChildren = Array.from(viewWriter.createRangeIn(viewElement).getItems()); - const viewElements = viewChildren.filter(viewChild => Object.keys(config.elementsWithCustomClassesMap).includes(viewChild.name)); + const viewChildren = Array.from(viewWriter.createRangeIn(viewElement).getItems()) as ViewNode[]; + const viewElements = viewChildren.filter((viewChild): viewChild is ViewElement => { + return isViewElement(viewChild) && Object.keys(config.elementsWithCustomClassesMap).includes(viewChild.name); + }); if (addHeadingColumns) { viewElements.forEach(viewElement => { @@ -267,15 +280,15 @@ export default class OpCustomCssClassesPlugin extends Plugin { viewWriter.addClass(elementClasses, viewElement); }); } else { - viewElements - .filter(viewElement => viewElement.hasClass(config.elementsWithCustomClassesMap.th[1])) - .forEach(viewElement => { - const nextSibling = viewElement.nextSibling; - - if (nextSibling && nextSibling.name !== 'th') { - viewWriter.removeClass(config.elementsWithCustomClassesMap.th[1], viewElement); - } - }); + viewElements + .filter((headingCell) => headingCell.hasClass(config.elementsWithCustomClassesMap.th[1])) + .forEach((headingCell) => { + const nextSibling = headingCell.nextSibling; + + if (isViewElement(nextSibling) && nextSibling.name !== 'th') { + viewWriter.removeClass(config.elementsWithCustomClassesMap.th[1], headingCell); + } + }); } } else if (attributeName === 'width') { if (viewElement.hasClass('image_resized')) { @@ -283,8 +296,10 @@ export default class OpCustomCssClassesPlugin extends Plugin { } } else if (attributeName === 'uploadStatus') { if (data.attributeNewValue === 'complete') { - const viewChildren = Array.from(viewWriter.createRangeIn(viewElement).getItems()); - let placeholderElement = viewChildren.find(viewChild => viewChild.hasClass('ck-upload-placeholder-loader')); + const viewChildren = Array.from(viewWriter.createRangeIn(viewElement).getItems()) as ViewNode[]; + const placeholderElement = viewChildren.find((viewChild) => { + return isViewElement(viewChild) && viewChild.hasClass('ck-upload-placeholder-loader'); + }); if (placeholderElement) { viewWriter.remove(viewWriter.createRangeOn(placeholderElement)); diff --git a/src/plugins/op-help-link-plugin/op-help-link-plugin.ts b/src/plugins/op-help-link-plugin/op-help-link-plugin.ts index f6b976b..cbf243c 100644 --- a/src/plugins/op-help-link-plugin/op-help-link-plugin.ts +++ b/src/plugins/op-help-link-plugin/op-help-link-plugin.ts @@ -1,4 +1,3 @@ -// @ts-nocheck // This SVG file import will be handled by webpack's raw-text loader. // This means that imageIcon will hold the source SVG. import imageIcon from './../../icons/help.svg'; @@ -15,7 +14,7 @@ export default class OPHelpLinkPlugin extends Plugin { init() { const editor = this.editor; - const helpURL = editor.config.get('openProject.helpURL'); + const helpURL = String(editor.config.get('openProject.helpURL') || ''); editor.ui.componentFactory.add( 'openProjectShowFormattingHelp', locale => { const view = new ButtonView( locale ); diff --git a/src/plugins/op-image-attachment-lookup/op-image-attachment-lookup-plugin.ts b/src/plugins/op-image-attachment-lookup/op-image-attachment-lookup-plugin.ts index 0ef357d..8995b0d 100644 --- a/src/plugins/op-image-attachment-lookup/op-image-attachment-lookup-plugin.ts +++ b/src/plugins/op-image-attachment-lookup/op-image-attachment-lookup-plugin.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import { Plugin } from '@ckeditor/ckeditor5-core'; import {getOPResource} from '../op-context/op-context'; import {originalSrcAttribute} from '../../commonmark/commonmarkdataprocessor'; diff --git a/src/plugins/op-macro-child-pages/op-macro-child-pages-editing.ts b/src/plugins/op-macro-child-pages/op-macro-child-pages-editing.ts index 9ab3839..6e83938 100644 --- a/src/plugins/op-macro-child-pages/op-macro-child-pages-editing.ts +++ b/src/plugins/op-macro-child-pages/op-macro-child-pages-editing.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import { ButtonView } from '@ckeditor/ckeditor5-ui'; import { Plugin } from '@ckeditor/ckeditor5-core'; diff --git a/src/plugins/op-macro-child-pages/op-macro-child-pages-plugin.ts b/src/plugins/op-macro-child-pages/op-macro-child-pages-plugin.ts index 529006d..45d302f 100644 --- a/src/plugins/op-macro-child-pages/op-macro-child-pages-plugin.ts +++ b/src/plugins/op-macro-child-pages/op-macro-child-pages-plugin.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import { Widget } from '@ckeditor/ckeditor5-widget'; import { Plugin } from '@ckeditor/ckeditor5-core'; import OPChildPagesEditing from './op-macro-child-pages-editing'; diff --git a/src/plugins/op-macro-child-pages/op-macro-child-pages-toolbar.ts b/src/plugins/op-macro-child-pages/op-macro-child-pages-toolbar.ts index 1d3db13..dc21fc7 100644 --- a/src/plugins/op-macro-child-pages/op-macro-child-pages-toolbar.ts +++ b/src/plugins/op-macro-child-pages/op-macro-child-pages-toolbar.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import { Plugin } from '@ckeditor/ckeditor5-core'; import { ContextualBalloon } from '@ckeditor/ckeditor5-ui'; @@ -29,7 +28,7 @@ export default class OPChildPagesToolbar extends Plugin { const macroService = pluginContext.services.macros; const pageAttribute = widget.getAttribute('page'); const includeParent = widget.getAttribute('includeParent'); - const page = (pageAttribute && pageAttribute.length > 0) ? pageAttribute : ''; + const page = typeof pageAttribute === 'string' && pageAttribute.length > 0 ? pageAttribute : ''; macroService .configureChildPages(page, includeParent) .then((macroConf) => model.change(writer => { diff --git a/src/plugins/op-macro-child-pages/utils.ts b/src/plugins/op-macro-child-pages/utils.ts index 39b9b5b..c57c9fa 100644 --- a/src/plugins/op-macro-child-pages/utils.ts +++ b/src/plugins/op-macro-child-pages/utils.ts @@ -1,4 +1,3 @@ -// @ts-nocheck const childPagesMacroSymbol = Symbol( 'isWpButtonMacroSymbol' ); import {toWidget, isWidget} from '@ckeditor/ckeditor5-widget/src/utils'; diff --git a/src/plugins/op-macro-embedded-table/embedded-table-editing.ts b/src/plugins/op-macro-embedded-table/embedded-table-editing.ts index 5d181c3..e94f3fc 100644 --- a/src/plugins/op-macro-embedded-table/embedded-table-editing.ts +++ b/src/plugins/op-macro-embedded-table/embedded-table-editing.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import { ButtonView } from '@ckeditor/ckeditor5-ui'; import { Plugin } from '@ckeditor/ckeditor5-core'; @@ -6,7 +5,14 @@ import { Plugin } from '@ckeditor/ckeditor5-core'; import {toEmbeddedTableWidget} from './utils'; import {getPluginContext} from '../op-context/op-context'; +interface EmbeddedTableI18n { + button:string; + macro_text:string; +} + export default class EmbeddedTableEditing extends Plugin { + text:EmbeddedTableI18n = { button: '', macro_text: '' }; + label = ''; static get pluginName() { return 'EmbeddedTableEditing'; diff --git a/src/plugins/op-macro-embedded-table/embedded-table-plugin.ts b/src/plugins/op-macro-embedded-table/embedded-table-plugin.ts index 7972f08..29a0291 100644 --- a/src/plugins/op-macro-embedded-table/embedded-table-plugin.ts +++ b/src/plugins/op-macro-embedded-table/embedded-table-plugin.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import EmbeddedTableEditing from './embedded-table-editing'; import { Widget } from '@ckeditor/ckeditor5-widget'; import { Plugin } from '@ckeditor/ckeditor5-core'; diff --git a/src/plugins/op-macro-embedded-table/embedded-table-toolbar.ts b/src/plugins/op-macro-embedded-table/embedded-table-toolbar.ts index c046dc5..9c14491 100644 --- a/src/plugins/op-macro-embedded-table/embedded-table-toolbar.ts +++ b/src/plugins/op-macro-embedded-table/embedded-table-toolbar.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import { Plugin } from '@ckeditor/ckeditor5-core'; import { ContextualBalloon } from '@ckeditor/ckeditor5-ui'; diff --git a/src/plugins/op-macro-embedded-table/utils.ts b/src/plugins/op-macro-embedded-table/utils.ts index 3e11ba5..e76c141 100644 --- a/src/plugins/op-macro-embedded-table/utils.ts +++ b/src/plugins/op-macro-embedded-table/utils.ts @@ -1,4 +1,3 @@ -// @ts-nocheck const embeddedTableSymbol = Symbol( 'isOPEmbeddedTable' ); import {toWidget, isWidget} from '@ckeditor/ckeditor5-widget/src/utils'; diff --git a/src/plugins/op-macro-list-plugin.ts b/src/plugins/op-macro-list-plugin.ts index 1d20fae..6722bc5 100644 --- a/src/plugins/op-macro-list-plugin.ts +++ b/src/plugins/op-macro-list-plugin.ts @@ -1,9 +1,17 @@ -// @ts-nocheck import { Plugin } from '@ckeditor/ckeditor5-core'; import { createDropdown, addToolbarToDropdown } from '@ckeditor/ckeditor5-ui/src/dropdown/utils'; import {opMacroPlugins} from "../op-plugins"; +import type { PluginConstructor, Editor } from '@ckeditor/ckeditor5-core'; + +function pluginNameOf(plugin:string|PluginConstructor):string { + if (typeof plugin === 'string') { + return plugin; + } + + return (plugin as { pluginName?:string }).pluginName || ''; +} /** * Adding a drop down list of macros to the toolbar. @@ -13,7 +21,8 @@ import {opMacroPlugins} from "../op-plugins"; export default class OPMacroListPlugin extends Plugin { init() { const editor = this.editor; - const disabledPluginNames = (editor.config.get('removePlugins') || []).map(p => p.pluginName); + const removePlugins = editor.config.get('removePlugins') || []; + const disabledPluginNames = removePlugins.map(pluginNameOf); const dropdownTooltip = window.I18n.t('js.editor.macro.dropdown.chose_macro'); // Skip if we don't have any macros here diff --git a/src/plugins/op-macro-toc-plugin.ts b/src/plugins/op-macro-toc-plugin.ts index 7a49fec..7d29294 100644 --- a/src/plugins/op-macro-toc-plugin.ts +++ b/src/plugins/op-macro-toc-plugin.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import { ButtonView } from '@ckeditor/ckeditor5-ui'; import { Plugin } from '@ckeditor/ckeditor5-core'; diff --git a/src/plugins/op-macro-wp-button/op-macro-wp-button-editing.ts b/src/plugins/op-macro-wp-button/op-macro-wp-button-editing.ts index fd69541..a8122ae 100644 --- a/src/plugins/op-macro-wp-button/op-macro-wp-button-editing.ts +++ b/src/plugins/op-macro-wp-button/op-macro-wp-button-editing.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import { ButtonView } from '@ckeditor/ckeditor5-ui'; import { Plugin } from '@ckeditor/ckeditor5-core'; @@ -102,7 +101,7 @@ export default class OPMacroWpButtonEditing extends Plugin { } ); } - macroLabel(type) { + macroLabel(type?:string) { if (type) { return window.I18n.t('js.editor.macro.work_package_button.with_type', { typename: type }); } else { diff --git a/src/plugins/op-macro-wp-button/op-macro-wp-button-plugin.ts b/src/plugins/op-macro-wp-button/op-macro-wp-button-plugin.ts index b142dc3..99c0aa0 100644 --- a/src/plugins/op-macro-wp-button/op-macro-wp-button-plugin.ts +++ b/src/plugins/op-macro-wp-button/op-macro-wp-button-plugin.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import { Widget } from '@ckeditor/ckeditor5-widget'; import { Plugin } from '@ckeditor/ckeditor5-core'; import OPMacroWpButtonEditing from './op-macro-wp-button-editing'; diff --git a/src/plugins/op-macro-wp-button/op-macro-wp-button-toolbar.ts b/src/plugins/op-macro-wp-button/op-macro-wp-button-toolbar.ts index 03b44f6..f7c4f21 100644 --- a/src/plugins/op-macro-wp-button/op-macro-wp-button-toolbar.ts +++ b/src/plugins/op-macro-wp-button/op-macro-wp-button-toolbar.ts @@ -1,4 +1,3 @@ -// @ts-nocheck import { Plugin } from '@ckeditor/ckeditor5-core'; import { ContextualBalloon } from '@ckeditor/ckeditor5-ui'; diff --git a/src/plugins/op-macro-wp-button/utils.ts b/src/plugins/op-macro-wp-button/utils.ts index 8db8bde..e922106 100644 --- a/src/plugins/op-macro-wp-button/utils.ts +++ b/src/plugins/op-macro-wp-button/utils.ts @@ -1,4 +1,3 @@ -// @ts-nocheck const wpButtonMacroSymbol = Symbol( 'isWpButtonMacroSymbol' ); import {toWidget, isWidget} from '@ckeditor/ckeditor5-widget/src/utils'; diff --git a/src/plugins/op-preview.plugin.ts b/src/plugins/op-preview.plugin.ts index 25ea035..f116343 100644 --- a/src/plugins/op-preview.plugin.ts +++ b/src/plugins/op-preview.plugin.ts @@ -1,4 +1,3 @@ -// @ts-nocheck // This SVG file import will be handled by webpack's raw-text loader. // This means that imageIcon will hold the source SVG. import imageIcon from '../icons/preview.svg'; diff --git a/src/plugins/op-source-code.plugin.ts b/src/plugins/op-source-code.plugin.ts index 954c9dd..f51d155 100644 --- a/src/plugins/op-source-code.plugin.ts +++ b/src/plugins/op-source-code.plugin.ts @@ -1,4 +1,3 @@ -// @ts-nocheck // This SVG file import will be handled by webpack's raw-text loader. // This means that imageIcon will hold the source SVG. import sourceIcon from '../icons/source.svg'; @@ -35,7 +34,7 @@ export default class OPSourceCodePlugin extends Plugin { } ); - let showSource = function(_preview) { + let showSource = function() { const editableElement = editor.ui.getEditableElement(); const reference = editableElement?.parentElement; if (!reference?.parentElement) { diff --git a/src/plugins/op-upload-plugin.ts b/src/plugins/op-upload-plugin.ts index ee3ec08..b67c2a5 100644 --- a/src/plugins/op-upload-plugin.ts +++ b/src/plugins/op-upload-plugin.ts @@ -1,6 +1,6 @@ -// @ts-nocheck import { Plugin } from '@ckeditor/ckeditor5-core'; import { FileRepository } from '@ckeditor/ckeditor5-upload'; +import type {FileLoader} from '@ckeditor/ckeditor5-upload'; import OpUploadResourceAdapter from './op-upload-resource-adapter'; import {getOPResource} from './op-context/op-context'; import { ImageUpload } from '@ckeditor/ckeditor5-image'; @@ -16,7 +16,7 @@ export default class OpUploadPlugin extends Plugin { } init() { - this.editor.plugins.get('FileRepository').createUploadAdapter = (loader) => { + this.editor.plugins.get('FileRepository').createUploadAdapter = (loader:FileLoader) => { const resource = getOPResource(this.editor); return new OpUploadResourceAdapter(loader, resource, this.editor); } diff --git a/src/plugins/op-upload-resource-adapter.ts b/src/plugins/op-upload-resource-adapter.ts index 678f4f8..b4f93b7 100644 --- a/src/plugins/op-upload-resource-adapter.ts +++ b/src/plugins/op-upload-resource-adapter.ts @@ -1,39 +1,71 @@ -// @ts-nocheck import {getOPService} from './op-context/op-context'; +import type {Editor} from "@ckeditor/ckeditor5-core"; +import type {FileLoader} from "@ckeditor/ckeditor5-upload"; +import type {UploadResponse} from "@ckeditor/ckeditor5-upload"; + +type OpenProjectResource = Record; + +interface UploadResourceService { + attachFiles(resource:OpenProjectResource, files:File[]):{ + toPromise():Promise; + }; +} + +interface AttachmentUploadResult { + _links:{ + staticDownloadLocation:{ + href:string; + }; + }; +} export default class OpUploadResourceAdapter { - constructor(loader, resource, editor) { + loader:FileLoader; + resource:OpenProjectResource | null; + editor:Editor; + + constructor(loader:FileLoader, resource:OpenProjectResource | null, editor:Editor) { this.loader = loader; this.resource = resource; this.editor = editor; } - upload() { + upload():Promise { const resource = this.resource; - const resourceService = getOPService(this.editor, 'attachmentsResourceService'); + const resourceService = getOPService(this.editor, 'attachmentsResourceService') as UploadResourceService; if (!resource) { console.warn(`resource not available in this CKEditor instance`); - return Promise.reject("Not possible to upload attachments without resource"); + return Promise.reject(new Error("Not possible to upload attachments without resource")); } return this.loader.file - .then(file => { + .then((file) => { + if (!file) { + throw new Error("Not possible to upload empty file payload"); + } + return resourceService .attachFiles(resource, [file]) .toPromise() .then((result) => { + if (!result[0]) { + throw new Error("Attachment upload succeeded without a response payload"); + } + this.editor.model.fire('op:attachment-added', result); return this.buildResponse(result[0]) - }).catch((error) => { - console.error("Failed upload %O", error); }); }) + .catch((error:Error) => { + console.error("Failed upload %O", error); + throw error; + }); } - buildResponse(result) { + buildResponse(result:AttachmentUploadResult):UploadResponse { return { default: result._links.staticDownloadLocation.href }; } From 2bf120a4dd644cee8de1f301c314804e1efcfdef Mon Sep 17 00:00:00 2001 From: Alexander Brandon Coles Date: Thu, 5 Mar 2026 16:36:04 -0300 Subject: [PATCH 08/11] Spike CKEditor GFM dependency and parity wrapper Add markdown-gfm 44.3.0 plus an experimental OpenProject GFM processor wrapper with parity tests for macro/mention/page-break. --- package-lock.json | 5 ++- package.json | 1 + src/commonmark/op-gfm-data-processor.ts | 32 ++++++++++++++++ tests/commonmark/gfm-spike-parity.test.js | 45 +++++++++++++++++++++++ 4 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 src/commonmark/op-gfm-data-processor.ts create mode 100644 tests/commonmark/gfm-spike-parity.test.js diff --git a/package-lock.json b/package-lock.json index a4d923e..7767355 100644 --- a/package-lock.json +++ b/package-lock.json @@ -36,6 +36,7 @@ "@ckeditor/ckeditor5-image": "44.3.0", "@ckeditor/ckeditor5-link": "44.3.0", "@ckeditor/ckeditor5-list": "44.3.0", + "@ckeditor/ckeditor5-markdown-gfm": "^44.3.0", "@ckeditor/ckeditor5-media-embed": "44.3.0", "@ckeditor/ckeditor5-mention": "44.3.0", "@ckeditor/ckeditor5-page-break": "44.3.0", @@ -9563,6 +9564,7 @@ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", "dev": true, + "peer": true, "bin": { "jiti": "bin/jiti.js" } @@ -21347,7 +21349,8 @@ "version": "1.21.0", "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", - "dev": true + "dev": true, + "peer": true }, "js-tokens": { "version": "4.0.0", diff --git a/package.json b/package.json index 0356c54..34820e6 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "@ckeditor/ckeditor5-image": "44.3.0", "@ckeditor/ckeditor5-link": "44.3.0", "@ckeditor/ckeditor5-list": "44.3.0", + "@ckeditor/ckeditor5-markdown-gfm": "^44.3.0", "@ckeditor/ckeditor5-media-embed": "44.3.0", "@ckeditor/ckeditor5-mention": "44.3.0", "@ckeditor/ckeditor5-page-break": "44.3.0", diff --git a/src/commonmark/op-gfm-data-processor.ts b/src/commonmark/op-gfm-data-processor.ts new file mode 100644 index 0000000..7f02207 --- /dev/null +++ b/src/commonmark/op-gfm-data-processor.ts @@ -0,0 +1,32 @@ +import GFMDataProcessor from '@ckeditor/ckeditor5-markdown-gfm/src/gfmdataprocessor'; +import type { ViewDocument, ViewDocumentFragment } from '@ckeditor/ckeditor5-engine'; +import { PAGE_BREAK_MARKDOWN } from './utils/page-breaks'; + +export default class OpenProjectGFMDataProcessor { + private readonly gfm:GFMDataProcessor; + + constructor(document:ViewDocument) { + this.gfm = new GFMDataProcessor(document); + + // Preserve OpenProject-specific HTML nodes in markdown output. + this.gfm.keepHtml('macro' as never); + this.gfm.keepHtml('mention' as never); + this.gfm.keepHtml('table'); + this.gfm.keepHtml('figure'); + this.gfm.keepHtml('div'); + } + + toView(data:string):ViewDocumentFragment { + return this.gfm.toView(data); + } + + toData(viewFragment:ViewDocumentFragment):string { + const markdown = this.gfm.toData(viewFragment); + + return markdown + // Keep legacy OpenProject page-break markdown token. + .replace(/
    <\/div>/g, PAGE_BREAK_MARKDOWN) + // Keep legacy macro formatting with a trailing newline before closing tag. + .replace(/]*)><\/macro>/g, '\\n'); + } +} diff --git a/tests/commonmark/gfm-spike-parity.test.js b/tests/commonmark/gfm-spike-parity.test.js new file mode 100644 index 0000000..29d02cd --- /dev/null +++ b/tests/commonmark/gfm-spike-parity.test.js @@ -0,0 +1,45 @@ +import CommonMarkDataProcessor from '../../src/commonmark/commonmarkdataprocessor'; +import OpenProjectGFMDataProcessor from '../../src/commonmark/op-gfm-data-processor'; +import { StylesProcessor, ViewDocument } from '@ckeditor/ckeditor5-engine'; + +function createProcessors() { + const viewDocument = new ViewDocument(new StylesProcessor()); + + return { + legacy: new CommonMarkDataProcessor(viewDocument), + gfm: new OpenProjectGFMDataProcessor(viewDocument), + }; +} + +function roundTripViaView(markdown) { + const { legacy, gfm } = createProcessors(); + const viewFragment = legacy.toView(markdown); + + return { + legacyOut: legacy.toData(viewFragment), + gfmOut: gfm.toData(viewFragment), + }; +} + +describe('OpenProject GFM spike parity', () => { + it('keeps macro markup compatible', () => { + const markdown = ''; + const { legacyOut, gfmOut } = roundTripViaView(markdown); + + expect(gfmOut).toEqual(legacyOut); + }); + + it('keeps mention markup compatible', () => { + const markdown = '@admin'; + const { legacyOut, gfmOut } = roundTripViaView(markdown); + + expect(gfmOut).toEqual(legacyOut); + }); + + it('keeps page-break markdown token compatible', () => { + const markdown = '
    '; + const { legacyOut, gfmOut } = roundTripViaView(markdown); + + expect(gfmOut).toEqual(legacyOut); + }); +}); From d20f49c122c1a3826487d10fc15120a7ede2335f Mon Sep 17 00:00:00 2001 From: Alexander Brandon Coles Date: Thu, 5 Mar 2026 16:44:58 -0300 Subject: [PATCH 09/11] Document current GFM migration gap coverage Add spike test coverage showing table round-trip remains the main divergence between legacy OP processor and GFM wrapper. --- tests/commonmark/gfm-spike-gaps.test.js | 36 +++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 tests/commonmark/gfm-spike-gaps.test.js diff --git a/tests/commonmark/gfm-spike-gaps.test.js b/tests/commonmark/gfm-spike-gaps.test.js new file mode 100644 index 0000000..d56c599 --- /dev/null +++ b/tests/commonmark/gfm-spike-gaps.test.js @@ -0,0 +1,36 @@ +import CommonMarkDataProcessor from '../../src/commonmark/commonmarkdataprocessor'; +import OpenProjectGFMDataProcessor from '../../src/commonmark/op-gfm-data-processor'; +import { StylesProcessor, ViewDocument } from '@ckeditor/ckeditor5-engine'; + +function createProcessors() { + const viewDocument = new ViewDocument(new StylesProcessor()); + + return { + legacy: new CommonMarkDataProcessor(viewDocument), + gfm: new OpenProjectGFMDataProcessor(viewDocument), + }; +} + +function roundTripViaView(markdown) { + const { legacy, gfm } = createProcessors(); + const viewFragment = legacy.toView(markdown); + + return { + legacyOut: legacy.toData(viewFragment), + gfmOut: gfm.toData(viewFragment), + }; +} + +describe('OpenProject GFM spike known gaps', () => { + it('still differs on table markdown-vs-html round-trip strategy', () => { + const markdown = + '| Heading 1 | Heading 2\n' + + '| --- | ---\n' + + '| Cell 1 | Cell 2\n'; + + const { legacyOut, gfmOut } = roundTripViaView(markdown); + + expect(gfmOut).not.toEqual(legacyOut); + expect(legacyOut).toContain(''); + }); +}); From dceddd8822b5fe785c924b6aaeafb6cf15ae96da Mon Sep 17 00:00:00 2001 From: Alexander Brandon Coles Date: Thu, 5 Mar 2026 16:46:18 -0300 Subject: [PATCH 10/11] Add transitional table shim for GFM wrapper Delegate table serialization to legacy processor inside the experimental GFM wrapper and update coverage accordingly. --- src/commonmark/op-gfm-data-processor.ts | 9 +++++++++ tests/commonmark/gfm-spike-gaps.test.js | 6 +++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/commonmark/op-gfm-data-processor.ts b/src/commonmark/op-gfm-data-processor.ts index 7f02207..487af17 100644 --- a/src/commonmark/op-gfm-data-processor.ts +++ b/src/commonmark/op-gfm-data-processor.ts @@ -1,12 +1,15 @@ import GFMDataProcessor from '@ckeditor/ckeditor5-markdown-gfm/src/gfmdataprocessor'; import type { ViewDocument, ViewDocumentFragment } from '@ckeditor/ckeditor5-engine'; +import CommonMarkDataProcessor from './commonmarkdataprocessor'; import { PAGE_BREAK_MARKDOWN } from './utils/page-breaks'; export default class OpenProjectGFMDataProcessor { private readonly gfm:GFMDataProcessor; + private readonly legacy:CommonMarkDataProcessor; constructor(document:ViewDocument) { this.gfm = new GFMDataProcessor(document); + this.legacy = new CommonMarkDataProcessor(document); // Preserve OpenProject-specific HTML nodes in markdown output. this.gfm.keepHtml('macro' as never); @@ -22,6 +25,12 @@ export default class OpenProjectGFMDataProcessor { toData(viewFragment:ViewDocumentFragment):string { const markdown = this.gfm.toData(viewFragment); + const legacyMarkdown = this.legacy.toData(viewFragment); + + // Transitional shim: preserve OpenProject's legacy table serialization strategy. + if (legacyMarkdown.includes(' { - it('still differs on table markdown-vs-html round-trip strategy', () => { +describe('OpenProject GFM spike gap closure', () => { + it('matches table markdown-vs-html round-trip via transitional shim', () => { const markdown = '| Heading 1 | Heading 2\n' + '| --- | ---\n' + @@ -30,7 +30,7 @@ describe('OpenProject GFM spike known gaps', () => { const { legacyOut, gfmOut } = roundTripViaView(markdown); - expect(gfmOut).not.toEqual(legacyOut); + expect(gfmOut).toEqual(legacyOut); expect(legacyOut).toContain('
    '); }); }); From a721c45fc65703d3e2428819c8d9ea7fb1e766e0 Mon Sep 17 00:00:00 2001 From: Alexander Brandon Coles Date: Thu, 5 Mar 2026 16:47:13 -0300 Subject: [PATCH 11/11] Gate experimental GFM processor behind flag Wire CommonMark plugin to opt into OpenProject GFM wrapper via openProject.useExperimentalGfmDataProcessor (default off). --- src/commonmark/commonmark.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/commonmark/commonmark.ts b/src/commonmark/commonmark.ts index 00519d7..d8c82cb 100644 --- a/src/commonmark/commonmark.ts +++ b/src/commonmark/commonmark.ts @@ -4,11 +4,17 @@ */ import CommonMarkDataProcessor from './commonmarkdataprocessor'; +import OpenProjectGFMDataProcessor from './op-gfm-data-processor'; + +interface CommonMarkEditorConfig { + get(path:string):unknown; +} interface CommonMarkEditor { data:{ processor:unknown; }; + config?:CommonMarkEditorConfig; editing:{ view:{ document:unknown; @@ -16,7 +22,13 @@ interface CommonMarkEditor { }; } +function useExperimentalGfmProcessor(editor:CommonMarkEditor):boolean { + return editor.config?.get('openProject.useExperimentalGfmDataProcessor') === true; +} + // Simple plugin which loads the data processor. export default function CommonMarkPlugin(editor:CommonMarkEditor) { - editor.data.processor = new CommonMarkDataProcessor(editor.editing.view.document); + editor.data.processor = useExperimentalGfmProcessor(editor) + ? new OpenProjectGFMDataProcessor(editor.editing.view.document as never) + : new CommonMarkDataProcessor(editor.editing.view.document); }