Skip to content

Latest commit

 

History

History
235 lines (198 loc) · 21.8 KB

File metadata and controls

235 lines (198 loc) · 21.8 KB

AGENTS.md — go-json

Overview

Standalone JSON/JSONC programming language engine. Embeddable in Go applications. Part of the BitCode platform but independently usable.

Pipeline: JSONC pre-process → JSON parse → import resolution → AST → compile (struct registration, structural validation, limit resolution) → immutable Program → VM execution with debug hooks.

Expression evaluation delegated to expr-lang/expr via ExprEngine abstraction layer. The VM never calls expr-lang directly.

Phase 4.5a design: docs/plans/2026-07-14-runtime-engine-phase-4.5a-go-json-core-language.md Phase 4.5b design: docs/plans/2026-07-14-runtime-engine-phase-4.5b-go-json-modularity.md Phase 4.5b plan: docs/plans/2026-07-14-runtime-engine-phase-4.5b-go-json-modularity-plan.md Phase 4.5g design: docs/plans/2026-07-15-phase-4.5g-lambda-language-core.md Decisions: docs/plans/2026-04-28-go-json-brainstorming-design.md

Package Structure

packages/go-json/
├── lang/           Core language engine (AST, parser, compiler, VM, scope, types, errors, expr engine, debugger, import resolver)
├── stdlib/         Layer 2 stdlib (135+ functions + crypto/validate namespaces + regex + path + JSON + env + higher-order). Layer 1 = expr-lang built-ins (~68 functions)
├── runtime/        Runtime API: NewRuntime(), Execute(), ExecuteFunction(), CompileFile(), Close(), program cache, limits, logger, session, extensions. Also: EvalExpr(), EvalExprBool(), EvalExprFloat(), ParseExpr(), ValidateExpr() — lightweight expression evaluation API for engine consumers (shared singleton ExprLangEngine with stdlib + compilation cache).
├── io/             I/O modules: HTTP, FS, SQL, Exec, MongoDB, Redis with security layer + unified SQL param translation (Phase 4.5c-d)
├── codegen/        Code generation: Go/JS/Python generators + server codegen (Fiber/net-http/Express/FastAPI) + dependency management (Phase 4.5c-d)
├── server/         Web server execution mode: adapters (Fiber/net-http/Echo/Gin/Chi), middleware, JWT, auth, templates, static, OpenAPI (Phase 4.5d)
├── server/adapters/ Framework adapter implementations (ServerAdapter interface)
├── generate/       CRUD generator, auth scaffold, project scaffold, pattern templates, DB introspection (Phase 4.5d)
├── cmd/go-json/    CLI: run, serve, check, test, ast, codegen, generate, openapi, migrate commands
└── testdata/       Test fixture programs (.json, .jsonc)

Key Architecture Decisions

  1. ExprEngine abstraction — VM never calls expr-lang directly. All expression work goes through ExprEngine interface for testability and swappability.
  2. Compile-once, run-manyCompiledProgram is immutable after compilation. Each execution gets fresh VM + scope. Multiple goroutines can run the same program concurrently.
  3. Structural validation at compile time, expression validation at runtime — expr-lang's compile-time type checking requires a fully-typed environment which we don't have with gradual typing. Runtime catches expression errors.
  4. Scope isolation for functions and methodsIsolatedChild() creates scope WITHOUT parent link. Functions and methods cannot access caller variables. self is injected into method scope. Block scope (NewChild()) for if/for/while allows reading and mutating outer variables.
  5. Sentinel types for control flowreturnValue, breakSignal, continueSignal are unexported struct types that propagate through executeSteps() return values.
  6. Resource limits at every step — step count, call depth, loop iterations, timeout checked before each step execution. MaxVariables, MaxVariableSize checked after every Declare(). MaxOutputSize checked on program return.
  7. JSON param ordering — Go maps don't preserve insertion order. extractOrderedKeys() uses json.Decoder tokenization to recover function param order from raw JSON.
  8. Built-in name protectionlet blocks variable names that shadow critical built-in functions (len, abs, min, max, etc.). Curated list excludes common-word functions (count, filter, sort) that are also natural variable names.
  9. Implicit scope variablessession.* (user_id, locale, tenant_id, groups) and execution.* (id, program, started_at, depth, step_count) injected automatically into every execution.
  10. Trace enrichmentTraceEntry captures Var/Value for let/set, Condition/Result for if/while/switch, per step type via enrichTraceEntry().

