feat: Add packet diagram
This commit is contained in:
parent
271b779995
commit
c41594d220
|
@ -23,6 +23,7 @@ const MERMAID_CONFIG_DIAGRAM_KEYS = [
|
|||
'gitGraph',
|
||||
'c4',
|
||||
'sankey',
|
||||
'packet',
|
||||
] as const;
|
||||
|
||||
/**
|
||||
|
|
|
@ -9,9 +9,10 @@ import { generateLangium } from '../.build/generateLangium.js';
|
|||
const parserCtx = await context(
|
||||
getBuildConfig({ ...defaultOptions, minify: false, core: false, entryName: 'parser' })
|
||||
);
|
||||
const mermaidCtx = await context(
|
||||
getBuildConfig({ ...defaultOptions, minify: false, core: false, entryName: 'mermaid' })
|
||||
);
|
||||
const mermaidCtx = await context({
|
||||
...getBuildConfig({ ...defaultOptions, minify: false, core: false, entryName: 'mermaid' }),
|
||||
sourcemap: 'linked',
|
||||
});
|
||||
const mermaidIIFECtx = await context(
|
||||
getBuildConfig({
|
||||
...defaultOptions,
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<title>Mermaid Quick Test Page</title>
|
||||
<link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo=" />
|
||||
<style>
|
||||
div.mermaid {
|
||||
font-family: 'Courier New', Courier, monospace !important;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>Packet diagram demo</h1>
|
||||
<pre class="mermaid">
|
||||
packet-beta
|
||||
0-15: "Source Port"
|
||||
16-31: "Destination Port"
|
||||
32-63: "Sequence Number"
|
||||
64-95: "Acknowledgment Number"
|
||||
96-99: "Data Offset"
|
||||
100-105: "Reserved"
|
||||
106: "URG"
|
||||
107: "ACK"
|
||||
108: "PSH"
|
||||
109: "RST"
|
||||
110: "SYN"
|
||||
111: "FIN"
|
||||
112-127: "Window"
|
||||
128-143: "Checksum"
|
||||
144-159: "Urgent Pointer"
|
||||
160-191: "(Options and Padding)"
|
||||
192-223: "data"
|
||||
</pre>
|
||||
|
||||
<script type="module">
|
||||
import mermaid from '/mermaid.esm.mjs';
|
||||
mermaid.initialize({
|
||||
theme: 'forest',
|
||||
logLevel: 3,
|
||||
securityLevel: 'loose',
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
#### Defined in
|
||||
|
||||
[defaultConfig.ts:268](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L268)
|
||||
[defaultConfig.ts:275](https://github.com/mermaid-js/mermaid/blob/master/packages/mermaid/src/defaultConfig.ts#L275)
|
||||
|
||||
---
|
||||
|
||||
|
|
|
@ -140,10 +140,43 @@ export interface MermaidConfig {
|
|||
gitGraph?: GitGraphDiagramConfig;
|
||||
c4?: C4DiagramConfig;
|
||||
sankey?: SankeyDiagramConfig;
|
||||
packet?: PacketDiagramConfig;
|
||||
dompurifyConfig?: DOMPurifyConfiguration;
|
||||
wrap?: boolean;
|
||||
fontSize?: number;
|
||||
}
|
||||
/**
|
||||
* The object containing configurations specific for packet diagrams.
|
||||
*
|
||||
* This interface was referenced by `MermaidConfig`'s JSON-Schema
|
||||
* via the `definition` "PacketDiagramConfig".
|
||||
*/
|
||||
export interface PacketDiagramConfig extends BaseDiagramConfig {
|
||||
/**
|
||||
* The height of each row in the packet diagram.
|
||||
*/
|
||||
rowHeight?: number;
|
||||
/**
|
||||
* The width of each bit in the packet diagram.
|
||||
*/
|
||||
bitWidth?: number;
|
||||
/**
|
||||
* The number of bits to display per row.
|
||||
*/
|
||||
bitsPerRow?: number;
|
||||
/**
|
||||
* Toggle to display or hide bit numbers.
|
||||
*/
|
||||
showBits?: boolean;
|
||||
/**
|
||||
* The horizontal padding between the blocks in a row.
|
||||
*/
|
||||
paddingX?: number;
|
||||
/**
|
||||
* The vertical padding between the rows.
|
||||
*/
|
||||
paddingY?: number;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `MermaidConfig`'s JSON-Schema
|
||||
* via the `definition` "BaseDiagramConfig".
|
||||
|
|
|
@ -253,6 +253,13 @@ const config: RequiredDeep<MermaidConfig> = {
|
|||
// TODO: can we make this default to `true` instead?
|
||||
useMaxWidth: false,
|
||||
},
|
||||
packet: {
|
||||
...defaultConfigJson.packet,
|
||||
useWidth: undefined,
|
||||
// this is false, unlike every other diagram (other than gitGraph)
|
||||
// TODO: can we make this default to `true` instead?
|
||||
useMaxWidth: false,
|
||||
},
|
||||
};
|
||||
|
||||
const keyify = (obj: any, prefix = ''): string[] =>
|
||||
|
|
|
@ -19,6 +19,7 @@ import flowchartElk from '../diagrams/flowchart/elk/detector.js';
|
|||
import timeline from '../diagrams/timeline/detector.js';
|
||||
import mindmap from '../diagrams/mindmap/detector.js';
|
||||
import sankey from '../diagrams/sankey/sankeyDetector.js';
|
||||
import { packet } from '../diagrams/packet/detector.js';
|
||||
import { registerLazyLoadedDiagrams } from './detectType.js';
|
||||
import { registerDiagram } from './diagramAPI.js';
|
||||
|
||||
|
@ -84,6 +85,7 @@ export const addDiagrams = () => {
|
|||
state,
|
||||
journey,
|
||||
quadrantChart,
|
||||
sankey
|
||||
sankey,
|
||||
packet
|
||||
);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
import type { Block, PacketDB, Word } from './types.js';
|
||||
import { log } from '../../logger.js';
|
||||
import type { PacketDiagramConfig } from '../../config.type.js';
|
||||
import DEFAULT_CONFIG from '../../defaultConfig.js';
|
||||
import { getConfig as commonGetConfig } from '../../config.js';
|
||||
|
||||
interface PacketData {
|
||||
packet: Word[];
|
||||
}
|
||||
|
||||
const defaultPacketData: PacketData = {
|
||||
packet: [],
|
||||
};
|
||||
|
||||
let data: PacketData = structuredClone(defaultPacketData);
|
||||
export const DEFAULT_PACKET_CONFIG: Required<PacketDiagramConfig> = DEFAULT_CONFIG.packet;
|
||||
|
||||
export const getConfig = (): Required<PacketDiagramConfig> => {
|
||||
return structuredClone({
|
||||
...DEFAULT_PACKET_CONFIG,
|
||||
...commonGetConfig().packet,
|
||||
});
|
||||
};
|
||||
|
||||
export const getPacket = (): Word[] => data.packet;
|
||||
|
||||
export const getNextFittingBlock = (
|
||||
block: Block,
|
||||
row: number,
|
||||
bitsPerRow: number
|
||||
): [Block, Block | undefined] => {
|
||||
block.end = block.end ?? block.start;
|
||||
|
||||
if (block.start > block.end) {
|
||||
throw new Error(`Block start ${block.start} is greater than block end ${block.end}.`);
|
||||
}
|
||||
|
||||
if (block.end + 1 <= row * bitsPerRow) {
|
||||
return [block, undefined];
|
||||
}
|
||||
|
||||
return [
|
||||
{
|
||||
start: block.start,
|
||||
end: row * bitsPerRow - 1,
|
||||
label: block.label,
|
||||
},
|
||||
{
|
||||
start: row * bitsPerRow,
|
||||
end: block.end,
|
||||
label: block.label,
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
export const populate = ({ blocks }: { blocks: Block[] }) => {
|
||||
let lastByte = -1;
|
||||
let word: Block[] = [];
|
||||
data.packet = [];
|
||||
let row = 1;
|
||||
const { bitsPerRow } = getConfig();
|
||||
for (let { start, end, label } of blocks) {
|
||||
if (end < start) {
|
||||
throw new Error(`Packet block ${start} - ${end} is invalid. End must be greater than start.`);
|
||||
}
|
||||
if (start != lastByte + 1) {
|
||||
throw new Error(
|
||||
`Packet block ${start} - ${end} is not contiguous. It should start from ${lastByte + 1}.`
|
||||
);
|
||||
}
|
||||
lastByte = end ?? start;
|
||||
log.debug(`Packet block ${start} - ${lastByte} with label ${label}`);
|
||||
|
||||
while (word.length <= bitsPerRow + 1 && data.packet.length < 10_000) {
|
||||
const [block, nextBlock] = getNextFittingBlock({ start, end, label }, row, bitsPerRow);
|
||||
word.push(block);
|
||||
if (block.end + 1 === row * bitsPerRow) {
|
||||
data.packet.push(word);
|
||||
word = [];
|
||||
row++;
|
||||
}
|
||||
if (!nextBlock) {
|
||||
break;
|
||||
}
|
||||
({ start, end, label } = nextBlock);
|
||||
}
|
||||
}
|
||||
if (word.length > 0) {
|
||||
data.packet.push(word);
|
||||
}
|
||||
log.debug(data);
|
||||
};
|
||||
|
||||
export const clear = () => {
|
||||
data = structuredClone(defaultPacketData);
|
||||
};
|
||||
|
||||
export const db: PacketDB = {
|
||||
getPacket,
|
||||
getConfig,
|
||||
};
|
|
@ -0,0 +1,22 @@
|
|||
import type {
|
||||
DiagramDetector,
|
||||
DiagramLoader,
|
||||
ExternalDiagramDefinition,
|
||||
} from '../../diagram-api/types.js';
|
||||
|
||||
const id = 'packet';
|
||||
|
||||
const detector: DiagramDetector = (txt) => {
|
||||
return /^\s*packet-beta/.test(txt);
|
||||
};
|
||||
|
||||
const loader: DiagramLoader = async () => {
|
||||
const { diagram } = await import('./diagram.js');
|
||||
return { id, diagram };
|
||||
};
|
||||
|
||||
export const packet: ExternalDiagramDefinition = {
|
||||
id,
|
||||
detector,
|
||||
loader,
|
||||
};
|
|
@ -0,0 +1,12 @@
|
|||
import type { DiagramDefinition } from '../../diagram-api/types.js';
|
||||
import { parser } from './parser.js';
|
||||
import { db } from './db.js';
|
||||
import { renderer } from './renderer.js';
|
||||
import { styles } from './styles.js';
|
||||
|
||||
export const diagram: DiagramDefinition = {
|
||||
parser,
|
||||
db,
|
||||
renderer,
|
||||
styles,
|
||||
};
|
|
@ -0,0 +1,31 @@
|
|||
import { parser } from './parser.js';
|
||||
|
||||
describe('info', () => {
|
||||
it('should handle an info definition', () => {
|
||||
const str = `info`;
|
||||
expect(() => {
|
||||
parser.parse(str);
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
it('should handle an info definition with showInfo', () => {
|
||||
const str = `info showInfo`;
|
||||
expect(() => {
|
||||
parser.parse(str);
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
it('should throw because of unsupported info grammar', () => {
|
||||
const str = `info unsupported`;
|
||||
expect(() => {
|
||||
parser.parse(str);
|
||||
}).toThrow('Parsing failed: unexpected character: ->u<- at offset: 5, skipped 11 characters.');
|
||||
});
|
||||
|
||||
it('should throw because of unsupported info grammar', () => {
|
||||
const str = `info unsupported`;
|
||||
expect(() => {
|
||||
parser.parse(str);
|
||||
}).toThrow('Parsing failed: unexpected character: ->u<- at offset: 5, skipped 11 characters.');
|
||||
});
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
import type { Packet } from 'mermaid-parser';
|
||||
import type { ParserDefinition } from '../../diagram-api/types.js';
|
||||
|
||||
import { parse } from 'mermaid-parser';
|
||||
import { log } from '../../logger.js';
|
||||
import { populate } from './db.js';
|
||||
|
||||
export const parser: ParserDefinition = {
|
||||
parse: (input: string): void => {
|
||||
const ast: Packet = parse('packet', input);
|
||||
log.debug(ast);
|
||||
populate(ast);
|
||||
},
|
||||
};
|
|
@ -0,0 +1,81 @@
|
|||
import { configureSvgSize } from '../../setupGraphViewbox.js';
|
||||
import type { DrawDefinition, Group, SVG } from '../../diagram-api/types.js';
|
||||
import { selectSvgElement } from '../../rendering-util/selectSvgElement.js';
|
||||
import type { PacketDB, Word } from './types.js';
|
||||
import type { PacketDiagramConfig } from '../../config.type.js';
|
||||
import type { Diagram } from '../../Diagram.js';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const draw: DrawDefinition = (_text, id, _version, diagram: Diagram) => {
|
||||
const db = diagram.db as PacketDB;
|
||||
const config = db.getConfig?.() as Required<PacketDiagramConfig>;
|
||||
const { rowHeight, paddingY, bitWidth, bitsPerRow } = config;
|
||||
const words = db.getPacket();
|
||||
const svgHeight = (rowHeight + paddingY) * words.length + paddingY;
|
||||
const svgWidth = bitWidth * bitsPerRow + 2;
|
||||
|
||||
const svg: SVG = selectSvgElement(id);
|
||||
configureSvgSize(svg, svgHeight, svgWidth, true);
|
||||
svg.attr('height', svgHeight + 'px');
|
||||
|
||||
for (const [row, packet] of words.entries()) {
|
||||
drawWord(svg, packet, row, config);
|
||||
}
|
||||
};
|
||||
|
||||
const drawWord = (
|
||||
svg: SVG,
|
||||
word: Word,
|
||||
row: number,
|
||||
{ rowHeight, paddingX, paddingY, bitWidth, bitsPerRow }: Required<PacketDiagramConfig>
|
||||
) => {
|
||||
const group: Group = svg.append('g');
|
||||
const wordY = row * (rowHeight + paddingY) + paddingY;
|
||||
for (const block of word) {
|
||||
const blockX = (block.start % bitsPerRow) * bitWidth + 1;
|
||||
const width = (block.end - block.start + 1) * bitWidth - paddingX;
|
||||
// Block rectangle
|
||||
group
|
||||
.append('rect')
|
||||
.attr('x', blockX)
|
||||
.attr('y', wordY)
|
||||
.attr('width', width)
|
||||
.attr('height', rowHeight)
|
||||
.attr('class', 'block');
|
||||
|
||||
// Block label
|
||||
group
|
||||
.append('text')
|
||||
.attr('x', blockX + width / 2)
|
||||
.attr('y', wordY + rowHeight / 2)
|
||||
.attr('class', 'label')
|
||||
.attr('dominant-baseline', 'middle')
|
||||
.attr('text-anchor', 'middle')
|
||||
.text(block.label);
|
||||
|
||||
// Start byte count
|
||||
const isSingleBlock = block.end === block.start;
|
||||
const byteNumberY = wordY - 2;
|
||||
group
|
||||
.append('text')
|
||||
.attr('x', blockX + (isSingleBlock ? width / 2 : 0))
|
||||
.attr('y', byteNumberY)
|
||||
.attr('class', 'byte start')
|
||||
.attr('dominant-baseline', 'auto')
|
||||
.attr('text-anchor', isSingleBlock ? 'middle' : 'start')
|
||||
.text(block.start);
|
||||
|
||||
// Draw end byte count if it is not the same as start byte count
|
||||
if (!isSingleBlock) {
|
||||
group
|
||||
.append('text')
|
||||
.attr('x', blockX + width)
|
||||
.attr('y', byteNumberY)
|
||||
.attr('class', 'byte end')
|
||||
.attr('dominant-baseline', 'auto')
|
||||
.attr('text-anchor', 'end')
|
||||
.text(block.end);
|
||||
}
|
||||
}
|
||||
};
|
||||
export const renderer = { draw };
|
|
@ -0,0 +1,27 @@
|
|||
import { log } from '../../logger.js';
|
||||
|
||||
export const styles = (options: any = {}) => {
|
||||
log.debug({ options });
|
||||
return `
|
||||
.byte {
|
||||
font-size: ${options.packet?.byteFontSize ?? '10px'};
|
||||
}
|
||||
.byte.start {
|
||||
fill: ${options.packet?.startByteColor ?? 'black'};
|
||||
}
|
||||
.byte.end {
|
||||
fill: ${options.packet?.endByteColor ?? 'black'};
|
||||
}
|
||||
.label {
|
||||
fill: ${options.packet?.labelColor ?? 'black'};
|
||||
font-size: ${options.packet?.labelFontSize ?? '12px'};
|
||||
}
|
||||
.block {
|
||||
stroke: ${options.packet?.blockStrokeColor ?? 'black'};
|
||||
stroke-width: ${options.packet?.blockStrokeWidth ?? '1'};
|
||||
fill: ${options.packet?.blockFillColor ?? '#efefef'};
|
||||
}
|
||||
`;
|
||||
};
|
||||
|
||||
export default styles;
|
|
@ -0,0 +1,10 @@
|
|||
import type { Packet } from 'mermaid-parser';
|
||||
import type { DiagramDB } from '../../diagram-api/types.js';
|
||||
|
||||
export type ArrayElement<A> = A extends readonly (infer T)[] ? T : never;
|
||||
export type Block = Pick<ArrayElement<Packet['blocks']>, 'start' | 'end' | 'label'>;
|
||||
export type Word = Block[];
|
||||
|
||||
export interface PacketDB extends DiagramDB {
|
||||
getPacket: () => Word[];
|
||||
}
|
|
@ -48,6 +48,7 @@ required:
|
|||
- gitGraph
|
||||
- c4
|
||||
- sankey
|
||||
- packet
|
||||
properties:
|
||||
theme:
|
||||
description: |
|
||||
|
@ -201,6 +202,8 @@ properties:
|
|||
$ref: '#/$defs/C4DiagramConfig'
|
||||
sankey:
|
||||
$ref: '#/$defs/SankeyDiagramConfig'
|
||||
packet:
|
||||
$ref: '#/$defs/PacketDiagramConfig'
|
||||
dompurifyConfig:
|
||||
title: DOM Purify Configuration
|
||||
description: Configuration options to pass to the `dompurify` library.
|
||||
|
@ -1853,6 +1856,32 @@ $defs: # JSON Schema definition (maybe we should move these to a seperate file)
|
|||
type: string
|
||||
default: ''
|
||||
|
||||
PacketDiagramConfig:
|
||||
title: Packet Diagram Config
|
||||
allOf: [{ $ref: '#/$defs/BaseDiagramConfig' }]
|
||||
description: The object containing configurations specific for packet diagrams.
|
||||
type: object
|
||||
unevaluatedProperties: false
|
||||
properties:
|
||||
rowHeight:
|
||||
description: The height of each row in the packet diagram.
|
||||
default: 32
|
||||
bitWidth:
|
||||
description: The width of each bit in the packet diagram.
|
||||
default: 32
|
||||
bitsPerRow:
|
||||
description: The number of bits to display per row.
|
||||
default: 32
|
||||
showBits:
|
||||
description: Toggle to display or hide bit numbers.
|
||||
default: true
|
||||
paddingX:
|
||||
description: The horizontal padding between the blocks in a row.
|
||||
default: 5
|
||||
paddingY:
|
||||
description: The vertical padding between the rows.
|
||||
default: 15
|
||||
|
||||
FontCalculator:
|
||||
title: Font Calculator
|
||||
description: |
|
||||
|
|
|
@ -28,6 +28,7 @@ import state from './diagrams/state/styles.js';
|
|||
import journey from './diagrams/user-journey/styles.js';
|
||||
import timeline from './diagrams/timeline/styles.js';
|
||||
import mindmap from './diagrams/mindmap/styles.js';
|
||||
import packet from './diagrams/packet/styles.js';
|
||||
import themes from './themes/index.js';
|
||||
|
||||
async function checkValidStylisCSSStyleSheet(stylisString: string) {
|
||||
|
@ -96,6 +97,7 @@ describe('styles', () => {
|
|||
sequence,
|
||||
state,
|
||||
timeline,
|
||||
packet,
|
||||
})) {
|
||||
test(`should return a valid style for diagram ${diagramId} and theme ${themeId}`, async () => {
|
||||
const { default: getStyles, addStylesForDiagram } = await import('./styles.js');
|
||||
|
|
|
@ -5,6 +5,11 @@
|
|||
"id": "info",
|
||||
"grammar": "src/language/info/info.langium",
|
||||
"fileExtensions": [".mmd", ".mermaid"]
|
||||
},
|
||||
{
|
||||
"id": "packet",
|
||||
"grammar": "src/language/packet/packet.langium",
|
||||
"fileExtensions": [".mmd", ".mermaid"]
|
||||
}
|
||||
],
|
||||
"mode": "production",
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
export type { Info } from './language/index.js';
|
||||
export type { Info, Packet } from './language/index.js';
|
||||
export type { DiagramAST } from './parse.js';
|
||||
export { parse, MermaidParseError } from './parse.js';
|
||||
|
|
|
@ -4,3 +4,4 @@ export * from './generated/module.js';
|
|||
|
||||
export * from './common/index.js';
|
||||
export * from './info/index.js';
|
||||
export * from './packet/index.js';
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
export * from './module.js';
|
|
@ -0,0 +1,72 @@
|
|||
import type {
|
||||
DefaultSharedModuleContext,
|
||||
LangiumServices,
|
||||
LangiumSharedServices,
|
||||
Module,
|
||||
PartialLangiumServices,
|
||||
} from 'langium';
|
||||
import { EmptyFileSystem, createDefaultModule, createDefaultSharedModule, inject } from 'langium';
|
||||
|
||||
import { CommonLexer } from '../common/lexer.js';
|
||||
import { MermaidGeneratedSharedModule, PacketGeneratedModule } from '../generated/module.js';
|
||||
import { PacketTokenBuilder } from './tokenBuilder.js';
|
||||
import { CommonValueConverter } from '../common/valueConverter.js';
|
||||
|
||||
/**
|
||||
* Declaration of `Packet` services.
|
||||
*/
|
||||
type PacketAddedServices = {
|
||||
parser: {
|
||||
Lexer: CommonLexer;
|
||||
TokenBuilder: PacketTokenBuilder;
|
||||
ValueConverter: CommonValueConverter;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Union of Langium default services and `Packet` services.
|
||||
*/
|
||||
export type PacketServices = LangiumServices & PacketAddedServices;
|
||||
|
||||
/**
|
||||
* Dependency injection module that overrides Langium default services and
|
||||
* contributes the declared `Packet` services.
|
||||
*/
|
||||
export const PacketModule: Module<PacketServices, PartialLangiumServices & PacketAddedServices> = {
|
||||
parser: {
|
||||
Lexer: (services: PacketServices) => new CommonLexer(services),
|
||||
TokenBuilder: () => new PacketTokenBuilder(),
|
||||
ValueConverter: () => new CommonValueConverter(),
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Create the full set of services required by Langium.
|
||||
*
|
||||
* First inject the shared services by merging two modules:
|
||||
* - Langium default shared services
|
||||
* - Services generated by langium-cli
|
||||
*
|
||||
* Then inject the language-specific services by merging three modules:
|
||||
* - Langium default language-specific services
|
||||
* - Services generated by langium-cli
|
||||
* - Services specified in this file
|
||||
* @param context - Optional module context with the LSP connection
|
||||
* @returns An object wrapping the shared services and the language-specific services
|
||||
*/
|
||||
export function createPacketServices(context: DefaultSharedModuleContext = EmptyFileSystem): {
|
||||
shared: LangiumSharedServices;
|
||||
Packet: PacketServices;
|
||||
} {
|
||||
const shared: LangiumSharedServices = inject(
|
||||
createDefaultSharedModule(context),
|
||||
MermaidGeneratedSharedModule
|
||||
);
|
||||
const Packet: PacketServices = inject(
|
||||
createDefaultModule({ shared }),
|
||||
PacketGeneratedModule,
|
||||
PacketModule
|
||||
);
|
||||
shared.ServiceRegistry.register(Packet);
|
||||
return { shared, Packet };
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
grammar Packet
|
||||
import "../common/common";
|
||||
|
||||
entry Packet:
|
||||
"packet-beta" NEWLINE*
|
||||
TitleAndAccessibilities?
|
||||
(blocks+=Block)*;
|
||||
|
||||
Block:
|
||||
start=INT ('-' end=INT)? ':' label=STRING;
|
||||
|
||||
hidden terminal WS: /\s+/;
|
||||
terminal INT returns number: /[0-9]+/;
|
||||
terminal STRING: /"[^"]*"|'[^']*'/;
|
|
@ -0,0 +1,7 @@
|
|||
import { MermaidTokenBuilder } from '../common/index.js';
|
||||
|
||||
export class PacketTokenBuilder extends MermaidTokenBuilder {
|
||||
public constructor() {
|
||||
super(['packet-beta']);
|
||||
}
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
import type { LangiumParser, ParseResult } from 'langium';
|
||||
import type { Info } from './index.js';
|
||||
import { createInfoServices } from './language/index.js';
|
||||
import type { Info, Packet } from './index.js';
|
||||
import { createInfoServices, createPacketServices } from './language/index.js';
|
||||
|
||||
export type DiagramAST = Info;
|
||||
export type DiagramAST = Info | Packet;
|
||||
|
||||
const parsers: Record<string, LangiumParser> = {};
|
||||
|
||||
|
@ -13,8 +13,13 @@ const initializers = {
|
|||
const parser = createInfoServices().Info.parser.LangiumParser;
|
||||
parsers['info'] = parser;
|
||||
},
|
||||
packet: () => {
|
||||
const parser = createPacketServices().Packet.parser.LangiumParser;
|
||||
parsers['packet'] = parser;
|
||||
},
|
||||
} as const;
|
||||
export function parse(diagramType: 'info', text: string): Info;
|
||||
export function parse(diagramType: 'packet', text: string): Packet;
|
||||
export function parse<T extends DiagramAST>(
|
||||
diagramType: keyof typeof initializers,
|
||||
text: string
|
||||
|
|
Loading…
Reference in New Issue