feat(goctl): supports api multi-level importing (#1747)
* feat(goctl): supports api multi-level importing Resolves: #1744 * fix(goctl): import-cycle, etc. import-cycle will not be allowed e.g., a.api -> b.api -> a.api regular multiple-import will be allowed e.g., a.api -> b.api -> c.api -> c.api * refactor(goctl): adds comments to exported var * fix(goctl): typo in a commentmaster
parent
252fabcc4b
commit
6d9dfc08f9
@ -0,0 +1,99 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/zeromicro/go-zero/tools/goctl/util/pathx"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_ImportCycle(t *testing.T) {
|
||||||
|
const (
|
||||||
|
mainFilename = "main.api"
|
||||||
|
subAFilename = "a.api"
|
||||||
|
subBFilename = "b.api"
|
||||||
|
mainSrc = `import "./a.api"`
|
||||||
|
subASrc = `import "./b.api"`
|
||||||
|
subBSrc = `import "./a.api"`
|
||||||
|
)
|
||||||
|
var err error
|
||||||
|
dir := pathx.MustTempDir()
|
||||||
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
|
mainPath := filepath.Join(dir, mainFilename)
|
||||||
|
err = ioutil.WriteFile(mainPath, []byte(mainSrc), 0777)
|
||||||
|
require.NoError(t, err)
|
||||||
|
subAPath := filepath.Join(dir, subAFilename)
|
||||||
|
err = ioutil.WriteFile(subAPath, []byte(subASrc), 0777)
|
||||||
|
require.NoError(t, err)
|
||||||
|
subBPath := filepath.Join(dir, subBFilename)
|
||||||
|
err = ioutil.WriteFile(subBPath, []byte(subBSrc), 0777)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = NewParser().Parse(mainPath)
|
||||||
|
assert.ErrorIs(t, err, ErrImportCycleNotAllowed)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_MultiImportedShouldAllowed(t *testing.T) {
|
||||||
|
const (
|
||||||
|
mainFilename = "main.api"
|
||||||
|
subAFilename = "a.api"
|
||||||
|
subBFilename = "b.api"
|
||||||
|
mainSrc = "import \"./b.api\"\n" +
|
||||||
|
"import \"./a.api\"\n" +
|
||||||
|
"type Main { b B `json:\"b\"`}"
|
||||||
|
subASrc = "import \"./b.api\"\n" +
|
||||||
|
"type A { b B `json:\"b\"`}\n"
|
||||||
|
subBSrc = `type B{}`
|
||||||
|
)
|
||||||
|
var err error
|
||||||
|
dir := pathx.MustTempDir()
|
||||||
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
|
mainPath := filepath.Join(dir, mainFilename)
|
||||||
|
err = ioutil.WriteFile(mainPath, []byte(mainSrc), 0777)
|
||||||
|
require.NoError(t, err)
|
||||||
|
subAPath := filepath.Join(dir, subAFilename)
|
||||||
|
err = ioutil.WriteFile(subAPath, []byte(subASrc), 0777)
|
||||||
|
require.NoError(t, err)
|
||||||
|
subBPath := filepath.Join(dir, subBFilename)
|
||||||
|
err = ioutil.WriteFile(subBPath, []byte(subBSrc), 0777)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = NewParser().Parse(mainPath)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_RedundantDeclarationShouldNotBeAllowed(t *testing.T) {
|
||||||
|
const (
|
||||||
|
mainFilename = "main.api"
|
||||||
|
subAFilename = "a.api"
|
||||||
|
subBFilename = "b.api"
|
||||||
|
mainSrc = "import \"./a.api\"\n" +
|
||||||
|
"import \"./b.api\"\n"
|
||||||
|
subASrc = `import "./b.api"
|
||||||
|
type A{}`
|
||||||
|
subBSrc = `type A{}`
|
||||||
|
)
|
||||||
|
var err error
|
||||||
|
dir := pathx.MustTempDir()
|
||||||
|
defer os.RemoveAll(dir)
|
||||||
|
|
||||||
|
mainPath := filepath.Join(dir, mainFilename)
|
||||||
|
err = ioutil.WriteFile(mainPath, []byte(mainSrc), 0777)
|
||||||
|
require.NoError(t, err)
|
||||||
|
subAPath := filepath.Join(dir, subAFilename)
|
||||||
|
err = ioutil.WriteFile(subAPath, []byte(subASrc), 0777)
|
||||||
|
require.NoError(t, err)
|
||||||
|
subBPath := filepath.Join(dir, subBFilename)
|
||||||
|
err = ioutil.WriteFile(subBPath, []byte(subBSrc), 0777)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
_, err = NewParser().Parse(mainPath)
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.Contains(t, err.Error(), "duplicate type declaration")
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package ast
|
||||||
|
|
||||||
|
import "errors"
|
||||||
|
|
||||||
|
// ErrImportCycleNotAllowed defines an error for circular importing
|
||||||
|
var ErrImportCycleNotAllowed = errors.New("import cycle not allowed")
|
||||||
|
|
||||||
|
// importStack a stack of import paths
|
||||||
|
type importStack []string
|
||||||
|
|
||||||
|
func (s *importStack) push(p string) error {
|
||||||
|
for _, x := range *s {
|
||||||
|
if x == p {
|
||||||
|
return ErrImportCycleNotAllowed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*s = append(*s, p)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *importStack) pop() {
|
||||||
|
*s = (*s)[0 : len(*s)-1]
|
||||||
|
}
|
Loading…
Reference in New Issue