Step Types (20)

let, set, if/elif/else, switch, for (each + range), while, break, continue, return, call, try/catch/finally, error, log, parallel, match, sleep, retry, assert, _c (comment)

Struct System (Phase 4.5b)

  • Structs defined in structs block with fields, methods, optional frozen: true
  • Construction via {"let": "x", "new": "StructName", "with": {...}}
  • Nested construction: "field": {"new": "Other", "with": {...}}
  • Runtime type-checking on construction: field values validated against declared types (TYPE_MISMATCH error)
  • Methods with implicit self binding, callable at expression and step level
  • Frozen structs: compile-time rejection of set "self.*" in methods
  • self reassignment blocked in all node types (if/for/while/try/switch/parallel)
  • Forward references resolved via two-pass compilation
  • Circular non-nullable struct references detected at compile time

Import System (Phase 4.5b)

  • Import key: "import" (preferred) or "imports" (compat)
  • Path types: relative (./), stdlib (stdlib:), extension (ext:), I/O (io:), script (script:), WASM (wasm:), native plugin (plugin:)
  • Imported items namespaced via alias: alias.StructName, alias.functionName
  • Circular import detection via import stack
  • Import alias collision detection (compile error on duplicate namespaced names)
  • Barrel file re-export via {"alias": "imported.Type"} in structs block
  • Diamond imports handled correctly (loaded once, cached)
  • Wired via Runtime.CompileFile(path) — import resolution between parse and compile
  • Script imports (script:./path.py) — resolved at runtime via ScriptRuntime interface (Phase 4.5j)
  • WASM imports (wasm:./plugin.wasm) — resolved via .wasm extension to WASM runtime (Phase 4.5k)
  • Native plugin imports (plugin:./plugin.so) — resolved via .so/.dylib extension to native runtime (Phase 4.5k)

Script Plugin System (Phase 4.5j)

  • ScriptRuntime interface in runtime/script_runtime.go — defines contract for external script engines
  • ScriptRuntimeRegistry — manages multiple runtimes, resolves by file extension
  • WithScriptRuntime(rt) / WithScriptBridge(bridge) — runtime options
  • script: imports recorded in RequestedModules, resolved at execution time
  • Script proxy injected as map[string]any{"call": fn, "exec": fn} — expression-level: ml.call("predict", data)
  • Step-level calls: {"call": "ml.call", "with": ["'predict'", "data"]} via existing namespace function dispatch
  • Path validation: absolute paths rejected, traversal prevented via filepath.Clean + prefix check
  • SourcePath field on Program AST — set by CompileFile for relative path resolution
  • go-json core remains zero-dependency — ScriptRuntime is interface only
  • Implementations live in packages/go-json-runtimes/ (separate go.mod)

Parallel Execution (Phase 4.5b)

  • {"parallel": {"branch1": [...], "branch2": [...]}, "into": "results"}
  • Each branch gets own VM + scope (read parent, cannot write parent)
  • Compile-time check: set targeting parent variable in parallel branch = error
  • Join modes: all (default, wait for all), any (first success wins), settled (wait for all regardless of errors, errors collected as error objects)
  • Error modes: cancel_all (default), continue, collect
  • Goroutine leak prevention: drain channel after cancel
  • Shared step counter across branches via sync/atomic — prevents step limit bypass via many parallel branches
  • Struct instances are NOT thread-safe — do not share mutable struct instances across parallel branches

Stdlib Layers

