smart-md-editor 0.5.1
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/LICENSE +21 -0
- package/README.md +974 -0
- package/dist/smart-editor.cjs.js +83280 -0
- package/dist/smart-editor.cjs.js.map +1 -0
- package/dist/smart-editor.esm.js +83272 -0
- package/dist/smart-editor.esm.js.map +1 -0
- package/dist/smart-editor.iife.js +83285 -0
- package/dist/smart-editor.iife.js.map +1 -0
- package/package.json +61 -0
- package/scripts/download-drawio.mjs +220 -0
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "smart-md-editor",
|
|
3
|
+
"version": "0.5.1",
|
|
4
|
+
"description": "WYSIWYG Markdown editor — split view, extensible toolbar, markdown-it powered",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/smart-editor.cjs.js",
|
|
7
|
+
"module": "dist/smart-editor.esm.js",
|
|
8
|
+
"browser": "dist/smart-editor.iife.js",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": "./dist/smart-editor.esm.js",
|
|
12
|
+
"require": "./dist/smart-editor.cjs.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"bin": {
|
|
16
|
+
"smart-md-editor": "./scripts/download-drawio.mjs"
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist/*.js",
|
|
20
|
+
"dist/*.js.map",
|
|
21
|
+
"scripts/download-drawio.mjs"
|
|
22
|
+
],
|
|
23
|
+
"publishConfig": {
|
|
24
|
+
"access": "public"
|
|
25
|
+
},
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "rollup -c",
|
|
28
|
+
"dev": "rollup -c --watch",
|
|
29
|
+
"test": "vitest run",
|
|
30
|
+
"test:watch": "vitest",
|
|
31
|
+
"test:coverage": "vitest run --coverage",
|
|
32
|
+
"test:e2e": "playwright test",
|
|
33
|
+
"drawio:download": "node scripts/download-drawio.mjs",
|
|
34
|
+
"prepack": "npm run build"
|
|
35
|
+
},
|
|
36
|
+
"license": "MIT",
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"adm-zip": "^0.5.10",
|
|
39
|
+
"@codemirror/commands": "^6.7.1",
|
|
40
|
+
"@codemirror/lang-markdown": "^6.3.1",
|
|
41
|
+
"@codemirror/language": "^6.10.8",
|
|
42
|
+
"@codemirror/state": "^6.5.1",
|
|
43
|
+
"@codemirror/view": "^6.36.3",
|
|
44
|
+
"dompurify": "^3.2.4",
|
|
45
|
+
"highlight.js": "^11.11.1",
|
|
46
|
+
"katex": "^0.16.21",
|
|
47
|
+
"markdown-it": "^14.1.0"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@playwright/test": "^1.58.2",
|
|
51
|
+
"@rollup/plugin-commonjs": "^28.0.2",
|
|
52
|
+
"@rollup/plugin-node-resolve": "^15.3.1",
|
|
53
|
+
"@testing-library/dom": "^10.4.1",
|
|
54
|
+
"@testing-library/user-event": "^14.6.1",
|
|
55
|
+
"@vitest/coverage-v8": "^4.1.2",
|
|
56
|
+
"jsdom": "^29.0.1",
|
|
57
|
+
"playwright": "^1.58.2",
|
|
58
|
+
"rollup": "^4.34.9",
|
|
59
|
+
"vitest": "^4.1.2"
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Downloads the draw.io webapp from GitHub and extracts it to a target directory.
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* node scripts/download-drawio.mjs
|
|
7
|
+
* -> installs to vendor/drawio (repo maintenance mode)
|
|
8
|
+
*
|
|
9
|
+
* npx smart-md-editor drawio:download --out ./public/drawio --version latest
|
|
10
|
+
* -> installs to app-owned target folder (consumer mode)
|
|
11
|
+
*
|
|
12
|
+
* Pinned version: DRAWIO_VERSION constant below.
|
|
13
|
+
* Env override: DRAWIO_VERSION=27.0.0
|
|
14
|
+
*
|
|
15
|
+
* The script is a no-op when target/.version already equals requested version.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import {
|
|
19
|
+
existsSync,
|
|
20
|
+
mkdirSync,
|
|
21
|
+
readFileSync,
|
|
22
|
+
writeFileSync,
|
|
23
|
+
rmSync,
|
|
24
|
+
} from 'node:fs';
|
|
25
|
+
import { join, dirname, resolve, sep } from 'node:path';
|
|
26
|
+
import { fileURLToPath } from 'node:url';
|
|
27
|
+
|
|
28
|
+
/** @type {string} Pinned draw.io version — change this constant to upgrade. */
|
|
29
|
+
const DRAWIO_VERSION = process.env.DRAWIO_VERSION ?? '26.0.16';
|
|
30
|
+
|
|
31
|
+
const __DIR = dirname(fileURLToPath(import.meta.url));
|
|
32
|
+
const ROOT = resolve(__DIR, '..');
|
|
33
|
+
const DEFAULT_REPO_TARGET_DIR = join(ROOT, 'vendor', 'drawio');
|
|
34
|
+
const HOSTED_DRAWIO_EMBED_URL = 'https://embed.diagrams.net/?embed=1&proto=json&spin=1&ui=min&libraries=1';
|
|
35
|
+
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
// Helpers
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Resolves "latest" to the actual version by querying the GitHub Releases API.
|
|
42
|
+
* @param {string} ver
|
|
43
|
+
* @returns {Promise<string>}
|
|
44
|
+
*/
|
|
45
|
+
async function resolveVersion(ver) {
|
|
46
|
+
if (ver !== 'latest') return ver;
|
|
47
|
+
console.log('[draw.io] Fetching latest version from GitHub...');
|
|
48
|
+
const res = await fetch(
|
|
49
|
+
'https://api.github.com/repos/jgraph/drawio/releases/latest',
|
|
50
|
+
{ headers: { 'User-Agent': 'md-wysiwyg-editor/drawio-downloader' } },
|
|
51
|
+
);
|
|
52
|
+
if (!res.ok) throw new Error(`GitHub API returned HTTP ${res.status}`);
|
|
53
|
+
const { tag_name } = await res.json();
|
|
54
|
+
return tag_name.replace(/^v/, '');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Downloads the source archive ZIP for the given version and returns it as a Buffer.
|
|
59
|
+
* @param {string} version
|
|
60
|
+
* @returns {Promise<Buffer>}
|
|
61
|
+
*/
|
|
62
|
+
async function fetchArchive(version) {
|
|
63
|
+
const url = `https://github.com/jgraph/drawio/archive/refs/tags/v${version}.zip`;
|
|
64
|
+
console.log(`[draw.io] Downloading ${url}`);
|
|
65
|
+
const res = await fetch(url, {
|
|
66
|
+
redirect: 'follow',
|
|
67
|
+
headers: { 'User-Agent': 'md-wysiwyg-editor/drawio-downloader' },
|
|
68
|
+
});
|
|
69
|
+
if (!res.ok) throw new Error(`HTTP ${res.status} fetching ${url}`);
|
|
70
|
+
return Buffer.from(await res.arrayBuffer());
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* @param {string[]} argv
|
|
75
|
+
* @returns {{ command:string|null, out:string|null, version:string, help:boolean }}
|
|
76
|
+
*/
|
|
77
|
+
function parseCliArgs(argv) {
|
|
78
|
+
let command = null;
|
|
79
|
+
const args = [...argv];
|
|
80
|
+
|
|
81
|
+
if (args[0] && !args[0].startsWith('-')) {
|
|
82
|
+
command = args.shift();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
let out = null;
|
|
86
|
+
let version = DRAWIO_VERSION;
|
|
87
|
+
let help = false;
|
|
88
|
+
|
|
89
|
+
for (let i = 0; i < args.length; i++) {
|
|
90
|
+
const token = args[i];
|
|
91
|
+
if (token === '--help' || token === '-h') {
|
|
92
|
+
help = true;
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (token === '--out' || token === '-o') {
|
|
96
|
+
if (!args[i + 1] || args[i + 1].startsWith('-')) {
|
|
97
|
+
throw new Error('Missing value for --out');
|
|
98
|
+
}
|
|
99
|
+
out = args[i + 1];
|
|
100
|
+
i++;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (token === '--version' || token === '-v') {
|
|
104
|
+
if (!args[i + 1] || args[i + 1].startsWith('-')) {
|
|
105
|
+
throw new Error('Missing value for --version');
|
|
106
|
+
}
|
|
107
|
+
version = args[i + 1];
|
|
108
|
+
i++;
|
|
109
|
+
continue;
|
|
110
|
+
}
|
|
111
|
+
throw new Error(`Unknown argument: ${token}`);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return { command, out, version, help };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function printHelp() {
|
|
118
|
+
console.log([
|
|
119
|
+
'smart-md-editor draw.io downloader',
|
|
120
|
+
'',
|
|
121
|
+
'Commands:',
|
|
122
|
+
' drawio:download Download draw.io webapp to a target folder.',
|
|
123
|
+
'',
|
|
124
|
+
'Options:',
|
|
125
|
+
' -o, --out <path> Output directory. Defaults:',
|
|
126
|
+
` - repo mode: ${DEFAULT_REPO_TARGET_DIR}`,
|
|
127
|
+
' - CLI mode: ./drawio',
|
|
128
|
+
` -v, --version <v> draw.io version (default: ${DRAWIO_VERSION}, supports "latest")`,
|
|
129
|
+
' -h, --help Show this help.',
|
|
130
|
+
'',
|
|
131
|
+
'Examples:',
|
|
132
|
+
' node scripts/download-drawio.mjs',
|
|
133
|
+
' npx smart-md-editor drawio:download --out ./public/drawio --version latest',
|
|
134
|
+
'',
|
|
135
|
+
'Tip:',
|
|
136
|
+
` Hosted mode URL (no local assets needed): ${HOSTED_DRAWIO_EMBED_URL}`,
|
|
137
|
+
].join('\n'));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ---------------------------------------------------------------------------
|
|
141
|
+
// Main
|
|
142
|
+
// ---------------------------------------------------------------------------
|
|
143
|
+
|
|
144
|
+
async function main() {
|
|
145
|
+
const args = parseCliArgs(process.argv.slice(2));
|
|
146
|
+
|
|
147
|
+
if (args.help) {
|
|
148
|
+
printHelp();
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (args.command && args.command !== 'drawio:download') {
|
|
153
|
+
throw new Error(`Unknown command: ${args.command}`);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const cliMode = args.command === 'drawio:download';
|
|
157
|
+
const targetDir = args.out
|
|
158
|
+
? resolve(process.cwd(), args.out)
|
|
159
|
+
: (cliMode ? resolve(process.cwd(), 'drawio') : DEFAULT_REPO_TARGET_DIR);
|
|
160
|
+
const versionFile = join(targetDir, '.version');
|
|
161
|
+
|
|
162
|
+
const version = await resolveVersion(args.version);
|
|
163
|
+
|
|
164
|
+
if (existsSync(versionFile) && readFileSync(versionFile, 'utf8').trim() === version) {
|
|
165
|
+
console.log(`[draw.io] Already at v${version} in ${targetDir} — skipping download.`);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const buf = await fetchArchive(version);
|
|
170
|
+
|
|
171
|
+
// Dynamically import adm-zip (devDependency installed by npm before postinstall runs).
|
|
172
|
+
const { default: AdmZip } = await import('adm-zip');
|
|
173
|
+
|
|
174
|
+
console.log('[draw.io] Extracting webapp...');
|
|
175
|
+
const zip = new AdmZip(buf);
|
|
176
|
+
|
|
177
|
+
// Source archive layout: drawio-{version}/src/main/webapp/
|
|
178
|
+
const prefix = `drawio-${version}/src/main/webapp/`;
|
|
179
|
+
|
|
180
|
+
if (existsSync(targetDir)) {
|
|
181
|
+
rmSync(targetDir, { recursive: true, force: true });
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const targetResolved = resolve(targetDir);
|
|
185
|
+
let count = 0;
|
|
186
|
+
|
|
187
|
+
for (const entry of zip.getEntries()) {
|
|
188
|
+
if (!entry.entryName.startsWith(prefix)) continue;
|
|
189
|
+
|
|
190
|
+
const rel = entry.entryName.slice(prefix.length);
|
|
191
|
+
if (!rel) continue;
|
|
192
|
+
|
|
193
|
+
const dest = resolve(targetDir, rel);
|
|
194
|
+
|
|
195
|
+
// Prevent path traversal: destination must stay inside targetDir.
|
|
196
|
+
if (!dest.startsWith(targetResolved + sep)) continue;
|
|
197
|
+
|
|
198
|
+
if (entry.isDirectory) {
|
|
199
|
+
mkdirSync(dest, { recursive: true });
|
|
200
|
+
} else {
|
|
201
|
+
mkdirSync(dirname(dest), { recursive: true });
|
|
202
|
+
writeFileSync(dest, entry.getData());
|
|
203
|
+
count++;
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (count === 0) {
|
|
208
|
+
throw new Error(
|
|
209
|
+
`No files extracted — verify version "${version}" exists and archive contains "${prefix}"`,
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
writeFileSync(versionFile, version, 'utf8');
|
|
214
|
+
console.log(`[draw.io] v${version} installed to ${targetDir} (${count} files).`);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
main().catch(err => {
|
|
218
|
+
console.error('[draw.io] Download failed:', err.message);
|
|
219
|
+
process.exit(1);
|
|
220
|
+
});
|