testeranto 0.233.2 → 0.233.3
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/package.json +1 -1
- package/src/grafeovidajo/package.json +2 -2
- package/src/viz-app/MarkdownChart.tsx +0 -115
- package/src/viz-app/hooks/useChartSync.ts +0 -66
- package/src/viz-app/hooks/useMarkdownFiles.ts +0 -84
- package/src/viz-app/index.ts +0 -10
- package/src/viz-app/markdown/parser.ts +0 -115
- package/src/viz-app/types.ts +0 -40
package/package.json
CHANGED
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import React, { useMemo, useCallback } from 'react';
|
|
2
|
-
import { GraphData, VizComponentProps, Node } from 'viz';
|
|
3
|
-
import { MarkdownChartProps } from './types';
|
|
4
|
-
import { useMarkdownFiles } from './hooks/useMarkdownFiles';
|
|
5
|
-
import { useChartSync } from './hooks/useChartSync';
|
|
6
|
-
import { markdownFilesToGraphData } from './markdown/parser';
|
|
7
|
-
|
|
8
|
-
export const MarkdownChart: React.FC<MarkdownChartProps> = ({
|
|
9
|
-
filePattern,
|
|
10
|
-
watchFiles = false,
|
|
11
|
-
chartComponent: ChartComponent,
|
|
12
|
-
chartConfig,
|
|
13
|
-
attributeMapping,
|
|
14
|
-
onFileChange,
|
|
15
|
-
onNodeUpdate,
|
|
16
|
-
width,
|
|
17
|
-
height
|
|
18
|
-
}) => {
|
|
19
|
-
const {
|
|
20
|
-
files,
|
|
21
|
-
loading,
|
|
22
|
-
error,
|
|
23
|
-
updateFile
|
|
24
|
-
} = useMarkdownFiles(filePattern, watchFiles);
|
|
25
|
-
|
|
26
|
-
const { handleNodeUpdate, handleNodeDrag } = useChartSync(
|
|
27
|
-
files,
|
|
28
|
-
updateFile,
|
|
29
|
-
attributeMapping
|
|
30
|
-
);
|
|
31
|
-
|
|
32
|
-
// Convert markdown files to graph data
|
|
33
|
-
const graphData = useMemo<GraphData>(() => {
|
|
34
|
-
return markdownFilesToGraphData(files, attributeMapping);
|
|
35
|
-
}, [files, attributeMapping]);
|
|
36
|
-
|
|
37
|
-
// Handle node interactions
|
|
38
|
-
const handleNodeClick = useCallback((node: Node) => {
|
|
39
|
-
// Could open the markdown file for editing
|
|
40
|
-
console.log('Node clicked:', node);
|
|
41
|
-
}, []);
|
|
42
|
-
|
|
43
|
-
const handleNodeHover = useCallback((node: Node | null) => {
|
|
44
|
-
// Could show tooltip with file info
|
|
45
|
-
console.log('Node hover:', node);
|
|
46
|
-
}, []);
|
|
47
|
-
|
|
48
|
-
const handleNodeInteraction = useCallback(async (
|
|
49
|
-
node: Node,
|
|
50
|
-
interactionType: 'drag' | 'attributeChange',
|
|
51
|
-
data: any
|
|
52
|
-
) => {
|
|
53
|
-
try {
|
|
54
|
-
if (interactionType === 'drag') {
|
|
55
|
-
await handleNodeDrag(node, data);
|
|
56
|
-
} else if (interactionType === 'attributeChange') {
|
|
57
|
-
await handleNodeUpdate(node, data);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Notify parent component
|
|
61
|
-
onNodeUpdate?.(node, data);
|
|
62
|
-
} catch (error) {
|
|
63
|
-
console.error('Failed to handle node interaction:', error);
|
|
64
|
-
}
|
|
65
|
-
}, [handleNodeDrag, handleNodeUpdate, onNodeUpdate]);
|
|
66
|
-
|
|
67
|
-
if (loading) {
|
|
68
|
-
return <div>Loading markdown files...</div>;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
if (error) {
|
|
72
|
-
return <div>Error loading files: {error.message}</div>;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if (files.length === 0) {
|
|
76
|
-
return <div>No markdown files found matching pattern: {filePattern}</div>;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// Enhance chart config with attribute mapping
|
|
80
|
-
const enhancedConfig = {
|
|
81
|
-
...chartConfig,
|
|
82
|
-
projection: {
|
|
83
|
-
...chartConfig.projection,
|
|
84
|
-
xAttribute: attributeMapping.xAttribute || chartConfig.projection.xAttribute,
|
|
85
|
-
yAttribute: attributeMapping.yAttribute || chartConfig.projection.yAttribute
|
|
86
|
-
}
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
return (
|
|
90
|
-
<div className="markdown-chart-container">
|
|
91
|
-
<div className="chart-header">
|
|
92
|
-
<h3>Visualizing {files.length} markdown files</h3>
|
|
93
|
-
<div className="file-info">
|
|
94
|
-
Files will be updated as you interact with the chart
|
|
95
|
-
</div>
|
|
96
|
-
</div>
|
|
97
|
-
|
|
98
|
-
<ChartComponent
|
|
99
|
-
data={graphData}
|
|
100
|
-
config={enhancedConfig}
|
|
101
|
-
width={width}
|
|
102
|
-
height={height}
|
|
103
|
-
onNodeClick={handleNodeClick}
|
|
104
|
-
onNodeHover={handleNodeHover}
|
|
105
|
-
// Additional props for drag interactions could be passed here
|
|
106
|
-
/>
|
|
107
|
-
|
|
108
|
-
<div className="chart-footer">
|
|
109
|
-
<small>
|
|
110
|
-
Each node represents a markdown file. Drag nodes to update their attributes.
|
|
111
|
-
</small>
|
|
112
|
-
</div>
|
|
113
|
-
</div>
|
|
114
|
-
);
|
|
115
|
-
};
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { useCallback } from 'react';
|
|
2
|
-
import { Node } from 'viz';
|
|
3
|
-
import { MarkdownFile } from '../types';
|
|
4
|
-
|
|
5
|
-
export function useChartSync(
|
|
6
|
-
files: MarkdownFile[],
|
|
7
|
-
updateFile: (filePath: string, updates: Record<string, any>) => Promise<MarkdownFile>,
|
|
8
|
-
attributeMapping: { idAttribute: string; xAttribute?: string; yAttribute?: string }
|
|
9
|
-
) {
|
|
10
|
-
const handleNodeUpdate = useCallback(async (
|
|
11
|
-
node: Node,
|
|
12
|
-
updates: Record<string, any>
|
|
13
|
-
) => {
|
|
14
|
-
const filePath = node.attributes._path;
|
|
15
|
-
if (!filePath) {
|
|
16
|
-
console.warn('Node has no associated file path:', node.id);
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// Remove internal attributes from updates
|
|
21
|
-
const cleanUpdates = { ...updates };
|
|
22
|
-
delete cleanUpdates._path;
|
|
23
|
-
delete cleanUpdates._body;
|
|
24
|
-
|
|
25
|
-
try {
|
|
26
|
-
await updateFile(filePath, cleanUpdates);
|
|
27
|
-
} catch (error) {
|
|
28
|
-
console.error('Failed to update file:', error);
|
|
29
|
-
throw error;
|
|
30
|
-
}
|
|
31
|
-
}, [updateFile]);
|
|
32
|
-
|
|
33
|
-
const handleNodeDrag = useCallback(async (
|
|
34
|
-
node: Node,
|
|
35
|
-
newPosition: { x: number; y: number }
|
|
36
|
-
) => {
|
|
37
|
-
// Map screen coordinates back to attribute values
|
|
38
|
-
// This depends on the projection configuration
|
|
39
|
-
const updates: Record<string, any> = {};
|
|
40
|
-
|
|
41
|
-
if (attributeMapping.xAttribute) {
|
|
42
|
-
// This is a simplification - actual mapping would depend on projection config
|
|
43
|
-
updates[attributeMapping.xAttribute] = newPosition.x;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
if (attributeMapping.yAttribute) {
|
|
47
|
-
updates[attributeMapping.yAttribute] = newPosition.y;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return handleNodeUpdate(node, updates);
|
|
51
|
-
}, [handleNodeUpdate, attributeMapping]);
|
|
52
|
-
|
|
53
|
-
const handleNodeAttributeChange = useCallback(async (
|
|
54
|
-
node: Node,
|
|
55
|
-
attribute: string,
|
|
56
|
-
value: any
|
|
57
|
-
) => {
|
|
58
|
-
return handleNodeUpdate(node, { [attribute]: value });
|
|
59
|
-
}, [handleNodeUpdate]);
|
|
60
|
-
|
|
61
|
-
return {
|
|
62
|
-
handleNodeUpdate,
|
|
63
|
-
handleNodeDrag,
|
|
64
|
-
handleNodeAttributeChange
|
|
65
|
-
};
|
|
66
|
-
}
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import { useState, useEffect, useCallback } from 'react';
|
|
2
|
-
import { MarkdownFile, FileSystemAdapter } from '../types';
|
|
3
|
-
import { parseMarkdownFile, updateMarkdownFile } from '../markdown/parser';
|
|
4
|
-
|
|
5
|
-
// Default file system adapter (can be overridden)
|
|
6
|
-
const defaultFileSystemAdapter: FileSystemAdapter = {
|
|
7
|
-
async readFiles(pattern: string | string[]): Promise<MarkdownFile[]> {
|
|
8
|
-
// This would be implemented with actual file system access
|
|
9
|
-
// For now, return empty array - implementation depends on environment
|
|
10
|
-
console.warn('Default file system adapter not implemented');
|
|
11
|
-
return [];
|
|
12
|
-
},
|
|
13
|
-
|
|
14
|
-
async writeFile(file: MarkdownFile): Promise<void> {
|
|
15
|
-
console.warn('Default file system adapter not implemented');
|
|
16
|
-
},
|
|
17
|
-
|
|
18
|
-
watchFiles(pattern: string | string[], callback: (files: MarkdownFile[]) => void): () => void {
|
|
19
|
-
console.warn('Default file system adapter not implemented');
|
|
20
|
-
return () => {};
|
|
21
|
-
}
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
export function useMarkdownFiles(
|
|
25
|
-
filePattern: string | string[],
|
|
26
|
-
watchFiles: boolean = false,
|
|
27
|
-
fileSystemAdapter: FileSystemAdapter = defaultFileSystemAdapter
|
|
28
|
-
) {
|
|
29
|
-
const [files, setFiles] = useState<MarkdownFile[]>([]);
|
|
30
|
-
const [loading, setLoading] = useState(true);
|
|
31
|
-
const [error, setError] = useState<Error | null>(null);
|
|
32
|
-
|
|
33
|
-
const loadFiles = useCallback(async () => {
|
|
34
|
-
try {
|
|
35
|
-
setLoading(true);
|
|
36
|
-
const fileContents = await fileSystemAdapter.readFiles(filePattern);
|
|
37
|
-
setFiles(fileContents);
|
|
38
|
-
setError(null);
|
|
39
|
-
} catch (err) {
|
|
40
|
-
setError(err instanceof Error ? err : new Error('Failed to load files'));
|
|
41
|
-
} finally {
|
|
42
|
-
setLoading(false);
|
|
43
|
-
}
|
|
44
|
-
}, [filePattern, fileSystemAdapter]);
|
|
45
|
-
|
|
46
|
-
const updateFile = useCallback(async (
|
|
47
|
-
filePath: string,
|
|
48
|
-
updates: Record<string, any>
|
|
49
|
-
) => {
|
|
50
|
-
const file = files.find(f => f.path === filePath);
|
|
51
|
-
if (!file) throw new Error(`File not found: ${filePath}`);
|
|
52
|
-
|
|
53
|
-
const updatedFile = updateMarkdownFile(file, updates);
|
|
54
|
-
|
|
55
|
-
await fileSystemAdapter.writeFile(updatedFile);
|
|
56
|
-
|
|
57
|
-
// Update local state
|
|
58
|
-
setFiles(prev => prev.map(f =>
|
|
59
|
-
f.path === filePath ? updatedFile : f
|
|
60
|
-
));
|
|
61
|
-
|
|
62
|
-
return updatedFile;
|
|
63
|
-
}, [files, fileSystemAdapter]);
|
|
64
|
-
|
|
65
|
-
useEffect(() => {
|
|
66
|
-
loadFiles();
|
|
67
|
-
|
|
68
|
-
if (watchFiles) {
|
|
69
|
-
const unwatch = fileSystemAdapter.watchFiles(filePattern, (newFiles) => {
|
|
70
|
-
setFiles(newFiles);
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
return unwatch;
|
|
74
|
-
}
|
|
75
|
-
}, [filePattern, watchFiles, fileSystemAdapter, loadFiles]);
|
|
76
|
-
|
|
77
|
-
return {
|
|
78
|
-
files,
|
|
79
|
-
loading,
|
|
80
|
-
error,
|
|
81
|
-
reload: loadFiles,
|
|
82
|
-
updateFile
|
|
83
|
-
};
|
|
84
|
-
}
|
package/src/viz-app/index.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export { MarkdownChart } from './MarkdownChart';
|
|
2
|
-
export { useMarkdownFiles } from './hooks/useMarkdownFiles';
|
|
3
|
-
export { useChartSync } from './hooks/useChartSync';
|
|
4
|
-
export { parseMarkdownFile, markdownFilesToGraphData, updateMarkdownFile } from './markdown/parser';
|
|
5
|
-
|
|
6
|
-
export type {
|
|
7
|
-
MarkdownChartProps,
|
|
8
|
-
MarkdownFile,
|
|
9
|
-
FileSystemAdapter
|
|
10
|
-
} from './types';
|
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import { MarkdownFile } from '../types';
|
|
2
|
-
import { GraphData } from 'viz';
|
|
3
|
-
|
|
4
|
-
const FRONTMATTER_REGEX = /^---\s*\n([\s\S]*?)\n---\s*\n([\s\S]*)$/;
|
|
5
|
-
|
|
6
|
-
export function parseMarkdownFile(path: string, content: string): MarkdownFile {
|
|
7
|
-
const match = content.match(FRONTMATTER_REGEX);
|
|
8
|
-
|
|
9
|
-
if (match) {
|
|
10
|
-
const [, frontmatterStr, body] = match;
|
|
11
|
-
const frontmatter = parseYAML(frontmatterStr);
|
|
12
|
-
|
|
13
|
-
return {
|
|
14
|
-
path,
|
|
15
|
-
content,
|
|
16
|
-
frontmatter,
|
|
17
|
-
body: body.trim()
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// No frontmatter - treat entire content as body
|
|
22
|
-
return {
|
|
23
|
-
path,
|
|
24
|
-
content,
|
|
25
|
-
frontmatter: {},
|
|
26
|
-
body: content.trim()
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function parseYAML(yamlStr: string): Record<string, any> {
|
|
31
|
-
try {
|
|
32
|
-
// Simple YAML parser for basic key-value pairs
|
|
33
|
-
const result: Record<string, any> = {};
|
|
34
|
-
const lines = yamlStr.split('\n');
|
|
35
|
-
|
|
36
|
-
for (const line of lines) {
|
|
37
|
-
const trimmed = line.trim();
|
|
38
|
-
if (!trimmed || trimmed.startsWith('#')) continue;
|
|
39
|
-
|
|
40
|
-
const colonIndex = trimmed.indexOf(':');
|
|
41
|
-
if (colonIndex > 0) {
|
|
42
|
-
const key = trimmed.substring(0, colonIndex).trim();
|
|
43
|
-
let value = trimmed.substring(colonIndex + 1).trim();
|
|
44
|
-
|
|
45
|
-
// Try to parse values
|
|
46
|
-
if (value === 'true') value = true;
|
|
47
|
-
else if (value === 'false') value = false;
|
|
48
|
-
else if (value === 'null') value = null;
|
|
49
|
-
else if (!isNaN(Number(value)) && value !== '') value = Number(value);
|
|
50
|
-
else if (value.startsWith('"') && value.endsWith('"')) {
|
|
51
|
-
value = value.slice(1, -1);
|
|
52
|
-
} else if (value.startsWith("'") && value.endsWith("'")) {
|
|
53
|
-
value = value.slice(1, -1);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
result[key] = value;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return result;
|
|
61
|
-
} catch (error) {
|
|
62
|
-
console.warn('Failed to parse YAML frontmatter:', error);
|
|
63
|
-
return {};
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export function markdownFilesToGraphData(
|
|
68
|
-
files: MarkdownFile[],
|
|
69
|
-
attributeMapping: { idAttribute: string; xAttribute?: string; yAttribute?: string }
|
|
70
|
-
): GraphData {
|
|
71
|
-
const nodes = files.map(file => {
|
|
72
|
-
const id = file.frontmatter[attributeMapping.idAttribute] ||
|
|
73
|
-
file.path.split('/').pop()?.replace('.md', '') ||
|
|
74
|
-
`node-${Math.random().toString(36).substr(2, 9)}`;
|
|
75
|
-
|
|
76
|
-
return {
|
|
77
|
-
id,
|
|
78
|
-
attributes: {
|
|
79
|
-
...file.frontmatter,
|
|
80
|
-
_path: file.path,
|
|
81
|
-
_body: file.body
|
|
82
|
-
}
|
|
83
|
-
};
|
|
84
|
-
});
|
|
85
|
-
|
|
86
|
-
return { nodes };
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
export function updateMarkdownFile(
|
|
90
|
-
file: MarkdownFile,
|
|
91
|
-
updatedAttributes: Record<string, any>
|
|
92
|
-
): MarkdownFile {
|
|
93
|
-
const newFrontmatter = { ...file.frontmatter, ...updatedAttributes };
|
|
94
|
-
|
|
95
|
-
// Remove internal attributes that shouldn't be in frontmatter
|
|
96
|
-
delete newFrontmatter._path;
|
|
97
|
-
delete newFrontmatter._body;
|
|
98
|
-
|
|
99
|
-
// Convert frontmatter back to YAML
|
|
100
|
-
const frontmatterLines = Object.entries(newFrontmatter)
|
|
101
|
-
.map(([key, value]) => {
|
|
102
|
-
if (value === null || value === undefined) return `${key}: null`;
|
|
103
|
-
if (typeof value === 'string') return `${key}: "${value}"`;
|
|
104
|
-
if (typeof value === 'boolean') return `${key}: ${value}`;
|
|
105
|
-
return `${key}: ${value}`;
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
const newContent = `---\n${frontmatterLines.join('\n')}\n---\n\n${file.body}`;
|
|
109
|
-
|
|
110
|
-
return {
|
|
111
|
-
...file,
|
|
112
|
-
content: newContent,
|
|
113
|
-
frontmatter: newFrontmatter
|
|
114
|
-
};
|
|
115
|
-
}
|
package/src/viz-app/types.ts
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
import { GraphData, Node, VizConfig, VizComponentProps } from 'viz';
|
|
2
|
-
|
|
3
|
-
export interface MarkdownFile {
|
|
4
|
-
path: string;
|
|
5
|
-
content: string;
|
|
6
|
-
frontmatter: Record<string, any>;
|
|
7
|
-
body: string;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface MarkdownChartProps {
|
|
11
|
-
// File system configuration
|
|
12
|
-
filePattern: string | string[]; // Glob pattern(s) for markdown files
|
|
13
|
-
watchFiles?: boolean; // Watch for file changes
|
|
14
|
-
|
|
15
|
-
// Chart configuration
|
|
16
|
-
chartComponent: React.ComponentType<VizComponentProps>;
|
|
17
|
-
chartConfig: VizConfig;
|
|
18
|
-
|
|
19
|
-
// Attribute mapping
|
|
20
|
-
attributeMapping: {
|
|
21
|
-
idAttribute: string; // Which frontmatter field becomes node.id
|
|
22
|
-
xAttribute?: string; // Maps to projection.xAttribute
|
|
23
|
-
yAttribute?: string; // Maps to projection.yAttribute
|
|
24
|
-
// Additional attribute mappings can be inferred from frontmatter
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
// Callbacks
|
|
28
|
-
onFileChange?: (file: MarkdownFile) => void;
|
|
29
|
-
onNodeUpdate?: (node: Node, oldAttributes: Record<string, any>) => void;
|
|
30
|
-
|
|
31
|
-
// Display
|
|
32
|
-
width: number;
|
|
33
|
-
height: number;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export interface FileSystemAdapter {
|
|
37
|
-
readFiles(pattern: string | string[]): Promise<MarkdownFile[]>;
|
|
38
|
-
writeFile(file: MarkdownFile): Promise<void>;
|
|
39
|
-
watchFiles(pattern: string | string[], callback: (files: MarkdownFile[]) => void): () => void;
|
|
40
|
-
}
|