Layer Contents Ownership
Layer 1 expr-lang built-ins (~68 functions: abs, ceil, floor, round, min, max, len, upper, lower, trim, split, filter, map, reduce, find, sort, int, float, string, type, etc.) expr-lang — DO NOT reimplement
Layer 2 go-json additions (135+ functions + crypto/validate namespaces). Phase 4.5a: clamp, sign, randomInt, randomFloat, pow, sqrt, mod, padLeft, padRight, substring, format, matches, append, prepend, slice, chunk, zip, bool, isNil. Phase 4.5b: has, get, merge, pick, omit, formatDate (universal format), addDuration, diffDates, urlEncode, urlDecode, sprintf, crypto.sha256, crypto.md5, crypto.uuid, crypto.hmac. Phase 4.5d: toJSON, fromJSON, basename, dirname, extname, joinpath, cleanpath, isabs, stemname, pathsep. Phase 4.5f: capitalize, title, camelCase, snakeCase, kebabCase, pascalCase, truncate, slugify, strReverse, strCount, replaceFirst, lines, words, isDigit, isAlpha, isAlphaNum, isEmpty, isBlank, escapeHTML, unescapeHTML, sin, cos, tan, asin, acos, atan, atan2, log, log2, log10, exp, trunc, random, isNaN, isInfinite, isFinite, PI, E, Infinity, NaN, toUnix, fromUnix, toISO, startOfDay, endOfDay, startOfMonth, endOfMonth, isWeekend, isBefore, isAfter, daysInMonth, isLeapYear, compact, includes, arrayIndexOf, keyBy, difference, intersection, union, fill, drop, takeRight, flatMap, partition, deepMerge, deepClone, deepEqual, setIn, deleteIn, defaults, mapKeys, mapValues, toFixed, formatNumber, formatBytes, formatPercent, env(), validate.isEmail, validate.isURL, validate.isIP, validate.isUUID, validate.isJSON, validate.isNumeric, validate.isAlpha, validate.isBase64, validate.isHexColor, validate.isCreditCard, crypto.sha512, crypto.encrypt, crypto.decrypt, crypto.hashPassword, crypto.verifyPassword, crypto.randomBytes. Phase 4.5g: mapFn, filterFn, rejectFn, reduceFn, findFn, everyFn, someFn, sortFn, takeWhileFn, dropWhileFn, partitionFn, applyEach, identity stdlib/ package
Layer 3 I/O modules (HTTP, FS, SQL, Exec, MongoDB, Redis, Cache, Email) with two-layer security gating. Regex stdlib (match, findAll, replace with LRU caching). FS enhancements: stat, copy, move, glob. SQL unified query parameter translation (?/:name across drivers). Cache: in-memory key-value with TTL + cleanup goroutine. Email: SMTP with STARTTLS + env var config. io/ and stdlib/regex.go

Conventions

  • Follow root AGENTS.md conventions (no unnecessary comments, tests required)
  • All exported types and functions need Go doc comments
  • go build ./... and go vet ./... must pass
  • Tests: go test ./... -v

Testing

cd packages/go-json
go test ./... -v          # All tests (1018)
go test ./lang/ -v        # Language engine tests
go test ./lang/ -run TestStruct -v       # Struct tests
go test ./lang/ -run TestMethod -v       # Method tests
go test ./lang/ -run TestParallel -v     # Parallel tests
go test ./lang/ -run TestImport -v       # Import tests
go test ./lang/ -run TestIntegration -v  # Integration tests
go test ./stdlib/ -v                     # Stdlib tests (including regex, path, JSON)
go test ./io/ -v                         # I/O + SQL param translation tests
go test ./runtime/ -v                    # Runtime + extension tests
go test ./codegen/ -v                    # Code generation + server codegen tests
go test ./server/ -v                     # Server config, routing, handler, auth, JWT, middleware, OpenAPI, template, static tests
go test ./generate/ -v                   # CRUD generator, auth scaffold, project scaffold, introspection, pattern tests

What's Done (Phase 4.5b)

  • Struct definitions with fields, defaults, frozen, methods
  • Struct construction (new + with), nested construction, return with new
  • Method system with self binding, mutation, frozen compile-time check
  • Import system with relative file resolution, circular detection, barrel files
  • Parallel execution with 3 error modes, scope isolation, compile-time parent write check
  • Stdlib Layer 2 extensions: maps, datetime, encoding, crypto (namespaced), format
  • Nullable type support (?T), optional chaining via expr-lang

