marhup 0.1.7 → 0.1.9
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 +481 -4
- package/dist/cli.js +659 -78
- package/dist/cli.js.map +1 -1
- package/dist/errors.d.ts +29 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +62 -0
- package/dist/errors.js.map +1 -0
- package/dist/generator/code.d.ts +4 -3
- package/dist/generator/code.d.ts.map +1 -1
- package/dist/generator/code.js +7 -7
- package/dist/generator/code.js.map +1 -1
- package/dist/generator/gen-animations.d.ts +13 -0
- package/dist/generator/gen-animations.d.ts.map +1 -0
- package/dist/generator/gen-animations.js +77 -0
- package/dist/generator/gen-animations.js.map +1 -0
- package/dist/generator/image.d.ts +4 -3
- package/dist/generator/image.d.ts.map +1 -1
- package/dist/generator/image.js +67 -80
- package/dist/generator/image.js.map +1 -1
- package/dist/generator/index.d.ts +2 -0
- package/dist/generator/index.d.ts.map +1 -1
- package/dist/generator/index.js +9 -18
- package/dist/generator/index.js.map +1 -1
- package/dist/generator/list.d.ts +4 -3
- package/dist/generator/list.d.ts.map +1 -1
- package/dist/generator/list.js +15 -17
- package/dist/generator/list.js.map +1 -1
- package/dist/generator/mermaid.d.ts +9 -4
- package/dist/generator/mermaid.d.ts.map +1 -1
- package/dist/generator/mermaid.js +120 -85
- package/dist/generator/mermaid.js.map +1 -1
- package/dist/generator/pptx.d.ts +1 -1
- package/dist/generator/pptx.d.ts.map +1 -1
- package/dist/generator/pptx.js +232 -60
- package/dist/generator/pptx.js.map +1 -1
- package/dist/generator/presentation.d.ts +149 -0
- package/dist/generator/presentation.d.ts.map +1 -0
- package/dist/generator/presentation.js +163 -0
- package/dist/generator/presentation.js.map +1 -0
- package/dist/generator/table.d.ts +4 -3
- package/dist/generator/table.d.ts.map +1 -1
- package/dist/generator/table.js +12 -33
- package/dist/generator/table.js.map +1 -1
- package/dist/generator/text.d.ts +5 -4
- package/dist/generator/text.d.ts.map +1 -1
- package/dist/generator/text.js +34 -20
- package/dist/generator/text.js.map +1 -1
- package/dist/generator/video.d.ts +18 -0
- package/dist/generator/video.d.ts.map +1 -0
- package/dist/generator/video.js +83 -0
- package/dist/generator/video.js.map +1 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +144 -55
- package/dist/index.js.map +1 -1
- package/dist/layout/auto.d.ts +14 -2
- package/dist/layout/auto.d.ts.map +1 -1
- package/dist/layout/auto.js +129 -37
- package/dist/layout/auto.js.map +1 -1
- package/dist/layout/engine.d.ts +1 -1
- package/dist/layout/engine.d.ts.map +1 -1
- package/dist/layout/engine.js +10 -12
- package/dist/layout/engine.js.map +1 -1
- package/dist/layout/index.d.ts +1 -1
- package/dist/layout/index.d.ts.map +1 -1
- package/dist/layout/index.js +2 -10
- package/dist/layout/index.js.map +1 -1
- package/dist/layout/types.d.ts +1 -0
- package/dist/layout/types.d.ts.map +1 -1
- package/dist/layout/types.js +1 -2
- package/dist/layout/types.js.map +1 -1
- package/dist/mcp-handlers.d.ts.map +1 -1
- package/dist/mcp-handlers.js +45 -54
- package/dist/mcp-handlers.js.map +1 -1
- package/dist/mcp.js +10 -12
- package/dist/mcp.js.map +1 -1
- package/dist/parser/frontmatter.d.ts.map +1 -1
- package/dist/parser/frontmatter.js +95 -16
- package/dist/parser/frontmatter.js.map +1 -1
- package/dist/parser/grid.d.ts +5 -7
- package/dist/parser/grid.d.ts.map +1 -1
- package/dist/parser/grid.js +217 -30
- package/dist/parser/grid.js.map +1 -1
- package/dist/parser/index.js +3 -13
- package/dist/parser/index.js.map +1 -1
- package/dist/parser/markdown.d.ts +1 -1
- package/dist/parser/markdown.d.ts.map +1 -1
- package/dist/parser/markdown.js +249 -137
- package/dist/parser/markdown.js.map +1 -1
- package/dist/theme/default.d.ts +1 -1
- package/dist/theme/default.d.ts.map +1 -1
- package/dist/theme/default.js +16 -8
- package/dist/theme/default.js.map +1 -1
- package/dist/theme/index.d.ts +11 -0
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/index.js +70 -7
- package/dist/theme/index.js.map +1 -1
- package/dist/types/index.d.ts +56 -2
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +4 -6
- package/dist/types/index.js.map +1 -1
- package/dist/types/plugin.d.ts +50 -0
- package/dist/types/plugin.d.ts.map +1 -0
- package/dist/types/plugin.js +5 -0
- package/dist/types/plugin.js.map +1 -0
- package/dist/utils/file-lock.d.ts +27 -0
- package/dist/utils/file-lock.d.ts.map +1 -0
- package/dist/utils/file-lock.js +118 -0
- package/dist/utils/file-lock.js.map +1 -0
- package/dist/utils/i18n.d.ts +5 -0
- package/dist/utils/i18n.d.ts.map +1 -0
- package/dist/utils/i18n.js +41 -0
- package/dist/utils/i18n.js.map +1 -0
- package/dist/utils/logger.d.ts +7 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +43 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/path-validation.d.ts +20 -0
- package/dist/utils/path-validation.d.ts.map +1 -0
- package/dist/utils/path-validation.js +39 -0
- package/dist/utils/path-validation.js.map +1 -0
- package/dist/utils/plugin-manager.d.ts +18 -0
- package/dist/utils/plugin-manager.d.ts.map +1 -0
- package/dist/utils/plugin-manager.js +108 -0
- package/dist/utils/plugin-manager.js.map +1 -0
- package/dist/utils/sanitizer.d.ts +14 -0
- package/dist/utils/sanitizer.d.ts.map +1 -0
- package/dist/utils/sanitizer.js +73 -0
- package/dist/utils/sanitizer.js.map +1 -0
- package/package.json +23 -8
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path validation utilities to prevent directory traversal attacks
|
|
3
|
+
*/
|
|
4
|
+
import * as path from 'path';
|
|
5
|
+
/**
|
|
6
|
+
* Check if a resolved path is within the allowed directory
|
|
7
|
+
* @param resolvedPath - The absolute path to check
|
|
8
|
+
* @param allowedDir - The absolute path of the allowed directory
|
|
9
|
+
* @returns true if the path is safe (within allowedDir or subdirectories)
|
|
10
|
+
*/
|
|
11
|
+
export function isPathWithinDirectory(resolvedPath, allowedDir) {
|
|
12
|
+
const normalizedPath = path.normalize(resolvedPath);
|
|
13
|
+
const normalizedAllowed = path.normalize(allowedDir);
|
|
14
|
+
// Ensure allowedDir ends with separator for proper prefix check
|
|
15
|
+
const allowedWithSep = normalizedAllowed.endsWith(path.sep) ? normalizedAllowed : normalizedAllowed + path.sep;
|
|
16
|
+
return normalizedPath.startsWith(allowedWithSep) || normalizedPath === normalizedAllowed;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Validate and resolve a file path, ensuring it's within the allowed directory
|
|
20
|
+
* @param inputPath - The input path (can be relative or absolute)
|
|
21
|
+
* @param allowedDir - The absolute path of the allowed directory
|
|
22
|
+
* @param basePath - Optional base path for relative resolution
|
|
23
|
+
* @returns The resolved absolute path if valid
|
|
24
|
+
* @throws Error if the path is outside the allowed directory
|
|
25
|
+
*/
|
|
26
|
+
export function validateAndResolvePath(inputPath, allowedDir, basePath) {
|
|
27
|
+
let resolvedPath;
|
|
28
|
+
if (basePath && !path.isAbsolute(inputPath)) {
|
|
29
|
+
resolvedPath = path.resolve(basePath, inputPath);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
resolvedPath = path.resolve(inputPath);
|
|
33
|
+
}
|
|
34
|
+
if (!isPathWithinDirectory(resolvedPath, allowedDir)) {
|
|
35
|
+
throw new Error(`Path traversal detected: ${inputPath} resolves to ${resolvedPath} which is outside allowed directory ${allowedDir}`);
|
|
36
|
+
}
|
|
37
|
+
return resolvedPath;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=path-validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-validation.js","sourceRoot":"","sources":["../../src/utils/path-validation.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,YAAoB,EAAE,UAAkB;IAC5E,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;IACpD,MAAM,iBAAiB,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;IAErD,gEAAgE;IAChE,MAAM,cAAc,GAAG,iBAAiB,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,iBAAiB,GAAG,IAAI,CAAC,GAAG,CAAC;IAE/G,OAAO,cAAc,CAAC,UAAU,CAAC,cAAc,CAAC,IAAI,cAAc,KAAK,iBAAiB,CAAC;AAC3F,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,sBAAsB,CAAC,SAAiB,EAAE,UAAkB,EAAE,QAAiB;IAC7F,IAAI,YAAoB,CAAC;IAEzB,IAAI,QAAQ,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC5C,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,SAAS,CAAC,CAAC;IACnD,CAAC;SAAM,CAAC;QACN,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACzC,CAAC;IAED,IAAI,CAAC,qBAAqB,CAAC,YAAY,EAAE,UAAU,CAAC,EAAE,CAAC;QACrD,MAAM,IAAI,KAAK,CAAC,4BAA4B,SAAS,gBAAgB,YAAY,uCAAuC,UAAU,EAAE,CAAC,CAAC;IACxI,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin Manager
|
|
3
|
+
*/
|
|
4
|
+
import type { PluginManager as IPluginManager, PluginContext, ElementParser, ElementGenerator, PluginHooks } from '../types/plugin.js';
|
|
5
|
+
declare class PluginManagerImpl implements IPluginManager {
|
|
6
|
+
private plugins;
|
|
7
|
+
private elementParsers;
|
|
8
|
+
private elementGenerators;
|
|
9
|
+
loadPlugins(pluginDir: string): Promise<void>;
|
|
10
|
+
private validatePlugin;
|
|
11
|
+
getElementParser(type: string): ElementParser | undefined;
|
|
12
|
+
getElementGenerator(type: string): ElementGenerator | undefined;
|
|
13
|
+
executeHook<K extends keyof PluginHooks>(hook: K, ...args: Parameters<NonNullable<PluginHooks[K]>>): Promise<void>;
|
|
14
|
+
init(context: PluginContext): Promise<void>;
|
|
15
|
+
}
|
|
16
|
+
export declare const pluginManager: PluginManagerImpl;
|
|
17
|
+
export { PluginManagerImpl as PluginManager };
|
|
18
|
+
//# sourceMappingURL=plugin-manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-manager.d.ts","sourceRoot":"","sources":["../../src/utils/plugin-manager.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,OAAO,KAAK,EAAU,aAAa,IAAI,cAAc,EAAE,aAAa,EAAE,aAAa,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAG/I,cAAM,iBAAkB,YAAW,cAAc;IAC/C,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,cAAc,CAAyC;IAC/D,OAAO,CAAC,iBAAiB,CAA4C;IAE/D,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA+DnD,OAAO,CAAC,cAAc;IAItB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAIzD,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS;IAIzD,WAAW,CAAC,CAAC,SAAS,MAAM,WAAW,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,EAAE,UAAU,CAAC,WAAW,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAYlH,IAAI,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;CAWlD;AAED,eAAO,MAAM,aAAa,mBAA0B,CAAC;AACrD,OAAO,EAAE,iBAAiB,IAAI,aAAa,EAAE,CAAC"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin Manager
|
|
3
|
+
*/
|
|
4
|
+
import * as fs from 'fs';
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
import { NodeVM } from 'vm2';
|
|
7
|
+
import logger from './logger.js';
|
|
8
|
+
class PluginManagerImpl {
|
|
9
|
+
plugins = [];
|
|
10
|
+
elementParsers = new Map();
|
|
11
|
+
elementGenerators = new Map();
|
|
12
|
+
async loadPlugins(pluginDir) {
|
|
13
|
+
if (!fs.existsSync(pluginDir)) {
|
|
14
|
+
logger.debug('Plugin directory does not exist', { pluginDir });
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const files = fs.readdirSync(pluginDir).filter(file => file.endsWith('.js'));
|
|
18
|
+
for (const file of files) {
|
|
19
|
+
try {
|
|
20
|
+
const pluginPath = path.join(pluginDir, file);
|
|
21
|
+
const code = fs.readFileSync(pluginPath, 'utf8');
|
|
22
|
+
const vm = new NodeVM({
|
|
23
|
+
console: 'inherit',
|
|
24
|
+
sandbox: {
|
|
25
|
+
console,
|
|
26
|
+
RegExp,
|
|
27
|
+
String,
|
|
28
|
+
Array,
|
|
29
|
+
Object,
|
|
30
|
+
Math,
|
|
31
|
+
Date,
|
|
32
|
+
JSON,
|
|
33
|
+
Error,
|
|
34
|
+
parseInt,
|
|
35
|
+
parseFloat,
|
|
36
|
+
isNaN,
|
|
37
|
+
isFinite,
|
|
38
|
+
encodeURIComponent,
|
|
39
|
+
decodeURIComponent,
|
|
40
|
+
},
|
|
41
|
+
require: {
|
|
42
|
+
external: false,
|
|
43
|
+
builtin: [],
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
const pluginModule = vm.run(code);
|
|
47
|
+
const plugin = pluginModule;
|
|
48
|
+
if (this.validatePlugin(plugin)) {
|
|
49
|
+
this.plugins.push(plugin);
|
|
50
|
+
logger.info(`Loaded plugin: ${plugin.name}`);
|
|
51
|
+
// Register parsers and generators
|
|
52
|
+
if (plugin.elementParsers) {
|
|
53
|
+
for (const [type, parser] of Object.entries(plugin.elementParsers)) {
|
|
54
|
+
this.elementParsers.set(type, parser);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (plugin.elementGenerators) {
|
|
58
|
+
for (const [type, generator] of Object.entries(plugin.elementGenerators)) {
|
|
59
|
+
this.elementGenerators.set(type, generator);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
logger.warn(`Invalid plugin: ${file}`);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
logger.error(`Failed to load plugin ${file}`, { error: error instanceof Error ? error.message : String(error) });
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
validatePlugin(plugin) {
|
|
73
|
+
return typeof plugin === 'object' && plugin !== null && typeof plugin.name === 'string';
|
|
74
|
+
}
|
|
75
|
+
getElementParser(type) {
|
|
76
|
+
return this.elementParsers.get(type);
|
|
77
|
+
}
|
|
78
|
+
getElementGenerator(type) {
|
|
79
|
+
return this.elementGenerators.get(type);
|
|
80
|
+
}
|
|
81
|
+
async executeHook(hook, ...args) {
|
|
82
|
+
for (const plugin of this.plugins) {
|
|
83
|
+
if (plugin.hooks && plugin.hooks[hook]) {
|
|
84
|
+
try {
|
|
85
|
+
await plugin.hooks[hook](...args);
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
logger.error(`Plugin ${plugin.name} hook ${hook} failed`, { error: error instanceof Error ? error.message : String(error) });
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
async init(context) {
|
|
94
|
+
for (const plugin of this.plugins) {
|
|
95
|
+
if (plugin.hooks?.onInit) {
|
|
96
|
+
try {
|
|
97
|
+
await plugin.hooks.onInit(context);
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
logger.error(`Plugin ${plugin.name} init failed`, { error: error instanceof Error ? error.message : String(error) });
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
export const pluginManager = new PluginManagerImpl();
|
|
107
|
+
export { PluginManagerImpl as PluginManager };
|
|
108
|
+
//# sourceMappingURL=plugin-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-manager.js","sourceRoot":"","sources":["../../src/utils/plugin-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { SlideElement } from '../types/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* テキストコンテンツをサニタイズ
|
|
4
|
+
*/
|
|
5
|
+
export declare function sanitizeText(text: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* SVGコンテンツをサニタイズ
|
|
8
|
+
*/
|
|
9
|
+
export declare function sanitizeSvg(svgContent: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* SlideElementのcontentをサニタイズ
|
|
12
|
+
*/
|
|
13
|
+
export declare function sanitizeElement(element: SlideElement): void;
|
|
14
|
+
//# sourceMappingURL=sanitizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitizer.d.ts","sourceRoot":"","sources":["../../src/utils/sanitizer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAMtD;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGjD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CActD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,CAsC3D"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import DOMPurify from 'dompurify';
|
|
2
|
+
import { JSDOM } from 'jsdom';
|
|
3
|
+
// DOMPurifyのセットアップ
|
|
4
|
+
const window = new JSDOM('').window;
|
|
5
|
+
const DOMPurifyInstance = DOMPurify(window);
|
|
6
|
+
/**
|
|
7
|
+
* テキストコンテンツをサニタイズ
|
|
8
|
+
*/
|
|
9
|
+
export function sanitizeText(text) {
|
|
10
|
+
// HTMLタグを除去し、テキストのみを返す
|
|
11
|
+
return DOMPurifyInstance.sanitize(text, { ALLOWED_TAGS: [] });
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* SVGコンテンツをサニタイズ
|
|
15
|
+
*/
|
|
16
|
+
export function sanitizeSvg(svgContent) {
|
|
17
|
+
// SVGの安全なタグのみを許可
|
|
18
|
+
return DOMPurifyInstance.sanitize(svgContent, {
|
|
19
|
+
ALLOWED_TAGS: [
|
|
20
|
+
'svg', 'g', 'path', 'circle', 'rect', 'text', 'line', 'polyline', 'polygon', 'ellipse',
|
|
21
|
+
'defs', 'linearGradient', 'radialGradient', 'stop', 'use', 'symbol', 'clipPath', 'mask'
|
|
22
|
+
],
|
|
23
|
+
ALLOWED_ATTR: [
|
|
24
|
+
'd', 'cx', 'cy', 'r', 'x', 'y', 'x1', 'y1', 'x2', 'y2', 'width', 'height', 'fill', 'stroke',
|
|
25
|
+
'stroke-width', 'stroke-linecap', 'stroke-linejoin', 'transform', 'viewBox', 'xmlns',
|
|
26
|
+
'version', 'id', 'class', 'points', 'rx', 'ry', 'offset', 'stop-color', 'stop-opacity',
|
|
27
|
+
'gradientUnits', 'gradientTransform', 'href', 'clip-path', 'mask'
|
|
28
|
+
],
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* SlideElementのcontentをサニタイズ
|
|
33
|
+
*/
|
|
34
|
+
export function sanitizeElement(element) {
|
|
35
|
+
switch (element.type) {
|
|
36
|
+
case 'heading':
|
|
37
|
+
case 'paragraph':
|
|
38
|
+
case 'code':
|
|
39
|
+
case 'blockquote':
|
|
40
|
+
case 'mermaid':
|
|
41
|
+
case 'image':
|
|
42
|
+
case 'video':
|
|
43
|
+
if (typeof element.content === 'string') {
|
|
44
|
+
element.content = sanitizeText(element.content);
|
|
45
|
+
}
|
|
46
|
+
break;
|
|
47
|
+
case 'list':
|
|
48
|
+
if (Array.isArray(element.content)) {
|
|
49
|
+
element.content.forEach(item => {
|
|
50
|
+
item.content = sanitizeText(item.content);
|
|
51
|
+
if (item.children) {
|
|
52
|
+
item.children.forEach(child => {
|
|
53
|
+
child.content = sanitizeText(child.content);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
break;
|
|
59
|
+
case 'table':
|
|
60
|
+
if (element.content && typeof element.content === 'object' && 'headers' in element.content && 'rows' in element.content) {
|
|
61
|
+
element.content.headers = element.content.headers.map(sanitizeText);
|
|
62
|
+
element.content.rows = element.content.rows.map(row => row.map(sanitizeText));
|
|
63
|
+
}
|
|
64
|
+
break;
|
|
65
|
+
default:
|
|
66
|
+
// プラグインなどのカスタム要素もcontentがstringならサニタイズ
|
|
67
|
+
if (typeof element.content === 'string') {
|
|
68
|
+
element.content = sanitizeText(element.content);
|
|
69
|
+
}
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=sanitizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitizer.js","sourceRoot":"","sources":["../../src/utils/sanitizer.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "marhup",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "Markdownからグリッドベースのレイアウトで PowerPoint (PPTX) を生成するCLIツール",
|
|
5
|
+
"type": "module",
|
|
5
6
|
"main": "dist/index.js",
|
|
6
7
|
"types": "dist/index.d.ts",
|
|
7
8
|
"bin": {
|
|
@@ -40,24 +41,38 @@
|
|
|
40
41
|
"dependencies": {
|
|
41
42
|
"@mermaid-js/mermaid-cli": "^11.12.0",
|
|
42
43
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
44
|
+
"@types/chokidar": "^2.1.7",
|
|
45
|
+
"@types/dompurify": "^3.2.0",
|
|
46
|
+
"chokidar": "^5.0.0",
|
|
43
47
|
"commander": "^12.1.0",
|
|
48
|
+
"dompurify": "^3.3.1",
|
|
49
|
+
"i18next": "^25.8.0",
|
|
50
|
+
"i18next-fs-backend": "^2.6.1",
|
|
44
51
|
"image-size": "^2.0.2",
|
|
52
|
+
"jsdom": "^27.4.0",
|
|
45
53
|
"marked": "^11.2.0",
|
|
46
|
-
"pptxgenjs": "^
|
|
54
|
+
"pptxgenjs": "^4.0.1",
|
|
55
|
+
"vm2": "^3.10.3",
|
|
56
|
+
"winston": "^3.19.0",
|
|
47
57
|
"yaml": "^2.3.4"
|
|
48
58
|
},
|
|
49
59
|
"devDependencies": {
|
|
50
|
-
"@types/
|
|
51
|
-
"@
|
|
52
|
-
"@typescript-eslint/
|
|
53
|
-
"eslint": "^8.
|
|
60
|
+
"@types/jsdom": "^27.0.0",
|
|
61
|
+
"@types/node": "^22.0.0",
|
|
62
|
+
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
63
|
+
"@typescript-eslint/parser": "^8.0.0",
|
|
64
|
+
"@vitest/coverage-v8": "^4.0.18",
|
|
65
|
+
"eslint": "^9.0.0",
|
|
54
66
|
"npm-run-all": "^4.1.5",
|
|
55
67
|
"prettier": "^3.2.0",
|
|
56
68
|
"typescript": "^5.3.3",
|
|
57
|
-
"vitest": "^
|
|
69
|
+
"vitest": "^4.0.0"
|
|
58
70
|
},
|
|
59
71
|
"engines": {
|
|
60
|
-
"node": ">=
|
|
72
|
+
"node": ">=20.0.0"
|
|
73
|
+
},
|
|
74
|
+
"overrides": {
|
|
75
|
+
"lodash-es": "^4.17.23"
|
|
61
76
|
},
|
|
62
77
|
"files": [
|
|
63
78
|
"dist",
|