Summary
This proposal standardizes source-level resource semantics for XGo classfile frameworks.
It introduces:
- framework-declared resource kinds
- canonical string-based resource reference types
- optional handle-bearing types for top-level resource kinds
- active-project-group pack documents as the standardized discovery substrate
- discovery-based concrete resource introduction over pack documents
- typed API-position scope bindings for scoped canonical resource references
- one narrow work-classfile implication rule for top-level resource identities
- shared static semantics for resource references, completion, hover, rename, and diagnostics
Problem
Today, tool support for classfile-framework resources is framework-specific and mostly hardcoded.
For example, a tool such as xgolsw can provide good support for spx resources only because it already knows all of the following:
- which types mean
sprite, sound, backdrop, widget, and scoped sprite resources
- how one active project group derives its pack root and pack document
- how to discover concrete instances from pack-document object trees rooted at framework-declared config directories
- how to infer the scope of
SpriteCostumeName or SpriteCostumeFrameName from the current sprite context
This does not scale across frameworks.
Goals
- Let one framework declare its resource schema in framework source code
- Let tooling obtain concrete resource instances without executing arbitrary framework code
- Keep resource identity stable and independent from runtime object identity or storage paths
- Make scoped resource discovery natural for frameworks such as spx
- Support precise source-level resource semantics for canonical typed references
- Let tooling obtain explicit scope for scoped API positions when type information alone is insufficient
- Keep the model small enough that different frameworks can realistically adopt it
Non-goals
- Standardize runtime resource loading or runtime lookup keys
- Standardize one whole-project file-tree document as the discovery substrate
- Standardize declaration-based resource introduction for framework-declared named values such as
Direction or EffectKind
- Standardize project-class implied resources
- Standardize scoped classfile-implied resources beyond one narrow work-classfile rule
- Standardize API-position kind binding for plain
string parameters
- Replace editor-specific input-slot or input-type protocols
- Turn DQL into a general-purpose result-construction language
Proposed model
1. Resource kinds and type bindings
Framework source declarations may declare resource kinds through source-attached directive comments:
//xgo:class:resource sprite
type SpriteName = string
type (
//xgo:class:resource sprite.costume
SpriteCostumeName = string
)
//xgo:class:resource sprite
type Sprite interface { Name() string }
These comments attach to one top-level type spec. That includes one type spec inside a grouped type (...) declaration when the comment belongs to that specific type spec. It does not include one grouped type declaration as a whole.
This proposal uses dotted resource-kind spelling to encode kind hierarchy directly:
sprite is top-level
sprite.costume is scoped under sprite
sprite.costume.frame is scoped under sprite.costume
The //xgo:class:resource <kind> form means one of the following:
- one string-based type declares the canonical resource reference type of one kind
- one top-level kind may additionally declare one or more handle-bearing interface or struct types
2. Pack roots and pack documents
This proposal depends on one pack document derived per active project group at the classfile-spec layer.
One active project group may declare one pack directive in gox.mod:
That directive determines:
- one pack root directory, resolved from the named relative directory under the project root directory
- one exact index file name, such as
index.json, index.yml, or index.yaml
The pack document is the logical merged object derived from that pack root and that exact index file name:
- the root object is parsed from
R/F
- each descendant directory of
R that also contains F contributes one child object
- that child object is merged at its relative directory path from
R
- intermediate objects are created as needed
- files other than contributing
F files are outside the standardized pack-document model
One spx-style pack document may look like:
{
"zorder": ["Hero", "Enemy"],
"sprites": {
"Hero": {
"costumes": [
{"name": "idle", "frames": [{"name": "f1"}, {"name": "f2"}]},
{"name": "run", "frames": [{"name": "f1"}]}
]
},
"Enemy": {
"costumes": [
{"name": "idle", "frames": [{"name": "f1"}]}
]
}
},
"widgets": {
"Score": {
"id": "score-widget"
}
}
}
An implementation may materialize that document as index_pack.json, index_pack.yml, or index_pack.yaml, but the logical pack document is the standardized artifact.
3. Concrete resource introduction
Concrete resource introduction occurs in two forms:
- discovery-based introduction over pack documents
- one narrow work-classfile implication rule
3.1. Discovery-based introduction
Project-derived resource instances are declared on canonical resource reference types through:
//xgo:class:resource-discovery <DQL>
//xgo:class:resource-name-discovery <DQL>
resource-discovery selects discovery origin nodes.
resource-name-discovery, when present, resolves local names relative to those origin nodes.
For each discovery origin node, resource-name-discovery must resolve to exactly one matched node. The local resource name is then taken from:
- that node's string scalar value, if any
- otherwise that node's key name
- otherwise that node's string member
name
- otherwise the candidate is invalid
Without resource-name-discovery, local names use a default extraction rule:
- discovery origin node key name
- otherwise its string member
name
- otherwise the match is invalid
Example:
//xgo:class:resource sprite
//xgo:class:resource-discovery sprites.*
type SpriteName = string
//xgo:class:resource sprite.costume
//xgo:class:resource-discovery costumes.*
type SpriteCostumeName = string
//xgo:class:resource widget
//xgo:class:resource-discovery widgets.*
//xgo:class:resource-name-discovery id
type WidgetName = string
Discovery execution is intentionally relative:
- top-level kinds run on the root of the active project group's pack document, if any
- scoped kinds run relative to each discovered direct parent origin node
- scoped-kind queries remain short and framework-authored, for example:
sprites.*
costumes.*
frames.*
On the example pack document above:
sprites.* on the pack-document root discovers the sprite origins Hero and Enemy
costumes.* relative to the Hero sprite origin discovers idle and run
frames.* relative to the idle costume origin discovers f1 and f2
3.2. Work classfile implication
If the registered work base class declaration of one work file kind bears //xgo:class:resource <kind>, each work classfile of that kind implies one top-level resource identity whose local resource name is the class file stem.
This rule remains intentionally narrow:
- it applies only to work classfiles
- it applies only to one top-level kind
- it does not create discovery origin nodes
- it does not by itself create scoped child discovery roots
4. Typed resource references
This proposal keeps resource participation type-bound.
For canonical resource reference types:
- ordinary Go typing determines whether a position participates in standardized resource semantics
- string literals and statically evaluable string constants are resource reference candidates
- lookup uses full resource identity, including scope chain when applicable
- unresolved scope keeps the reference
scope-unknown
5. Typed API-position scope bindings
Scoped canonical resource references may obtain explicit direct-parent scope through:
//xgo:class:resource-api-scope-binding <target> <source>
where:
<target> is one param.n
<source> is receiver or one param.n
These comments belong to one framework callable site:
- one top-level function declaration
- one top-level method declaration
- one method spec declared by one top-level handle-bearing interface type declaration
Example:
//xgo:class:resource sprite
type Sprite interface {
//xgo:class:resource-api-scope-binding param.0 receiver
SetCostume__0(costume SpriteCostumeName)
}
//xgo:class:resource-api-scope-binding param.0 receiver
func (p *SpriteImpl) SetCostume__0(costume SpriteCostumeName)
//xgo:class:resource-api-scope-binding param.0 receiver
//xgo:class:resource-api-scope-binding param.1 param.0
func (p *SpriteImpl) SetCostumeAndFrame(costume SpriteCostumeName, frame SpriteCostumeFrameName)
This means:
costume gets its direct parent scope from the sprite receiver
frame gets its direct parent scope from the costume argument
- the same binding model applies whether the callable site is one function declaration, one method declaration, or one
interface method spec
6. Scoped owner inference
This proposal still keeps one narrow fallback inference rule for scoped canonical references inside work classfiles.
If all of the following hold:
- the current source position is inside one work classfile
- the registered work base class declaration bears a top-level resource comment for
<parentKind>
- the referenced scoped kind has direct parent kind
<parentKind>
- no explicit scope is otherwise available
then the direct parent identity is the implied top-level resource of the containing work classfile.
Why this shape
Why source-attached metadata
Resource kinds and introduction rules belong to framework declarations, not to gox.mod.
This keeps:
- classfile registration metadata in
gox.mod
- resource schema metadata in framework source
Why pack documents instead of one whole-project file-tree document
The accepted pack direction already gives classfile frameworks one configuration substrate per active project group.
Using that substrate keeps discovery aligned with framework-authored config structure and avoids standardizing a separate whole-project tree model that is broader than current framework needs.
Why DQL only for discovery
DQL fits pack-document discovery well because it queries tree-shaped configuration data.
It does not fit API-position scope binding as well. API scope binding is a relation between:
- receiver
- parameter positions
That is better modeled as a small declarative relation set than as a synthetic query document.
Why typed references only
Canonical string-based resource reference types already provide an exact, portable hook for static semantics.
By contrast, plain string parameters mix many unrelated meanings:
- route text
- template names
- command text
- arbitrary framework-specific text
This proposal keeps the standardized model narrow and type-bound.
Why no project-class implied resources
Work classfiles have one clean naming source: the class file stem.
Project classes do not.
In particular:
- explicit
main project classfiles do not provide one useful semantic name
- synthesized default project classes have no source file of their own
So project-class implied resources are intentionally left out.
Expected impact on tooling
For xgolsw-style tooling, this proposal replaces framework-specific hardcoded resource logic with declarative framework-authored metadata.
In practical terms, tooling gains:
- one shared resource schema model across frameworks
- one shared discovery execution model over active-project-group pack documents
- one shared identity model for hover, completion, rename, references, and diagnostics
- one shared way to obtain exact scope for typed scoped API positions
This still does not replace the full input-slot or input-type layer. It standardizes the semantic substrate that those tooling layers can consume.
Example: spx
Assume the active .spx project group in gox.mod declares:
Framework source declarations:
//xgo:class:resource sprite
//xgo:class:resource-discovery sprites.*
type SpriteName = string
//xgo:class:resource sprite.costume
//xgo:class:resource-discovery costumes.*
type SpriteCostumeName = string
//xgo:class:resource sprite.costume.frame
//xgo:class:resource-discovery frames.*
type SpriteCostumeFrameName = string
//xgo:class:resource sprite
type SpriteImpl struct{}
//xgo:class:resource-api-scope-binding param.0 receiver
func (p *SpriteImpl) SetCostume__0(costume SpriteCostumeName)
//xgo:class:resource-api-scope-binding param.0 receiver
//xgo:class:resource-api-scope-binding param.1 param.0
func (p *SpriteImpl) SetCostumeAndFrame(costume SpriteCostumeName, frame SpriteCostumeFrameName)
Then:
- the active
.spx project group derives its pack document from assets/index.json
sprites.* discovers sprite origins at the pack-document root
costumes.* discovers one sprite's costumes relative to that sprite origin
frames.* discovers one costume's frame resources relative to that costume origin
- one call to
SetCostume__0("idle") on Hero can resolve idle against scope (sprite, Hero)
- one call to
SetCostumeAndFrame("idle", "f1") on Hero can resolve "f1" against scope (sprite, Hero) + (sprite.costume, idle)
Deferred items
- stronger framework-defined owner inference
- one stronger standardized exactness model for missing-resource diagnostics
Summary
This proposal standardizes source-level resource semantics for XGo classfile frameworks.
It introduces:
Problem
Today, tool support for classfile-framework resources is framework-specific and mostly hardcoded.
For example, a tool such as xgolsw can provide good support for spx resources only because it already knows all of the following:
sprite,sound,backdrop,widget, and scoped sprite resourcesSpriteCostumeNameorSpriteCostumeFrameNamefrom the current sprite contextThis does not scale across frameworks.
Goals
Non-goals
DirectionorEffectKindstringparametersProposed model
1. Resource kinds and type bindings
Framework source declarations may declare resource kinds through source-attached directive comments:
These comments attach to one top-level type spec. That includes one type spec inside a grouped
type (...)declaration when the comment belongs to that specific type spec. It does not include one grouped type declaration as a whole.This proposal uses dotted resource-kind spelling to encode kind hierarchy directly:
spriteis top-levelsprite.costumeis scoped underspritesprite.costume.frameis scoped undersprite.costumeThe
//xgo:class:resource <kind>form means one of the following:2. Pack roots and pack documents
This proposal depends on one pack document derived per active project group at the classfile-spec layer.
One active project group may declare one
packdirective ingox.mod:That directive determines:
index.json,index.yml, orindex.yamlThe pack document is the logical merged object derived from that pack root and that exact index file name:
R/FRthat also containsFcontributes one child objectRFfiles are outside the standardized pack-document modelOne spx-style pack document may look like:
{ "zorder": ["Hero", "Enemy"], "sprites": { "Hero": { "costumes": [ {"name": "idle", "frames": [{"name": "f1"}, {"name": "f2"}]}, {"name": "run", "frames": [{"name": "f1"}]} ] }, "Enemy": { "costumes": [ {"name": "idle", "frames": [{"name": "f1"}]} ] } }, "widgets": { "Score": { "id": "score-widget" } } }An implementation may materialize that document as
index_pack.json,index_pack.yml, orindex_pack.yaml, but the logical pack document is the standardized artifact.3. Concrete resource introduction
Concrete resource introduction occurs in two forms:
3.1. Discovery-based introduction
Project-derived resource instances are declared on canonical resource reference types through:
resource-discoveryselects discovery origin nodes.resource-name-discovery, when present, resolves local names relative to those origin nodes.For each discovery origin node,
resource-name-discoverymust resolve to exactly one matched node. The local resource name is then taken from:nameWithout
resource-name-discovery, local names use a default extraction rule:nameExample:
Discovery execution is intentionally relative:
sprites.*costumes.*frames.*On the example pack document above:
sprites.*on the pack-document root discovers the sprite originsHeroandEnemycostumes.*relative to theHerosprite origin discoversidleandrunframes.*relative to theidlecostume origin discoversf1andf23.2. Work classfile implication
If the registered work base class declaration of one work file kind bears
//xgo:class:resource <kind>, each work classfile of that kind implies one top-level resource identity whose local resource name is the class file stem.This rule remains intentionally narrow:
4. Typed resource references
This proposal keeps resource participation type-bound.
For canonical resource reference types:
scope-unknown5. Typed API-position scope bindings
Scoped canonical resource references may obtain explicit direct-parent scope through:
//xgo:class:resource-api-scope-binding <target> <source>where:
<target>is oneparam.n<source>isreceiveror oneparam.nThese comments belong to one framework callable site:
Example:
This means:
costumegets its direct parent scope from the sprite receiverframegets its direct parent scope from thecostumeargumentinterface method spec
6. Scoped owner inference
This proposal still keeps one narrow fallback inference rule for scoped canonical references inside work classfiles.
If all of the following hold:
<parentKind><parentKind>then the direct parent identity is the implied top-level resource of the containing work classfile.
Why this shape
Why source-attached metadata
Resource kinds and introduction rules belong to framework declarations, not to
gox.mod.This keeps:
gox.modWhy pack documents instead of one whole-project file-tree document
The accepted
packdirection already gives classfile frameworks one configuration substrate per active project group.Using that substrate keeps discovery aligned with framework-authored config structure and avoids standardizing a separate whole-project tree model that is broader than current framework needs.
Why DQL only for discovery
DQL fits pack-document discovery well because it queries tree-shaped configuration data.
It does not fit API-position scope binding as well. API scope binding is a relation between:
That is better modeled as a small declarative relation set than as a synthetic query document.
Why typed references only
Canonical string-based resource reference types already provide an exact, portable hook for static semantics.
By contrast, plain
stringparameters mix many unrelated meanings:This proposal keeps the standardized model narrow and type-bound.
Why no project-class implied resources
Work classfiles have one clean naming source: the class file stem.
Project classes do not.
In particular:
mainproject classfiles do not provide one useful semantic nameSo project-class implied resources are intentionally left out.
Expected impact on tooling
For xgolsw-style tooling, this proposal replaces framework-specific hardcoded resource logic with declarative framework-authored metadata.
In practical terms, tooling gains:
This still does not replace the full input-slot or input-type layer. It standardizes the semantic substrate that those tooling layers can consume.
Example: spx
Assume the active
.spxproject group ingox.moddeclares:Framework source declarations:
Then:
.spxproject group derives its pack document fromassets/index.jsonsprites.*discovers sprite origins at the pack-document rootcostumes.*discovers one sprite's costumes relative to that sprite originframes.*discovers one costume's frame resources relative to that costume originSetCostume__0("idle")onHerocan resolveidleagainst scope(sprite, Hero)SetCostumeAndFrame("idle", "f1")onHerocan resolve"f1"against scope(sprite, Hero) + (sprite.costume, idle)Deferred items