...

Source file src/oss.terrastruct.com/d2/e2etests/stable_test.go

Documentation: oss.terrastruct.com/d2/e2etests

     1  package e2etests
     2  
     3  import (
     4  	_ "embed"
     5  	"testing"
     6  )
     7  
     8  // based on https://github.com/mxstbr/markdown-test-file
     9  //
    10  //go:embed markdowntest.md
    11  var testMarkdown string
    12  
    13  func testStable(t *testing.T) {
    14  	tcs := []testCase{
    15  		{
    16  			name: "legend_with_near_key",
    17  			script: `
    18  				direction: right
    19  
    20  				x -> y: {
    21  					style.stroke: green
    22  				}
    23  
    24  				y -> z: {
    25  					style.stroke: red
    26  				}
    27  
    28  				legend: {
    29  					near: bottom-center
    30  					color1: foo {
    31  						shape: text
    32  						style.font-color: green
    33  					}
    34  
    35  					color2: bar {
    36  						shape: text
    37  						style.font-color: red
    38  					}
    39  				}
    40  			`,
    41  		},
    42  		{
    43  			name: "near_keys_for_container",
    44  			script: `title: |md
    45    # Service-Cluster Provisioning ("Outside view")
    46  | {near: top-center}`,
    47  		},
    48  		{
    49  			name: "near_keys_for_container",
    50  			script: `
    51  				x: {
    52  					near: top-left
    53  					a -> b
    54  					c -> d
    55  				}
    56  				y: {
    57  					near: top-right
    58  					a -> b
    59  					c -> d
    60  				}
    61  				z: {
    62  					near: bottom-center
    63  					a -> b
    64  					c -> d
    65  				}
    66  
    67  				a: {
    68  					near: top-center
    69  					b: {
    70  						c
    71  					}
    72  				}
    73  				b: {
    74  					near: bottom-right
    75  					a: {
    76  						c: {
    77  							d
    78  						}
    79  					}
    80  				}
    81  			`,
    82  		},
    83  		{
    84  			name: "class_and_sqlTable_border_radius",
    85  			script: `
    86  				a: {
    87  					shape: sql_table
    88  					id: int {constraint: primary_key}
    89  					disk: int {constraint: foreign_key}
    90  
    91  					json: jsonb  {constraint: unique}
    92  					last_updated: timestamp with time zone
    93  
    94  					style: {
    95  						fill: red
    96  						border-radius: 10
    97  					}
    98  				}
    99  
   100  				b: {
   101  					shape: class
   102  
   103  					field: "[]string"
   104  					method(a uint64): (x, y int)
   105  
   106  					style: {
   107  						border-radius: 10
   108  					}
   109  				}
   110  
   111  				c: {
   112  					shape: class
   113  					style: {
   114  						border-radius: 5
   115  					}
   116  				}
   117  
   118  				d: {
   119  					shape: sql_table
   120  					style: {
   121  						border-radius: 5
   122  					}
   123  				}
   124  			`,
   125  		},
   126  		{
   127  			name: "elk_border_radius",
   128  			script: `
   129  				a -> b
   130  				a -> c: {
   131  					style: {
   132  						border-radius: 0
   133  					}
   134  				}
   135  				a -> e: {
   136  					style: {
   137  						border-radius: 5
   138  					}
   139  				}
   140  				a -> f: {
   141  					style: {
   142  						border-radius: 10
   143  					}
   144  				}
   145  				a -> g: {
   146  					style: {
   147  						border-radius: 20
   148  					}
   149  				}
   150  			`,
   151  		},
   152  		{
   153  			name: "elk_container_height",
   154  			script: `i can not see the title: {
   155    shape: cylinder
   156    x
   157  }
   158  `,
   159  		},
   160  		{
   161  			name: "elk_shim",
   162  			script: `network: {
   163    cell tower: {
   164  		satellites: {
   165  			shape: stored_data
   166        style.multiple: true
   167        width: 140
   168  		}
   169  
   170  		transmitter: {
   171        width: 140
   172      }
   173  
   174  		satellites -> transmitter: send {
   175  		}
   176  		satellites -> transmitter: send {
   177  		}
   178  		satellites -> transmitter: send {
   179  		}
   180    }
   181  
   182    # long label to expand
   183    online portal: ONLINE PORTALLLL {
   184      ui: { shape: hexagon }
   185    }
   186  
   187    data processor: {
   188      storage: {
   189        shape: cylinder
   190        style.multiple: true
   191      }
   192    }
   193  
   194    cell tower.transmitter -> data processor.storage: phone logs
   195  }
   196  
   197  user: {
   198    shape: person
   199    width: 130
   200  }
   201  
   202  user -> network.cell tower: make call
   203  user -> network.online portal.ui: access {
   204    style.stroke-dash: 3
   205  }
   206  
   207  api server -> network.online portal.ui: display
   208  api server -> logs: persist
   209  logs: { shape: page; style.multiple: true }
   210  
   211  network.data processor -> api server
   212  			`,
   213  		},
   214  		{
   215  			name: "edge-label-overflow",
   216  			script: `student -> committee chair: Apply for appeal
   217  student <- committee chair: Deny. Need more information
   218  committee chair -> committee: Accept appeal`,
   219  		},
   220  		{
   221  			name: "mono-edge",
   222  			script: `direction: right
   223  x -> y: hi { style.font: mono }`,
   224  		},
   225  		{
   226  			name: "bold-mono",
   227  			script: `not bold mono.style.font: mono
   228  not bold mono.style.bold: false
   229  bold mono.style.font: mono`,
   230  		},
   231  		{
   232  			name: "mono-font",
   233  			script: `satellites: SATELLITES {
   234    shape: stored_data
   235    style: {
   236      font: mono
   237      fill: white
   238      stroke: black
   239      multiple: true
   240    }
   241  }
   242  
   243  transmitter: TRANSMITTER {
   244    style: {
   245      font: mono
   246      fill: white
   247      stroke: black
   248    }
   249  }
   250  
   251  satellites -> transmitter: SEND {
   252    style.stroke: black
   253    style.font: mono
   254  }
   255  satellites -> transmitter: SEND {
   256    style.stroke: black
   257    style.font: mono
   258  }
   259  satellites -> transmitter: SEND {
   260    style.stroke: black
   261    style.font: mono
   262  }
   263  `,
   264  		},
   265  		{
   266  			name: "connected_container",
   267  			script: `a.b -> c.d -> f.h.g
   268  `,
   269  		},
   270  		{
   271  			name: "circular_dependency",
   272  			script: `a -> b -> c -> b -> a
   273  `,
   274  		},
   275  		{
   276  			name: "all_shapes",
   277  			script: `
   278  rectangle: {shape: "rectangle"}
   279  square: {shape: "square"}
   280  page: {shape: "page"}
   281  parallelogram: {shape: "parallelogram"}
   282  document: {shape: "document"}
   283  cylinder: {shape: "cylinder"}
   284  queue: {shape: "queue"}
   285  package: {shape: "package"}
   286  step: {shape: "step"}
   287  callout: {shape: "callout"}
   288  stored_data: {shape: "stored_data"}
   289  person: {shape: "person"}
   290  diamond: {shape: "diamond"}
   291  oval: {shape: "oval"}
   292  circle: {shape: "circle"}
   293  hexagon: {shape: "hexagon"}
   294  cloud: {shape: "cloud"}
   295  
   296  rectangle -> square -> page
   297  parallelogram -> document -> cylinder
   298  queue -> package -> step
   299  callout -> stored_data -> person
   300  diamond -> oval -> circle
   301  hexagon -> cloud
   302  `,
   303  		},
   304  		{
   305  			name: "all_shapes_multiple",
   306  			script: `
   307  rectangle: {shape: "rectangle"}
   308  square: {shape: "square"}
   309  page: {shape: "page"}
   310  parallelogram: {shape: "parallelogram"}
   311  document: {shape: "document"}
   312  cylinder: {shape: "cylinder"}
   313  queue: {shape: "queue"}
   314  package: {shape: "package"}
   315  step: {shape: "step"}
   316  callout: {shape: "callout"}
   317  stored_data: {shape: "stored_data"}
   318  person: {shape: "person"}
   319  diamond: {shape: "diamond"}
   320  oval: {shape: "oval"}
   321  circle: {shape: "circle"}
   322  hexagon: {shape: "hexagon"}
   323  cloud: {shape: "cloud"}
   324  
   325  rectangle -> square -> page
   326  parallelogram -> document -> cylinder
   327  queue -> package -> step
   328  callout -> stored_data -> person
   329  diamond -> oval -> circle
   330  hexagon -> cloud
   331  
   332  rectangle.style.multiple: true
   333  square.style.multiple: true
   334  page.style.multiple: true
   335  parallelogram.style.multiple: true
   336  document.style.multiple: true
   337  cylinder.style.multiple: true
   338  queue.style.multiple: true
   339  package.style.multiple: true
   340  step.style.multiple: true
   341  callout.style.multiple: true
   342  stored_data.style.multiple: true
   343  person.style.multiple: true
   344  diamond.style.multiple: true
   345  oval.style.multiple: true
   346  circle.style.multiple: true
   347  hexagon.style.multiple: true
   348  cloud.style.multiple: true
   349  `,
   350  		},
   351  		{
   352  			name: "all_shapes_shadow",
   353  			script: `
   354  rectangle: {shape: "rectangle"}
   355  square: {shape: "square"}
   356  page: {shape: "page"}
   357  parallelogram: {shape: "parallelogram"}
   358  document: {shape: "document"}
   359  cylinder: {shape: "cylinder"}
   360  queue: {shape: "queue"}
   361  package: {shape: "package"}
   362  step: {shape: "step"}
   363  callout: {shape: "callout"}
   364  stored_data: {shape: "stored_data"}
   365  person: {shape: "person"}
   366  diamond: {shape: "diamond"}
   367  oval: {shape: "oval"}
   368  circle: {shape: "circle"}
   369  hexagon: {shape: "hexagon"}
   370  cloud: {shape: "cloud"}
   371  
   372  rectangle -> square -> page
   373  parallelogram -> document -> cylinder
   374  queue -> package -> step
   375  callout -> stored_data -> person
   376  diamond -> oval -> circle
   377  hexagon -> cloud
   378  
   379  rectangle.style.shadow: true
   380  square.style.shadow: true
   381  page.style.shadow: true
   382  parallelogram.style.shadow: true
   383  document.style.shadow: true
   384  cylinder.style.shadow: true
   385  queue.style.shadow: true
   386  package.style.shadow: true
   387  step.style.shadow: true
   388  callout.style.shadow: true
   389  stored_data.style.shadow: true
   390  person.style.shadow: true
   391  diamond.style.shadow: true
   392  oval.style.shadow: true
   393  circle.style.shadow: true
   394  hexagon.style.shadow: true
   395  cloud.style.shadow: true
   396  `,
   397  		},
   398  		{
   399  			name: "square_3d",
   400  			script: `
   401  rectangle: {shape: "rectangle"}
   402  square: {shape: "square"}
   403  
   404  rectangle -> square
   405  
   406  rectangle.style.3d: true
   407  square.style.3d: true
   408  `,
   409  		},
   410  		{
   411  			name: "hexagon_3d",
   412  			script: `
   413  hexagon: {shape: "hexagon"}
   414  hexagon.style.3d: true
   415  `,
   416  		},
   417  		{
   418  			name: "3d_fill_and_stroke",
   419  			script: `
   420  hexagon: {
   421    shape: hexagon
   422    style.3d: true
   423    style.fill: honeydew
   424  }
   425  
   426  
   427  rect: {
   428    shape: rectangle
   429    style.3d: true
   430    style.fill: honeydew
   431  }
   432  
   433  square: {
   434    shape: square
   435    style.3d: true
   436    style.fill: honeydew
   437  }
   438  hexagon -> square -> rect
   439  `,
   440  		},
   441  		{
   442  			name: "container_edges",
   443  			script: `a -> g.b -> d.h.c
   444  d -> g.e -> f -> g -> d.h
   445  `,
   446  		},
   447  		{
   448  			name: "one_three_one_container",
   449  			script: `top2.start -> a
   450  top2.start -> b
   451  top2.start -> c
   452  a -> bottom.end
   453  b -> bottom.end
   454  c -> bottom.end
   455  `,
   456  		},
   457  		{
   458  			name: "straight_hierarchy_container",
   459  			script: `a
   460  c
   461  b
   462  
   463  l1: {
   464  	b
   465  	a
   466  	c
   467  }
   468  
   469  b -> l1.b
   470  a -> l1.a
   471  c -> l1.c
   472  
   473  l2c1: {
   474  	a
   475  }
   476  l1.a -> l2c1.a
   477  
   478  l2c3: {
   479  	c
   480  }
   481  l1.c -> l2c3.c
   482  
   483  l2c2: {
   484  	b
   485  }
   486  l1.b -> l2c2.b
   487  
   488  l3c1: {
   489  	a
   490  	b
   491  }
   492  l2c1.a -> l3c1.a
   493  l2c2.b -> l3c1.b
   494  
   495  l3c2: {
   496  	c
   497  }
   498  l2c3.c -> l3c2.c
   499  
   500  l4: {
   501  	c1: {
   502  		a
   503  	}
   504  	c2: {
   505  		b
   506  	}
   507  	c3: {
   508  		c
   509  	}
   510  }
   511  l3c1.a -> l4.c1.a
   512  l3c1.b -> l4.c2.b
   513  l3c2.c -> l4.c3.c`,
   514  		},
   515  		{
   516  			name: "different_subgraphs",
   517  			script: `a -> tree
   518  a -> and
   519  a -> nodes
   520  and -> some
   521  tree -> more
   522  tree -> many
   523  
   524  then -> here
   525  here -> you
   526  have -> hierarchy
   527  then -> hierarchy
   528  
   529  finally -> another
   530  another -> of
   531  nesting -> trees
   532  finally -> trees
   533  finally: {
   534  	a -> tree
   535  	inside -> a
   536  	tree -> hierarchy
   537  	a -> root
   538  }`,
   539  		},
   540  		{
   541  			name: "binary_tree",
   542  			script: `a -> b
   543  a -> c
   544  b -> d
   545  b -> e
   546  c -> f
   547  c -> g
   548  d -> h
   549  d -> i
   550  e -> j
   551  e -> k
   552  f -> l
   553  f -> m
   554  g -> n
   555  g -> o`,
   556  		},
   557  		{
   558  			name: "dense",
   559  			script: `
   560  a-> b
   561  c -> b
   562  d-> e
   563  f-> e
   564  b-> f
   565  b-> g
   566  g-> f
   567  b-> h
   568  b-> i
   569  b-> d
   570  j-> c
   571  j-> a
   572  b-> j
   573  i-> k
   574  d-> l
   575  l-> e
   576  m-> l
   577  m-> n
   578  n-> i
   579  d-> n
   580  f-> n
   581  b-> o
   582  p-> l
   583  e-> q`,
   584  		},
   585  		{
   586  			name: "multiple_trees",
   587  			script: `
   588  a-> b
   589  a-> c
   590  a-> d
   591  a-> e
   592  a-> f
   593  g-> a
   594  a-> h
   595  i-> b
   596  j-> b
   597  k-> g
   598  l-> g
   599  c-> m
   600  c-> n
   601  d-> o
   602  d-> p
   603  e-> q
   604  e-> r
   605  p-> s
   606  f-> t
   607  f-> u
   608  v-> h
   609  w-> h
   610  `,
   611  		},
   612  		{
   613  			name: "one_container_loop",
   614  			script: `
   615  a.b-> c
   616  d-> c
   617  e-> c
   618  f-> d
   619  a-> e
   620  g-> f
   621  a.h-> g
   622  `,
   623  		},
   624  		{
   625  			name: "large_arch",
   626  			script: `
   627  a
   628  b
   629  c
   630  d
   631  e
   632  f
   633  g
   634  h
   635  i
   636  i.j
   637  i.j.k
   638  i.j.l
   639  i.m
   640  i.n
   641  i.o
   642  i.o.p
   643  q
   644  r
   645  r.s
   646  r.s.t
   647  r.s.u.v
   648  r.s.w
   649  r.s.x
   650  r.s.y
   651  r.z
   652  r.aa
   653  r.bb
   654  r.bb.cc
   655  r.bb.dd
   656  r.ee
   657  r.ff
   658  r.gg
   659  
   660  i.j.k-> i.m
   661  i.j.l-> i.o.p
   662  q-> i.m
   663  i.m-> q
   664  i.n-> q
   665  i.m-> c
   666  i.m-> d
   667  i.m-> g
   668  i.m-> f
   669  d-> e
   670  r.s.x-> r.s.t
   671  r.s.x-> r.s.w
   672  r.gg-> r.s.t
   673  r.s.u.v-> r.z
   674  r.aa-> r.s.t
   675  r.s.w-> i.m
   676  r.s.t-> g
   677  r.s.t-> h
   678  r.ee -> r.ff
   679  `,
   680  		},
   681  		{
   682  			name: "n22_e32",
   683  			script: `
   684  a-> b
   685  c-> a
   686  d-> a
   687  d-> b
   688  d-> e
   689  e-> f
   690  f-> b
   691  c-> f
   692  g-> c
   693  g-> h
   694  h-> i
   695  i-> j
   696  j-> k
   697  k-> e
   698  j-> f
   699  l-> m
   700  n-> l
   701  n-> l
   702  n-> m
   703  n-> o
   704  o-> p
   705  p-> m
   706  n-> p
   707  q-> n
   708  q-> r
   709  r-> s
   710  s-> t
   711  t-> u
   712  u-> o
   713  t-> p
   714  c-> t
   715  s-> a
   716  u-> a
   717  `,
   718  		},
   719  		{
   720  			name: "chaos1",
   721  			script: `
   722  aaa: {
   723  	bbb.shape: callout
   724  }
   725  aaa.ccc -- aaa
   726  (aaa.ccc -- aaa)[0]: '111'
   727  ddd.shape: cylinder
   728  eee.shape: document
   729  eee <- aaa.ccc
   730  (eee <- aaa.ccc)[0]: '222'
   731  `,
   732  			dagreFeatureError: `Connection "(aaa.ccc -- aaa)[0]" goes from a container to a descendant, but layout engine "dagre" does not support this. See https://d2lang.com/tour/layouts/#layout-specific-functionality for more.`,
   733  		},
   734  		{
   735  			name: "chaos2",
   736  			script: `
   737  aa: {
   738  	bb: {
   739  		cc:  {
   740  			dd: {
   741  				shape: rectangle
   742  				ee: {shape: text}
   743  				ff
   744  			}
   745  			gg: {shape: text}
   746  			hh
   747  			dd.ee -- gg: '11'
   748  			gg -- hh: '22'
   749  		}
   750  		ii: {
   751  			shape: package
   752  			jj: {shape: diamond}
   753  		}
   754  		ii -> cc.dd
   755  		kk: {shape: circle}
   756  	}
   757  	ll
   758  	mm: {shape: cylinder}
   759  	ll <-> bb: '33'
   760  	mm -> bb.cc: '44'
   761  	mm->ll
   762  	mm <-> bb: '55'
   763  	ll <-> bb.cc.gg
   764  	mm <- bb.ii: '66'
   765  	bb.cc <- ll: '77'
   766  	nn: {shape: text}
   767  	oo
   768  	bb.ii <-> ll: '88'
   769  }
   770  			`,
   771  		},
   772  		{
   773  			name: "us_map",
   774  			script: `
   775  AL -- FL -- GA -- MS -- TN
   776  AK
   777  AZ -- CA -- NV -- NM -- UT
   778  AR -- LA -- MS -- MO -- OK -- TN -- TX
   779  CA -- NV -- OR
   780  CO -- KS -- NE -- NM -- OK -- UT -- WY
   781  CT -- MA -- NY -- RI
   782  DE -- MD -- NJ -- PA
   783  FL -- GA
   784  GA -- NC -- SC -- TN
   785  HI
   786  ID -- MT -- NV -- OR -- UT -- WA -- WY
   787  IL -- IN -- IA -- MI -- KY -- MO -- WI
   788  IN -- KY -- MI -- OH
   789  IA -- MN -- MO -- NE -- SD -- WI
   790  KS -- MO -- NE -- OK
   791  KY -- MO -- OH -- TN -- VA -- WV
   792  LA -- MS -- TX
   793  ME -- NH
   794  MD -- PA -- VA -- WV
   795  MA -- NH -- NY -- RI -- VT
   796  MI -- MN -- OH -- WI
   797  MN -- ND -- SD -- WI
   798  MS -- TN
   799  MO -- NE -- OK -- TN
   800  MT -- ND -- SD -- WY
   801  NE -- SD -- WY
   802  NV -- OR -- UT
   803  NH -- VT
   804  NJ -- NY -- PA
   805  NM -- OK -- TX
   806  NY -- PA -- RI -- VT
   807  NC -- SC -- TN -- VA
   808  ND -- SD
   809  OH -- PA -- WV
   810  OK -- TX
   811  OR -- WA
   812  PA -- WV
   813  SD -- WY
   814  TN -- VA
   815  UT -- WY
   816  VA -- WV
   817  `,
   818  		},
   819  		{
   820  			name: "investigate",
   821  			script: `
   822  aa.shape: step
   823  bb.shape: step
   824  cc.shape: step
   825  aa -- bb -- cc
   826  
   827  aa -> dd.ee: 1
   828  bb -> ff.gg: 2
   829  cc -> dd.hh: 3
   830  
   831  dd.ee.shape: diamond
   832  dd.ee -> ii
   833  
   834  ii -- jj -> kk
   835  
   836  ll.mm.shape: circle
   837  ff.mm.shape: circle
   838  kk -> ff.mm: 4
   839  ff.mm -> ll.mm: 5
   840  ll.mm -> nn.oo: 6
   841  
   842  ff.gg.shape: diamond
   843  ff.gg -> ff.pp -> ll.qq -> ll.rr
   844  
   845  dd.hh.shape: diamond
   846  dd.hh -> ss.tt -> uu.vv
   847  
   848  kk -> ww
   849  uu.vv -> ww
   850  ww -> rm
   851  
   852  ww: {
   853  	shape: queue
   854  	icon: https://icons.terrastruct.com/essentials/time.svg
   855  }
   856  
   857  rm -> nn.xx
   858  ll.rr -> yy.zz
   859  
   860  rm -> yy.zz
   861  yy.zz.shape: queue
   862  yy.zz.icon: https://icons.terrastruct.com/essentials/time.svg
   863  
   864  yy.zz -> yy.ab -> nn.ac -> ad
   865  
   866  ad.style.fill: red
   867  ad.shape: parallelogram
   868  
   869  nn.shape: cylinder
   870  
   871  ww -> ff.gg
   872  `,
   873  		},
   874  		{
   875  			name:   "multiline_text",
   876  			script: `hey: this\ngoes\nmultiple lines`,
   877  		},
   878  		{
   879  			name: "markdown",
   880  			script: `hey: |md
   881  # Every frustum longs to be a cone
   882  
   883  - A continuing flow of paper is sufficient to continue the flow of paper
   884  - Please remain calm, it's no use both of us being hysterical at the same time
   885  - Visits always give pleasure: if not on arrival, then on the departure
   886  
   887  *Festivity Level 1*: Your guests are chatting amiably with each other.
   888  
   889  test ~~strikethrough~~ test
   890  |
   891  
   892  x -> hey -> y
   893  `,
   894  		},
   895  		{
   896  			name: "md_fontsize_10",
   897  			script: `hey: |md
   898  # Every frustum longs to be a cone
   899  
   900  - A continuing flow of paper is sufficient to continue the flow of paper
   901  - Please remain calm, it's no use both of us being hysterical at the same time
   902  - Visits always give pleasure: if not on arrival, then on the departure
   903  
   904  *Festivity Level 1*: Your guests are chatting amiably with each other.
   905  
   906  test ~~strikethrough~~ test
   907  |
   908  
   909  hey.style.font-size: 10
   910  
   911  x -> hey -> y
   912  `,
   913  		},
   914  		{
   915  			name: "font_sizes_containers_large",
   916  			script: `
   917  ninety nine: {
   918  	style.font-size: 99
   919  	sixty four: {
   920  		style.font-size: 64
   921  		thirty two:{
   922  			style.font-size: 32
   923  			sixteen: {
   924  				style.font-size: 16
   925  				eight: {
   926  					style.font-size: 8
   927  				}
   928  			}
   929  		}
   930  	}
   931  }
   932  `,
   933  		},
   934  		{
   935  			name: "font_sizes_containers_large_right",
   936  			script: `
   937  direction: right
   938  
   939  ninety nine: {
   940  	style.font-size: 99
   941  	sixty four: {
   942  		style.font-size: 64
   943  		thirty two:{
   944  			style.font-size: 32
   945  			sixteen: {
   946  				style.font-size: 16
   947  				eight: {
   948  					style.font-size: 8
   949  				}
   950  			}
   951  		}
   952  	}
   953  }
   954  `,
   955  		},
   956  		{
   957  			name: "lone_h1",
   958  			script: mdTestScript(`
   959  # Markdown: Syntax
   960  `),
   961  		},
   962  		// newlines should be ignored here in md text measurement
   963  		{
   964  			name: "p",
   965  			script: mdTestScript(`
   966  A paragraph is simply one or more consecutive lines of text, separated
   967  by one or more blank lines. (A blank line is any line that looks like a
   968  blank line -- a line containing nothing but spaces or tabs is considered
   969  blank.) Normal paragraphs should not be indented with spaces or tabs.
   970  `),
   971  		},
   972  		{
   973  			name: "li1",
   974  			script: mdTestScript(`
   975  - [Overview](#overview)
   976    - [Philosophy](#philosophy)
   977    - [Inline HTML](#html)
   978      - [Automatic Escaping for Special Characters](#autoescape)
   979  `),
   980  		},
   981  		{
   982  			name: "li2",
   983  			script: mdTestScript(`
   984  - [Overview](#overview) ok _this is all measured_
   985  	- [Philosophy](#philosophy)
   986  	- [Inline HTML](#html)
   987  `),
   988  		},
   989  		{
   990  			name: "li3",
   991  			script: mdTestScript(`
   992  - [Overview](#overview)
   993    - [Philosophy](#philosophy)
   994    - [Inline HTML](#html)
   995    - [Automatic Escaping for Special Characters](#autoescape)
   996  - [Block Elements](#block)
   997    - [Paragraphs and Line Breaks](#p)
   998    - [Headers](#header)
   999    - [Blockquotes](#blockquote)
  1000    - [Lists](#list)
  1001    - [Code Blocks](#precode)
  1002    - [Horizontal Rules](#hr)
  1003  - [Span Elements](#span)
  1004    - [Links](#link)
  1005    - [Emphasis](#em)
  1006    - [Code](#code)
  1007    - [Images](#img)
  1008  - [Miscellaneous](#misc)
  1009    - [Backslash Escapes](#backslash)
  1010    - [Automatic Links](#autolink)
  1011  `),
  1012  		},
  1013  		{
  1014  			name: "li4",
  1015  			script: mdTestScript(`
  1016  List items may consist of multiple paragraphs. Each subsequent
  1017  paragraph in a list item must be indented by either 4 spaces
  1018  or one tab:
  1019  
  1020  1.  This is a list item with two paragraphs. Lorem ipsum dolor
  1021      sit amet, consectetuer adipiscing elit. Aliquam hendrerit
  1022      mi posuere lectus.
  1023  
  1024      Vestibulum enim wisi, viverra nec, fringilla in, laoreet
  1025      vitae, risus. Donec sit amet nisl. Aliquam semper ipsum
  1026      sit amet velit.
  1027  
  1028  2.  Suspendisse id sem consectetuer libero luctus adipiscing.
  1029  
  1030  It looks nice if you indent every line of the subsequent
  1031  paragraphs, but here again, Markdown will allow you to be
  1032  lazy:
  1033  
  1034  - This is a list item with two paragraphs.
  1035  
  1036        This is the second paragraph in the list item. You're
  1037  
  1038    only required to indent the first line. Lorem ipsum dolor
  1039    sit amet, consectetuer adipiscing elit.
  1040  
  1041  - Another item in the same list.
  1042  `),
  1043  		},
  1044  		{
  1045  			name: "hr",
  1046  			script: mdTestScript(`
  1047  **Note:** This document is itself written using Markdown; you
  1048  can [see the source for it by adding '.text' to the URL](/projects/markdown/syntax.text).
  1049  
  1050  ---
  1051  
  1052  ## Overview
  1053  `),
  1054  		},
  1055  		{
  1056  			name: "pre",
  1057  			script: mdTestScript(`
  1058  Here is an example of AppleScript:
  1059  
  1060      tell application "Foo"
  1061          beep
  1062      end tell
  1063  
  1064  A code block continues until it reaches a line that is not indented
  1065  (or the end of the article).
  1066  `),
  1067  		},
  1068  		{
  1069  			name: "br",
  1070  			script: `copy: |md
  1071    # Headline 1
  1072    ## Headline 2
  1073    Lorem ipsum dolor
  1074    <br />
  1075    ## Headline 3
  1076    Lorem ipsum dolor
  1077    <br />
  1078    <br />
  1079    ## Headline 3
  1080    This just disappears
  1081    <br />
  1082  |
  1083  `,
  1084  		},
  1085  		{
  1086  			name:   "giant_markdown_test",
  1087  			script: mdTestScript(testMarkdown),
  1088  		},
  1089  		{
  1090  			name: "code_snippet",
  1091  			script: `hey: |go
  1092  // RegisterHash registers a function that returns a new instance of the given
  1093  // hash function. This is intended to be called from the init function in
  1094  // packages that implement hash functions.
  1095  func RegisterHash(h Hash, f func() hash.Hash) {
  1096  	if h >= maxHash {
  1097  		panic("crypto: RegisterHash of unknown hash function")
  1098  	}
  1099  	hashes[h] = f
  1100  }
  1101  |
  1102  x -> hey -> y`,
  1103  		}, {
  1104  			name: "arrowhead_adjustment",
  1105  			script: `a <-> b: {
  1106  				style.stroke-width: 6
  1107  				style.stroke-dash: 4
  1108  				source-arrowhead: {
  1109  				  shape: arrow
  1110  				}
  1111  			  }
  1112  
  1113  			  c -> b: {
  1114  				style.stroke-width: 7
  1115  				style.stroke: "#20222a"
  1116  			  }
  1117  			  c.style.stroke-width: 7
  1118  			  c.style.stroke: "#b2350d"
  1119  			  c.shape: document
  1120  			  b.style.stroke-width: 8
  1121  			  b.style.stroke: "#0db254"
  1122  			  a.style.border-radius: 10
  1123  			  a.style.stroke-width: 8
  1124  			  a.style.stroke: "#2bc3d8"
  1125  			  Oval: "" {
  1126  				shape: oval
  1127  				style.stroke-width: 6
  1128  				style.stroke: "#a1a4af"
  1129  			  }
  1130  			  a <-> Oval: {
  1131  				style.stroke-width: 6
  1132  				source-arrowhead: {
  1133  				  shape: diamond
  1134  				}
  1135  				target-arrowhead: * {
  1136  				  shape: diamond
  1137  				  style.filled: true
  1138  				}
  1139  			  }
  1140  			  c -- a: {style.stroke-width: 7}
  1141  			  Oval <-> c`,
  1142  		},
  1143  		{
  1144  			name: "md_code_inline",
  1145  			script: `md: |md
  1146  ` + "`code`" + `
  1147  |
  1148  a -> md -> b
  1149  `,
  1150  		},
  1151  		{
  1152  			name: "md_code_block_fenced",
  1153  			script: `md: |md
  1154  ` + "```" + `
  1155  {
  1156  	fenced: "block",
  1157  	of: "json",
  1158  }
  1159  ` + "```" + `
  1160  |
  1161  a -> md -> b
  1162  `,
  1163  		},
  1164  		{
  1165  			name: "md_code_block_indented",
  1166  			script: `md: |md
  1167  a line of text and an
  1168  
  1169  	{
  1170  		indented: "block",
  1171  		of: "json",
  1172  	}
  1173  
  1174  |
  1175  a -> md -> b
  1176  `,
  1177  		},
  1178  		{
  1179  			name: "class",
  1180  			script: `manager: BatchManager {
  1181    shape: class
  1182    -num: int
  1183    -timeout: int
  1184    -pid
  1185  
  1186    +getStatus(): Enum
  1187    +getJobs(): "Job[]"
  1188    +setTimeout(seconds int)
  1189  }
  1190  `,
  1191  		}, {
  1192  			name: "sql_tables",
  1193  			script: `
  1194  direction: left
  1195  
  1196  users: {
  1197  	shape: sql_table
  1198  	id: int { constraint: primary_key }
  1199  	name: string
  1200  	email: string
  1201  	password: string
  1202  	last_login: datetime
  1203  }
  1204  
  1205  products: {
  1206  	shape: sql_table
  1207  	id: int { constraint: primary_key }
  1208  	price: decimal
  1209  	sku: string
  1210  	name: string
  1211  }
  1212  
  1213  orders: {
  1214  	shape: sql_table
  1215  	id: int { constraint: primary_key }
  1216  	user_id: int { constraint: foreign_key }
  1217  	product_id: int { constraint: foreign_key }
  1218  }
  1219  
  1220  shipments: {
  1221  	shape: sql_table
  1222  	id: int { constraint: primary_key }
  1223  	order_id: int { constraint: foreign_key }
  1224  	tracking_number: string
  1225  	status: string
  1226  }
  1227  
  1228  orders.user_id -> users.id
  1229  orders.product_id -> products.id
  1230  shipments.order_id -> orders.id`,
  1231  		}, {
  1232  			name: "sql_table_row_connections",
  1233  			script: `
  1234  direction: left
  1235  
  1236  a: {
  1237  	shape: sql_table
  1238  	id: int { constraint: primary_key }
  1239  }
  1240  
  1241  b: {
  1242  	shape: sql_table
  1243  	id: int { constraint: primary_key }
  1244  	a_1: int { constraint: foreign_key }
  1245  	a_2: int { constraint: foreign_key }
  1246  }
  1247  
  1248  b.a_1 -> a.id
  1249  b.a_2 -> a.id`,
  1250  		}, {
  1251  			name: "images",
  1252  			script: `a: {
  1253    shape: image
  1254    icon: https://icons.terrastruct.com/essentials/004-picture.svg
  1255  }
  1256  
  1257  b: {
  1258    shape: image
  1259    icon: https://icons.terrastruct.com/essentials/004-picture.svg
  1260  }
  1261  a -> b
  1262  `,
  1263  		},
  1264  		{
  1265  			name: "icon-containers",
  1266  			script: `vpc: VPC 1 10.1.0.0./16 {
  1267    icon: https://icons.terrastruct.com/aws%2F_Group%20Icons%2FVirtual-private-cloud-VPC_light-bg.svg
  1268  	style: {
  1269  	  stroke: green
  1270  		font-color: green
  1271  		fill: white
  1272  	}
  1273    az: Availability Zone A {
  1274  		style: {
  1275  			stroke: blue
  1276  			font-color: blue
  1277  			stroke-dash: 3
  1278  			fill: white
  1279  		}
  1280  		firewall: Firewall Subnet A {
  1281  			icon: https://icons.terrastruct.com/aws%2FNetworking%20&%20Content%20Delivery%2FAmazon-Route-53_Hosted-Zone_light-bg.svg
  1282  			style: {
  1283  				stroke: purple
  1284  				font-color: purple
  1285  				fill: "#e1d5e7"
  1286  			}
  1287  			ec2: EC2 Instance {
  1288  				icon: https://icons.terrastruct.com/aws%2FCompute%2F_Instance%2FAmazon-EC2_C4-Instance_light-bg.svg
  1289  			}
  1290  		}
  1291    }
  1292  }
  1293  `,
  1294  		},
  1295  		{
  1296  			name: "arrowhead_labels",
  1297  			script: `
  1298  a -> b: To err is human, to moo bovine {
  1299  	source-arrowhead: 1
  1300  	target-arrowhead: * {
  1301  		shape: diamond
  1302  	}
  1303  }
  1304  `,
  1305  		},
  1306  		{
  1307  			name: "stylish",
  1308  			script: `
  1309  x: {
  1310    style: {
  1311      opacity: 0.6
  1312      fill: orange
  1313      stroke: "#53C0D8"
  1314      stroke-width: 5
  1315      shadow: true
  1316    }
  1317  }
  1318  
  1319  y: {
  1320    style: {
  1321      stroke-dash: 5
  1322      opacity: 0.6
  1323      fill: red
  1324      3d: true
  1325      stroke: black
  1326    }
  1327  }
  1328  
  1329  x -> y: in style {
  1330    style: {
  1331      stroke: green
  1332      opacity: 0.5
  1333      stroke-width: 2
  1334      stroke-dash: 5
  1335  	fill: lavender
  1336    }
  1337  }
  1338  `,
  1339  		},
  1340  		{
  1341  			name: "md_2space_newline",
  1342  			script: `
  1343  markdown: {
  1344    md: |md
  1345  Lorem ipsum dolor sit amet, consectetur adipiscing elit,  ` + `
  1346  sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
  1347  |
  1348  }
  1349  `,
  1350  		},
  1351  		{
  1352  			name: "md_backslash_newline",
  1353  			script: `
  1354  markdown: {
  1355    md: |md
  1356  Lorem ipsum dolor sit amet, consectetur adipiscing elit,\
  1357  sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
  1358  |
  1359  }
  1360  `,
  1361  		},
  1362  		{
  1363  			name: "font_colors",
  1364  			script: `
  1365  alpha: {
  1366  	style.font-color: '#4A6FF3'
  1367  }
  1368  beta: {
  1369  	style.font-color: red
  1370  }
  1371  alpha -> beta: gamma {
  1372  	style.font-color: green
  1373  }
  1374  c: |md
  1375    colored
  1376  | {
  1377    style.font-color: blue
  1378  }
  1379  `,
  1380  		},
  1381  		{
  1382  			name: "latex",
  1383  			script: `a: |latex
  1384  \\Huge{\\frac{\\alpha g^2}{\\omega^5} e^{[ -0.74\\bigl\\{\\frac{\\omega U_\\omega 19.5}{g}\\bigr\\}^{\\!-4}\\,]}}
  1385  |
  1386  
  1387  b: |latex
  1388  e = mc^2
  1389  |
  1390  
  1391  z: |latex
  1392  gibberish\\; math:\\sum_{i=0}^\\infty i^2
  1393  |
  1394  
  1395  z -> a
  1396  z -> b
  1397  
  1398  a -> c
  1399  b -> c
  1400  sugar -> c
  1401  c: mixed together
  1402  
  1403  c -> solution: we get
  1404  
  1405  Linear program: {
  1406    formula: |latex
  1407      \\min_{ \\mathclap{\\substack{ x \\in \\mathbb{R}^n \\ x \\geq 0 \\ Ax \\leq b }}} c^T x
  1408    |
  1409  }
  1410  `,
  1411  		},
  1412  		{
  1413  			name: "direction",
  1414  			script: `a -> b -> c -> d -> e
  1415  b: {
  1416    direction: right
  1417    1 -> 2 -> 3 -> 4 -> 5
  1418  
  1419    2: {
  1420      direction: up
  1421      a -> b -> c -> d -> e
  1422    }
  1423  }
  1424  `,
  1425  		},
  1426  		{
  1427  			name: "transparent_3d",
  1428  			script: `
  1429  cube: {
  1430  	style: {
  1431  		3d: true
  1432  		opacity: 0.5
  1433  		fill: orange
  1434  		stroke: "#53C0D8"
  1435  		stroke-width: 7
  1436  	}
  1437  }
  1438  `,
  1439  		},
  1440  		{
  1441  			name: "font_sizes",
  1442  			script: `
  1443  size XS.style.font-size: 13
  1444  size S.style.font-size: 14
  1445  size M.style.font-size: 16
  1446  size L.style.font-size: 20
  1447  size XL.style.font-size: 24
  1448  size XXL.style.font-size: 28
  1449  size XXXL.style.font-size: 32
  1450  
  1451  custom 8.style.font-size: 8
  1452  custom 12.style.font-size: 12
  1453  custom 18.style.font-size: 18
  1454  custom 21.style.font-size: 21
  1455  custom 64.style.font-size: 64
  1456  
  1457  custom 8 -> size XS: custom 10 {
  1458  	style.font-size: 10
  1459  }
  1460  size S -> size M: custom 15 {
  1461  	style.font-size: 15
  1462  }
  1463  size XXXL -> custom 64: custom 48 {
  1464  	style.font-size: 48
  1465  	style.fill: lavender
  1466  }
  1467  `,
  1468  		}, {
  1469  			name: "sequence_diagram_simple",
  1470  			script: `shape: sequence_diagram
  1471  alice: "Alice\nline\nbreaker" {
  1472      shape: person
  1473      style.stroke: red
  1474  }
  1475  bob: "Bob" {
  1476      shape: person
  1477      style.stroke-width: 5
  1478  }
  1479  db: {
  1480      shape: cylinder
  1481  }
  1482  queue: {
  1483      shape: queue
  1484  }
  1485  service: "an\nodd\nservice\nwith\na\nname\nin\nmultiple lines"
  1486  
  1487  alice -> bob: "Authentication Request"
  1488  bob -> service: "make request for something that is quite far away and requires a really long label to take all the space between the objects"
  1489  service -> db: "validate credentials"
  1490  db -> service: {
  1491      style.stroke-dash: 4
  1492  }
  1493  service -> bob: {
  1494      style.stroke-dash: 4
  1495  }
  1496  bob -> alice: "Authentication Response"
  1497  alice -> bob: "Another authentication Request"
  1498  bob -> queue: "do it later"
  1499  queue -> bob: "stored" {
  1500      style.stroke-dash: 3
  1501      style.stroke-width: 5
  1502      style.stroke: green
  1503  }
  1504  
  1505  bob -> alice: "Another authentication Response"`,
  1506  		}, {
  1507  			name: "sequence_diagram_span",
  1508  			script: `shape: sequence_diagram
  1509  
  1510  scorer.t -> itemResponse.t: getItem()
  1511  scorer.t <- itemResponse.t: item
  1512  
  1513  scorer.t -> item.t1: getRubric()
  1514  scorer.t <- item.t1: rubric
  1515  
  1516  scorer.t -> essayRubric.t: applyTo(essayResp)
  1517  itemResponse -> essayRubric.t.c
  1518  essayRubric.t.c -> concept.t: match(essayResponse)
  1519  scorer <- essayRubric.t: score
  1520  
  1521  scorer.t -> itemOutcome.t1: new
  1522  scorer.t -> item.t2: getNormalMinimum()
  1523  scorer.t -> item.t3: getNormalMaximum()
  1524  
  1525  scorer.t -> itemOutcome.t2: setScore(score)
  1526  scorer.t -> itemOutcome.t3: setFeedback(missingConcepts)`,
  1527  		}, {
  1528  			name: "sequence_diagram_nested_span",
  1529  			script: `shape: sequence_diagram
  1530  
  1531  scorer: {
  1532      style.stroke: red
  1533      style.stroke-width: 5
  1534  }
  1535  
  1536  scorer.abc: {
  1537      style.fill: yellow
  1538      style.stroke-width: 7
  1539  }
  1540  
  1541  scorer -> itemResponse.a: {
  1542      style.stroke-width: 10
  1543  }
  1544  itemResponse.a -> item.a.b
  1545  item.a.b -> essayRubric.a.b.c
  1546  essayRubric.a.b.c -> concept.a.b.c.d
  1547  item.a -> essayRubric.a.b
  1548  concept.a.b.c.d -> itemOutcome.a.b.c.d.e
  1549  
  1550  scorer.abc -> item.a
  1551  
  1552  itemOutcome.a.b.c.d.e -> scorer
  1553  scorer -> itemResponse.c`,
  1554  		}, {
  1555  			name: "sequence_diagrams",
  1556  			script: `a_shape.shape: circle
  1557  a_sequence: {
  1558      shape: sequence_diagram
  1559  
  1560      scorer.t -> itemResponse.t: getItem()
  1561      scorer.t <- itemResponse.t: item
  1562  
  1563      scorer.t -> item.t1: getRubric()
  1564      scorer.t <- item.t1: rubric
  1565  
  1566      scorer.t -> essayRubric.t: applyTo(essayResp)
  1567      itemResponse -> essayRubric.t.c
  1568      essayRubric.t.c -> concept.t: match(essayResponse)
  1569      scorer <- essayRubric.t: score
  1570  
  1571      scorer.t <-> itemOutcome.t1: new
  1572      scorer.t <-> item.t2: getNormalMinimum()
  1573      scorer.t -> item.t3: getNormalMaximum()
  1574  
  1575      scorer.t -- itemOutcome.t2: setScore(score)
  1576      scorer.t -- itemOutcome.t3: setFeedback(missingConcepts)
  1577  }
  1578  
  1579  another: {
  1580      sequence: {
  1581          shape: sequence_diagram
  1582  
  1583  		# scoped edges
  1584          scorer.t -> itemResponse.t: getItem()
  1585          scorer.t <- itemResponse.t: item
  1586  
  1587          scorer.t -> item.t1: getRubric()
  1588          scorer.t <- item.t1: rubric
  1589  
  1590          scorer.t -> essayRubric.t: applyTo(essayResp)
  1591          itemResponse -> essayRubric.t.c
  1592          essayRubric.t.c -> concept.t: match(essayResponse)
  1593          scorer <- essayRubric.t: score
  1594  
  1595          scorer.t -> itemOutcome.t1: new
  1596          scorer.t <-> item.t2: getNormalMinimum()
  1597          scorer.t -> item.t3: getNormalMaximum()
  1598  
  1599          scorer.t -> itemOutcome.t2: setScore(score)
  1600          scorer.t -> itemOutcome.t3: setFeedback(missingConcepts)
  1601      }
  1602  }
  1603  
  1604  a_shape -> a_sequence
  1605  a_shape -> another.sequence
  1606  a_sequence -> sequence
  1607  another.sequence <-> finally.sequence
  1608  a_shape -- finally
  1609  
  1610  
  1611  finally: {
  1612      shape: queue
  1613      sequence: {
  1614          shape: sequence_diagram
  1615  		# items appear in this order
  1616          scorer {
  1617  					style.stroke: red
  1618  					style.stroke-dash: 2
  1619  				}
  1620          concept {
  1621  					style.stroke-width: 6
  1622  				}
  1623          essayRubric
  1624          item
  1625          itemOutcome
  1626          itemResponse
  1627      }
  1628  }
  1629  
  1630  # full path edges
  1631  finally.sequence.itemResponse.a -> finally.sequence.item.a.b
  1632  finally.sequence.item.a.b -> finally.sequence.essayRubric.a.b.c
  1633  finally.sequence.essayRubric.a.b.c -> finally.sequence.concept.a.b.c.d
  1634  finally.sequence.item.a -> finally.sequence.essayRubric.a.b
  1635  finally.sequence.concept.a.b.c.d -> finally.sequence.itemOutcome.a.b.c.d.e
  1636  finally.sequence.scorer.abc -> finally.sequence.item.a
  1637  finally.sequence.itemOutcome.a.b.c.d.e -> finally.sequence.scorer
  1638  finally.sequence.scorer -> finally.sequence.itemResponse.c`,
  1639  		},
  1640  		{
  1641  			name: "number_connections",
  1642  			script: `1 -> 2
  1643  foo baz: Foo Baz
  1644  
  1645  foo baz -> hello
  1646  `,
  1647  		}, {
  1648  			name: "sequence_diagram_all_shapes",
  1649  			script: `shape: sequence_diagram
  1650  
  1651  a: "a label" {
  1652      shape: callout
  1653  }
  1654  b: "b\nlabels" {
  1655      shape: circle
  1656  }
  1657  c: "a class" {
  1658      shape: class
  1659      +public() bool
  1660      -private() int
  1661  }
  1662  d: "cloudyyyy" {
  1663      shape: cloud
  1664  }
  1665  e: |go
  1666      a := 5
  1667      b := a + 7
  1668      fmt.Printf("%d", b)
  1669  |
  1670  f: "cyl" {
  1671      shape: cylinder
  1672  }
  1673  g: "dia" {
  1674      shape: diamond
  1675  }
  1676  h: "docs" {
  1677      shape: document
  1678  }
  1679  i: "six corners" {
  1680      shape: hexagon
  1681  }
  1682  j: "a random icon" {
  1683      shape: image
  1684      icon: https://icons.terrastruct.com/essentials/004-picture.svg
  1685  }
  1686  k: "over" {
  1687      shape: oval
  1688  }
  1689  l: "pack" {
  1690      shape: package
  1691  }
  1692  m: "docs page" {
  1693      shape: page
  1694  }
  1695  n: "too\nhard\to say" {
  1696      shape: parallelogram
  1697  }
  1698  o: "single\nperson" {
  1699      shape: person
  1700  }
  1701  p: "a queue" {
  1702      shape: queue
  1703  }
  1704  q: "a square" {
  1705      shape: square
  1706  }
  1707  r: "a step at a time" {
  1708      shape: step
  1709  }
  1710  s: "data" {
  1711      shape: stored_data
  1712  }
  1713  
  1714  t: "users" {
  1715      shape: sql_table
  1716      id: int
  1717      name: varchar
  1718  }
  1719  
  1720  a -> b: |go
  1721      result := callThisFunction(obj, 5)
  1722  |
  1723  b <-> c: "mid" {
  1724      source-arrowhead: "this side" {
  1725          shape: diamond
  1726      }
  1727      target-arrowhead: "other side" {
  1728          shape: triangle
  1729      }
  1730  }
  1731  c -> d
  1732  d -> e
  1733  e -> f
  1734  f -> g
  1735  g -> h
  1736  h -> i
  1737  i -> j
  1738  j -> k
  1739  k -> l
  1740  l -> m
  1741  m -> n
  1742  n -> o
  1743  o -> p
  1744  p -> q
  1745  q -> r
  1746  r -> s
  1747  s -> t`,
  1748  		},
  1749  		{
  1750  			name: "self-referencing",
  1751  			script: `x -> x -> x -> y
  1752  z -> y
  1753  z -> z: hello
  1754  `,
  1755  		}, {
  1756  			name: "sequence_diagram_self_edges",
  1757  			script: `shape: sequence_diagram
  1758  a -> a: a self edge here
  1759  a -> b: between actors
  1760  b -> b.1: to descendant
  1761  b.1 -> b.1.2: to deeper descendant
  1762  b.1.2 -> b: to parent
  1763  b -> a.1.2: actor
  1764  a.1 -> b.3`,
  1765  		},
  1766  		{
  1767  			name: "icon-label",
  1768  			script: `ww: {
  1769    label: hello
  1770    icon: https://icons.terrastruct.com/essentials/time.svg
  1771  }
  1772  `,
  1773  		},
  1774  		{
  1775  			name: "sequence_diagram_note",
  1776  			script: `shape: sequence_diagram
  1777  a; b; c; d
  1778  a -> b
  1779  a.explanation
  1780  a.another explanation
  1781  b -> c
  1782  b."Some one who believes imaginary things\n appear right before your i's."
  1783  c -> b: okay
  1784  d."The earth is like a tiny grain of sand, only much, much heavier"
  1785  `,
  1786  		},
  1787  		{
  1788  			name: "sequence_diagram_groups",
  1789  			script: `shape: sequence_diagram
  1790  a;b;c;d
  1791  a -> b
  1792  ggg: {
  1793  	a -> b: lala
  1794  }
  1795  group 1: {
  1796    b -> c
  1797  	c -> b: ey
  1798    nested guy: {
  1799      c -> b: okay
  1800    }
  1801    b.t1 -> c.t1
  1802    b.t1.t2 -> c.t1
  1803    c.t1 -> b.t1
  1804  }
  1805  group b: {
  1806    b -> c
  1807  	c."what would arnold say"
  1808    c -> b: okay
  1809  }
  1810  choo: {
  1811    d."this note"
  1812  }
  1813  `,
  1814  		},
  1815  		{
  1816  			name: "sequence_diagram_nested_groups",
  1817  			script: `shape: sequence_diagram
  1818  
  1819  a; b; c
  1820  
  1821  this is a message group: {
  1822      a -> b
  1823      and this is a nested message group: {
  1824          a -> b
  1825          what about more nesting: {
  1826              a -> b
  1827  						crazy town: {
  1828  								a."a note"
  1829  								a -> b
  1830  							whoa: {
  1831  									a -> b
  1832  							}
  1833              }
  1834          }
  1835      }
  1836  }
  1837  
  1838  alt: {
  1839      case 1: {
  1840          b -> c
  1841      }
  1842      case 2: {
  1843          b -> c
  1844      }
  1845      case 3: {
  1846          b -> c
  1847      }
  1848      case 4: {
  1849          b -> c
  1850      }
  1851  }
  1852  
  1853  b.note: "a note here to remember that padding must consider notes too"
  1854  a.note: "just\na\nlong\nnote\nhere"
  1855  c: "just an actor"
  1856  `,
  1857  		},
  1858  		{
  1859  			name: "sequence_diagram_real",
  1860  			script: `How this is rendered: {
  1861    shape: sequence_diagram
  1862  
  1863  	CLI; d2ast; d2compiler; d2layout; d2exporter; d2themes; d2renderer; d2sequencelayout; d2dagrelayout
  1864  
  1865    CLI -> d2ast: "'How this is rendered: {...}'"
  1866    d2ast -> CLI: tokenized AST
  1867    CLI -> d2compiler: compile AST
  1868    d2compiler."measurements also take place"
  1869    d2compiler -> CLI: objects and edges
  1870    CLI -> d2layout.layout: run layout engines
  1871    d2layout.layout -> d2sequencelayout: run engine on shape: sequence_diagram, temporarily remove
  1872    only if root is not sequence: {
  1873      d2layout.layout -> d2dagrelayout: run core engine on rest
  1874    }
  1875    d2layout.layout <- d2sequencelayout: add back in sequence diagrams
  1876    d2layout -> CLI: diagram with correct positions and dimensions
  1877    CLI -> d2exporter: export diagram with chosen theme and renderer
  1878    d2exporter.export -> d2themes: get theme styles
  1879    d2exporter.export -> d2renderer: render to SVG
  1880    d2exporter.export -> CLI: resulting SVG
  1881  }
  1882  `,
  1883  		},
  1884  		{
  1885  			name: "sequence_diagram_actor_distance",
  1886  			script: `shape: sequence_diagram
  1887  a: "an actor with a really long label that will break everything"
  1888  c: "an\nactor\nwith\na\nreally\nlong\nlabel\nthat\nwill\nbreak\neverything"
  1889  d: "simple"
  1890  e: "a short one"
  1891  b: "far away"
  1892  f: "what if there were no labels between this actor and the previous one"
  1893  a -> b: "short"
  1894  a -> b: "long label for testing purposes and it must be really, really long"
  1895  c -> d: "short"
  1896  a -> d: "this should span many actors lifelines so we know how it will look like when redering a long label over many actors"
  1897  d -> e: "long label for testing purposes and it must be really, really long"
  1898  a -> f`,
  1899  		}, {
  1900  			name: "sequence_diagram_long_note",
  1901  			script: `shape: sequence_diagram
  1902  a -> b
  1903  b.note: "a note here to remember that padding must consider notes too"
  1904  a.note: "just\na\nlong\nnote\nhere"`,
  1905  		},
  1906  		{
  1907  			name: "sequence_diagram_distance",
  1908  			script: `shape: sequence_diagram
  1909  alice -> bob: what does it mean to be well-adjusted
  1910  bob -> alice: The ability to play bridge or golf as if they were games
  1911  `,
  1912  		},
  1913  		{
  1914  			name: "markdown_stroke_fill",
  1915  			script: `
  1916  container.md: |md
  1917  # a header
  1918  
  1919  a line of text and an
  1920  
  1921  	{
  1922  		indented: "block",
  1923  		of: "json",
  1924  	}
  1925  
  1926  walk into a bar.
  1927  | {
  1928  	style.stroke: darkorange
  1929  }
  1930  
  1931  container -> no container
  1932  
  1933  no container: |md
  1934  they did it in style
  1935  |
  1936  
  1937  no container.style: {
  1938  	stroke: red
  1939  	fill: "#CEEDEE"
  1940  }
  1941  `,
  1942  		},
  1943  		{
  1944  			name: "overlapping_image_container_labels",
  1945  			script: `
  1946  root: {
  1947  	shape: image
  1948  	icon: https://icons.terrastruct.com/essentials/004-picture.svg
  1949  }
  1950  
  1951  root -> container.root
  1952  
  1953  container: {
  1954  	root: {
  1955  		shape: image
  1956  		icon: https://icons.terrastruct.com/essentials/004-picture.svg
  1957  	}
  1958  
  1959  	left2: {
  1960  		root: {
  1961  			shape: image
  1962  			icon: https://icons.terrastruct.com/essentials/004-picture.svg
  1963  		}
  1964  		inner: {
  1965  			left2: {
  1966  				shape: image
  1967  				icon: https://icons.terrastruct.com/essentials/004-picture.svg
  1968  			}
  1969  			right: {
  1970  				shape: image
  1971  				icon: https://icons.terrastruct.com/essentials/004-picture.svg
  1972  			}
  1973  		}
  1974  		root -> inner.left2: {
  1975  			label: to inner left2
  1976  		}
  1977  		root -> inner.right: {
  1978  			label: to inner right
  1979  		}
  1980  	}
  1981  
  1982  	right: {
  1983  		root: {
  1984  			shape: image
  1985  			icon: https://icons.terrastruct.com/essentials/004-picture.svg
  1986  		}
  1987  		inner: {
  1988  			left2: {
  1989  				shape: image
  1990  				icon: https://icons.terrastruct.com/essentials/004-picture.svg
  1991  			}
  1992  			right: {
  1993  				shape: image
  1994  				icon: https://icons.terrastruct.com/essentials/004-picture.svg
  1995  			}
  1996  		}
  1997  		root -> inner.left2: {
  1998  			label: to inner left2
  1999  		}
  2000  		root -> inner.right: {
  2001  			label: to inner right
  2002  		}
  2003  	}
  2004  
  2005  	root -> left2.root: {
  2006  		label: to left2 container root
  2007  	}
  2008  
  2009  	root -> right.root: {
  2010  		label: to right container root
  2011  	}
  2012  }
  2013  `,
  2014  		},
  2015  		{
  2016  			name: "constant_near_stress",
  2017  			script: `x -> y
  2018  The top of the mountain: { shape: text; near: top-center }
  2019  Joe: { shape: person; near: center-left }
  2020  Donald: { shape: person; near: center-right }
  2021  bottom: |md
  2022  	# Cats, no less liquid than their shadows, offer no angles to the wind.
  2023  
  2024    If we can't fix it, it ain't broke.
  2025  
  2026    Dieters live life in the fasting lane.
  2027  | { near: bottom-center }
  2028  i am top left: { shape: text; near: top-left }
  2029  i am top right: { shape: text; near: top-right }
  2030  i am bottom left: { shape: text; near: bottom-left }
  2031  i am bottom right: { shape: text; near: bottom-right }
  2032  `,
  2033  		},
  2034  		{
  2035  			name: "md_mixed",
  2036  			script: `example: {
  2037    explanation: |md
  2038      *one* __two__ three!
  2039    |
  2040  }
  2041  `,
  2042  		},
  2043  		{
  2044  			name: "constant_near_title",
  2045  			script: `title: |md
  2046    # A winning strategy
  2047  | { near: top-center }
  2048  
  2049  poll the people -> results
  2050  results -> unfavorable -> poll the people
  2051  results -> favorable -> will of the people
  2052  `,
  2053  		},
  2054  		{
  2055  			name: "text_font_sizes",
  2056  			script: `bear: { shape: text; style.font-size: 22; style.bold: true }
  2057  mama bear: { shape: text; style.font-size: 28; style.italic: true }
  2058  papa bear: { shape: text; style.font-size: 32; style.underline: true }
  2059  mama bear -> bear
  2060  papa bear -> bear
  2061  `,
  2062  		},
  2063  		{
  2064  			name: "basic-tooltips",
  2065  			script: `x: { tooltip: Total abstinence is easier than perfect moderation }
  2066  y: { tooltip: Gee, I feel kind of LIGHT in the head now,\nknowing I can't make my satellite dish PAYMENTS! }
  2067  x -> y
  2068  `,
  2069  		},
  2070  		{
  2071  			name: "links",
  2072  			script: `x: { link: https://d2lang.com }
  2073  			y: { link: https://terrastruct.com; tooltip: Gee, I feel kind of LIGHT in the head now,\nknowing I can't make my satellite dish PAYMENTS! }
  2074  x -> y
  2075  `,
  2076  		},
  2077  		{
  2078  			name: "unnamed_only_width",
  2079  			script: `
  2080  
  2081  class2 -> users -> code -> package -> no width
  2082  
  2083  class2: "" {
  2084  	shape: class
  2085  	-num: int
  2086  	-timeout: int
  2087  	-pid
  2088  
  2089  	+getStatus(): Enum
  2090  	+getJobs(): "Job[]"
  2091  	+setTimeout(seconds int)
  2092  }
  2093  
  2094  users: "" {
  2095  	shape: sql_table
  2096  	id: int
  2097  	name: string
  2098  	email: string
  2099  	password: string
  2100  	last_login: datetime
  2101  }
  2102  
  2103  code: |go
  2104      a := 5
  2105      b := a + 7
  2106      fmt.Printf("%d", b)
  2107  |
  2108  
  2109  package: "" { shape: package }
  2110  no width: ""
  2111  
  2112  
  2113  class2.width: 512
  2114  users.width: 512
  2115  code.width: 512
  2116  package.width: 512
  2117  `,
  2118  		},
  2119  		{
  2120  			name: "unnamed_only_height",
  2121  			script: `
  2122  
  2123  class2 -> users -> code -> package -> no height
  2124  
  2125  class2: "" {
  2126  	shape: class
  2127  	-num: int
  2128  	-timeout: int
  2129  	-pid
  2130  
  2131  	+getStatus(): Enum
  2132  	+getJobs(): "Job[]"
  2133  	+setTimeout(seconds int)
  2134  }
  2135  
  2136  users: "" {
  2137  	shape: sql_table
  2138  	id: int
  2139  	name: string
  2140  	email: string
  2141  	password: string
  2142  	last_login: datetime
  2143  }
  2144  
  2145  code: |go
  2146      a := 5
  2147      b := a + 7
  2148      fmt.Printf("%d", b)
  2149  |
  2150  
  2151  package: "" { shape: package }
  2152  no height: ""
  2153  
  2154  
  2155  class2.height: 512
  2156  users.height: 512
  2157  code.height: 512
  2158  package.height: 512
  2159  `,
  2160  		},
  2161  		{
  2162  			name: "container_dimensions",
  2163  			script: `a: {
  2164    width: 500
  2165    b -> c
  2166  	b.width: 400
  2167  	c.width: 600
  2168  }
  2169  
  2170  b: {
  2171    width: 700
  2172    b -> c
  2173  	e: {
  2174  		height: 300
  2175  	}
  2176  }
  2177  
  2178  c: {
  2179    width: 200
  2180    height: 300
  2181    a
  2182  }
  2183  `,
  2184  			dagreFeatureError: `Object "a" has attribute "width" and/or "height" set, but layout engine "dagre" does not support dimensions set on containers. See https://d2lang.com/tour/layouts/#layout-specific-functionality for more.`,
  2185  		},
  2186  		{
  2187  			name: "crow_foot_arrowhead",
  2188  			script: `
  2189  a1 <-> b1: {
  2190  	style.stroke-width: 1
  2191  	source-arrowhead: {
  2192  		shape: cf-many
  2193  	}
  2194  	target-arrowhead: {
  2195  		shape: cf-many
  2196  	}
  2197  }
  2198  a2 <-> b2: {
  2199  	style.stroke-width: 3
  2200  	source-arrowhead: {
  2201  		shape: cf-many
  2202  	}
  2203  	target-arrowhead: {
  2204  		shape: cf-many
  2205  	}
  2206  }
  2207  a3 <-> b3: {
  2208  	style.stroke-width: 6
  2209  	source-arrowhead: {
  2210  		shape: cf-many
  2211  	}
  2212  	target-arrowhead: {
  2213  		shape: cf-many
  2214  	}
  2215  }
  2216  
  2217  c1 <-> d1: {
  2218  	style.stroke-width: 1
  2219  	source-arrowhead: {
  2220  		shape: cf-many-required
  2221  	}
  2222  	target-arrowhead: {
  2223  		shape: cf-many-required
  2224  	}
  2225  }
  2226  c2 <-> d2: {
  2227  	style.stroke-width: 3
  2228  	source-arrowhead: {
  2229  		shape: cf-many-required
  2230  	}
  2231  	target-arrowhead: {
  2232  		shape: cf-many-required
  2233  	}
  2234  }
  2235  c3 <-> d3: {
  2236  	style.stroke-width: 6
  2237  	source-arrowhead: {
  2238  		shape: cf-many-required
  2239  	}
  2240  	target-arrowhead: {
  2241  		shape: cf-many-required
  2242  	}
  2243  }
  2244  
  2245  e1 <-> f1: {
  2246  	style.stroke-width: 1
  2247  	source-arrowhead: {
  2248  		shape: cf-one
  2249  	}
  2250  	target-arrowhead: {
  2251  		shape: cf-one
  2252  	}
  2253  }
  2254  e2 <-> f2: {
  2255  	style.stroke-width: 3
  2256  	source-arrowhead: {
  2257  		shape: cf-one
  2258  	}
  2259  	target-arrowhead: {
  2260  		shape: cf-one
  2261  	}
  2262  }
  2263  e3 <-> f3: {
  2264  	style.stroke-width: 6
  2265  	source-arrowhead: {
  2266  		shape: cf-one
  2267  	}
  2268  	target-arrowhead: {
  2269  		shape: cf-one
  2270  	}
  2271  }
  2272  
  2273  g1 <-> h1: {
  2274  	style.stroke-width: 1
  2275  	source-arrowhead: {
  2276  		shape: cf-one-required
  2277  	}
  2278  	target-arrowhead: {
  2279  		shape: cf-one-required
  2280  	}
  2281  }
  2282  g2 <-> h2: {
  2283  	style.stroke-width: 3
  2284  	source-arrowhead: {
  2285  		shape: cf-one-required
  2286  	}
  2287  	target-arrowhead: {
  2288  		shape: cf-one-required
  2289  	}
  2290  }
  2291  g3 <-> h3: {
  2292  	style.stroke-width: 6
  2293  	source-arrowhead: {
  2294  		shape: cf-one-required
  2295  	}
  2296  	target-arrowhead: {
  2297  		shape: cf-one-required
  2298  	}
  2299  }
  2300  
  2301  c <-> d <-> f: {
  2302  	style.stroke-width: 1
  2303  	style.stroke: "orange"
  2304  	source-arrowhead: {
  2305  		shape: cf-many-required
  2306  	}
  2307  	target-arrowhead: {
  2308  		shape: cf-one
  2309  	}
  2310  }
  2311  `,
  2312  		},
  2313  		{
  2314  			name: "circle_arrowhead",
  2315  			script: `
  2316  a <-> b: circle {
  2317    source-arrowhead: {
  2318      shape: circle
  2319    }
  2320    target-arrowhead: {
  2321      shape: circle
  2322    }
  2323  }
  2324  
  2325  c <-> d: filled-circle {
  2326    source-arrowhead: {
  2327      shape: circle
  2328      style.filled: true
  2329    }
  2330    target-arrowhead: {
  2331      shape: circle
  2332      style.filled: true
  2333    }
  2334  }`,
  2335  		},
  2336  		{
  2337  			name: "animated",
  2338  			script: `
  2339  your love life will be -> happy: { style.animated: true }
  2340  your love life will be -> harmonious: { style.animated: true }
  2341  
  2342  boredom <- immortality: { style.animated: true }
  2343  
  2344  Friday <-> Monday: { style.animated: true }
  2345  
  2346  Insomnia -- Sleep: { style.animated: true }
  2347  Insomnia -- Wake: {
  2348  	style: {
  2349  		animated: true
  2350  		stroke-width: 2
  2351  	}
  2352  }
  2353  
  2354  Insomnia -- Dream: {
  2355  	style: {
  2356  		animated: true
  2357  		stroke-width: 8
  2358  	}
  2359  }
  2360  
  2361  Listen <-> Talk: {
  2362  	style.animated: true
  2363  	source-arrowhead.shape: cf-one
  2364  	target-arrowhead.shape: diamond
  2365  	label: hear
  2366  }
  2367  `,
  2368  		},
  2369  		{
  2370  			name: "dagre-container",
  2371  			script: `a: {
  2372    a
  2373    b
  2374    c
  2375  }
  2376  
  2377  b: {
  2378    a
  2379    b
  2380    c
  2381  }
  2382  
  2383  a -> b
  2384  `,
  2385  		},
  2386  		{
  2387  			name: "sql_table_tooltip_animated",
  2388  			script: `
  2389  direction: left
  2390  
  2391  x: {
  2392    shape: sql_table
  2393  	y { constraint: primary_key }
  2394  	tooltip: I like turtles
  2395  }
  2396  
  2397  a: {
  2398    shape: sql_table
  2399  	b { constraint: foreign_key }
  2400  }
  2401  
  2402  a.b <-> x.y: {
  2403    style.animated: true
  2404      source-arrowhead: {
  2405        shape: cf-many
  2406      }
  2407    target-arrowhead: {
  2408        shape: cf-one
  2409    }
  2410  }
  2411  `,
  2412  		},
  2413  		{
  2414  			name: "sql_table_column_styles",
  2415  			script: `Humor in the Court: {
  2416    shape: sql_table
  2417  	Could you see him from where you were standing?: "I could see his head."
  2418  	And where was his head?: Just above his shoulders.
  2419    style.fill: red
  2420    style.stroke: lightgray
  2421    style.font-color: orange
  2422    style.font-size: 20
  2423  }
  2424  
  2425  Humor in the Court2: {
  2426    shape: sql_table
  2427  	Could you see him from where you were standing?: "I could see his head."
  2428  	And where was his head?: Just above his shoulders.
  2429    style.fill: red
  2430    style.stroke: lightgray
  2431    style.font-color: orange
  2432    style.font-size: 30
  2433  }
  2434  
  2435  manager: BatchManager {
  2436    shape: class
  2437  	style.font-size: 20
  2438  
  2439    -num: int
  2440    -timeout: int
  2441    -pid
  2442  
  2443    +getStatus(): Enum
  2444    +getJobs(): "Job[]"
  2445    +setTimeout(seconds int)
  2446  }
  2447  
  2448  manager2: BatchManager {
  2449    shape: class
  2450  	style.font-size: 30
  2451  
  2452    -num: int
  2453    -timeout: int
  2454    -pid
  2455  
  2456    +getStatus(): Enum
  2457    +getJobs(): "Job[]"
  2458    +setTimeout(seconds int)
  2459  }
  2460  `,
  2461  		},
  2462  		{
  2463  			name: "sql_table_constraints_width",
  2464  			script: `
  2465  a: {
  2466  	shape: sql_table
  2467  	x: INT {constraint: unique}
  2468  }
  2469  
  2470  b: {
  2471  	shape: sql_table
  2472  	x: INT {constraint: [primary_key; foreign_key]}
  2473  }
  2474  
  2475  c: {
  2476  	shape: sql_table
  2477  	x: INT {constraint: [foreign_key; unique]}
  2478  }
  2479  
  2480  d: {
  2481  	shape: sql_table
  2482  	x: INT {constraint: [primary_key; foreign_key; unique]}
  2483  }
  2484  e: {
  2485  	shape: sql_table
  2486  	x: INT {constraint: [no_abbrev; foreign_key; hello]}
  2487  	y: string
  2488  	z: STRING {constraint: yo}
  2489  }
  2490  f: {
  2491  	shape: sql_table
  2492  	x: INT
  2493  }
  2494  `,
  2495  		},
  2496  		{
  2497  			name: "near-alone",
  2498  			script: `
  2499  x: {
  2500  	near: top-center
  2501  }
  2502  y: {
  2503  	near: bottom-center
  2504  }
  2505  z: {
  2506  	near: center-left
  2507  }
  2508  `,
  2509  		},
  2510  		{
  2511  			name: "classes",
  2512  			script: `classes: {
  2513    dragon_ball: {
  2514      label: ""
  2515      shape: circle
  2516      style.fill: orange
  2517  		style.stroke-width: 0
  2518  		width: 50
  2519    }
  2520    path: {
  2521      label: "then"
  2522      style.stroke-width: 4
  2523    }
  2524  }
  2525  nostar: { class: dragon_ball }
  2526  1star: { label: "*"; class: dragon_ball }
  2527  2star: { label: "**"; class: dragon_ball }
  2528  
  2529  nostar -> 1star: { class: path }
  2530  1star -> 2star: { class: path }
  2531  `,
  2532  		},
  2533  		{
  2534  			name: "array-classes",
  2535  			script: `classes: {
  2536    button: {
  2537  	  style.border-radius: 999
  2538  		style.stroke: black
  2539  	}
  2540    success: {
  2541  	  style.fill: "#90EE90"
  2542  	}
  2543    error: {
  2544  	  style.fill: "#EA9999"
  2545  	}
  2546  }
  2547  yay: Successful { class: [button; success] }
  2548  nay: Failure { class: [button; error] }
  2549  `,
  2550  		},
  2551  		{
  2552  			name: "border-radius",
  2553  			script: `
  2554  x: {
  2555  	style.border-radius: 4
  2556  }
  2557  y: {
  2558  	style.border-radius: 10
  2559  }
  2560  multiple2: {
  2561  	style.border-radius: 6
  2562  	style.multiple: true
  2563  }
  2564  double: {
  2565  	style.border-radius: 6
  2566  	style.double-border: true
  2567  }
  2568  three-dee: {
  2569  	style.border-radius: 6
  2570  	style.3d: true
  2571  }
  2572  `,
  2573  		},
  2574  		{
  2575  			name: "border-radius-pill-shape",
  2576  			script: `
  2577  x: {
  2578  	style.border-radius: 999
  2579  }
  2580  y: {
  2581  	style.border-radius: 999
  2582  }
  2583  multiple2: {
  2584  	style.border-radius: 999
  2585  	style.multiple: true
  2586  }
  2587  double: {
  2588  	style.border-radius: 999
  2589  	style.double-border: true
  2590  }
  2591  three-dee: {
  2592  	style.border-radius: 999
  2593  	style.3d: true
  2594  }
  2595  `,
  2596  		},
  2597  		{
  2598  			name: "cycle-order",
  2599  			script: `direction: right
  2600  classes: {
  2601    group: {
  2602      style: {
  2603        fill: transparent
  2604        stroke-dash: 5
  2605      }
  2606    }
  2607    icon: {
  2608      shape: image
  2609      height: 70
  2610      width: 70
  2611    }
  2612  }
  2613  
  2614  Plan -> Code -> Build -> Test -> Check -> Release -> Deploy -> Operate -> Monitor -> Plan
  2615  
  2616  Plan: {
  2617    class: group
  2618    ClickUp: {
  2619      class: icon
  2620      icon: https://avatars.githubusercontent.com/u/27873294?s=200&v=4
  2621    }
  2622  }
  2623  Code: {
  2624    class: group
  2625    Git: {
  2626      class: icon
  2627      icon: https://icons.terrastruct.com/dev%2Fgit.svg
  2628    }
  2629  }
  2630  Build: {
  2631    class: group
  2632    Docker: {
  2633      class: icon
  2634      icon: https://icons.terrastruct.com/dev%2Fdocker.svg
  2635    }
  2636  }
  2637  Test: {
  2638    class: group
  2639    Playwright: {
  2640      class: icon
  2641      icon: https://playwright.dev/img/playwright-logo.svg
  2642    }
  2643  }
  2644  Check: {
  2645    class: group
  2646    TruffleHog: {
  2647      class: icon
  2648      icon: https://avatars.githubusercontent.com/u/79229934?s=200&v=4
  2649    }
  2650  }
  2651  Release: {
  2652    class: group
  2653    Github Action: {
  2654      class: icon
  2655      icon: https://icons.terrastruct.com/dev%2Fgithub.svg
  2656    }
  2657  }
  2658  Deploy: {
  2659    class: group
  2660    "AWS Copilot": {
  2661      class: icon
  2662      icon: https://icons.terrastruct.com/aws%2FDeveloper%20Tools%2FAWS-CodeDeploy.svg
  2663    }
  2664  }
  2665  Operate: {
  2666    class: group
  2667    "AWS ECS": {
  2668      class: icon
  2669      icon: https://icons.terrastruct.com/aws%2FCompute%2FAWS-Fargate.svg
  2670    }
  2671  }
  2672  Monitor: {
  2673    class: group
  2674    Grafana: {
  2675      class: icon
  2676      icon: https://avatars.githubusercontent.com/u/7195757?s=200&v=4
  2677    }
  2678  }
  2679  `,
  2680  		},
  2681  		{
  2682  			name: "sequence-inter-span-self",
  2683  			script: `
  2684  shape: sequence_diagram
  2685  a: A
  2686  b: B
  2687  
  2688  a.sp1 -> b: foo
  2689  a.sp1 -> a.sp2: redirect
  2690  a.sp2 -> b: bar
  2691  `,
  2692  		},
  2693  		{
  2694  			name: "people",
  2695  			script: `
  2696  a.shape: person
  2697  b.shape: person
  2698  c.shape: person
  2699  d.shape: person
  2700  e.shape: person
  2701  f.shape: person
  2702  g.shape: person
  2703  
  2704  a: -
  2705  b: --
  2706  c: ----
  2707  d: --------
  2708  e: ----------------
  2709  f: --------------------------------
  2710  g: ----------------------------------------------------------------
  2711  
  2712  1.shape: person
  2713  2.shape: person
  2714  3.shape: person
  2715  4.shape: person
  2716  5.shape: person
  2717  
  2718  1.width: 16
  2719  2.width: 64
  2720  3.width: 128
  2721  4.width: 512
  2722  
  2723  # entering both width and height overrides aspect ratio limit
  2724  5.height: 256
  2725  5.width: 32
  2726  `,
  2727  		},
  2728  		{
  2729  			name: "ovals",
  2730  			script: `
  2731  a.shape: oval
  2732  b.shape: oval
  2733  c.shape: oval
  2734  d.shape: oval
  2735  e.shape: oval
  2736  f.shape: oval
  2737  g.shape: oval
  2738  
  2739  a: -
  2740  b: --
  2741  c: ----
  2742  d: --------
  2743  e: ----------------
  2744  f: --------------------------------
  2745  g: ----------------------------------------------------------------
  2746  
  2747  1.shape: oval
  2748  2.shape: oval
  2749  3.shape: oval
  2750  4.shape: oval
  2751  5.shape: oval
  2752  
  2753  1.width: 16
  2754  2.width: 64
  2755  3.width: 128
  2756  4.width: 512
  2757  
  2758  # entering both width and height overrides aspect ratio limit
  2759  5.height: 256
  2760  5.width: 32
  2761  `,
  2762  		},
  2763  		{
  2764  			name: "complex-layers",
  2765  			script: `
  2766  desc: Multi-layer diagram of a home.
  2767  
  2768  window: {
  2769    style.double-border: true
  2770  }
  2771  roof
  2772  garage
  2773  
  2774  layers: {
  2775    window: {
  2776      blinds
  2777      glass
  2778    }
  2779    roof: {
  2780      shingles
  2781      starlink
  2782      utility hookup
  2783    }
  2784    garage: {
  2785      tools
  2786      vehicles
  2787    }
  2788    repair: {
  2789      desc: How to repair a home.
  2790  
  2791      steps: {
  2792        1: {
  2793          find contractors: {
  2794            craigslist
  2795            facebook
  2796          }
  2797        }
  2798        2: {
  2799          find contractors -> solicit quotes
  2800        }
  2801        3: {
  2802          obtain quotes -> negotiate
  2803        }
  2804        4: {
  2805          negotiate -> book the best bid
  2806        }
  2807      }
  2808    }
  2809  }
  2810  
  2811  scenarios: {
  2812    storm: {
  2813      water
  2814      rain
  2815      thunder
  2816    }
  2817  }`,
  2818  		},
  2819  		{
  2820  			name: "label-near",
  2821  			script: `
  2822  direction: right
  2823  x -> y
  2824  
  2825  x: worker {
  2826    label.near: top-center
  2827    icon: https://icons.terrastruct.com/essentials%2F005-programmer.svg
  2828    icon.near: outside-top-right
  2829  }
  2830  
  2831  y: profits {
  2832    label.near: bottom-right
  2833    icon: https://icons.terrastruct.com/essentials%2Fprofits.svg
  2834    icon.near: outside-bottom-center
  2835  }
  2836  `,
  2837  		},
  2838  		loadFromFile(t, "arrowhead_scaling"),
  2839  		loadFromFile(t, "teleport_grid"),
  2840  		loadFromFile(t, "dagger_grid"),
  2841  		loadFromFile(t, "grid_tests"),
  2842  		loadFromFile(t, "executive_grid"),
  2843  		loadFromFile(t, "grid_animated"),
  2844  		loadFromFile(t, "grid_gap"),
  2845  		loadFromFile(t, "grid_even"),
  2846  		loadFromFile(t, "ent2d2_basic"),
  2847  		loadFromFile(t, "ent2d2_right"),
  2848  		loadFromFile(t, "grid_large_checkered"),
  2849  		loadFromFile(t, "grid_nested"),
  2850  		loadFromFile(t, "grid_nested_gap0"),
  2851  		loadFromFile(t, "grid_icon"),
  2852  		loadFromFile(t, "multiple_offset"),
  2853  		loadFromFile(t, "multiple_offset_left"),
  2854  		loadFromFile(t, "multiple_box_selection"),
  2855  		loadFromFile(t, "multiple_person_label"),
  2856  		loadFromFile(t, "outside_bottom_labels"),
  2857  		loadFromFile(t, "label_positions"),
  2858  		loadFromFile(t, "icon_positions"),
  2859  		loadFromFile(t, "centered_horizontal_connections"),
  2860  		loadFromFile(t, "all_shapes_link"),
  2861  		loadFromFile(t, "nested_shape_labels"),
  2862  		loadFromFile(t, "overlapping_child_label"),
  2863  		loadFromFile(t, "dagre_spacing"),
  2864  		loadFromFile(t, "dagre_spacing_right"),
  2865  		loadFromFile(t, "simple_grid_edges"),
  2866  		loadFromFile(t, "grid_nested_simple_edges"),
  2867  		loadFromFile(t, "nested_diagram_types"),
  2868  		loadFromFile(t, "grid_outside_labels"),
  2869  		loadFromFile(t, "grid_edge_across_cell"),
  2870  		loadFromFile(t, "nesting_power"),
  2871  		loadFromFile(t, "unfilled_triangle"),
  2872  		loadFromFile(t, "grid_container_dimensions"),
  2873  		loadFromFile(t, "grid_label_positions"),
  2874  	}
  2875  
  2876  	runa(t, tcs)
  2877  }
  2878  

View as plain text