Modules and imports
Meta: three audiences, in this order so each can stop reading early — single-file users (next section), directory-module users, then people wiring up dang.toml. import/shadowing/cycles follow.
A single file is a module
- top-level declarations are the module's surface
pubis exported,letis private (see Fields:pubandlet)- order doesn't matter — declarations are hoisted; forward references work
A directory is also a module
- all
.dangfiles in a directory are one module - file boundaries are invisible to type resolution
- files load in unspecified order — code must be order-independent
mymod/ main.dang types.dang utils.dang
- a type defined in
types.dangcan be constructed/extended fromutils.dangormain.dangwith no import
dang.toml
dang.toml is discovered by walking up from the working directory (stopping at a .git boundary).
[imports.Dagger]
dagger = true
[imports.MyApi]
schema = "./schema.graphqls"
service = ["go", "run", "./server"]
[imports.Remote]
endpoint = "https://api.example.com/graphql"
authorization = "Bearer ${API_TOKEN}"
The endpoint, authorization, and headers values support ${VAR} environment expansion; $(...) command substitution is not supported.
- one
[imports.<Name>]per imported GraphQL source;<Name>is the qualifier (MyApi.User) - must specify at least one of
dagger,schema,endpoint, orservice schema = "..."— path to a local.graphqlsSDL file (relative todang.toml); used for type-checking and the LSPendpoint = "..."— GraphQL HTTP URL for runtime queries; if set withoutschema, the schema is introspected (and cached) from itservice = [...]— command that starts a GraphQL server, printing its endpoint URL as the first stdout line; started lazily, killed on exitdagger = true— connect to a Dagger Engine session;servicedefaults to["dagger", "session"]authorization = "..."— value for theAuthorizationheader[imports.<Name>.headers]— extra HTTP headers (table of key = value)authorization/endpoint/headersvalues support${ENV_VAR}expansion (note: the oldDANG_GRAPHQL_*env-var config was dropped)- runtime queries are GraphQL interop; see GraphQL interop
import declarations
import Dagger
import MyApi
- exposes both qualified (
MyApi.User) and unqualified (User) names - covers types, root
Query/Mutationfunctions, interfaces, unions, enums, scalars, and directives (see GraphQL interop) - enum values become unqualified too:
ACTIVE(==Status.ACTIVE) if no collision (see Enums and scalars) - imported directives are usable unqualified:
@customDirective(...)(see Directives)
Shadowing
- a local
type User { ... }shadows the importedUser(qualifiedMyApi.Userstill works) - a local declaration also resolves an otherwise-ambiguous unqualified name (local wins)
- without a local shadow, an unqualified name provided by two imports is an error:
ambiguous reference to "Status": provided by imports [Other Test]— must qualify - same for unqualified
Mutationand directives (ambiguous reference to directive @experimental)
Ordering and cycles
- forward references across files work
- direct circular variable initializers are caught statically:
circular module variable initializer: a -> b -> a - cycles hidden behind an auto-called function or constructor default are caught at runtime when the variable is forced:
initialization cycle while evaluating variable "..." - circular types (interface-implementing-interface, mutually-referencing types across files) are fine
What a module exports
- every
pubfield, type, interface, union, enum, scalar, directive - nothing
let
Meta: dang.toml discovery walks up from the file's directory to the nearest .git boundary; the dang CLI runs the resolved module (see CLI reference).