Enteee / plantuml-parser

Parse PlantUML with JavaScript or TypeScript
https://duckpond.ch/category/plantuml-parser
Apache License 2.0
136 stars 33 forks source link

Syntax error when reading empty spaced-out brackets #82

Closed songyang-dev closed 2 years ago

songyang-dev commented 2 years ago

The parser cannot read the plantuml file if it contains brackets separated on different lines and if there is nothing inside the brackets.

@startuml
!theme plain
    class AbstractNode 
    {
    }
@enduml

Error message from NodeJS.

$ node extraction/plantuml-test.js 
C:\Users\songy\node_modules\plantuml-parser\dist\plantuml.js:704
        return new SyntaxError(SyntaxError.buildMessage(expected1, found), expected1, found, location1);
               ^

Error [SyntaxError]: Expected "'", "(", "/'", "BiRel", "BiRel_D", "BiRel_Down", "BiRel_L", "BiRel_Left", "BiRel_Neighbor", "Bi
Rel_R", "BiRel_Right", "BiRel_U", "BiRel_Up", "Boundary", "Component", "ComponentDb", "ComponentDb_Ext", "ComponentQueue", "Co
mponentQueue_Ext", "Component_Ext", "Container", "ContainerDb", "ContainerDb_Ext", "ContainerQueue", "ContainerQueue_Ext", "Co
ntainer_Boundary", "Container_Ext", "Deployment_Node", "Deployment_Node_L", "Deployment_Node_R", "Enterprise_Boundary", "Node"
, "Node_L", "Node_R", "Person", "Person_Ext", "Rel", "Rel_", "Rel_Back", "Rel_Back_Neighbor", "Rel_D", "Rel_Down", "Rel_L", "R
el_Left", "Rel_Neighbor", "Rel_R", "Rel_Right", "Rel_U", "Rel_Up", "System", "SystemDb", "SystemDb_Ext", "SystemQueue", "Syste
mQueue_Ext", "System_Boundary", "System_Ext", "[", "abstract ", "class ", "cloud", "component ", "database", "digraph", "enum 
", "folder", "frame", "interface ", "namespace", "node", "note ", "package", "rectangle", "skinparam ", "state", "together ", 
"usecase ", [ ,\t], or [A-Z,a-z,0-9,.,_] but "}" found.
    at peg$buildStructuredError (C:\Users\songy\node_modules\plantuml-parser\dist\plantuml.js:704:16)
    at peg$parse (C:\Users\songy\node_modules\plantuml-parser\dist\plantuml.js:11598:15)
    at parseSync (C:\Users\songy\node_modules\plantuml-parser\dist\index.js:64:12)
    at file:///C:/Users/songy/Documents/My%20Documents/UDEM/master%20thesis/uml%20data/database/cleaning/three-step/extraction
/plantuml-test.js:14:16
    at ModuleJob.run (node:internal/modules/esm/module_job:197:25)
    at async Promise.all (index 0)
    at async ESMLoader.import (node:internal/modules/esm/loader:337:24)
    at async loadESM (node:internal/process/esm_loader:88:5)
    at async handleMainPromise (node:internal/modules/run_main:61:12) {
  expected: [
    {
      type: 'class',
      parts: [ ' ', '\t' ],
      inverted: false,
      ignoreCase: false
    },
    { type: 'literal', text: "'", ignoreCase: false },
    {
      type: 'class',
      parts: [ ' ', '\t' ],
      inverted: false,
      ignoreCase: false
    },
    { type: 'literal', text: "/'", ignoreCase: false },
    {
      type: 'class',
      parts: [ ' ', '\t' ],
      inverted: false,
      ignoreCase: false
    },
    { type: 'literal', text: '[', ignoreCase: false },
    { type: 'literal', text: '[', ignoreCase: false },
    { type: 'literal', text: '(', ignoreCase: false },
    { type: 'literal', text: '(', ignoreCase: false },
    {
      type: 'class',
      parts: [ [ 'A', 'Z' ], [ 'a', 'z' ], [ '0', '9' ], '.', '_' ],
      inverted: false,
      ignoreCase: false
    },
    {
      type: 'class',
      parts: [ ' ', '\t' ],
      inverted: false,
      ignoreCase: false
    },
    { type: 'literal', text: '[', ignoreCase: false },
    { type: 'literal', text: '[', ignoreCase: false },
    { type: 'literal', text: '(', ignoreCase: false },
    { type: 'literal', text: '(', ignoreCase: false },
    {
      type: 'class',
      parts: [ [ 'A', 'Z' ], [ 'a', 'z' ], [ '0', '9' ], '.', '_' ],
      inverted: false,
      ignoreCase: false
    },
    {
      type: 'class',
      parts: [ ' ', '\t' ],
      inverted: false,
      ignoreCase: false
    },
    { type: 'literal', text: 'skinparam ', ignoreCase: true },
    {
      type: 'class',
      parts: [ ' ', '\t' ],
      inverted: false,
      ignoreCase: false
    },
    { type: 'literal', text: 'skinparam ', ignoreCase: true },
    {
      type: 'class',
      parts: [ ' ', '\t' ],
      inverted: false,
      ignoreCase: false
    },
    { type: 'literal', text: 'together ', ignoreCase: true },
    {
      type: 'class',
      parts: [ ' ', '\t' ],
      inverted: false,
      ignoreCase: false
    },
    { type: 'literal', text: 'package', ignoreCase: true },
    { type: 'literal', text: 'namespace', ignoreCase: true },
    { type: 'literal', text: 'node', ignoreCase: true },
    { type: 'literal', text: 'folder', ignoreCase: true },
    { type: 'literal', text: 'frame', ignoreCase: true },
    { type: 'literal', text: 'cloud', ignoreCase: true },
    { type: 'literal', text: 'database', ignoreCase: true },
    { type: 'literal', text: 'rectangle', ignoreCase: true },
    {
      type: 'class',
      parts: [ ' ', '\t' ],
      inverted: false,
      ignoreCase: false
    },
    { type: 'literal', text: 'note ', ignoreCase: true },
    {
      type: 'class',
      parts: [ ' ', '\t' ],
      inverted: false,
      ignoreCase: false
    },
    { type: 'literal', text: 'note ', ignoreCase: true },
    {
      type: 'class',
      parts: [ ' ', '\t' ],
      inverted: false,
      ignoreCase: false
    },
    { type: 'literal', text: 'note ', ignoreCase: true },
    {
      type: 'class',
      parts: [ ' ', '\t' ],
      inverted: false,
      ignoreCase: false
    },
    { type: 'literal', text: 'note ', ignoreCase: true },
    {
      type: 'class',
      parts: [ ' ', '\t' ],
      inverted: false,
      ignoreCase: false
    },
    { type: 'literal', text: 'abstract ', ignoreCase: true },
    {
      type: 'class',
      parts: [ ' ', '\t' ],
      inverted: false,
      ignoreCase: false
    },
    { type: 'literal', text: 'class ', ignoreCase: false },
    {
      type: 'class',
      parts: [ ' ', '\t' ],
      inverted: false,
      ignoreCase: false
    },
    { type: 'literal', text: 'abstract ', ignoreCase: true },
    {
      type: 'class',
      parts: [ ' ', '\t' ],
      inverted: false,
      ignoreCase: false
    },
    { type: 'literal', text: 'class ', ignoreCase: false },
    {
      type: 'class',
      parts: [ ' ', '\t' ],
      inverted: false,
      ignoreCase: false
    },
    { type: 'literal', text: 'interface ', ignoreCase: true },
    {
      type: 'class',
      parts: [ ' ', '\t' ],
      inverted: false,
      ignoreCase: false
    },
    { type: 'literal', text: 'interface ', ignoreCase: true },
    {
      type: 'class',
      parts: [ ' ', '\t' ],
      inverted: false,
      ignoreCase: false
    },
    { type: 'literal', text: 'enum ', ignoreCase: true },
    {
      type: 'class',
      parts: [ ' ', '\t' ],
      inverted: false,
      ignoreCase: false
    },
    { type: 'literal', text: 'enum ', ignoreCase: true },
    {
      type: 'class',
      parts: [ ' ', '\t' ],
      inverted: false,
      ignoreCase: false
    },
    { type: 'literal', text: 'component ', ignoreCase: true },
    {
      type: 'class',
      parts: [ ' ', '\t' ],
      inverted: false,
      ignoreCase: false
    },
    { type: 'literal', text: '[', ignoreCase: false },
    { type: 'literal', text: '[', ignoreCase: false },
    {
      type: 'class',
      parts: [ ' ', '\t' ],
      inverted: false,
      ignoreCase: false
    },
    { type: 'literal', text: 'usecase ', ignoreCase: true },
    {
      type: 'class',
      parts: [ ' ', '\t' ],
      inverted: false,
      ignoreCase: false
    },
    { type: 'literal', text: '(', ignoreCase: false },
    { type: 'literal', text: '(', ignoreCase: false },
    {
      type: 'class',
      parts: [ ' ', '\t' ],
      inverted: false,
      ignoreCase: false
    },
    { type: 'literal', text: 'Person_Ext', ignoreCase: true },
    { type: 'literal', text: 'SystemDb_Ext', ignoreCase: true },
    { type: 'literal', text: 'SystemQueue_Ext', ignoreCase: true },
    { type: 'literal', text: 'Person', ignoreCase: true },
    { type: 'literal', text: 'System_Ext', ignoreCase: true },
    { type: 'literal', text: 'SystemDb', ignoreCase: true },
    { type: 'literal', text: 'SystemQueue', ignoreCase: true },
    { type: 'literal', text: 'System', ignoreCase: true },
    {
      type: 'class',
      parts: [ ' ', '\t' ],
      inverted: false,
      ignoreCase: false
    },
    { type: 'literal', text: 'ContainerQueue_Ext', ignoreCase: true },
    { type: 'literal', text: 'ContainerQueue', ignoreCase: true },
    { type: 'literal', text: 'ContainerDb_Ext', ignoreCase: true },
    { type: 'literal', text: 'ContainerDb', ignoreCase: true },
    { type: 'literal', text: 'Container_Ext', ignoreCase: true },
    { type: 'literal', text: 'Container', ignoreCase: true },
    { type: 'literal', text: 'ComponentQueue_Ext', ignoreCase: true },
    { type: 'literal', text: 'ComponentQueue', ignoreCase: true },
    { type: 'literal', text: 'ComponentDb_Ext', ignoreCase: true },
    { type: 'literal', text: 'ComponentDb', ignoreCase: true },
    { type: 'literal', text: 'Component_Ext', ignoreCase: true },
    { type: 'literal', text: 'Component', ignoreCase: true },
    {
      type: 'class',
      parts: [ ' ', '\t' ],
    { type: 'literal', text: 'Rel_Up', ignoreCase: true },
    ... 30 more items
  ],
  found: '}',
  location: {
    start: { offset: 58, line: 6, column: 5 },
    end: { offset: 59, line: 6, column: 6 }
  }
}
songyang-dev commented 2 years ago

This is a minimal reproducible bug from the larger plantuml file I'm dealing with.

@startuml
!theme plain
class AbstractNode
{
}
class Node
{
}
Node "1" --> "1" AbstractNode : falseConditionNode
class ConditionalNode
{
}
class Expression
{
expressionName : String
}
@enduml
Enteee commented 2 years ago

Thank you for reporting this, i will have a look :+1:

Enteee commented 2 years ago

this should be fixed with the linked pull request. Thank you for reporting :rocket: