setup imports with tests
This commit is contained in:
parent
5436cb6b5f
commit
bae5705674
5 changed files with 374 additions and 29 deletions
|
|
@ -51,6 +51,7 @@ func Compile(p string, r io.Reader, opts *CompileOptions) (*d2graph.Graph, *d2ta
|
|||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
g.FS = opts.FS
|
||||
g.SortObjectsByAST()
|
||||
g.SortEdgesByAST()
|
||||
return g, compileConfig(ir), nil
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"math"
|
||||
"net/url"
|
||||
"sort"
|
||||
|
|
@ -36,6 +37,7 @@ const DEFAULT_SHAPE_SIZE = 100.
|
|||
const MIN_SHAPE_SIZE = 5
|
||||
|
||||
type Graph struct {
|
||||
FS fs.FS `json:"-"`
|
||||
Parent *Graph `json:"-"`
|
||||
Name string `json:"name"`
|
||||
// IsFolderOnly indicates a board or scenario itself makes no modifications from its
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ func Create(g *d2graph.Graph, boardPath []string, key string) (_ *d2graph.Graph,
|
|||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
g, err = recompile(g.AST)
|
||||
g, err = recompile(g)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
|
@ -112,7 +112,7 @@ func Set(g *d2graph.Graph, boardPath []string, key string, tag, value *string) (
|
|||
}
|
||||
}
|
||||
|
||||
return recompile(g.AST)
|
||||
return recompile(g)
|
||||
}
|
||||
|
||||
func ReconnectEdge(g *d2graph.Graph, boardPath []string, edgeKey string, srcKey, dstKey *string) (_ *d2graph.Graph, err error) {
|
||||
|
|
@ -271,7 +271,7 @@ func ReconnectEdge(g *d2graph.Graph, boardPath []string, edgeKey string, srcKey,
|
|||
}
|
||||
}
|
||||
|
||||
return recompile(g.AST)
|
||||
return recompile(g)
|
||||
}
|
||||
|
||||
func pathFromScopeKey(g *d2graph.Graph, key *d2ast.Key, scopeak []string) ([]*d2ast.StringBox, error) {
|
||||
|
|
@ -303,13 +303,15 @@ func pathFromScopeObj(g *d2graph.Graph, key *d2ast.Key, fromScope *d2graph.Objec
|
|||
return pathFromScopeKey(g, key, scopeak)
|
||||
}
|
||||
|
||||
func recompile(ast *d2ast.Map) (*d2graph.Graph, error) {
|
||||
s := d2format.Format(ast)
|
||||
g, _, err := d2compiler.Compile(ast.Range.Path, strings.NewReader(s), nil)
|
||||
func recompile(g *d2graph.Graph) (*d2graph.Graph, error) {
|
||||
s := d2format.Format(g.AST)
|
||||
g2, _, err := d2compiler.Compile(g.AST.Range.Path, strings.NewReader(s), &d2compiler.CompileOptions{
|
||||
FS: g.FS,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to recompile:\n%s\n%w", s, err)
|
||||
}
|
||||
return g, nil
|
||||
return g2, nil
|
||||
}
|
||||
|
||||
// TODO merge flat styles
|
||||
|
|
@ -451,7 +453,9 @@ func _set(g *d2graph.Graph, baseAST *d2ast.Map, key string, tag, value *string)
|
|||
return nil
|
||||
}
|
||||
}
|
||||
ir, err := d2ir.Compile(g.AST, nil)
|
||||
ir, err := d2ir.Compile(g.AST, &d2ir.CompileOptions{
|
||||
FS: g.FS,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -897,12 +901,12 @@ func Delete(g *d2graph.Graph, boardPath []string, key string) (_ *d2graph.Graph,
|
|||
if !replaced {
|
||||
return nil, fmt.Errorf("board %v AST not found", boardPath)
|
||||
}
|
||||
return recompile(g.AST)
|
||||
return recompile(g)
|
||||
}
|
||||
return recompile(boardG.AST)
|
||||
return recompile(boardG)
|
||||
}
|
||||
|
||||
prevG, _ := recompile(boardG.AST)
|
||||
prevG, _ := recompile(boardG)
|
||||
|
||||
boardG, err = renameConflictsToParent(boardG, mk.Key)
|
||||
if err != nil {
|
||||
|
|
@ -939,10 +943,10 @@ func Delete(g *d2graph.Graph, boardPath []string, key string) (_ *d2graph.Graph,
|
|||
if !replaced {
|
||||
return nil, fmt.Errorf("board %v AST not found", boardPath)
|
||||
}
|
||||
return recompile(g.AST)
|
||||
return recompile(g)
|
||||
}
|
||||
|
||||
return recompile(boardG.AST)
|
||||
return recompile(boardG)
|
||||
}
|
||||
|
||||
func bumpChildrenUnderscores(m *d2ast.Map) {
|
||||
|
|
@ -1182,7 +1186,7 @@ func deleteReserved(g *d2graph.Graph, mk *d2ast.Key) (*d2graph.Graph, error) {
|
|||
if err := deleteEdgeField(g, e, targetKey.Path[len(targetKey.Path)-1].Unbox().ScalarString()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return recompile(g.AST)
|
||||
return recompile(g)
|
||||
}
|
||||
|
||||
isStyleKey := false
|
||||
|
|
@ -1221,7 +1225,7 @@ func deleteReserved(g *d2graph.Graph, mk *d2ast.Key) (*d2graph.Graph, error) {
|
|||
}
|
||||
}
|
||||
|
||||
return recompile(g.AST)
|
||||
return recompile(g)
|
||||
}
|
||||
|
||||
func deleteMapField(m *d2ast.Map, field string) {
|
||||
|
|
@ -1285,7 +1289,7 @@ func deleteObjField(g *d2graph.Graph, obj *d2graph.Object, field string) error {
|
|||
copy(tmpNodes, ref.Scope.Nodes)
|
||||
// If I delete this, will the object still exist?
|
||||
deleteFromMap(ref.Scope, ref.MapKey)
|
||||
g2, err := recompile(g.AST)
|
||||
g2, err := recompile(g)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -1605,10 +1609,10 @@ func move(g *d2graph.Graph, boardPath []string, key, newKey string, includeDesce
|
|||
ref.MapKey.Edges[ref.MapKeyEdgeIndex].SrcArrow = mk2.Edges[0].SrcArrow
|
||||
ref.MapKey.Edges[ref.MapKeyEdgeIndex].DstArrow = mk2.Edges[0].DstArrow
|
||||
}
|
||||
return recompile(g.AST)
|
||||
return recompile(g)
|
||||
}
|
||||
|
||||
prevG, _ := recompile(boardG.AST)
|
||||
prevG, _ := recompile(boardG)
|
||||
|
||||
ak := d2graph.Key(mk.Key)
|
||||
ak2 := d2graph.Key(mk2.Key)
|
||||
|
|
@ -2026,10 +2030,10 @@ func move(g *d2graph.Graph, boardPath []string, key, newKey string, includeDesce
|
|||
if !replaced {
|
||||
return nil, fmt.Errorf("board %v AST not found", boardPath)
|
||||
}
|
||||
return recompile(g.AST)
|
||||
return recompile(g)
|
||||
}
|
||||
|
||||
return recompile(boardG.AST)
|
||||
return recompile(boardG)
|
||||
}
|
||||
|
||||
// filterReserved takes a Value and splits it into 2
|
||||
|
|
@ -2141,7 +2145,7 @@ func updateNear(prevG, g *d2graph.Graph, from, to *string, includeDescendants bo
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tmpG, _ := recompile(prevG.AST)
|
||||
tmpG, _ := recompile(prevG)
|
||||
appendMapKey(tmpG.AST, valueMK)
|
||||
if to == nil {
|
||||
deltas, err := DeleteIDDeltas(tmpG, nil, *from)
|
||||
|
|
@ -2186,7 +2190,7 @@ func updateNear(prevG, g *d2graph.Graph, from, to *string, includeDescendants bo
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tmpG, _ := recompile(prevG.AST)
|
||||
tmpG, _ := recompile(prevG)
|
||||
appendMapKey(tmpG.AST, valueMK)
|
||||
if to == nil {
|
||||
deltas, err := DeleteIDDeltas(tmpG, nil, *from)
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@ package d2oracle_test
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
|
@ -732,6 +735,7 @@ func TestSet(t *testing.T) {
|
|||
boardPath []string
|
||||
name string
|
||||
text string
|
||||
fsTexts map[string]string
|
||||
key string
|
||||
tag *string
|
||||
value *string
|
||||
|
|
@ -1984,6 +1988,29 @@ scenarios: {
|
|||
c -> d
|
||||
}
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "import/1",
|
||||
|
||||
text: `x: {
|
||||
...@meow.x
|
||||
y
|
||||
}
|
||||
`,
|
||||
fsTexts: map[string]string{
|
||||
"meow": `x: {
|
||||
style.fill: blue
|
||||
}
|
||||
`,
|
||||
},
|
||||
key: `x.style.stroke`,
|
||||
value: go2.Pointer(`red`),
|
||||
exp: `x: {
|
||||
...@meow.x
|
||||
y
|
||||
style.stroke: red
|
||||
}
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
|
@ -1994,7 +2021,8 @@ scenarios: {
|
|||
t.Parallel()
|
||||
|
||||
et := editTest{
|
||||
text: tc.text,
|
||||
text: tc.text,
|
||||
fsTexts: tc.fsTexts,
|
||||
testFunc: func(g *d2graph.Graph) (*d2graph.Graph, error) {
|
||||
return d2oracle.Set(g, tc.boardPath, tc.key, tc.tag, tc.value)
|
||||
},
|
||||
|
|
@ -2412,6 +2440,7 @@ func TestRename(t *testing.T) {
|
|||
boardPath []string
|
||||
|
||||
text string
|
||||
fsTexts map[string]string
|
||||
key string
|
||||
newName string
|
||||
|
||||
|
|
@ -2922,7 +2951,8 @@ scenarios: {
|
|||
t.Parallel()
|
||||
|
||||
et := editTest{
|
||||
text: tc.text,
|
||||
text: tc.text,
|
||||
fsTexts: tc.fsTexts,
|
||||
testFunc: func(g *d2graph.Graph) (*d2graph.Graph, error) {
|
||||
objectsBefore := len(g.Objects)
|
||||
var err error
|
||||
|
|
@ -2956,6 +2986,7 @@ func TestMove(t *testing.T) {
|
|||
boardPath []string
|
||||
|
||||
text string
|
||||
fsTexts map[string]string
|
||||
key string
|
||||
newKey string
|
||||
includeDescendants bool
|
||||
|
|
@ -5190,7 +5221,8 @@ scenarios: {
|
|||
t.Parallel()
|
||||
|
||||
et := editTest{
|
||||
text: tc.text,
|
||||
text: tc.text,
|
||||
fsTexts: tc.fsTexts,
|
||||
testFunc: func(g *d2graph.Graph) (*d2graph.Graph, error) {
|
||||
objectsBefore := len(g.Objects)
|
||||
var err error
|
||||
|
|
@ -5221,8 +5253,9 @@ func TestDelete(t *testing.T) {
|
|||
name string
|
||||
boardPath []string
|
||||
|
||||
text string
|
||||
key string
|
||||
text string
|
||||
fsTexts map[string]string
|
||||
key string
|
||||
|
||||
expErr string
|
||||
exp string
|
||||
|
|
@ -6977,7 +7010,8 @@ scenarios: {
|
|||
t.Parallel()
|
||||
|
||||
et := editTest{
|
||||
text: tc.text,
|
||||
text: tc.text,
|
||||
fsTexts: tc.fsTexts,
|
||||
testFunc: func(g *d2graph.Graph) (*d2graph.Graph, error) {
|
||||
return d2oracle.Delete(g, tc.boardPath, tc.key)
|
||||
},
|
||||
|
|
@ -6993,6 +7027,7 @@ scenarios: {
|
|||
|
||||
type editTest struct {
|
||||
text string
|
||||
fsTexts map[string]string
|
||||
testFunc func(*d2graph.Graph) (*d2graph.Graph, error)
|
||||
|
||||
exp string
|
||||
|
|
@ -7002,7 +7037,13 @@ type editTest struct {
|
|||
|
||||
func (tc editTest) run(t *testing.T) {
|
||||
d2Path := fmt.Sprintf("d2/testdata/d2oracle/%v.d2", t.Name())
|
||||
g, _, err := d2compiler.Compile(d2Path, strings.NewReader(tc.text), nil)
|
||||
tfs := testFS(make(map[string]*testF))
|
||||
for name, text := range tc.fsTexts {
|
||||
tfs[name] = &testF{content: text}
|
||||
}
|
||||
g, _, err := d2compiler.Compile(d2Path, strings.NewReader(tc.text), &d2compiler.CompileOptions{
|
||||
FS: tfs,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
@ -8360,3 +8401,38 @@ scenarios: {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
type testF struct {
|
||||
content string
|
||||
readIndex int
|
||||
}
|
||||
|
||||
func (tf *testF) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (tf *testF) Read(p []byte) (int, error) {
|
||||
data := []byte(tf.content)
|
||||
if tf.readIndex >= len(data) {
|
||||
tf.readIndex = 0
|
||||
return 0, io.EOF
|
||||
}
|
||||
readBytes := copy(p, data[tf.readIndex:])
|
||||
tf.readIndex += readBytes
|
||||
return readBytes, nil
|
||||
}
|
||||
|
||||
func (tf *testF) Stat() (os.FileInfo, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
type testFS map[string]*testF
|
||||
|
||||
func (tfs testFS) Open(name string) (fs.File, error) {
|
||||
for k := range tfs {
|
||||
if strings.HasSuffix(name[:len(name)-3], k) {
|
||||
return tfs[k], nil
|
||||
}
|
||||
}
|
||||
return nil, fs.ErrNotExist
|
||||
}
|
||||
|
|
|
|||
262
testdata/d2oracle/TestSet/import/1.exp.json
generated
vendored
Normal file
262
testdata/d2oracle/TestSet/import/1.exp.json
generated
vendored
Normal file
|
|
@ -0,0 +1,262 @@
|
|||
{
|
||||
"graph": {
|
||||
"name": "",
|
||||
"isFolderOnly": false,
|
||||
"ast": {
|
||||
"range": "d2/testdata/d2oracle/TestSet/import/1.d2,0:0:0-5:0:44",
|
||||
"nodes": [
|
||||
{
|
||||
"map_key": {
|
||||
"range": "d2/testdata/d2oracle/TestSet/import/1.d2,0:0:0-4:1:43",
|
||||
"key": {
|
||||
"range": "d2/testdata/d2oracle/TestSet/import/1.d2,0:0:0-0:1:1",
|
||||
"path": [
|
||||
{
|
||||
"unquoted_string": {
|
||||
"range": "d2/testdata/d2oracle/TestSet/import/1.d2,0:0:0-0:1:1",
|
||||
"value": [
|
||||
{
|
||||
"string": "x",
|
||||
"raw_string": "x"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"primary": {},
|
||||
"value": {
|
||||
"map": {
|
||||
"range": "d2/testdata/d2oracle/TestSet/import/1.d2,0:3:3-4:1:43",
|
||||
"nodes": [
|
||||
{
|
||||
"import": {
|
||||
"range": "d2/testdata/d2oracle/TestSet/import/1.d2,1:2:7-1:12:17",
|
||||
"spread": true,
|
||||
"pre": "",
|
||||
"path": [
|
||||
{
|
||||
"unquoted_string": {
|
||||
"range": "d2/testdata/d2oracle/TestSet/import/1.d2,1:6:11-1:10:15",
|
||||
"value": [
|
||||
{
|
||||
"string": "meow",
|
||||
"raw_string": "meow"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"unquoted_string": {
|
||||
"range": "d2/testdata/d2oracle/TestSet/import/1.d2,1:11:16-1:12:17",
|
||||
"value": [
|
||||
{
|
||||
"string": "x",
|
||||
"raw_string": "x"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"map_key": {
|
||||
"range": "d2/testdata/d2oracle/TestSet/import/1.d2,2:2:20-2:3:21",
|
||||
"key": {
|
||||
"range": "d2/testdata/d2oracle/TestSet/import/1.d2,2:2:20-2:3:21",
|
||||
"path": [
|
||||
{
|
||||
"unquoted_string": {
|
||||
"range": "d2/testdata/d2oracle/TestSet/import/1.d2,2:2:20-2:3:21",
|
||||
"value": [
|
||||
{
|
||||
"string": "y",
|
||||
"raw_string": "y"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"primary": {},
|
||||
"value": {}
|
||||
}
|
||||
},
|
||||
{
|
||||
"map_key": {
|
||||
"range": "d2/testdata/d2oracle/TestSet/import/1.d2,3:2:24-3:19:41",
|
||||
"key": {
|
||||
"range": "d2/testdata/d2oracle/TestSet/import/1.d2,3:2:24-3:14:36",
|
||||
"path": [
|
||||
{
|
||||
"unquoted_string": {
|
||||
"range": "d2/testdata/d2oracle/TestSet/import/1.d2,3:2:24-3:7:29",
|
||||
"value": [
|
||||
{
|
||||
"string": "style",
|
||||
"raw_string": "style"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"unquoted_string": {
|
||||
"range": "d2/testdata/d2oracle/TestSet/import/1.d2,3:8:30-3:14:36",
|
||||
"value": [
|
||||
{
|
||||
"string": "stroke",
|
||||
"raw_string": "stroke"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"primary": {},
|
||||
"value": {
|
||||
"unquoted_string": {
|
||||
"range": "d2/testdata/d2oracle/TestSet/import/1.d2,3:16:38-3:19:41",
|
||||
"value": [
|
||||
{
|
||||
"string": "red",
|
||||
"raw_string": "red"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"root": {
|
||||
"id": "",
|
||||
"id_val": "",
|
||||
"attributes": {
|
||||
"label": {
|
||||
"value": ""
|
||||
},
|
||||
"labelDimensions": {
|
||||
"width": 0,
|
||||
"height": 0
|
||||
},
|
||||
"style": {},
|
||||
"near_key": null,
|
||||
"shape": {
|
||||
"value": ""
|
||||
},
|
||||
"direction": {
|
||||
"value": ""
|
||||
},
|
||||
"constraint": null
|
||||
},
|
||||
"zIndex": 0
|
||||
},
|
||||
"edges": null,
|
||||
"objects": [
|
||||
{
|
||||
"id": "x",
|
||||
"id_val": "x",
|
||||
"references": [
|
||||
{
|
||||
"key": {
|
||||
"range": "d2/testdata/d2oracle/TestSet/import/1.d2,0:0:0-0:1:1",
|
||||
"path": [
|
||||
{
|
||||
"unquoted_string": {
|
||||
"range": "d2/testdata/d2oracle/TestSet/import/1.d2,0:0:0-0:1:1",
|
||||
"value": [
|
||||
{
|
||||
"string": "x",
|
||||
"raw_string": "x"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"key_path_index": 0,
|
||||
"map_key_edge_index": -1
|
||||
}
|
||||
],
|
||||
"attributes": {
|
||||
"label": {
|
||||
"value": "x"
|
||||
},
|
||||
"labelDimensions": {
|
||||
"width": 0,
|
||||
"height": 0
|
||||
},
|
||||
"style": {
|
||||
"stroke": {
|
||||
"value": "red"
|
||||
},
|
||||
"fill": {
|
||||
"value": "blue"
|
||||
}
|
||||
},
|
||||
"near_key": null,
|
||||
"shape": {
|
||||
"value": "rectangle"
|
||||
},
|
||||
"direction": {
|
||||
"value": ""
|
||||
},
|
||||
"constraint": null
|
||||
},
|
||||
"zIndex": 0
|
||||
},
|
||||
{
|
||||
"id": "y",
|
||||
"id_val": "y",
|
||||
"references": [
|
||||
{
|
||||
"key": {
|
||||
"range": "d2/testdata/d2oracle/TestSet/import/1.d2,2:2:20-2:3:21",
|
||||
"path": [
|
||||
{
|
||||
"unquoted_string": {
|
||||
"range": "d2/testdata/d2oracle/TestSet/import/1.d2,2:2:20-2:3:21",
|
||||
"value": [
|
||||
{
|
||||
"string": "y",
|
||||
"raw_string": "y"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"key_path_index": 0,
|
||||
"map_key_edge_index": -1
|
||||
}
|
||||
],
|
||||
"attributes": {
|
||||
"label": {
|
||||
"value": "y"
|
||||
},
|
||||
"labelDimensions": {
|
||||
"width": 0,
|
||||
"height": 0
|
||||
},
|
||||
"style": {},
|
||||
"near_key": null,
|
||||
"shape": {
|
||||
"value": "rectangle"
|
||||
},
|
||||
"direction": {
|
||||
"value": ""
|
||||
},
|
||||
"constraint": null
|
||||
},
|
||||
"zIndex": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
"err": "<nil>"
|
||||
}
|
||||
Loading…
Reference in a new issue