@markdy/core 1.0.20 → 1.0.22
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 +2 -0
- package/dist/index.d.ts +13 -1
- package/dist/index.js +175 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -64,6 +64,8 @@ try {
|
|
|
64
64
|
|---|---|---|
|
|
65
65
|
| `parse` | `(source, opts?) => DiagramAST` | Parse MarkdyScript source into a diagram AST |
|
|
66
66
|
| `compile` | `(ast) => RenderPlan` | Lay out nodes, route edges, and schedule cues |
|
|
67
|
+
| `compilePlan` | `(ast, theme) => RenderPlan` | Compile AST against a resolved theme token set |
|
|
68
|
+
| `computeAdaptiveDimensions` | `(ast, edges?) => { width, height }` | Compute content-adaptive canvas dimensions from topology & items |
|
|
67
69
|
| `parseAndCompile` | `(source) => { ast, plan }` | Parse and compile in one call |
|
|
68
70
|
| `ParseError` | class | Error with `.line` number for diagnostics |
|
|
69
71
|
| `DiagramAST` | type | Parsed scene: meta, nodes, edges, groups, patterns, beats |
|
package/dist/index.d.ts
CHANGED
|
@@ -78,6 +78,10 @@ type SceneMeta = {
|
|
|
78
78
|
theme: string;
|
|
79
79
|
direction: LayoutDirection;
|
|
80
80
|
duration?: number;
|
|
81
|
+
/** Whether width was explicitly specified by the author in the script. */
|
|
82
|
+
explicitWidth?: boolean;
|
|
83
|
+
/** Whether height was explicitly specified by the author in the script. */
|
|
84
|
+
explicitHeight?: boolean;
|
|
81
85
|
/** Opt-in diagram mode; defaults to architecture. */
|
|
82
86
|
type?: DiagramType;
|
|
83
87
|
/** Playback, controls, interaction, and chrome behavior. Source of truth. */
|
|
@@ -369,6 +373,14 @@ type RenderPlan = {
|
|
|
369
373
|
duration: number;
|
|
370
374
|
};
|
|
371
375
|
|
|
376
|
+
/**
|
|
377
|
+
* Computes optimal, content-adaptive canvas width and height for a diagram AST
|
|
378
|
+
* when dimensions are omitted or partially specified in the script.
|
|
379
|
+
*/
|
|
380
|
+
declare function computeAdaptiveDimensions(ast: DiagramAST, edges?: RoutedEdge[]): {
|
|
381
|
+
width: number;
|
|
382
|
+
height: number;
|
|
383
|
+
};
|
|
372
384
|
declare function compilePlan(ast: DiagramAST, theme: ThemeTokens): RenderPlan;
|
|
373
385
|
|
|
374
386
|
/**
|
|
@@ -633,4 +645,4 @@ declare function resolveOutputPreset(name: string): OutputPreset;
|
|
|
633
645
|
/** List all available preset names. */
|
|
634
646
|
declare function listOutputPresets(): string[];
|
|
635
647
|
|
|
636
|
-
export { ARCH_RULE_PRESETS, type AnnotationDecl, type ArchRuleType, type ArchitecturePreset, type ArchitectureRule, type ArchitectureViolation, BEAT_CUE_KEYWORDS, type BeatDecl, type BeatRange, type Box, CUE_ALIASES, type CardinalPort, type Cue, DIAGRAM_TYPES, type Diagnostic, type DiagramAST, type DiagramDiffResult, type DiagramType, type DiffChangeType, EDGE_OPERATORS, type EdgeDecl, type EdgeDiff, type EdgeKind, type EdgeSelector, type FlowSegment, type GroupBoundary, type GroupDecl, type LayoutDirection, type MarkdyConfig, NODE_ALIASES, NODE_KINDS, type NodeDecl, type NodeDiff, type NodeSelector, type NodeShape, OUTPUT_PRESETS, type OutputPreset, PLAYER_FLAT_KEYS, PLAYER_GROUPS, ParseError, type ParseOptions, type ParseResult, type PatternDecl, type PlayerChromeConfig, type PlayerConfig, type PlayerControlsConfig, type PlayerInteractionConfig, type PlayerOverrides, type PlayerPlaybackConfig, type PlayerProgress, type PlayerScope, type Point, type PositionedNode, type RenderPlan, type RepairPromptBundle, type ResolvedPlayer, type RoutedEdge, type RoutedPath, type RuleSeverity, SCENE_KEYS, type SceneMeta, type SemanticProfile, type SequenceActivation, type SequenceMessage, type StyleDecl, TECHNICAL_NODE_KINDS, TECHNICAL_NODE_TYPES, THEMES, type ThemeGeneratorOptions, type ThemeTokens, type TimedCue, type TreeBus, VISUAL_PRIMITIVE_TYPES, analyzeAndBuildRepairPrompt, applyPlayerSetting, canonicalNodeKind, classifyTechnology, compile, compilePlan, compressMarkdyToUrlHash, decompressMarkdyFromUrlHash, diffDiagramASTs, generateThemeFromBrand, getBoxPortPosition, humanizeId, listOutputPresets, nodeRole, parse, parseAndCompile, resolveArchitectureConfig, resolveOutputPreset, resolvePlayer, resolveTheme, routeOrthogonalEdge, selectOptimalPorts, validateArchitecture };
|
|
648
|
+
export { ARCH_RULE_PRESETS, type AnnotationDecl, type ArchRuleType, type ArchitecturePreset, type ArchitectureRule, type ArchitectureViolation, BEAT_CUE_KEYWORDS, type BeatDecl, type BeatRange, type Box, CUE_ALIASES, type CardinalPort, type Cue, DIAGRAM_TYPES, type Diagnostic, type DiagramAST, type DiagramDiffResult, type DiagramType, type DiffChangeType, EDGE_OPERATORS, type EdgeDecl, type EdgeDiff, type EdgeKind, type EdgeSelector, type FlowSegment, type GroupBoundary, type GroupDecl, type LayoutDirection, type MarkdyConfig, NODE_ALIASES, NODE_KINDS, type NodeDecl, type NodeDiff, type NodeSelector, type NodeShape, OUTPUT_PRESETS, type OutputPreset, PLAYER_FLAT_KEYS, PLAYER_GROUPS, ParseError, type ParseOptions, type ParseResult, type PatternDecl, type PlayerChromeConfig, type PlayerConfig, type PlayerControlsConfig, type PlayerInteractionConfig, type PlayerOverrides, type PlayerPlaybackConfig, type PlayerProgress, type PlayerScope, type Point, type PositionedNode, type RenderPlan, type RepairPromptBundle, type ResolvedPlayer, type RoutedEdge, type RoutedPath, type RuleSeverity, SCENE_KEYS, type SceneMeta, type SemanticProfile, type SequenceActivation, type SequenceMessage, type StyleDecl, TECHNICAL_NODE_KINDS, TECHNICAL_NODE_TYPES, THEMES, type ThemeGeneratorOptions, type ThemeTokens, type TimedCue, type TreeBus, VISUAL_PRIMITIVE_TYPES, analyzeAndBuildRepairPrompt, applyPlayerSetting, canonicalNodeKind, classifyTechnology, compile, compilePlan, compressMarkdyToUrlHash, computeAdaptiveDimensions, decompressMarkdyFromUrlHash, diffDiagramASTs, generateThemeFromBrand, getBoxPortPosition, humanizeId, listOutputPresets, nodeRole, parse, parseAndCompile, resolveArchitectureConfig, resolveOutputPreset, resolvePlayer, resolveTheme, routeOrthogonalEdge, selectOptimalPorts, validateArchitecture };
|
package/dist/index.js
CHANGED
|
@@ -874,8 +874,8 @@ function assignRanks(nodeIds, edges, direction) {
|
|
|
874
874
|
}
|
|
875
875
|
return ranks;
|
|
876
876
|
}
|
|
877
|
-
function snapGrid(n) {
|
|
878
|
-
return Math.round(n /
|
|
877
|
+
function snapGrid(n, step = 4) {
|
|
878
|
+
return Math.round(n / step) * step;
|
|
879
879
|
}
|
|
880
880
|
function layoutRanked(ast, edges, opts) {
|
|
881
881
|
const nodeIds = Object.keys(ast.nodes);
|
|
@@ -1938,8 +1938,171 @@ function buildSequencePlan(ast, cues) {
|
|
|
1938
1938
|
});
|
|
1939
1939
|
return { messages, activations };
|
|
1940
1940
|
}
|
|
1941
|
+
function computeAdaptiveDimensions(ast, edges) {
|
|
1942
|
+
const explicitW = ast.meta.explicitWidth === true;
|
|
1943
|
+
const explicitH = ast.meta.explicitHeight === true;
|
|
1944
|
+
if (explicitW && explicitH) {
|
|
1945
|
+
return { width: ast.meta.width, height: ast.meta.height };
|
|
1946
|
+
}
|
|
1947
|
+
const effectiveEdges = edges ?? collectStructuralEdges(ast);
|
|
1948
|
+
const nodeIds = Object.keys(ast.nodes);
|
|
1949
|
+
const nodeCount = nodeIds.length;
|
|
1950
|
+
const dtype = diagramType(ast);
|
|
1951
|
+
const direction = ast.meta.direction ?? "LR";
|
|
1952
|
+
const isVertical = direction === "TB" || direction === "BT";
|
|
1953
|
+
const groupCount = Object.keys(ast.groups).length;
|
|
1954
|
+
let autoW = 1280;
|
|
1955
|
+
let autoH = 720;
|
|
1956
|
+
if (nodeCount === 0) {
|
|
1957
|
+
autoW = 1280;
|
|
1958
|
+
autoH = 720;
|
|
1959
|
+
} else if (dtype === "sequence") {
|
|
1960
|
+
const flowCues = ast.beats.flatMap((b) => b.cues).filter((c) => c.kind === "flow");
|
|
1961
|
+
const count = Math.max(nodeCount, 1);
|
|
1962
|
+
const flowCount = flowCues.length;
|
|
1963
|
+
const requiredW = SAFE * 2 + Math.max(count * 220, 800);
|
|
1964
|
+
const requiredH = TITLE_BAND + NODE_H + 56 + Math.max(flowCount * 76, 280) + SAFE + 48;
|
|
1965
|
+
autoW = Math.max(1088, Math.min(2560, requiredW));
|
|
1966
|
+
autoH = Math.max(640, Math.min(1800, requiredH));
|
|
1967
|
+
} else if (dtype === "tree") {
|
|
1968
|
+
let measureSubtree2 = function(id) {
|
|
1969
|
+
const kids = children.get(id) ?? [];
|
|
1970
|
+
if (kids.length === 0) {
|
|
1971
|
+
subtreeSpan.set(id, minLeafWidth);
|
|
1972
|
+
return minLeafWidth;
|
|
1973
|
+
}
|
|
1974
|
+
let total = 0;
|
|
1975
|
+
for (const kid of kids) total += measureSubtree2(kid);
|
|
1976
|
+
const span = Math.max(minLeafWidth, total);
|
|
1977
|
+
subtreeSpan.set(id, span);
|
|
1978
|
+
return span;
|
|
1979
|
+
};
|
|
1980
|
+
var measureSubtree = measureSubtree2;
|
|
1981
|
+
const children = /* @__PURE__ */ new Map();
|
|
1982
|
+
const hasParent = /* @__PURE__ */ new Set();
|
|
1983
|
+
for (const id of nodeIds) children.set(id, []);
|
|
1984
|
+
const treeEdges = effectiveEdges.some((e) => e.structural) ? effectiveEdges.filter((e) => e.structural) : effectiveEdges;
|
|
1985
|
+
for (const e of treeEdges) {
|
|
1986
|
+
if (ast.nodes[e.from] && ast.nodes[e.to] && e.from !== e.to) {
|
|
1987
|
+
children.get(e.from)?.push(e.to);
|
|
1988
|
+
hasParent.add(e.to);
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1991
|
+
const roots = nodeIds.filter((id) => !hasParent.has(id));
|
|
1992
|
+
const depth = /* @__PURE__ */ new Map();
|
|
1993
|
+
const queue = [...roots];
|
|
1994
|
+
for (const r of roots) depth.set(r, 0);
|
|
1995
|
+
while (queue.length > 0) {
|
|
1996
|
+
const cur = queue.shift();
|
|
1997
|
+
const d = depth.get(cur) ?? 0;
|
|
1998
|
+
for (const child of children.get(cur) ?? []) {
|
|
1999
|
+
if (!depth.has(child)) {
|
|
2000
|
+
depth.set(child, d + 1);
|
|
2001
|
+
queue.push(child);
|
|
2002
|
+
}
|
|
2003
|
+
}
|
|
2004
|
+
}
|
|
2005
|
+
for (const id of nodeIds) if (!depth.has(id)) depth.set(id, 0);
|
|
2006
|
+
const maxDepth = Math.max(...depth.values(), 0);
|
|
2007
|
+
const minLeafWidth = NODE_W + 48;
|
|
2008
|
+
const subtreeSpan = /* @__PURE__ */ new Map();
|
|
2009
|
+
let totalRootsWidth = 0;
|
|
2010
|
+
const activeRoots = roots.length > 0 ? roots : nodeIds;
|
|
2011
|
+
for (const r of activeRoots) totalRootsWidth += measureSubtree2(r);
|
|
2012
|
+
const requiredW = SAFE * 2 + totalRootsWidth;
|
|
2013
|
+
const requiredH = TITLE_BAND + SAFE * 2 + (maxDepth + 1) * 140;
|
|
2014
|
+
autoW = Math.max(1120, Math.min(2560, requiredW));
|
|
2015
|
+
autoH = Math.max(640, Math.min(1600, requiredH));
|
|
2016
|
+
} else if (dtype === "swimlane") {
|
|
2017
|
+
const laneCount = Math.max(groupCount, 1);
|
|
2018
|
+
const maxInLane = Math.max(
|
|
2019
|
+
...Object.values(ast.groups).map((g) => g.members.length),
|
|
2020
|
+
Math.ceil(nodeCount / laneCount),
|
|
2021
|
+
1
|
|
2022
|
+
);
|
|
2023
|
+
const requiredW = SAFE * 2 + 140 + maxInLane * 220;
|
|
2024
|
+
const requiredH = TITLE_BAND + SAFE * 2 + laneCount * 140;
|
|
2025
|
+
autoW = Math.max(1152, Math.min(2560, requiredW));
|
|
2026
|
+
autoH = Math.max(640, Math.min(1600, requiredH));
|
|
2027
|
+
} else if (dtype === "pyramid") {
|
|
2028
|
+
const tierCount = Math.max(nodeCount, 1);
|
|
2029
|
+
autoW = 1280;
|
|
2030
|
+
const requiredH = TITLE_BAND + SAFE * 2 + tierCount * 110;
|
|
2031
|
+
autoH = Math.max(640, Math.min(1440, requiredH));
|
|
2032
|
+
} else if (dtype === "layers") {
|
|
2033
|
+
const layerCount = Math.max(nodeCount, 1);
|
|
2034
|
+
autoW = 1280;
|
|
2035
|
+
const requiredH = TITLE_BAND + SAFE * 2 + layerCount * 96;
|
|
2036
|
+
autoH = Math.max(640, Math.min(1440, requiredH));
|
|
2037
|
+
} else if (dtype === "timeline" || dtype === "gantt") {
|
|
2038
|
+
const milestones = Math.max(nodeCount, 1);
|
|
2039
|
+
const requiredW = SAFE * 2 + milestones * 240;
|
|
2040
|
+
const requiredH = TITLE_BAND + SAFE * 2 + 380;
|
|
2041
|
+
autoW = Math.max(1200, Math.min(2560, requiredW));
|
|
2042
|
+
autoH = Math.max(640, Math.min(1200, requiredH));
|
|
2043
|
+
} else if (dtype === "loop" || dtype === "flywheel" || dtype === "radar" || dtype === "venn" || dtype === "constellation") {
|
|
2044
|
+
const N = Math.max(nodeCount, 3);
|
|
2045
|
+
const minRadius = 200;
|
|
2046
|
+
const radiusNeeded = Math.max(minRadius, N * 180 / (2 * Math.PI));
|
|
2047
|
+
const requiredW = SAFE * 2 + radiusNeeded * 2 + 240;
|
|
2048
|
+
const requiredH = TITLE_BAND + SAFE * 2 + radiusNeeded * 2 + 140;
|
|
2049
|
+
autoW = Math.max(1088, Math.min(2200, requiredW));
|
|
2050
|
+
autoH = Math.max(720, Math.min(1600, requiredH));
|
|
2051
|
+
} else if (dtype === "quadrant") {
|
|
2052
|
+
autoW = 1200;
|
|
2053
|
+
autoH = 800;
|
|
2054
|
+
} else {
|
|
2055
|
+
const forceVertical = dtype === "flowchart" && isVertical || isVertical;
|
|
2056
|
+
const ranks = assignRanks(nodeIds, effectiveEdges, forceVertical ? "TB" : "LR");
|
|
2057
|
+
const byRank = /* @__PURE__ */ new Map();
|
|
2058
|
+
for (const id of nodeIds) {
|
|
2059
|
+
const r = ranks.get(id) ?? 0;
|
|
2060
|
+
if (!byRank.has(r)) byRank.set(r, []);
|
|
2061
|
+
byRank.get(r).push(id);
|
|
2062
|
+
}
|
|
2063
|
+
const rankCount = Math.max(...byRank.keys(), 0) + 1;
|
|
2064
|
+
const maxInRank = Math.max(...[...byRank.values()].map((v) => v.length), 1);
|
|
2065
|
+
const groupPaddingBonus = groupCount > 0 ? GROUP_PAD * 2 : 0;
|
|
2066
|
+
if (forceVertical) {
|
|
2067
|
+
const requiredW = SAFE * 2 + maxInRank * NODE_W + (maxInRank - 1) * 44 + groupPaddingBonus;
|
|
2068
|
+
const requiredH = SAFE * 2 + TITLE_BAND + rankCount * NODE_H + (rankCount - 1) * 56 + groupPaddingBonus;
|
|
2069
|
+
if (nodeCount <= 2) {
|
|
2070
|
+
autoW = 960;
|
|
2071
|
+
autoH = 640;
|
|
2072
|
+
} else if (nodeCount <= 4 && rankCount <= 3) {
|
|
2073
|
+
autoW = 1024;
|
|
2074
|
+
autoH = 720;
|
|
2075
|
+
} else {
|
|
2076
|
+
autoW = Math.max(960, Math.min(2400, requiredW));
|
|
2077
|
+
autoH = Math.max(720, Math.min(2e3, requiredH));
|
|
2078
|
+
}
|
|
2079
|
+
} else {
|
|
2080
|
+
const requiredW = SAFE * 2 + rankCount * NODE_W + (rankCount - 1) * 44 + groupPaddingBonus;
|
|
2081
|
+
const requiredH = SAFE * 2 + TITLE_BAND + maxInRank * NODE_H + (maxInRank - 1) * 36 + groupPaddingBonus;
|
|
2082
|
+
if (nodeCount <= 2 && rankCount <= 2) {
|
|
2083
|
+
autoW = 1024;
|
|
2084
|
+
autoH = 576;
|
|
2085
|
+
} else if (nodeCount <= 4 && rankCount <= 3 && maxInRank <= 2) {
|
|
2086
|
+
autoW = 1152;
|
|
2087
|
+
autoH = 648;
|
|
2088
|
+
} else {
|
|
2089
|
+
autoW = Math.max(1152, Math.min(2560, requiredW));
|
|
2090
|
+
autoH = Math.max(648, Math.min(1600, requiredH));
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
return {
|
|
2095
|
+
width: explicitW ? ast.meta.width : snapGrid(autoW, 16),
|
|
2096
|
+
height: explicitH ? ast.meta.height : snapGrid(autoH, 16)
|
|
2097
|
+
};
|
|
2098
|
+
}
|
|
1941
2099
|
function compilePlan(ast, theme) {
|
|
1942
2100
|
const structuralEdges = collectStructuralEdges(ast);
|
|
2101
|
+
if (!ast.meta.explicitWidth || !ast.meta.explicitHeight) {
|
|
2102
|
+
const dims = computeAdaptiveDimensions(ast, structuralEdges);
|
|
2103
|
+
if (!ast.meta.explicitWidth) ast.meta.width = dims.width;
|
|
2104
|
+
if (!ast.meta.explicitHeight) ast.meta.height = dims.height;
|
|
2105
|
+
}
|
|
1943
2106
|
const nodes = layoutNodes(ast, structuralEdges);
|
|
1944
2107
|
const groupBoundaries = computeGroupBoundaries(ast, nodes);
|
|
1945
2108
|
const treeBuses = computeTreeBuses(ast, nodes, structuralEdges.filter((edge) => edge.structural));
|
|
@@ -2986,8 +3149,15 @@ function parse(source, opts = {}) {
|
|
|
2986
3149
|
diagnostics.push({ severity: "warning", message: `unknown scene property '${k}'`, line: lineNo });
|
|
2987
3150
|
continue;
|
|
2988
3151
|
}
|
|
2989
|
-
if (k === "width"
|
|
2990
|
-
|
|
3152
|
+
if (k === "width") {
|
|
3153
|
+
meta.width = Number(v);
|
|
3154
|
+
meta.explicitWidth = true;
|
|
3155
|
+
} else if (k === "height") {
|
|
3156
|
+
meta.height = Number(v);
|
|
3157
|
+
meta.explicitHeight = true;
|
|
3158
|
+
} else if (k === "fps") {
|
|
3159
|
+
meta.fps = Number(v);
|
|
3160
|
+
} else if (k === "duration") meta.duration = Number(v);
|
|
2991
3161
|
else if (k === "theme") meta.theme = String(v);
|
|
2992
3162
|
else if (k === "direction" || k === "layout") meta.direction = String(v).toUpperCase();
|
|
2993
3163
|
else if (PLAYER_FLAT_KEY_SET.has(k)) {
|
|
@@ -4270,6 +4440,7 @@ export {
|
|
|
4270
4440
|
compile,
|
|
4271
4441
|
compilePlan,
|
|
4272
4442
|
compressMarkdyToUrlHash,
|
|
4443
|
+
computeAdaptiveDimensions,
|
|
4273
4444
|
decompressMarkdyFromUrlHash,
|
|
4274
4445
|
diffDiagramASTs,
|
|
4275
4446
|
generateThemeFromBrand,
|
package/package.json
CHANGED