mirror of
https://github.com/mermaid-js/mermaid.git
synced 2025-09-13 12:29:42 +02:00
feat(parser): create pie
parser and export it
This commit is contained in:
@@ -5,6 +5,11 @@
|
|||||||
"id": "info",
|
"id": "info",
|
||||||
"grammar": "src/language/info/info.langium",
|
"grammar": "src/language/info/info.langium",
|
||||||
"fileExtensions": [".mmd", ".mermaid"]
|
"fileExtensions": [".mmd", ".mermaid"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "pie",
|
||||||
|
"grammar": "src/language/pie/pie.langium",
|
||||||
|
"fileExtensions": [".mmd", ".mermaid"]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"mode": "production",
|
"mode": "production",
|
||||||
|
@@ -1,3 +1,3 @@
|
|||||||
export type { Info } from './language/index.js';
|
export type { Info, Pie, PieSection } from './language/index.js';
|
||||||
export type { DiagramAST } from './parse.js';
|
export type { DiagramAST } from './parse.js';
|
||||||
export { parse, MermaidParseError } 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 './common/index.js';
|
||||||
export * from './info/index.js';
|
export * from './info/index.js';
|
||||||
|
export * from './pie/index.js';
|
||||||
|
1
packages/parser/src/language/pie/index.ts
Normal file
1
packages/parser/src/language/pie/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './pieModule.js';
|
20
packages/parser/src/language/pie/pie.langium
Normal file
20
packages/parser/src/language/pie/pie.langium
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
grammar Pie
|
||||||
|
import "../common/common";
|
||||||
|
|
||||||
|
entry Pie:
|
||||||
|
NEWLINE*
|
||||||
|
"pie" showData?="showData"?
|
||||||
|
(
|
||||||
|
NEWLINE* TitleAndAccessibilities sections+=PieSection*
|
||||||
|
| NEWLINE+ sections+=PieSection+
|
||||||
|
| NEWLINE*
|
||||||
|
)
|
||||||
|
;
|
||||||
|
|
||||||
|
PieSection:
|
||||||
|
label=PIE_SECTION_LABEL ":" value=PIE_SECTION_VALUE
|
||||||
|
NEWLINE+
|
||||||
|
;
|
||||||
|
|
||||||
|
terminal PIE_SECTION_LABEL: /"[^"]+"/;
|
||||||
|
terminal PIE_SECTION_VALUE returns number: /(0|[1-9][0-9]*)(\.[0-9]+)?/;
|
68
packages/parser/src/language/pie/pieModule.ts
Normal file
68
packages/parser/src/language/pie/pieModule.ts
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import type {
|
||||||
|
DefaultSharedModuleContext,
|
||||||
|
LangiumServices,
|
||||||
|
LangiumSharedServices,
|
||||||
|
Module,
|
||||||
|
PartialLangiumServices,
|
||||||
|
} from 'langium';
|
||||||
|
import { EmptyFileSystem, createDefaultModule, createDefaultSharedModule, inject } from 'langium';
|
||||||
|
|
||||||
|
import { MermaidGeneratedSharedModule, PieGeneratedModule } from '../generated/module.js';
|
||||||
|
import { CommonLexer } from '../common/commonLexer.js';
|
||||||
|
import { PieTokenBuilder } from './pieTokenBuilder.js';
|
||||||
|
import { PieValueConverter } from './pieValueConverter.js';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Declaration of `Pie` services.
|
||||||
|
*/
|
||||||
|
type PieAddedServices = {
|
||||||
|
parser: {
|
||||||
|
Lexer: CommonLexer;
|
||||||
|
TokenBuilder: PieTokenBuilder;
|
||||||
|
ValueConverter: PieValueConverter;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Union of Langium default services and `Pie` services.
|
||||||
|
*/
|
||||||
|
export type PieServices = LangiumServices & PieAddedServices;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dependency injection module that overrides Langium default services and
|
||||||
|
* contributes the declared `Pie` services.
|
||||||
|
*/
|
||||||
|
const PieModule: Module<PieServices, PartialLangiumServices & PieAddedServices> = {
|
||||||
|
parser: {
|
||||||
|
Lexer: (services) => new CommonLexer(services),
|
||||||
|
TokenBuilder: () => new PieTokenBuilder(),
|
||||||
|
ValueConverter: () => new PieValueConverter(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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 createPieServices(context: DefaultSharedModuleContext = EmptyFileSystem): {
|
||||||
|
shared: LangiumSharedServices;
|
||||||
|
Pie: PieServices;
|
||||||
|
} {
|
||||||
|
const shared: LangiumSharedServices = inject(
|
||||||
|
createDefaultSharedModule(context),
|
||||||
|
MermaidGeneratedSharedModule
|
||||||
|
);
|
||||||
|
const Pie: PieServices = inject(createDefaultModule({ shared }), PieGeneratedModule, PieModule);
|
||||||
|
shared.ServiceRegistry.register(Pie);
|
||||||
|
return { shared, Pie };
|
||||||
|
}
|
23
packages/parser/src/language/pie/pieTokenBuilder.ts
Normal file
23
packages/parser/src/language/pie/pieTokenBuilder.ts
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import type { GrammarAST, Stream, TokenBuilderOptions } from 'langium';
|
||||||
|
import { DefaultTokenBuilder } from 'langium';
|
||||||
|
|
||||||
|
import type { TokenType } from '../chevrotainWrapper.js';
|
||||||
|
|
||||||
|
export class PieTokenBuilder extends DefaultTokenBuilder {
|
||||||
|
protected override buildKeywordTokens(
|
||||||
|
rules: Stream<GrammarAST.AbstractRule>,
|
||||||
|
terminalTokens: TokenType[],
|
||||||
|
options?: TokenBuilderOptions
|
||||||
|
): TokenType[] {
|
||||||
|
const tokenTypes: TokenType[] = super.buildKeywordTokens(rules, terminalTokens, options);
|
||||||
|
tokenTypes.forEach((tokenType: TokenType): void => {
|
||||||
|
if (
|
||||||
|
(tokenType.name === 'pie' || tokenType.name === 'showData') &&
|
||||||
|
tokenType.PATTERN !== undefined
|
||||||
|
) {
|
||||||
|
tokenType.PATTERN = new RegExp(tokenType.PATTERN.toString() + '(?!\\S)');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return tokenTypes;
|
||||||
|
}
|
||||||
|
}
|
50
packages/parser/src/language/pie/pieValueConverter.ts
Normal file
50
packages/parser/src/language/pie/pieValueConverter.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import type { CstNode, GrammarAST, ValueType } from 'langium';
|
||||||
|
import { DefaultValueConverter } from 'langium';
|
||||||
|
|
||||||
|
import { CommonValueConverter } from '../common/commonValueConverters.js';
|
||||||
|
|
||||||
|
export class PieValueConverter extends DefaultValueConverter {
|
||||||
|
protected override runConverter(
|
||||||
|
rule: GrammarAST.AbstractRule,
|
||||||
|
input: string,
|
||||||
|
cstNode: CstNode
|
||||||
|
): ValueType {
|
||||||
|
let value: ValueType | undefined = CommonValueConverter.customRunConverter(
|
||||||
|
rule,
|
||||||
|
input,
|
||||||
|
cstNode
|
||||||
|
);
|
||||||
|
if (value === undefined) {
|
||||||
|
value = PieValueConverter.customRunConverter(rule, input, cstNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value === undefined) {
|
||||||
|
return super.runConverter(rule, input, cstNode);
|
||||||
|
} else {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A method contains convert logic to be used by class itself or `MermaidValueConverter`.
|
||||||
|
*
|
||||||
|
* @param rule - Parsed rule.
|
||||||
|
* @param input - Matched string.
|
||||||
|
* @param _cstNode - Node in the Concrete Syntax Tree (CST).
|
||||||
|
* @returns converted the value if it's pie rule or `null` if it's not.
|
||||||
|
*/
|
||||||
|
public static customRunConverter(
|
||||||
|
rule: GrammarAST.AbstractRule,
|
||||||
|
input: string,
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
_cstNode: CstNode
|
||||||
|
): ValueType | undefined {
|
||||||
|
if (rule.name === 'PIE_SECTION_LABEL') {
|
||||||
|
return input
|
||||||
|
.replace(/"/g, '')
|
||||||
|
.trim()
|
||||||
|
.replaceAll(/[\t ]{2,}/gm, ' ');
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
@@ -1,8 +1,8 @@
|
|||||||
import type { LangiumParser, ParseResult } from 'langium';
|
import type { LangiumParser, ParseResult } from 'langium';
|
||||||
import type { Info } from './index.js';
|
import type { Info, Pie } from './index.js';
|
||||||
import { createInfoServices } from './language/index.js';
|
import { createInfoServices, createPieServices } from './language/index.js';
|
||||||
|
|
||||||
export type DiagramAST = Info;
|
export type DiagramAST = Info | Pie;
|
||||||
|
|
||||||
const parsers: Record<string, LangiumParser> = {};
|
const parsers: Record<string, LangiumParser> = {};
|
||||||
|
|
||||||
@@ -13,8 +13,14 @@ const initializers = {
|
|||||||
const parser = createInfoServices().Info.parser.LangiumParser;
|
const parser = createInfoServices().Info.parser.LangiumParser;
|
||||||
parsers['info'] = parser;
|
parsers['info'] = parser;
|
||||||
},
|
},
|
||||||
|
pie: () => {
|
||||||
|
const parser = createPieServices().Pie.parser.LangiumParser;
|
||||||
|
parsers['pie'] = parser;
|
||||||
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
export function parse(diagramType: 'info', text: string): Info;
|
export function parse(diagramType: 'info', text: string): Info;
|
||||||
|
export function parse(diagramType: 'pie', text: string): Pie;
|
||||||
export function parse<T extends DiagramAST>(
|
export function parse<T extends DiagramAST>(
|
||||||
diagramType: keyof typeof initializers,
|
diagramType: keyof typeof initializers,
|
||||||
text: string
|
text: string
|
||||||
|
294
packages/parser/tests/pie.test.ts
Normal file
294
packages/parser/tests/pie.test.ts
Normal file
@@ -0,0 +1,294 @@
|
|||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
import type { LangiumParser, ParseResult } from 'langium';
|
||||||
|
|
||||||
|
import type { PieServices } from '../src/language/index.js';
|
||||||
|
import { Pie, createPieServices } from '../src/language/index.js';
|
||||||
|
|
||||||
|
const services: PieServices = createPieServices().Pie;
|
||||||
|
const parser: LangiumParser = services.parser.LangiumParser;
|
||||||
|
export function createPieTestServices(): {
|
||||||
|
services: PieServices;
|
||||||
|
parse: (input: string) => ParseResult<Pie>;
|
||||||
|
} {
|
||||||
|
const parse = (input: string) => {
|
||||||
|
return parser.parse<Pie>(input);
|
||||||
|
};
|
||||||
|
|
||||||
|
return { services, parse };
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('pie', () => {
|
||||||
|
const { parse } = createPieTestServices();
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
`pie`,
|
||||||
|
` pie `,
|
||||||
|
`\tpie\t`,
|
||||||
|
`
|
||||||
|
\tpie
|
||||||
|
`,
|
||||||
|
])('should handle regular pie', (context: string) => {
|
||||||
|
const result = parse(context);
|
||||||
|
expect(result.parserErrors).toHaveLength(0);
|
||||||
|
expect(result.lexerErrors).toHaveLength(0);
|
||||||
|
|
||||||
|
const value = result.value;
|
||||||
|
expect(value.$type).toBe(Pie);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
`pie showData`,
|
||||||
|
` pie showData `,
|
||||||
|
`\tpie\tshowData\t`,
|
||||||
|
`
|
||||||
|
pie\tshowData
|
||||||
|
`,
|
||||||
|
])('should handle regular showData', (context: string) => {
|
||||||
|
const result = parse(context);
|
||||||
|
expect(result.parserErrors).toHaveLength(0);
|
||||||
|
expect(result.lexerErrors).toHaveLength(0);
|
||||||
|
|
||||||
|
const value = result.value;
|
||||||
|
expect(value.$type).toBe(Pie);
|
||||||
|
expect(value.showData).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
`pie title sample title`,
|
||||||
|
` pie title sample title `,
|
||||||
|
`\tpie\ttitle sample title\t`,
|
||||||
|
`pie
|
||||||
|
\ttitle sample title
|
||||||
|
`,
|
||||||
|
])('should handle regular pie + title in same line', (context: string) => {
|
||||||
|
const result = parse(context);
|
||||||
|
expect(result.parserErrors).toHaveLength(0);
|
||||||
|
expect(result.lexerErrors).toHaveLength(0);
|
||||||
|
|
||||||
|
const value = result.value;
|
||||||
|
expect(value.$type).toBe(Pie);
|
||||||
|
expect(value.title).toBe('sample title');
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
`pie
|
||||||
|
title sample title`,
|
||||||
|
`pie
|
||||||
|
title sample title
|
||||||
|
`,
|
||||||
|
`pie
|
||||||
|
title sample title`,
|
||||||
|
`pie
|
||||||
|
title sample title
|
||||||
|
`,
|
||||||
|
])('should handle regular pie + title in different line', (context: string) => {
|
||||||
|
const result = parse(context);
|
||||||
|
expect(result.parserErrors).toHaveLength(0);
|
||||||
|
expect(result.lexerErrors).toHaveLength(0);
|
||||||
|
|
||||||
|
const value = result.value;
|
||||||
|
expect(value.$type).toBe(Pie);
|
||||||
|
expect(value.title).toBe('sample title');
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
`pie showData title sample title`,
|
||||||
|
`pie showData title sample title
|
||||||
|
`,
|
||||||
|
])('should handle regular pie + showData + title', (context: string) => {
|
||||||
|
const result = parse(context);
|
||||||
|
expect(result.parserErrors).toHaveLength(0);
|
||||||
|
expect(result.lexerErrors).toHaveLength(0);
|
||||||
|
|
||||||
|
const value = result.value;
|
||||||
|
expect(value.$type).toBe(Pie);
|
||||||
|
expect(value.showData).toBeTruthy();
|
||||||
|
expect(value.title).toBe('sample title');
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
`pie showData
|
||||||
|
title sample title`,
|
||||||
|
`pie showData
|
||||||
|
title sample title
|
||||||
|
`,
|
||||||
|
`pie showData
|
||||||
|
title sample title`,
|
||||||
|
`pie showData
|
||||||
|
title sample title
|
||||||
|
`,
|
||||||
|
])('should handle regular showData + title in different line', (context: string) => {
|
||||||
|
const result = parse(context);
|
||||||
|
expect(result.parserErrors).toHaveLength(0);
|
||||||
|
expect(result.lexerErrors).toHaveLength(0);
|
||||||
|
|
||||||
|
const value = result.value;
|
||||||
|
expect(value.$type).toBe(Pie);
|
||||||
|
expect(value.showData).toBeTruthy();
|
||||||
|
expect(value.title).toBe('sample title');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('sections', () => {
|
||||||
|
describe('normal', () => {
|
||||||
|
it.each([
|
||||||
|
`pie
|
||||||
|
"GitHub":100
|
||||||
|
"GitLab":50`,
|
||||||
|
`pie
|
||||||
|
"GitHub" : 100
|
||||||
|
"GitLab" : 50`,
|
||||||
|
`pie
|
||||||
|
"GitHub"\t:\t100
|
||||||
|
"GitLab"\t:\t50`,
|
||||||
|
`pie
|
||||||
|
\t"GitHub" \t : \t 100
|
||||||
|
\t"GitLab" \t : \t 50
|
||||||
|
`,
|
||||||
|
])('should handle regular secions', (context: string) => {
|
||||||
|
const result = parse(context);
|
||||||
|
expect(result.parserErrors).toHaveLength(0);
|
||||||
|
expect(result.lexerErrors).toHaveLength(0);
|
||||||
|
|
||||||
|
const value = result.value;
|
||||||
|
expect(value.$type).toBe(Pie);
|
||||||
|
|
||||||
|
const section0 = value.sections[0];
|
||||||
|
expect(section0?.label).toBe('GitHub');
|
||||||
|
expect(section0?.value).toBe(100);
|
||||||
|
|
||||||
|
const section1 = value.sections[1];
|
||||||
|
expect(section1?.label).toBe('GitLab');
|
||||||
|
expect(section1?.value).toBe(50);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle sections with showData', () => {
|
||||||
|
const context = `pie showData
|
||||||
|
"GitHub": 100
|
||||||
|
"GitLab": 50`;
|
||||||
|
const result = parse(context);
|
||||||
|
expect(result.parserErrors).toHaveLength(0);
|
||||||
|
expect(result.lexerErrors).toHaveLength(0);
|
||||||
|
|
||||||
|
const value = result.value;
|
||||||
|
expect(value.$type).toBe(Pie);
|
||||||
|
expect(value.showData).toBeTruthy();
|
||||||
|
|
||||||
|
const section0 = value.sections[0];
|
||||||
|
expect(section0?.label).toBe('GitHub');
|
||||||
|
expect(section0?.value).toBe(100);
|
||||||
|
|
||||||
|
const section1 = value.sections[1];
|
||||||
|
expect(section1?.label).toBe('GitLab');
|
||||||
|
expect(section1?.value).toBe(50);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle sections with title', () => {
|
||||||
|
const context = `pie title sample wow
|
||||||
|
"GitHub": 100
|
||||||
|
"GitLab": 50`;
|
||||||
|
const result = parse(context);
|
||||||
|
expect(result.parserErrors).toHaveLength(0);
|
||||||
|
expect(result.lexerErrors).toHaveLength(0);
|
||||||
|
|
||||||
|
const value = result.value;
|
||||||
|
expect(value.$type).toBe(Pie);
|
||||||
|
expect(value.title).toBe('sample wow');
|
||||||
|
|
||||||
|
const section0 = value.sections[0];
|
||||||
|
expect(section0?.label).toBe('GitHub');
|
||||||
|
expect(section0?.value).toBe(100);
|
||||||
|
|
||||||
|
const section1 = value.sections[1];
|
||||||
|
expect(section1?.label).toBe('GitLab');
|
||||||
|
expect(section1?.value).toBe(50);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle sections with accTitle', () => {
|
||||||
|
const context = `pie accTitle: sample wow
|
||||||
|
"GitHub": 100
|
||||||
|
"GitLab": 50`;
|
||||||
|
const result = parse(context);
|
||||||
|
expect(result.parserErrors).toHaveLength(0);
|
||||||
|
expect(result.lexerErrors).toHaveLength(0);
|
||||||
|
|
||||||
|
const value = result.value;
|
||||||
|
expect(value.$type).toBe(Pie);
|
||||||
|
expect(value.accTitle).toBe('sample wow');
|
||||||
|
|
||||||
|
const section0 = value.sections[0];
|
||||||
|
expect(section0?.label).toBe('GitHub');
|
||||||
|
expect(section0?.value).toBe(100);
|
||||||
|
|
||||||
|
const section1 = value.sections[1];
|
||||||
|
expect(section1?.label).toBe('GitLab');
|
||||||
|
expect(section1?.value).toBe(50);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle sections with single line accDescr', () => {
|
||||||
|
const context = `pie accDescr: sample wow
|
||||||
|
"GitHub": 100
|
||||||
|
"GitLab": 50`;
|
||||||
|
const result = parse(context);
|
||||||
|
expect(result.parserErrors).toHaveLength(0);
|
||||||
|
expect(result.lexerErrors).toHaveLength(0);
|
||||||
|
|
||||||
|
const value = result.value;
|
||||||
|
expect(value.$type).toBe(Pie);
|
||||||
|
expect(value.accDescr).toBe('sample wow');
|
||||||
|
|
||||||
|
const section0 = value.sections[0];
|
||||||
|
expect(section0?.label).toBe('GitHub');
|
||||||
|
expect(section0?.value).toBe(100);
|
||||||
|
|
||||||
|
const section1 = value.sections[1];
|
||||||
|
expect(section1?.label).toBe('GitLab');
|
||||||
|
expect(section1?.value).toBe(50);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle sections with multi line accDescr', () => {
|
||||||
|
const context = `pie accDescr {
|
||||||
|
sample wow
|
||||||
|
}
|
||||||
|
"GitHub": 100
|
||||||
|
"GitLab": 50`;
|
||||||
|
const result = parse(context);
|
||||||
|
expect(result.parserErrors).toHaveLength(0);
|
||||||
|
expect(result.lexerErrors).toHaveLength(0);
|
||||||
|
|
||||||
|
const value = result.value;
|
||||||
|
expect(value.$type).toBe(Pie);
|
||||||
|
expect(value.accDescr).toBe('sample wow');
|
||||||
|
|
||||||
|
const section0 = value.sections[0];
|
||||||
|
expect(section0?.label).toBe('GitHub');
|
||||||
|
expect(section0?.value).toBe(100);
|
||||||
|
|
||||||
|
const section1 = value.sections[1];
|
||||||
|
expect(section1?.label).toBe('GitLab');
|
||||||
|
expect(section1?.value).toBe(50);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('duplicate', () => {
|
||||||
|
it('should handle duplicate sections', () => {
|
||||||
|
const context = `pie
|
||||||
|
"GitHub": 100
|
||||||
|
"GitHub": 50`;
|
||||||
|
const result = parse(context);
|
||||||
|
expect(result.parserErrors).toHaveLength(0);
|
||||||
|
expect(result.lexerErrors).toHaveLength(0);
|
||||||
|
|
||||||
|
const value = result.value;
|
||||||
|
expect(value.$type).toBe(Pie);
|
||||||
|
|
||||||
|
const section0 = value.sections[0];
|
||||||
|
expect(section0?.label).toBe('GitHub');
|
||||||
|
expect(section0?.value).toBe(100);
|
||||||
|
|
||||||
|
const section1 = value.sections[1];
|
||||||
|
expect(section1?.label).toBe('GitHub');
|
||||||
|
expect(section1?.value).toBe(50);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
Reference in New Issue
Block a user