noteconnection 1.7.0 → 1.8.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/LICENSE +674 -21
- package/README.md +242 -62
- package/dist/src/agent_workspace.contract.parity.test.js +475 -0
- package/dist/src/agent_workspace.frontend.test.js +9989 -0
- package/dist/src/agent_workspace.locale.contract.test.js +95 -0
- package/dist/src/agent_workspace.runtime.behavior.test.js +5072 -0
- package/dist/src/copy.assets.contract.test.js +130 -0
- package/dist/src/core/PathBridge.js +28 -3
- package/dist/src/export/WorkspaceExportBundle.js +1130 -0
- package/dist/src/export/WorkspaceExportBundle.test.js +1480 -0
- package/dist/src/export/index.js +18 -0
- package/dist/src/export/types.js +2 -0
- package/dist/src/fixrisk.issue.verifier.contract.test.js +3 -1
- package/dist/src/foundation.ann.runtime.contract.test.js +81 -0
- package/dist/src/foundation.release.evidence.contract.test.js +406 -0
- package/dist/src/foundation.sqlite.runtime.contract.test.js +82 -0
- package/dist/src/frontend/README.md +242 -62
- package/dist/src/frontend/agent_workspace.js +5353 -0
- package/dist/src/frontend/agent_workspace_runtime.js +4434 -0
- package/dist/src/frontend/analysis.js +31 -4
- package/dist/src/frontend/app.js +2178 -62
- package/dist/src/frontend/focus_mode_interactions.js +33 -0
- package/dist/src/frontend/godot_future_path_renderer.js +540 -0
- package/dist/src/frontend/godot_tree_interactions.js +178 -0
- package/dist/src/frontend/graph_state.mjs +105 -0
- package/dist/src/frontend/hosted_future_path_runtime.js +157 -0
- package/dist/src/frontend/i18n.mjs +186 -0
- package/dist/src/frontend/index.html +641 -266
- package/dist/src/frontend/layout_gpu.js +12 -4
- package/dist/src/frontend/locales/en.json +721 -5
- package/dist/src/frontend/locales/zh.json +721 -5
- package/dist/src/frontend/main.mjs +60 -0
- package/dist/src/frontend/markdown_runtime.js +827 -0
- package/dist/src/frontend/notemd.css +49 -0
- package/dist/src/frontend/notemd.html +7 -1
- package/dist/src/frontend/notemd.js +64 -0
- package/dist/src/frontend/path.html +107 -0
- package/dist/src/frontend/path_app.js +2108 -130
- package/dist/src/frontend/path_layout.mjs +143 -0
- package/dist/src/frontend/path_mermaid_utils.mjs +108 -0
- package/dist/src/frontend/path_modules_bridge.js +486 -0
- package/dist/src/frontend/path_state.mjs +118 -0
- package/dist/src/frontend/path_styles.css +146 -0
- package/dist/src/frontend/path_worker_bridge.mjs +85 -0
- package/dist/src/frontend/reader.js +393 -33
- package/dist/src/frontend/runtime_bridge.js +67 -54
- package/dist/src/frontend/runtime_bridge.mjs +279 -0
- package/dist/src/frontend/settings.js +130 -12
- package/dist/src/frontend/source_manager.js +190 -21
- package/dist/src/frontend/styles.css +2720 -72
- package/dist/src/frontend/workbench_state.mjs +101 -0
- package/dist/src/frontend/workspace_panes.js +10168 -0
- package/dist/src/frontend.locale.contract.test.js +62 -0
- package/dist/src/godot.sidecar.bootstrap.contract.test.js +244 -0
- package/dist/src/indexing/IndexLifecycle.js +195 -0
- package/dist/src/indexing/IndexLifecycle.test.js +49 -0
- package/dist/src/indexing/SegmentBuilder.js +64 -0
- package/dist/src/indexing/UnitBuilder.js +48 -0
- package/dist/src/indexing/types.js +2 -0
- package/dist/src/knowledge.api.contract.test.js +170 -0
- package/dist/src/learning/KnowledgeLearningPlatform.js +10386 -0
- package/dist/src/learning/KnowledgeLearningPlatform.persistence.test.js +327 -0
- package/dist/src/learning/KnowledgeLearningPlatform.program-f.test.js +99 -0
- package/dist/src/learning/KnowledgeLearningPlatform.test.js +2971 -0
- package/dist/src/learning/KnowledgeWorkspaceConversationRegression.js +2974 -0
- package/dist/src/learning/KnowledgeWorkspaceConversationRegression.test.js +3928 -0
- package/dist/src/learning/answerReleaseReview.js +4319 -0
- package/dist/src/learning/answerReleaseReview.test.js +2888 -0
- package/dist/src/learning/api.js +2 -0
- package/dist/src/learning/conversationComposer.js +1480 -0
- package/dist/src/learning/conversationComposer.test.js +1817 -0
- package/dist/src/learning/domains/ConversationManager.js +53 -0
- package/dist/src/learning/domains/KnowledgeIngestor.js +238 -0
- package/dist/src/learning/domains/KnowledgeQuerier.js +187 -0
- package/dist/src/learning/domains/MasteryEngine.js +387 -0
- package/dist/src/learning/domains/MemoryPolicyManager.js +408 -0
- package/dist/src/learning/domains/QualityEvaluator.js +307 -0
- package/dist/src/learning/domains/TutorRouter.js +313 -0
- package/dist/src/learning/domains/index.js +33 -0
- package/dist/src/learning/domains/types.js +7 -0
- package/dist/src/learning/errors.js +29 -0
- package/dist/src/learning/evidenceContextAssembler.js +1176 -0
- package/dist/src/learning/evidenceContextAssembler.test.js +6332 -0
- package/dist/src/learning/graphContextAssembler.js +870 -0
- package/dist/src/learning/graphContextAssembler.test.js +1033 -0
- package/dist/src/learning/index.js +28 -0
- package/dist/src/learning/queryBackend.js +1898 -0
- package/dist/src/learning/queryBackend.test.js +955 -0
- package/dist/src/learning/ragContextPack.js +257 -0
- package/dist/src/learning/ragContextPack.test.js +160 -0
- package/dist/src/learning/ragPublicText.js +38 -0
- package/dist/src/learning/ragSufficiencyJudge.js +161 -0
- package/dist/src/learning/ragSufficiencyJudge.test.js +177 -0
- package/dist/src/learning/ragSufficiencyProviderJudge.js +227 -0
- package/dist/src/learning/ragSufficiencyProviderJudge.test.js +156 -0
- package/dist/src/learning/requestNormalization.js +198 -0
- package/dist/src/learning/runtimeCapability.js +4677 -0
- package/dist/src/learning/runtimeCapability.test.js +3635 -0
- package/dist/src/learning/store.js +1240 -0
- package/dist/src/learning/store.test.js +1126 -0
- package/dist/src/learning/tutorAdapter.js +2 -0
- package/dist/src/learning/types.js +2 -0
- package/dist/src/learning/vectorAccelerationAdapter.js +942 -0
- package/dist/src/learning/vectorAccelerationAdapter.test.js +382 -0
- package/dist/src/lfs.asset.policy.contract.test.js +153 -0
- package/dist/src/license.policy.contract.test.js +66 -0
- package/dist/src/memory/MemoryGovernance.js +74 -0
- package/dist/src/memory/MemoryGovernance.test.js +46 -0
- package/dist/src/memory/types.js +2 -0
- package/dist/src/mermaid.frontend.guard.contract.test.js +77 -0
- package/dist/src/middleware/auth.js +17 -0
- package/dist/src/middleware/body-parser.js +45 -0
- package/dist/src/middleware/cors.js +44 -0
- package/dist/src/middleware/index.js +21 -0
- package/dist/src/middleware/request-trace.js +96 -0
- package/dist/src/notemd/AppConfigToml.js +6 -4
- package/dist/src/notemd/MermaidProcessor.js +400 -50
- package/dist/src/notemd/NotemdService.js +498 -13
- package/dist/src/notemd/PromptManager.js +15 -0
- package/dist/src/notemd/cli/commands.js +357 -0
- package/dist/src/notemd/cli/dispatcher.js +225 -0
- package/dist/src/notemd/cli/index.js +169 -0
- package/dist/src/notemd/cli/parser.js +68 -0
- package/dist/src/notemd/cli/types.js +2 -0
- package/dist/src/notemd/constants.js +43 -0
- package/dist/src/notemd/diagram/diagramGenerationService.js +78 -0
- package/dist/src/notemd/diagram/diagramSpec.js +79 -0
- package/dist/src/notemd/diagram/diagramSpecResponseParser.js +131 -0
- package/dist/src/notemd/diagram/intent.js +95 -0
- package/dist/src/notemd/diagram/planner.js +71 -0
- package/dist/src/notemd/diagram/prompts/diagramSpecPrompt.js +42 -0
- package/dist/src/notemd/diagram/types.js +18 -0
- package/dist/src/notemd/index.js +26 -0
- package/dist/src/notemd/operations/capabilityManifest.js +23 -0
- package/dist/src/notemd/operations/cliContracts.js +17 -0
- package/dist/src/notemd/operations/configProfileCommands.js +85 -0
- package/dist/src/notemd/operations/registry.contract.test.js +95 -0
- package/dist/src/notemd/operations/registry.js +991 -0
- package/dist/src/notemd/operations/types.js +2 -0
- package/dist/src/notemd/providerDiagnostics.js +220 -0
- package/dist/src/notemd/providerProfiles.js +42 -0
- package/dist/src/notemd/providerTemplates.js +231 -0
- package/dist/src/notemd/search/DuckDuckGoProvider.js +39 -0
- package/dist/src/notemd/search/SearchManager.js +13 -0
- package/dist/src/notemd/search/SearchProvider.js +2 -0
- package/dist/src/notemd/search/TavilyProvider.js +44 -0
- package/dist/src/notemd.agent.manifest.test.js +85 -0
- package/dist/src/notemd.api.contract.test.js +14 -1
- package/dist/src/notemd.app_config_toml.test.js +2 -1
- package/dist/src/notemd.batch.workflow.test.js +117 -0
- package/dist/src/notemd.cli.e2e.test.js +136 -0
- package/dist/src/notemd.core.test.js +51 -0
- package/dist/src/notemd.diagram.pipeline.test.js +233 -0
- package/dist/src/notemd.providerTemplates.test.js +34 -0
- package/dist/src/notemd.server.integration.test.js +143 -35
- package/dist/src/notemd.workflow.pipeline.test.js +162 -0
- package/dist/src/pathbridge.handshake.contract.test.js +16 -2
- package/dist/src/pathmode.background.contract.test.js +69 -0
- package/dist/src/pathmode.settings.api.contract.test.js +9 -0
- package/dist/src/pkg.sidecar.contract.test.js +9 -3
- package/dist/src/platform/ExportProfile.js +58 -0
- package/dist/src/platform/PlatformCapabilities.js +45 -0
- package/dist/src/platform/PlatformCapabilities.test.js +30 -0
- package/dist/src/platform/RenderMaterializer.js +33 -0
- package/dist/src/platform/RenderMaterializer.test.js +32 -0
- package/dist/src/query_backend.external_http.integration.test.js +410 -0
- package/dist/src/reader_renderer.js +404 -3
- package/dist/src/reader_renderer.test.js +87 -0
- package/dist/src/release.godot.mirror.contract.test.js +73 -0
- package/dist/src/resources/ResourceRegistry.js +223 -0
- package/dist/src/resources/ResourceRegistry.test.js +61 -0
- package/dist/src/resources/types.js +2 -0
- package/dist/src/routes/agentWorkspaceDiagnostics.js +173 -0
- package/dist/src/routes/data.js +267 -0
- package/dist/src/routes/diagnostics.js +51 -0
- package/dist/src/routes/index.js +23 -0
- package/dist/src/routes/knowledge.js +968 -0
- package/dist/src/routes/markdown.js +287 -0
- package/dist/src/routes/notemd.js +565 -0
- package/dist/src/routes/registry.contract.test.js +130 -0
- package/dist/src/routes/render.js +285 -0
- package/dist/src/routes/runtimeRunbookRouteOps.js +149 -0
- package/dist/src/routes/runtimeRunbookRouteOps.test.js +194 -0
- package/dist/src/routes/settings.js +6 -0
- package/dist/src/routes/staticFiles.js +94 -0
- package/dist/src/routes/types.js +2 -0
- package/dist/src/runtime.transport.adapter.contract.test.js +81 -0
- package/dist/src/server.js +11090 -1549
- package/dist/src/server.migration.test.js +193 -21
- package/dist/src/server.port.fallback.contract.test.js +63 -0
- package/dist/src/session/SessionStateStore.js +81 -0
- package/dist/src/session/SessionStateStore.test.js +58 -0
- package/dist/src/session/types.js +2 -0
- package/dist/src/settings.runtime.contract.test.js +50 -0
- package/dist/src/shared/types.contract.test.js +107 -0
- package/dist/src/shared/types.js +22 -0
- package/dist/src/sidecar.replacement.boundary.contract.test.js +128 -0
- package/dist/src/sidecar.supply.readiness.contract.test.js +144 -0
- package/dist/src/source_manager.loadflow.test.js +46 -0
- package/dist/src/startup.layout.snapshot.contract.test.js +57 -0
- package/dist/src/tauri.frontend.build.contract.test.js +60 -0
- package/dist/src/tauri.sidecar.cleanup.contract.test.js +21 -0
- package/dist/src/utils/RuntimePaths.js +4 -13
- package/dist/src/utils/platform.js +153 -0
- package/dist/src/workflows/WorkflowArtifactStore.js +96 -0
- package/dist/src/workflows/WorkflowArtifactStore.test.js +80 -0
- package/dist/src/workflows/types.js +2 -0
- package/dist/src/workspace/WorkspaceRegistry.js +122 -0
- package/dist/src/workspace/WorkspaceRegistry.test.js +29 -0
- package/dist/src/workspace/types.js +2 -0
- package/package.json +53 -10
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* path_layout.mjs — Extracted path layout calculation utilities.
|
|
3
|
+
* Tree layout, orbital positioning, and node arrangement algorithms.
|
|
4
|
+
* Formerly inline in path_app.js.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/** Compute a simple tree layout from a flat node list with parent-child edges. */
|
|
8
|
+
export function computeTreeLayout(nodes, edges, rootId, options = {}) {
|
|
9
|
+
const { horizontalSpacing = 180, verticalSpacing = 120 } = options;
|
|
10
|
+
const adjacency = new Map();
|
|
11
|
+
const inDegree = new Map();
|
|
12
|
+
const positions = new Map();
|
|
13
|
+
|
|
14
|
+
for (const node of nodes) {
|
|
15
|
+
adjacency.set(node.id, []);
|
|
16
|
+
inDegree.set(node.id, 0);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
for (const edge of edges) {
|
|
20
|
+
const children = adjacency.get(edge.source);
|
|
21
|
+
if (children) children.push(edge.target);
|
|
22
|
+
inDegree.set(edge.target, (inDegree.get(edge.target) || 0) + 1);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// BFS from root to assign layers
|
|
26
|
+
const layers = [];
|
|
27
|
+
const visited = new Set();
|
|
28
|
+
const queue = [{ id: rootId, layer: 0 }];
|
|
29
|
+
visited.add(rootId);
|
|
30
|
+
|
|
31
|
+
while (queue.length > 0) {
|
|
32
|
+
const { id, layer } = queue.shift();
|
|
33
|
+
if (!layers[layer]) layers[layer] = [];
|
|
34
|
+
layers[layer].push(id);
|
|
35
|
+
|
|
36
|
+
const children = adjacency.get(id) || [];
|
|
37
|
+
for (const childId of children) {
|
|
38
|
+
if (!visited.has(childId)) {
|
|
39
|
+
visited.add(childId);
|
|
40
|
+
queue.push({ id: childId, layer: layer + 1 });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Position nodes within layers
|
|
46
|
+
for (let i = 0; i < layers.length; i++) {
|
|
47
|
+
const layerNodes = layers[i];
|
|
48
|
+
const totalWidth = (layerNodes.length - 1) * horizontalSpacing;
|
|
49
|
+
const startX = -totalWidth / 2;
|
|
50
|
+
|
|
51
|
+
for (let j = 0; j < layerNodes.length; j++) {
|
|
52
|
+
positions.set(layerNodes[j], {
|
|
53
|
+
x: startX + j * horizontalSpacing,
|
|
54
|
+
y: i * verticalSpacing,
|
|
55
|
+
layer: i,
|
|
56
|
+
index: j,
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return { positions, layers, nodeCount: nodes.length, depth: layers.length };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Compute orbital positions for path visualization.
|
|
66
|
+
* Nodes orbit around a central point with increasing radius per layer.
|
|
67
|
+
*/
|
|
68
|
+
export function computeOrbitalLayout(nodes, edges, centerId, options = {}) {
|
|
69
|
+
const { baseRadius = 200, radiusIncrement = 150, nodesPerOrbit = 8 } = options;
|
|
70
|
+
|
|
71
|
+
const treeResult = computeTreeLayout(nodes, edges, centerId, options);
|
|
72
|
+
const positions = new Map();
|
|
73
|
+
|
|
74
|
+
for (const [nodeId, treePos] of treeResult.positions) {
|
|
75
|
+
const angle = (treePos.index / Math.max(1, treeResult.layers[treePos.layer]?.length || 1)) * Math.PI * 2;
|
|
76
|
+
const radius = baseRadius + treePos.layer * radiusIncrement;
|
|
77
|
+
positions.set(nodeId, {
|
|
78
|
+
x: Math.cos(angle) * radius,
|
|
79
|
+
y: Math.sin(angle) * radius,
|
|
80
|
+
z: treePos.layer * 50,
|
|
81
|
+
layer: treePos.layer,
|
|
82
|
+
angle,
|
|
83
|
+
radius,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return { positions, depth: treeResult.depth, centerId };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Compute a force-directed radial layout for hierarchical path data.
|
|
92
|
+
*/
|
|
93
|
+
export function computeRadialLayout(nodes, edges, centerId, options = {}) {
|
|
94
|
+
const { radius = 300, spread = 60 } = options;
|
|
95
|
+
const adjacency = new Map();
|
|
96
|
+
|
|
97
|
+
for (const node of nodes) adjacency.set(node.id, []);
|
|
98
|
+
for (const edge of edges) {
|
|
99
|
+
const children = adjacency.get(edge.source);
|
|
100
|
+
if (children) children.push(edge.target);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const positions = new Map();
|
|
104
|
+
positions.set(centerId, { x: 0, y: 0, z: 0, isCenter: true });
|
|
105
|
+
|
|
106
|
+
const visited = new Set([centerId]);
|
|
107
|
+
const queue = [{ id: centerId, depth: 0, angleStart: 0, angleEnd: Math.PI * 2 }];
|
|
108
|
+
|
|
109
|
+
while (queue.length > 0) {
|
|
110
|
+
const { id, depth, angleStart, angleEnd } = queue.shift();
|
|
111
|
+
const children = adjacency.get(id) || [];
|
|
112
|
+
const angleRange = angleEnd - angleStart;
|
|
113
|
+
|
|
114
|
+
for (let i = 0; i < children.length; i++) {
|
|
115
|
+
const childId = children[i];
|
|
116
|
+
if (visited.has(childId)) continue;
|
|
117
|
+
visited.add(childId);
|
|
118
|
+
|
|
119
|
+
const angle = angleStart + (i + 0.5) * (angleRange / children.length);
|
|
120
|
+
const r = radius + depth * spread;
|
|
121
|
+
positions.set(childId, { x: Math.cos(angle) * r, y: Math.sin(angle) * r, z: depth * 40, depth: depth + 1, angle });
|
|
122
|
+
|
|
123
|
+
const childRange = angleRange / children.length;
|
|
124
|
+
queue.push({ id: childId, depth: depth + 1, angleStart: angleStart + i * childRange, angleEnd: angleStart + (i + 1) * childRange });
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return { positions, nodeCount: nodes.length };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Get the bounding box of computed positions for viewport fitting.
|
|
133
|
+
*/
|
|
134
|
+
export function getLayoutBounds(positions) {
|
|
135
|
+
let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
|
|
136
|
+
for (const pos of positions.values()) {
|
|
137
|
+
if (pos.x < minX) minX = pos.x;
|
|
138
|
+
if (pos.y < minY) minY = pos.y;
|
|
139
|
+
if (pos.x > maxX) maxX = pos.x;
|
|
140
|
+
if (pos.y > maxY) maxY = pos.y;
|
|
141
|
+
}
|
|
142
|
+
return { minX, minY, maxX, maxY, width: maxX - minX, height: maxY - minY };
|
|
143
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* path_mermaid_utils.mjs — Pure SVG/Mermaid utility functions
|
|
3
|
+
* extracted from path_app.js (v2.6).
|
|
4
|
+
*
|
|
5
|
+
* These are stateless pure functions with no DOM or event coupling.
|
|
6
|
+
* They can be independently tested and used by any module that
|
|
7
|
+
* needs SVG text measurement, CSS parsing, or glyph width estimation.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
export function normalizeBridgeInlineText(text) {
|
|
11
|
+
return String(text || '').replace(/\s+/g, ' ').trim();
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function parseBridgeNumericAttribute(element, name, fallback = 0) {
|
|
15
|
+
const numeric = Number.parseFloat(String(element?.getAttribute?.(name) || ''));
|
|
16
|
+
return Number.isFinite(numeric) ? numeric : fallback;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function extractBridgeInlineStyleValue(styleValue, propertyName) {
|
|
20
|
+
if (!styleValue) return null;
|
|
21
|
+
const pattern = new RegExp('(?:^|;)\\s*' + propertyName + '\\s*:\\s*([^;]+)', 'i');
|
|
22
|
+
const match = String(styleValue).match(pattern);
|
|
23
|
+
return match && match[1] ? String(match[1]).trim() : null;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function resolveBridgeTextProperty(element, propertyName) {
|
|
27
|
+
let current = element;
|
|
28
|
+
while (current) {
|
|
29
|
+
const attributeValue = current.getAttribute?.(propertyName);
|
|
30
|
+
if (attributeValue && String(attributeValue).trim()) {
|
|
31
|
+
return String(attributeValue).trim();
|
|
32
|
+
}
|
|
33
|
+
const styleValue = extractBridgeInlineStyleValue(
|
|
34
|
+
current.getAttribute?.('style'), propertyName
|
|
35
|
+
);
|
|
36
|
+
if (styleValue) return styleValue;
|
|
37
|
+
current = current.parentElement || null;
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export function parseBridgeCssLength(lengthValue, baseFontSize) {
|
|
43
|
+
if (!lengthValue) return 0;
|
|
44
|
+
const normalized = String(lengthValue).trim().toLowerCase();
|
|
45
|
+
if (!normalized || normalized === 'normal') return 0;
|
|
46
|
+
const numeric = Number.parseFloat(normalized);
|
|
47
|
+
if (!Number.isFinite(numeric) || numeric <= 0) return 0;
|
|
48
|
+
if (normalized.endsWith('em') || normalized.endsWith('rem')) {
|
|
49
|
+
return numeric * Math.max(10, baseFontSize || 16);
|
|
50
|
+
}
|
|
51
|
+
if (normalized.endsWith('%')) {
|
|
52
|
+
return (numeric / 100) * Math.max(10, baseFontSize || 16);
|
|
53
|
+
}
|
|
54
|
+
return numeric;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function resolveBridgeSvgFontSize(element) {
|
|
58
|
+
const resolvedValue = resolveBridgeTextProperty(element, 'font-size');
|
|
59
|
+
const parsed = parseBridgeCssLength(resolvedValue, 16);
|
|
60
|
+
return parsed > 0 ? parsed : 16;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function resolveBridgeSvgLineHeight(element, fontSize) {
|
|
64
|
+
const resolvedValue = resolveBridgeTextProperty(element, 'line-height');
|
|
65
|
+
const parsed = parseBridgeCssLength(resolvedValue, fontSize);
|
|
66
|
+
return parsed > 0 ? parsed : Math.max(fontSize * 1.18, fontSize + 4);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function isBridgeWideGlyph(char) {
|
|
70
|
+
return /[ᄀ-ᅟ⺀-가-힣豈-︐-︙︰-!-⦆¢-₩\u{1F300}-\u{1FAFF}]/u.test(char);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function estimateBridgeGlyphWidthUnits(char) {
|
|
74
|
+
if (!char) return 0;
|
|
75
|
+
if (/\s/.test(char)) return 0.35;
|
|
76
|
+
if (isBridgeWideGlyph(char)) return 1.02;
|
|
77
|
+
if (/[.,;:!'`|]/.test(char)) return 0.32;
|
|
78
|
+
if (/[(){}\[\]<>]/.test(char)) return 0.46;
|
|
79
|
+
if (/[\\/_-]/.test(char)) return 0.5;
|
|
80
|
+
if (/[0-9]/.test(char)) return 0.62;
|
|
81
|
+
if (/[A-Z]/.test(char)) return 0.72;
|
|
82
|
+
if (/[a-z]/.test(char)) return 0.64;
|
|
83
|
+
return 0.7;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function estimateBridgeTextLineWidth(text, fontSize) {
|
|
87
|
+
let units = 0;
|
|
88
|
+
for (const char of Array.from(String(text || ''))) {
|
|
89
|
+
units += estimateBridgeGlyphWidthUnits(char);
|
|
90
|
+
}
|
|
91
|
+
return Math.max(fontSize * 0.75, (units * fontSize) + Math.max(2, fontSize * 0.12));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function splitBridgeTokenForWrap(token, fontSize, maxLineWidth) {
|
|
95
|
+
const wrapped = [];
|
|
96
|
+
let segment = '';
|
|
97
|
+
for (const char of Array.from(token)) {
|
|
98
|
+
const candidate = segment + char;
|
|
99
|
+
if (!segment || estimateBridgeTextLineWidth(candidate, fontSize) <= maxLineWidth) {
|
|
100
|
+
segment = candidate;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
wrapped.push(segment);
|
|
104
|
+
segment = char;
|
|
105
|
+
}
|
|
106
|
+
if (segment) wrapped.push(segment);
|
|
107
|
+
return wrapped;
|
|
108
|
+
}
|