mirror of
				https://github.com/mermaid-js/mermaid.git
				synced 2025-11-04 04:44:08 +01:00 
			
		
		
		
	feat(parser): create pie parser and export it
				
					
				
			This commit is contained in:
		@@ -5,6 +5,11 @@
 | 
			
		||||
      "id": "info",
 | 
			
		||||
      "grammar": "src/language/info/info.langium",
 | 
			
		||||
      "fileExtensions": [".mmd", ".mermaid"]
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      "id": "pie",
 | 
			
		||||
      "grammar": "src/language/pie/pie.langium",
 | 
			
		||||
      "fileExtensions": [".mmd", ".mermaid"]
 | 
			
		||||
    }
 | 
			
		||||
  ],
 | 
			
		||||
  "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 { 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 './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 { Info } from './index.js';
 | 
			
		||||
import { createInfoServices } from './language/index.js';
 | 
			
		||||
import type { Info, Pie } from './index.js';
 | 
			
		||||
import { createInfoServices, createPieServices } from './language/index.js';
 | 
			
		||||
 | 
			
		||||
export type DiagramAST = Info;
 | 
			
		||||
export type DiagramAST = Info | Pie;
 | 
			
		||||
 | 
			
		||||
const parsers: Record<string, LangiumParser> = {};
 | 
			
		||||
 | 
			
		||||
@@ -13,8 +13,14 @@ const initializers = {
 | 
			
		||||
    const parser = createInfoServices().Info.parser.LangiumParser;
 | 
			
		||||
    parsers['info'] = parser;
 | 
			
		||||
  },
 | 
			
		||||
  pie: () => {
 | 
			
		||||
    const parser = createPieServices().Pie.parser.LangiumParser;
 | 
			
		||||
    parsers['pie'] = parser;
 | 
			
		||||
  },
 | 
			
		||||
} as const;
 | 
			
		||||
 | 
			
		||||
export function parse(diagramType: 'info', text: string): Info;
 | 
			
		||||
export function parse(diagramType: 'pie', text: string): Pie;
 | 
			
		||||
export function parse<T extends DiagramAST>(
 | 
			
		||||
  diagramType: keyof typeof initializers,
 | 
			
		||||
  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