func TestParse1(t *testing.T) { cb := tests.New().TempGopath(true) defer cb.Cleanup() path, dir := cb.TempPackage("a", map[string]string{ "a.json": `{ "description": "a", "type": "system:type", "id": "b", "fields": { "c": { "type": "system:@string" } } }`, }) cb.Path(path).Dir(dir).Cmd().Sempty().Jsystem() _, err := Parse(cb.Ctx(), path) require.NoError(t, err) scache := sysctx.FromContext(cb.Ctx()) i, ok := scache.GetType(path, "b") assert.True(t, ok) ty, ok := i.(*system.Type) assert.True(t, ok) assert.Equal(t, "a", ty.Description) }
func GetAllTypesThatImplementReflectInterface(ctx context.Context, reflectType reflect.Type) []*Type { if reflectType.Kind() != reflect.Interface { panic(kerr.New("JUCCMVNDLR", "%v is not an interface", reflectType).Error()) } scache := sysctx.FromContext(ctx) out := []*Type{} for _, pkgName := range scache.Keys() { pkgInfo, ok := scache.Get(pkgName) if !ok { // ke: {"block": {"notest": true}} continue } for _, typName := range pkgInfo.Types.Keys() { typ, ok := pkgInfo.Types.Get(typName) if !ok { // ke: {"block": {"notest": true}} continue } t := typ.Type.(*Type) if t.Interface { continue } if t.Implements(ctx, reflectType) { out = append(out, t) } } } return out }
func comparePackageHash(ctx context.Context, path string) (changes bool, err error) { scache := sysctx.FromContext(ctx) spi, ok := scache.Get(path) if !ok { return false, kerr.New("NHXWLPHCHL", "%s not found in sys ctx", path) } for _, aliasPath := range spi.Aliases { changes, err := comparePackageHash(ctx, aliasPath) if err != nil { return false, kerr.Wrap("DGJTLHQOCQ", err) } if changes { return true, nil } } jcache := jsonctx.FromContext(ctx) jpi, ok := jcache.Packages.Get(path) if !ok { return true, nil } // pcache.Environment.Hash is computed after parsing all the data files. // h.Hash is in generated.go (jsonctx.InitPackage), and correct when the types were generated. if jpi.Hash != spi.Hash { return true, nil } return false, nil }
func addNewFile(ctx context.Context, app *stores.App, all bool) { var types []*system.Type if all { rt := reflect.TypeOf((*system.ObjectInterface)(nil)).Elem() typesAll := system.GetAllTypesThatImplementReflectInterface(ctx, rt) // TODO: Work out a more elegant way of doing this! rule := reflect.TypeOf((*system.RuleInterface)(nil)).Elem() for _, t := range typesAll { if t.Id.Package == "kego.io/system" { // none of the system types should be added as a global continue } if t.Implements(ctx, rule) { // rules should never be added as a global continue } types = append(types, t) } } else { syscache := sysctx.FromContext(ctx) t, ok := syscache.GetType("kego.io/system", "type") if !ok { panic(kerr.New("NNFSJEXNKF", "Can't find system:type in sys ctx").Error()) } types = []*system.Type{t.(*system.Type)} } app.Dispatch(&actions.OpenAddPopup{ Types: types, }) }
func TestComparePackageHash(t *testing.T) { cb := tests.New().TempGopath(true) path, _ := cb.TempPackage("a", map[string]string{ "a.yaml": "type: system:package", }) cb.Path(path).Jempty().Spkg(path) // "a.b/c" not found in scache. changes, err := comparePackageHash(cb.Ctx(), "a.b/c") assert.IsError(t, err, "NHXWLPHCHL") assert.False(t, changes) // path not found in jcache changes, err = comparePackageHash(cb.Ctx(), path) require.NoError(t, err) assert.True(t, changes) cb.Jsystem().Jpkg(path, 999).Sauto(parser.Parse) // hash changed changes, err = comparePackageHash(cb.Ctx(), path) require.NoError(t, err) assert.True(t, changes) scache := sysctx.FromContext(cb.Ctx()) pi, _ := scache.Get(path) cb.Jpkg(path, pi.Hash) // hash correct changes, err = comparePackageHash(cb.Ctx(), path) require.NoError(t, err) assert.False(t, changes) pi.Aliases["c"] = "a.b/c" changes, err = comparePackageHash(cb.Ctx(), path) assert.IsError(t, err, "DGJTLHQOCQ") assert.False(t, changes) pi1 := scache.Set("a.b/c") changes, err = comparePackageHash(cb.Ctx(), path) require.NoError(t, err) assert.True(t, changes) cb.Jpkg("a.b/c", 1) pi1.Hash = 2 changes, err = comparePackageHash(cb.Ctx(), path) require.NoError(t, err) assert.True(t, changes) pi1.Hash = 1 changes, err = comparePackageHash(cb.Ctx(), path) require.NoError(t, err) assert.False(t, changes) }
func (c *ContextBuilder) initSys() *sysctx.SysCache { scache := sysctx.FromContextOrNil(c.ctx) if scache == nil { c.ctx = sysctx.NewContext(c.ctx) scache = sysctx.FromContext(c.ctx) } return scache }
func GetTypeFromCache(ctx context.Context, path string, name string) (*Type, bool) { scache := sysctx.FromContext(ctx) pcache, ok := scache.Get(path) if !ok { return nil, false } t, ok := pcache.Types.Get(name) if !ok { return nil, false } return t.Type.(*Type), true }
func NewStructFragmentView(ctx context.Context, node *node.Node, origin *system.Reference) *StructFragmentView { v := &StructFragmentView{} v.View = New(ctx, v) v.model = v.App.Editors.Get(node) v.origin = origin if ti, ok := sysctx.FromContext(ctx).GetType(origin.Package, origin.Name); ok { v.originType = ti.(*system.Type) } else { v.App.Fail <- kerr.New("DNMXCJXNVU", "Type %s not found in system context", origin.String()) return nil } return v }
func checkReflectType(ctx context.Context, t *testing.T, path string, name string, field string, output string) { scache := sysctx.FromContext(ctx) p, ok := scache.Get(path) assert.True(t, ok) typ, ok := p.Types.Get(name) assert.True(t, ok) ty, ok := typ.Type.(*system.Type) assert.True(t, ok) r, ok := ty.Fields[field] assert.True(t, ok) rh := system.WrapRule(ctx, r) rt, err := rh.GetReflectType() require.NoError(t, err) assert.Equal(t, output, rt.String()) }
func registerTypes(ctx context.Context, path string, imports map[string]shared.ImportInfo) (*sysctx.SysPackageInfo, error) { system.RegisterJsonTypes(ctx) scache := sysctx.FromContext(ctx) var current *sysctx.SysPackageInfo for _, info := range imports { env := &envctx.Env{Path: info.Path, Aliases: info.Aliases} pcache := scache.SetEnv(env) for _, ti := range info.Types { if err := parser.ProcessTypeFileBytes(ctx, env, ti.File, ti.Bytes, pcache, nil); err != nil { return nil, kerr.Wrap("UJLXYWCVUC", err) } } if path == info.Path { current = pcache } } return current, nil }
func TestRegisterTypes(t *testing.T) { cb := tests.New().Sempty().Jauto() imports := map[string]shared.ImportInfo{ "a": { Path: "b", Types: map[string]shared.TypeInfo{ "c": {Bytes: []byte(`{"type": "system:type", "id": "d"}`)}, }, }, "g": { Path: "h", Types: map[string]shared.TypeInfo{ "i": {Bytes: []byte(`{"type": "system:type", "id": "j"}`)}, }, }, } pi, err := registerTypes(cb.Ctx(), "b", imports) require.NoError(t, err) ti, ok := pi.Types.Get("d") assert.True(t, ok) assert.Equal(t, "b:d", ti.Type.(*system.Type).Id.String()) sc := sysctx.FromContext(cb.Ctx()) pi, ok = sc.Get("b") assert.True(t, ok) ti, ok = pi.Types.Get("d") assert.True(t, ok) assert.Equal(t, "b:d", ti.Type.(*system.Type).Id.String()) pi, ok = sc.Get("h") assert.True(t, ok) ti, ok = pi.Types.Get("j") assert.True(t, ok) assert.Equal(t, "h:j", ti.Type.(*system.Type).Id.String()) }
func GenerateAll(ctx context.Context, path string, done map[string]bool) error { if _, found := done[path]; found { return nil } scache := sysctx.FromContext(ctx) pi, ok := scache.Get(path) if !ok { return kerr.New("XMVXECGDOX", "%s not found in ctx", path) } if path != "kego.io/system" { if err := GenerateAll(ctx, "kego.io/system", done); err != nil { return kerr.Wrap("HBKXDVYWUP", err) } } for _, aliasPath := range pi.Aliases { if err := GenerateAll(ctx, aliasPath, done); err != nil { return kerr.Wrap("WVXTUBQYVT", err) } } info, found, err := getInfo(ctx, pi.Dir) if err != nil { return kerr.Wrap("SIMBVNBWOV", err) } if FORCE_GENERATE || !found || info.Hash != pi.Hash { if err := Generate(ctx, pi.Env); err != nil { return kerr.Wrap("TUFKDUPWMD", err) } } done[path] = true return nil }
func RegisterJsonTypes(ctx context.Context) { scache := sysctx.FromContext(ctx) pcache := scache.Set("kego.io/json") tr := NewReference("kego.io/system", "type") makeRule := func(name string) *Type { return &Type{ Object: &Object{ Id: NewReference("kego.io/json", fmt.Sprint(jsonctx.RULE_PREFIX, name)), Type: tr}, Interface: false, Embed: []*Reference{NewReference("kego.io/system", "rule")}, Native: NewString("object"), Fields: map[string]RuleInterface{}, Rule: (*Type)(nil)} } makeType := func(name string) *Type { return &Type{ Object: &Object{ Id: NewReference("kego.io/json", name), Type: tr}, Interface: false, Native: NewString(name), Fields: map[string]RuleInterface{}, Rule: makeRule(name)} } pcache.Types.Set("string", "", makeType("string")) pcache.Types.Set("number", "", makeType("number")) pcache.Types.Set("bool", "", makeType("bool")) pcache.Types.Set("@string", "", makeRule("string")) pcache.Types.Set("@number", "", makeRule("number")) pcache.Types.Set("@bool", "", makeRule("bool")) }
func root(ctx context.Context, w http.ResponseWriter, req *http.Request, auth auther.Auther) error { wgctx.Add(ctx, "root") defer wgctx.Done(ctx, "root") if b, err := static.Asset(req.URL.Path[1:]); err == nil { if strings.HasSuffix(req.URL.Path, ".css") { w.Header().Set("Content-Type", "text/css") } if err := writeWithTimeout(w, b); err != nil { return kerr.Wrap("PVPCXBIUJT", err) } return nil } path := req.URL.Path[1:] if strings.HasSuffix(path, "/") { path = path[0 : len(path)-1] } // use a new context with a blank sysctx for the duration of this function // to prevent caching ctx = sysctx.NewContext(ctx) scache := sysctx.FromContext(ctx) env, err := parser.ScanForEnv(ctx, path) if err != nil { if _, ok := kerr.Source(err).(gopackages.NotFoundError); ok { w.WriteHeader(404) return nil } return kerr.Wrap("ALINBMKDRP", err) } pcache, err := parser.Parse(ctx, path) if err != nil { return kerr.Wrap("HIHWJRPUKE", err) } if err := process.GenerateAll(ctx, env.Path, map[string]bool{}); err != nil { return kerr.Wrap("LVGHABDYNQ", err) } data := map[string]string{} for _, name := range pcache.Globals.Keys() { if g, ok := pcache.Globals.Get(name); ok { data[name] = g.File } } pkgBytes := pcache.PackageBytes pkgFilename := pcache.PackageFilename if pkgBytes == nil { b, err := system.Marshal(ctx, system.EmptyPackage()) if err != nil { return kerr.Wrap("OUBOTYGPKU", err) } pkgBytes = b pkgFilename = "package.ke.json" } imports := map[string]shared.ImportInfo{} var scan func(string) error scan = func(path string) error { if _, ok := imports[path]; ok { return nil } syspi, ok := scache.Get(path) if !ok { return kerr.New("VIGKIUPNCF", "%s not found in sys ctx", path) } info := shared.ImportInfo{ Path: path, Aliases: syspi.Aliases, Types: map[string]shared.TypeInfo{}, } for _, name := range syspi.Files.Keys() { if b, ok := syspi.Files.Get(name); ok { info.Types[name] = shared.TypeInfo{ File: b.File, Bytes: b.Bytes, } } } imports[path] = info for _, child := range syspi.Aliases { if err := scan(child); err != nil { return kerr.Wrap("NCULMUUUOT", err) } } return nil } // First we always import system if err := scan("kego.io/system"); err != nil { return kerr.Wrap("KRXSLOJKWV", err) } if err := scan(env.Path); err != nil { return kerr.Wrap("EELKQDCJGN", err) } info := shared.Info{ Path: env.Path, Aliases: env.Aliases, Data: data, Package: pkgBytes, PackageFilename: pkgFilename, Imports: imports, Hash: auth.Sign([]byte(env.Path)), } buf := bytes.NewBuffer([]byte{}) err = gob.NewEncoder(buf).Encode(info) if err != nil { return kerr.Wrap("OHBYTULHUQ", err) } base64EncodedString := base64.StdEncoding.EncodeToString(buf.Bytes()) attrib := base64EncodedString source := []byte(` <html> <head> <meta charset="utf-8"> <link rel="stylesheet" href="/bootstrap/css/bootstrap.min.css"> <link rel="stylesheet" href="/bootstrap/css/bootstrap-theme.min.css"> <link rel="stylesheet" href="/split.css"> <link rel="stylesheet" href="/editors.css"> <link rel="stylesheet" href="/tree.css"> <script src="/jquery-2.2.4.min.js"></script> <script src="/jquery-ui/jquery-ui.min.js"></script> <script src="/split.min.js"></script> <script src="/bootstrap/js/bootstrap.min.js"></script> <link rel="icon" type="image/png" href="data:image/png;base64,iVBORw0KGgo="> </head> <body id="body" info="` + attrib + `"></body> <script src="/` + env.Path + `/script.js"></script> </html>`) if err := writeWithTimeout(w, source); err != nil { return kerr.Wrap("ICJSAIMDRF", err) } return nil }
func parse(ctx context.Context, path string, queue []string) (*sysctx.SysPackageInfo, error) { scache := sysctx.FromContext(ctx) cmd := cmdctx.FromContext(ctx) for _, q := range queue { if q == path { return nil, kerr.New("SCSCFJPPHD", "Circular import %v -> %v", queue, path) } } if _, found := scache.Get("kego.io/json"); !found { system.RegisterJsonTypes(ctx) } hash := &PackageHasher{Path: path, Aliases: map[string]string{}, Types: map[string]uint64{}, Exports: map[string]uint64{}} importPackage := func(importPath string, importAlias string) error { if _, found := scache.Get(importPath); !found { _, err := parse(ctx, importPath, append(queue, path)) if err != nil { return kerr.Wrap("RIARRSCMVE", err) } } hash.Aliases[importAlias] = importPath return nil } packageDirectoryExists := true _, err := packages.GetDirFromPackage(ctx, path) if err != nil { _, ok := kerr.Source(err).(gopackages.NotFoundError) if ok { packageDirectoryExists = false } } if !packageDirectoryExists || cmd.Update { if err := GoGet(ctx, path); err != nil { return nil, kerr.Wrap("SBALWXUPKN", err) } } env, err := ScanForEnv(ctx, path) if err != nil { return nil, kerr.Wrap("GJRHNGGWFD", err) } // Always scan the system package first if we don't have it already if path != "kego.io/system" { if err := importPackage("kego.io/system", "system"); err != nil { return nil, kerr.Wrap("ORRCDNUPOX", err) } } for aliasName, aliasPath := range env.Aliases { if aliasPath == "kego.io/system" || aliasName == "system" { return nil, kerr.New("EWMLNJDXKC", "Illegal import %s", aliasName) } if err := importPackage(aliasPath, aliasName); err != nil { return nil, kerr.Wrap("NOVMGYKHHI", err) } } pcache := scache.SetEnv(env) cmd.Printf("Parsing %s...", path) if err := scanForTypesAndExports(ctx, env, pcache, hash); err != nil { return nil, kerr.Wrap("VFUNPHUFHD", err) } cmd.Println(" OK.") h, err := hash.Hash() if err != nil { return nil, kerr.Wrap("MIODRYNEJQ", err) } env.Hash = h return pcache, nil }
func Structs(ctx context.Context, env *envctx.Env) (source []byte, err error) { scache := sysctx.FromContext(ctx) pcache, ok := scache.Get(env.Path) if !ok { return nil, kerr.New("DQVQWTKRSK", "%s not found in sys ctx", env.Path) } types := pcache.Types exports := pcache.Exports g := builder.New(env.Path) infoBytes, _ := json.Marshal(InfoStruct{Path: env.Path, Hash: env.Hash}) g.SetPackageComment("info:" + string(infoBytes)) g.SetIntroComment(`ke: {"file": {"notest": true}}`) for _, name := range types.Keys() { t, ok := types.Get(name) if !ok { // ke: {"block": {"notest": true}} continue } typ := t.Type.(*system.Type) isRule := typ.Id.IsRule() isNativeCollection := typ.IsNativeCollection() && typ.Alias == nil if !typ.Interface && !typ.Custom { if typ.Alias != nil { if err := printAliasDefinition(ctx, env, g, typ); err != nil { return nil, kerr.Wrap("TRERIECOEP", err) } if kind, _ := typ.Kind(ctx); kind == system.KindValue { if err := printValueMethod(ctx, env, g, typ); err != nil { return nil, kerr.Wrap("PGDUJQVQGR", err) } } } else { if err := printStructDefinition(ctx, env, g, typ); err != nil { return nil, kerr.Wrap("XKRYMXUIJD", err) } } } if !typ.Interface && !isRule && !isNativeCollection { printInterfaceDefinition(ctx, env, g, typ) printInterfaceImplementation(ctx, env, g, typ) } if !isRule && !isNativeCollection { printInterfaceUnpacker(ctx, env, g, typ) } if !typ.Custom && !typ.Interface && !isNativeCollection { if err := printUnpacker(ctx, env, g, typ); err != nil { return nil, kerr.Wrap("YJNWUAUKXI", err) } if err := printRepacker(ctx, env, g, typ); err != nil { return nil, kerr.Wrap("NCFFXUHYNY", err) } } } printInitFunction(ctx, env, g, types) for _, name := range exports.Keys() { export, ok := exports.Get(name) if !ok { // ke: {"block": {"notest": true}} continue } if err := printExportFunction(ctx, env, g, export); err != nil { return nil, kerr.Wrap("YJHRXIASNO", err) } } b, err := g.Build() if err != nil { return nil, kerr.Wrap("XKYHSDKBEP", err) } return b, nil }