@ckeditor/ckeditor5-dev-manual-server 59.0.0 → 60.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -0
- package/dist/index.js +86 -43
- package/dist/manual-test-plugin/plugin.d.ts +1 -0
- package/dist/manual-test-plugin/translations.d.ts +10 -0
- package/package.json +2 -2
- package/theme/catalog.css +4 -4
package/README.md
CHANGED
|
@@ -8,6 +8,21 @@ Used to extend Vite to create a manual test server for CKEditor 5.
|
|
|
8
8
|
|
|
9
9
|
More information about development tools packages can be found at the following URL: <https://github.com/ckeditor/ckeditor5-dev>.
|
|
10
10
|
|
|
11
|
+
## Loading translations
|
|
12
|
+
|
|
13
|
+
Pass a language code to `manualTestsPlugin()` to load and combine that language's TypeScript translation files from the configured
|
|
14
|
+
package paths. The selected language becomes the default UI and content language for editors and contexts created by manual tests.
|
|
15
|
+
An explicit language in an editor or context configuration still takes precedence.
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
manualTestsPlugin( {
|
|
19
|
+
paths: [ 'packages/*' ],
|
|
20
|
+
language: process.env.CK_LANGUAGE || 'en'
|
|
21
|
+
} )
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
For example, start the manual test server in Polish using `CK_LANGUAGE=pl pnpm manual`.
|
|
25
|
+
|
|
11
26
|
## Changelog
|
|
12
27
|
|
|
13
28
|
See the [`CHANGELOG.md`](https://github.com/ckeditor/ckeditor5-dev/blob/master/packages/ckeditor5-dev-manual-server/CHANGELOG.md) file.
|
package/dist/index.js
CHANGED
|
@@ -88,6 +88,47 @@ function toManualPageEntry(relativeFilePath, workspaceRoot) {
|
|
|
88
88
|
};
|
|
89
89
|
}
|
|
90
90
|
//#endregion
|
|
91
|
+
//#region src/manual-test-plugin/translations.ts
|
|
92
|
+
/**
|
|
93
|
+
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
94
|
+
* For licensing, see LICENSE.md.
|
|
95
|
+
*/
|
|
96
|
+
const MANUAL_TRANSLATIONS_VIRTUAL_ID = "virtual:ckeditor5-manual-translations";
|
|
97
|
+
const RESOLVED_MANUAL_TRANSLATIONS_VIRTUAL_ID = `\0${MANUAL_TRANSLATIONS_VIRTUAL_ID}`;
|
|
98
|
+
/**
|
|
99
|
+
* Generates the virtual module that loads translations from every configured package root.
|
|
100
|
+
*/
|
|
101
|
+
function createManualTranslationsModule(paths, language) {
|
|
102
|
+
const translationPatterns = paths.map((packagePath) => {
|
|
103
|
+
return posix.join("/", toPosixPath(packagePath), `lang/translations/${language}.ts`);
|
|
104
|
+
});
|
|
105
|
+
return `
|
|
106
|
+
import { add } from '@ckeditor/ckeditor5-utils';
|
|
107
|
+
import { Context, Editor } from '@ckeditor/ckeditor5-core';
|
|
108
|
+
|
|
109
|
+
const translationModules = import.meta.glob(
|
|
110
|
+
${JSON.stringify(translationPatterns)},
|
|
111
|
+
{ eager: true, import: 'default' }
|
|
112
|
+
);
|
|
113
|
+
const language = ${JSON.stringify(language)};
|
|
114
|
+
const translations = Object.values( translationModules ).map( module => module[ language ] );
|
|
115
|
+
|
|
116
|
+
if ( !translations.length ) {
|
|
117
|
+
throw new Error( \`No CKEditor 5 translations found for "\${ language }".\` );
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if ( !translations.some( translation => translation.getPluralForm ) ) {
|
|
121
|
+
throw new Error( \`The ckeditor5-core translations for "\${ language }" were not loaded.\` );
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
for ( const translation of translations ) {
|
|
125
|
+
add( language, translation.dictionary, translation.getPluralForm );
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
Editor.defaultConfig = { ...Editor.defaultConfig, language: ${JSON.stringify(language)} };
|
|
129
|
+
Context.defaultConfig = { ...Context.defaultConfig, language: ${JSON.stringify(language)} };`;
|
|
130
|
+
}
|
|
131
|
+
//#endregion
|
|
91
132
|
//#region src/manual-test-plugin/plugin.ts
|
|
92
133
|
/**
|
|
93
134
|
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
@@ -137,33 +178,35 @@ function manualTestsPlugin(options) {
|
|
|
137
178
|
slug: entry.slug
|
|
138
179
|
}));
|
|
139
180
|
const getManualEntriesJson = () => JSON.stringify(getClientEntries(), null, 2);
|
|
181
|
+
const translationsModuleCode = options.language ? createManualTranslationsModule(options.paths, options.language) : null;
|
|
140
182
|
return {
|
|
141
183
|
name: "ckeditor5-manual-tests",
|
|
142
|
-
config() {
|
|
143
|
-
|
|
184
|
+
config(config = {}) {
|
|
185
|
+
workspaceRoot = resolve(config.root || process.cwd());
|
|
186
|
+
return { input: getManualBuildInputs() };
|
|
144
187
|
},
|
|
145
188
|
configResolved(config) {
|
|
146
189
|
workspaceRoot = config.root;
|
|
147
190
|
base = config.base || "/";
|
|
148
191
|
manualPagesCache.invalidate();
|
|
149
192
|
packageThemeEntryCache.clear();
|
|
150
|
-
config.build.rolldownOptions.input = getManualBuildInputs();
|
|
151
193
|
},
|
|
152
194
|
configureServer(server) {
|
|
153
195
|
server.middlewares.use((request, _response, next) => {
|
|
154
196
|
rewriteCatalogRequest(request, getManualCatalogPublicPath());
|
|
155
197
|
next();
|
|
156
198
|
});
|
|
157
|
-
|
|
158
|
-
keepManualHtmlSourceFresh(clientEnvironment.bundledDev?.memoryFiles, getManualPages, workspaceRoot);
|
|
199
|
+
keepManualHtmlSourceFresh(server.environments.client.bundledDev?.memoryFiles, getManualPages, workspaceRoot);
|
|
159
200
|
},
|
|
160
201
|
resolveId(source) {
|
|
161
202
|
if (source == MANUAL_ENTRIES_VIRTUAL_ID) return resolvedVirtualModuleId;
|
|
203
|
+
if (source == "virtual:ckeditor5-manual-translations" && translationsModuleCode) return RESOLVED_MANUAL_TRANSLATIONS_VIRTUAL_ID;
|
|
162
204
|
if (isManualCatalogBuildInputSpecifier(source, getManualCatalogBuildInputFilePath(), workspaceRoot)) return getManualCatalogBuildInputFilePath();
|
|
163
205
|
return null;
|
|
164
206
|
},
|
|
165
207
|
load(id) {
|
|
166
208
|
if (id == resolvedVirtualModuleId) return `export const manualTestEntries = ${getManualEntriesJson()};`;
|
|
209
|
+
if (id == RESOLVED_MANUAL_TRANSLATIONS_VIRTUAL_ID) return translationsModuleCode;
|
|
167
210
|
if (toPosixPath(id) == toPosixPath(getManualCatalogBuildInputFilePath())) return readFileSync(MANUAL_CATALOG_FILE_PATH, "utf8");
|
|
168
211
|
return null;
|
|
169
212
|
},
|
|
@@ -174,12 +217,13 @@ function manualTestsPlugin(options) {
|
|
|
174
217
|
const entry = getManualPageEntryForScriptSpecifier(scriptSpecifier);
|
|
175
218
|
if (!entry) return;
|
|
176
219
|
const packageRootSpecifier = entry.htmlFilePath.slice(0, entry.htmlFilePath.indexOf(MANUAL_TESTS_DIRECTORY));
|
|
177
|
-
const
|
|
178
|
-
|
|
220
|
+
const imports = getPackageThemeEntries(packageRootSpecifier).map((themeEntryFilePath) => {
|
|
221
|
+
return `import '${posix.relative(posix.dirname(scriptSpecifier), `${packageRootSpecifier}/${themeEntryFilePath}`)}';`;
|
|
222
|
+
});
|
|
223
|
+
if (options.language) imports.push(`import '${MANUAL_TRANSLATIONS_VIRTUAL_ID}';`);
|
|
224
|
+
if (!imports.length) return;
|
|
179
225
|
return {
|
|
180
|
-
code: `${code}\n${
|
|
181
|
-
return `import '${posix.relative(posix.dirname(scriptSpecifier), `${packageRootSpecifier}/${themeEntryFilePath}`)}';`;
|
|
182
|
-
}).join("\n")}\n`,
|
|
226
|
+
code: `${code}\n${imports.join("\n")}\n`,
|
|
183
227
|
map: null
|
|
184
228
|
};
|
|
185
229
|
}
|
|
@@ -207,7 +251,7 @@ function manualTestsPlugin(options) {
|
|
|
207
251
|
* produced by the rolldown dev engine. That engine emits the HTML output only during the initial
|
|
208
252
|
* build and never regenerates it when the source `.html` changes: its bundle state reports no
|
|
209
253
|
* stale output for HTML entries, `devEngine.invalidate()` throws on a non-JS module, and even a
|
|
210
|
-
* forced full build leaves the HTML memory file untouched (verified against Vite 8.1
|
|
254
|
+
* forced full build leaves the HTML memory file untouched (verified against Vite 8.2.1). A `.html`
|
|
211
255
|
* edit still triggers a full page reload, so without this the browser reloads into the same stale
|
|
212
256
|
* HTML until the server is restarted.
|
|
213
257
|
*
|
|
@@ -368,39 +412,40 @@ function getDebugFlags(debugOption = "") {
|
|
|
368
412
|
* For licensing, see LICENSE.md.
|
|
369
413
|
*/
|
|
370
414
|
const MANUAL_REFRESH_EVENT_NAME = "ckeditor5-manual:refresh-available";
|
|
371
|
-
const
|
|
415
|
+
const wrappedClients = /* @__PURE__ */ new WeakSet();
|
|
372
416
|
function refreshPlugin() {
|
|
373
417
|
return {
|
|
374
418
|
name: "ckeditor5-manual-refresh",
|
|
375
419
|
apply: "serve",
|
|
376
420
|
configureServer(server) {
|
|
377
|
-
const bundledDev = server.environments.client
|
|
378
|
-
|
|
379
|
-
wrapBundledDevClientSend(bundledDev.clients);
|
|
421
|
+
const { bundledDev } = server.environments.client;
|
|
422
|
+
wrapBundledDevClientSend(bundledDev);
|
|
380
423
|
wrapBundledDevFullReloads(bundledDev, server.config.root);
|
|
424
|
+
},
|
|
425
|
+
hotUpdate({ file, modules }) {
|
|
426
|
+
if (file.endsWith(".manual.html")) return modules;
|
|
381
427
|
}
|
|
382
428
|
};
|
|
383
429
|
}
|
|
384
|
-
function wrapBundledDevClientSend(
|
|
385
|
-
|
|
430
|
+
function wrapBundledDevClientSend(bundledDev) {
|
|
431
|
+
const clients = bundledDev.clients;
|
|
386
432
|
const setupIfNeeded = clients.setupIfNeeded.bind(clients);
|
|
387
433
|
clients.setupIfNeeded = (client, clientId) => {
|
|
388
|
-
if (!client
|
|
434
|
+
if (!wrappedClients.has(client)) {
|
|
389
435
|
const send = client.send.bind(client);
|
|
390
436
|
client.send = (payload) => {
|
|
391
|
-
sendManualRefreshPayload(payload, send);
|
|
437
|
+
sendManualRefreshPayload(bundledDev, payload, send);
|
|
392
438
|
};
|
|
393
|
-
client
|
|
439
|
+
wrappedClients.add(client);
|
|
394
440
|
}
|
|
395
441
|
return setupIfNeeded(client, clientId);
|
|
396
442
|
};
|
|
397
443
|
}
|
|
398
444
|
function wrapBundledDevFullReloads(bundledDev, workspaceRoot) {
|
|
399
|
-
if (typeof bundledDev.handleHmrOutput != "function") return;
|
|
400
445
|
const handleHmrOutput = bundledDev.handleHmrOutput.bind(bundledDev);
|
|
401
|
-
bundledDev.handleHmrOutput = (client, files, hmrOutput
|
|
402
|
-
if (hmrOutput.type != "FullReload") return handleHmrOutput(client, files, hmrOutput
|
|
403
|
-
if (!
|
|
446
|
+
bundledDev.handleHmrOutput = (client, files, hmrOutput) => {
|
|
447
|
+
if (hmrOutput.type != "FullReload") return handleHmrOutput(client, files, hmrOutput);
|
|
448
|
+
if (!shouldShowManualRefreshPrompt(files)) {
|
|
404
449
|
reloadClientAfterLatestBuildOutput(bundledDev, client, files, workspaceRoot);
|
|
405
450
|
return;
|
|
406
451
|
}
|
|
@@ -413,25 +458,26 @@ function wrapBundledDevFullReloads(bundledDev, workspaceRoot) {
|
|
|
413
458
|
}
|
|
414
459
|
async function reloadClientAfterLatestBuildOutput(bundledDev, client, files, workspaceRoot) {
|
|
415
460
|
try {
|
|
416
|
-
await bundledDev.devEngine
|
|
461
|
+
await bundledDev.devEngine.ensureLatestBuildOutput();
|
|
417
462
|
} catch {}
|
|
463
|
+
const htmlFile = files.find((file) => isHtmlFile(file));
|
|
418
464
|
client.send({
|
|
419
465
|
type: "full-reload",
|
|
420
|
-
path:
|
|
466
|
+
path: htmlFile ? toPublicFilePath(htmlFile, workspaceRoot) : void 0
|
|
421
467
|
});
|
|
422
468
|
}
|
|
423
|
-
function getChangedHtmlPublicPath(files, workspaceRoot) {
|
|
424
|
-
const htmlFile = files.find((file) => file.endsWith(".html"));
|
|
425
|
-
return htmlFile ? toPublicFilePath(htmlFile, workspaceRoot) : void 0;
|
|
426
|
-
}
|
|
427
469
|
function ensureLatestBuildOutput(bundledDev) {
|
|
428
470
|
try {
|
|
429
|
-
bundledDev.devEngine
|
|
471
|
+
bundledDev.devEngine.ensureLatestBuildOutput().catch(() => {});
|
|
430
472
|
} catch {}
|
|
431
473
|
}
|
|
432
|
-
function sendManualRefreshPayload(payload, send) {
|
|
433
|
-
if (payload.type == "update" &&
|
|
434
|
-
|
|
474
|
+
function sendManualRefreshPayload(bundledDev, payload, send) {
|
|
475
|
+
if (payload.type == "bundled-dev-update" && shouldShowManualRefreshPrompt(payload.changedIds)) {
|
|
476
|
+
ensureLatestBuildOutput(bundledDev);
|
|
477
|
+
send({
|
|
478
|
+
...payload,
|
|
479
|
+
changedIds: []
|
|
480
|
+
});
|
|
435
481
|
send({
|
|
436
482
|
type: "custom",
|
|
437
483
|
event: MANUAL_REFRESH_EVENT_NAME
|
|
@@ -440,17 +486,14 @@ function sendManualRefreshPayload(payload, send) {
|
|
|
440
486
|
}
|
|
441
487
|
send(payload);
|
|
442
488
|
}
|
|
443
|
-
function shouldShowManualRefreshPrompt(
|
|
444
|
-
|
|
445
|
-
return false;
|
|
489
|
+
function shouldShowManualRefreshPrompt(filePaths) {
|
|
490
|
+
return filePaths.some((filePath) => !isCssFile(filePath) && !isHtmlFile(filePath));
|
|
446
491
|
}
|
|
447
|
-
function
|
|
448
|
-
return
|
|
449
|
-
return update.type == "css-update" || update.type == "js-update" && update.acceptedPath.endsWith(".css");
|
|
450
|
-
});
|
|
492
|
+
function isCssFile(filePath) {
|
|
493
|
+
return filePath.split("?", 1)[0].endsWith(".css");
|
|
451
494
|
}
|
|
452
|
-
function
|
|
453
|
-
return
|
|
495
|
+
function isHtmlFile(filePath) {
|
|
496
|
+
return filePath.split("?", 1)[0].endsWith(".html");
|
|
454
497
|
}
|
|
455
498
|
//#endregion
|
|
456
499
|
//#region src/svg-plugin/plugin.ts
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license Copyright (c) 2003-2026, CKSource Holding sp. z o.o. All rights reserved.
|
|
3
|
+
* For licensing, see LICENSE.md.
|
|
4
|
+
*/
|
|
5
|
+
export declare const MANUAL_TRANSLATIONS_VIRTUAL_ID: string;
|
|
6
|
+
export declare const RESOLVED_MANUAL_TRANSLATIONS_VIRTUAL_ID: string;
|
|
7
|
+
/**
|
|
8
|
+
* Generates the virtual module that loads translations from every configured package root.
|
|
9
|
+
*/
|
|
10
|
+
export declare function createManualTranslationsModule(paths: Array<string>, language: string): string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ckeditor/ckeditor5-dev-manual-server",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "60.0.0",
|
|
4
4
|
"description": "Used to extend Vite to create a manual test server for CKEditor 5.",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"author": "CKSource (http://cksource.com/)",
|
|
@@ -25,6 +25,6 @@
|
|
|
25
25
|
],
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@ckeditor/ckeditor5-inspector": "^5.0.1",
|
|
28
|
-
"vite": "^8.1
|
|
28
|
+
"vite": "^8.2.1"
|
|
29
29
|
}
|
|
30
30
|
}
|
package/theme/catalog.css
CHANGED
|
@@ -143,10 +143,6 @@ a {
|
|
|
143
143
|
color: var(--text-muted);
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
-
.app__search:has(.app__search-input:placeholder-shown) .app__search-clear {
|
|
147
|
-
visibility: hidden;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
146
|
.app__search-clear {
|
|
151
147
|
margin-inline-end: 10px;
|
|
152
148
|
padding: 6px;
|
|
@@ -162,6 +158,10 @@ a {
|
|
|
162
158
|
background: var(--surface-hover);
|
|
163
159
|
}
|
|
164
160
|
|
|
161
|
+
.app__search:has(.app__search-input:placeholder-shown) .app__search-clear {
|
|
162
|
+
visibility: hidden;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
165
|
/* Catalog content. */
|
|
166
166
|
.app__list {
|
|
167
167
|
display: grid;
|