setup imports with tests

This commit is contained in:
Alexander Wang 2023-08-04 20:16:25 -07:00
parent 5436cb6b5f
commit bae5705674
No known key found for this signature in database
GPG key ID: D89FA31966BDBECE
5 changed files with 374 additions and 29 deletions

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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
View 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>"
}