What's Done (Phase 4.5c)

  • I/O module framework: IOModule interface, IORegistry, WithIO()/WithoutIO() runtime options
  • I/O security layer: SecurityConfig, two-layer gating (import + runtime enable), hardcoded deny lists, path traversal prevention, cloud metadata blocking
  • HTTP module: GET/POST/PUT/PATCH/DELETE with auth (bearer/basic), redirect following, response size limits, client reuse
  • FS module: read/write/append/exists/list/mkdir/remove with sandboxing, encoding (UTF-8/base64), symlink resolution
  • SQL module: query/execute with connection pooling per-DSN, DefaultDSN, multi-driver detection (postgres/mysql/sqlserver/oracle/sqlite), transactions with savepoints, DDL protection (blocked keywords + max query length), auto-rollback on Close/Cleanup
  • Exec module: command whitelisting, DeniedCommands (always blocked), env isolation, EngineSecrets stripping, output truncation
  • MongoDB module: find/findOne/insert/insertMany/update/delete/count/aggregate with NoSQL injection protection ($where/$function blocking), security config (AllowedDatabases, MaxDocumentSize, MaxResults, MaxPools)
  • Redis module: get/set/del/exists/expire/ttl/incr/decr/hget/hset/hgetall/lpush/rpush/lrange/sadd/smembers/publish with auto JSON serialize/deserialize, KeyPrefix tenant isolation, blocked commands (FLUSHALL, CONFIG, etc.)
  • Regex stdlib: match/findAll/replace with LRU cache (max 1000 patterns), ReDoS prevention
  • Extension API: Extension struct with Functions/Structs/Constants, WithExtension() runtime option, ext:name import support
  • Import resolver: io: and ext: imports recorded in RequestedModules, validated at runtime (two-layer security enforced)
  • Runtime.Close(): propagates to all I/O modules implementing Close() error
  • Bitcode bridge adapter: nested namespace maps for dotted access (bc.db.query), explicit type errors instead of silent coercion, optimized convertToAny
  • GoJSONRunner: uses CompileFile for proper import resolution
  • scripts/*.json support: detectRuntimeFromExtension detects .jsongo-json, GoJSONRunner implements EmbeddedRunner
  • Backward compatibility: ProcessDefinition.Runtime field, IsGoJSON() helper, old format unchanged
  • Process engine data step replacement: GoJSONDataHandler adapts old step types to bridge calls
  • CLI: run (--input/--input-file/--timeout/--io/--trace/stdin), check (--verbose), test (--filter/--verbose), ast (--output), codegen (--target/--output/--package), migrate (--from/--to/--dry-run, JSON-aware key renaming)
  • Code generation: CodeGenerator interface, Go/JavaScript/Python generators handling all step types including new/import/expression/switch
  • Windows path security: case-insensitive matching, directory boundary checks, filepath.Rel-based AllowedPaths validation
  • Security: AllowedHosts explicitly override BlockedHosts (explicitly allowed hosts skip blocked check)
  • Exec timeout: context deadline check prioritized over ExitError for reliable timeout detection
  • MongoDB module: real driver (go.mongodb.org/mongo-driver/v2), lazy connection, full CRUD + aggregation
  • Redis module: real driver (github.com/redis/go-redis/v9), lazy connection, 16 commands, auto JSON serialize
  • CLI: go-json ast --format flag (forward-compatible, json only for now)
  • 723 tests total across 10 packages (lang: 177, io: 132, stdlib: 103, server: 108, runtime: 79, generate: 48, cmd: 45, codegen: 36)

What's Done (Phase 4.5d)

  • Server execution mode (go-json serve): declarative routing, plugable framework adapters, middleware, template rendering, static files
  • ServerAdapter interface: framework-agnostic abstraction with RequestContext/Response types, adapter registry
  • Framework adapters: Fiber (default), net/http (stdlib), Echo (build-tagged), Gin (build-tagged), Chi (build-tagged)
  • Route system: declarative routes with groups, prefix nesting, middleware merging, route flattening, validation
  • Handler bridge: BuildHandler converts HTTP→go-json function→HTTP. ExecuteFunction added to Runtime and VM for direct function invocation
  • Request object: full body parsing (JSON, form, multipart, text), file upload with temp file handling + cleanup, path params, query, headers, cookies, IP, store
  • Response convention: status+body (JSON), data+render (template), redirect, cookies, headers, error field, 204 for nil
  • Middleware chain engine: built-in (logger, recover, CORS, secure headers, request_id, compress, rate_limit) + custom go-json functions with short-circuit
  • JWT module: middleware (header + cookie extraction, validation) + callable functions (sign, verify, decode, refresh)
  • Plugable auth system: AuthStrategy interface with Bearer/JWT, API Key, Basic Auth, Custom (go-json function) strategies. auth and auth:name middleware resolution
  • Template engine: Go html/template with 20+ built-in functions (json, formatDate, upper, lower, truncate, default, safeHTML, urlEncode, add/sub/mul/div/mod, seq, etc.), layouts, partials, dev-mode reload
  • Static file serving: configurable directory + prefix, path traversal protection, hidden file blocking
  • OpenAPI/Swagger: auto-generated OpenAPI 3.0 spec from routes, api annotation support (body/query/responses), security scheme mapping, Swagger UI at /docs, go-json openapi CLI command
  • Server codegen: ServerCodegenAdapter interface with language×framework registry. Implementations: Go+Fiber, Go+net/http, JS+Express, Python+FastAPI
  • Codegen dependency management: feature detection, go.mod/package.json/requirements.txt/.env.example generation
  • SQL unified query parameters: TranslateQuery converts ? and :name placeholders to driver-specific syntax (postgres $1, sqlserver @p1, oracle :1, sqlite/mysql ?). Integrated into SQL module
  • FS enhancements: fs.stat, fs.copy, fs.move, fs.glob + enhanced fs.list
  • Path stdlib: basename, dirname, extname, joinpath, cleanpath, isabs, stemname, pathsep
  • Stdlib additions: toJSON/fromJSON, formatDate universal format (YYYY-MM-DD → Go layout translation)
  • CRUD generator: database introspection (SQLite, PostgreSQL, MySQL), type mapping (DB→go-json→OpenAPI), manual fields mode, CRUD route+handler generation with validation
  • Auth scaffold generator: register, login, refresh, me, change-password endpoints with JWT
  • Project scaffold generator: full project structure (api.json, templates/, public/, migrations/, .env.example, README.md)
  • Pattern template engine: built-in patterns (simple, service-layer, DDD, hexagonal), custom template support, per-model file generation
  • CLI commands: go-json serve (--dev, --port, --host, --docs, --io), go-json generate (crud/auth/project with --table/--fields/--dsn/--auth/--output), go-json openapi (--output)
  • Server mode detection: IsServerProgram() checks for routes key
  • Health endpoint: built-in /health with status, name, uptime (bypasses middleware)
  • Graceful shutdown: SIGINT/SIGTERM handling with configurable timeout
  • 723 tests total across 9 packages (includes Phase 4.5a–d cumulative)
  • Pattern templates: 4 built-in patterns (simple, service-layer, ddd, hexagonal) with actual template files

What's Done (Phase 4.5g)

  • Lambda expressions: fn(params) => body (anonymous) and fn name(params) => body (named, recursive)
  • Named recursive lambda: self-reference via forward-declared closure, depth-limited by vm.limits.MaxDepth
  • Pattern matching: match step with structural patterns, variable binding ($var), wildcards (_, $_), guards (when), subset map match
  • Lambda preprocessing: standalone lambda detection, inline lambda extraction, placeholder replacement
  • Higher-order functions: mapFn, filterFn, reduceFn, applyEach, sortFn — accept callable lambdas
  • Dynamic call_ref: call resolves variable containing function name (string) or callable (lambda)
  • Sleep step: {"sleep": ms} with literal or expression duration, context cancellation, 5-minute max
  • Retry step: {"retry": {steps, max, delay, backoff}} with fixed/linear/exponential backoff
  • Assert step: {"assert": "condition", "message": "..."} — throws ASSERTION_FAILED on false
  • Constants block: "constants": {...} — immutable values, compile-time reassignment protection
  • Enum system: "enums": {...} — array enums (value=value) and map enums (key=value), dot access
  • Enhanced test runner: expect_error, before/after, skip/only, table (parameterized), per-case timeout
  • Codegen updates: sleep/retry/assert generation for Go, JavaScript, Python
  • 969 tests total across 9 packages (includes Phase 4.5a–g cumulative)

What's Done (Phase 4.5i)

  • Cache module (io:cache): in-memory key-value cache with TTL, background cleanup goroutine (60s interval), security limits (MaxEntries, MaxValueSize, MaxTTL), goroutine-safe (RWMutex), lazy eviction on read, double-close safe
  • Email module (io:email): SMTP client with STARTTLS, env var fallback (SMTP_HOST/PORT/USER/PASSWORD/FROM/TLS), runtime SetConfig(), security (AllowedRecipients glob, BlockedDomains, MaxBodySize, MaxRecipients), IPv6-safe (net.JoinHostPort)
  • Both modules follow IOModule interface, registered in All(), security configs in unified SecurityConfig
  • 1018 tests total across 9 packages (includes Phase 4.5a–i cumulative)

What's NOT Done

  • Expression-level compile-time type validation (deferred to runtime)
  • MongoDB/Redis require running servers for actual I/O (tests use miniredis for Redis, security-only tests for MongoDB)
  • REPL mode (future)
  • Dev mode file watching (fsnotify — optional dependency, not yet added)
  • Interactive mode for go-json generate (--interactive flag)