Skip to content

Editor types

happyview types <root> writes declaration files for the project at <root>, so your editor’s own language server can complete and check what a script sees: each happyview.* library, a handler’s input and return value from its lexicon, ctx, and records by NSID.

Terminal window
happyview types . # into .happyview/types/
happyview types . --out ./types # somewhere else
happyview types . --plugin ./plugins/lua # load this interpreter instead of the project's

It builds the project the way happyview check does, with no database and no network, then asks each interpreter the project uses to render the types in its own language. Each language gets its own directory, such as .happyview/types/lua/ and .happyview/types/typescript/, holding the files your language server already reads: LuaLS ---@meta files for Lua, .d.ts files for JavaScript and TypeScript.

Interpreters come from --plugin, else $PLUGIN_DIR, else <root>/.happyview/plugins, as for check. Libraries are loaded from the same places.

happyview dev keeps .happyview/types/ current on its own: it writes the types once it starts watching, and again after every build that changes what a script can see, printing a types: line only when it wrote something or failed. A failed build leaves the last good types in place.

One line per interpreter:

LineMeaning
types: lua: wrote 14 filesThe directory was replaced with a fresh set
types: lua: up to dateNothing changed since the last run, so nothing was written
types: lua: skipped: … needs happyview-plugin-sdk 0.4.0 or later for typesThe interpreter cannot render types
types: lua: failed: …The interpreter failed; its directory is left as it was

A library whose description does not parse is reported as types: library <id> describes itself wrongly: … and left out, and the other libraries are still typed.

A directory is replaced whole, so an editor never reads half of a set, and files from an earlier run that the interpreter no longer writes disappear. manifest.json in each directory records the interpreter and library versions and a hash of everything the types were made from; the next run compares it and writes nothing when they match, which keeps rerunning cheap.

CodeWhen
0Every interpreter wrote, was up to date, or was skipped
1The project does not build (nothing is written), or an interpreter failed
2A usage error, or a plugin that will not load

A language server cannot give a function’s parameters types from outside its file, so a handler names its types once. The names come from the lexicon’s NSID and the kind of script; each interpreter plugin documents its own. For a query com.example.getThing:

---@param input lexicons.com.example.getThing.Params
---@param ctx happyview.QueryCtx
---@return lexicons.com.example.getThing.Output
function handle(input, ctx)
end
import type { Params, Output } from "happyview:lexicons/com.example.getThing";
import type { QueryCtx } from "happyview:ctx";
export default async function handle(input: Params, ctx: QueryCtx): Promise<Output> {
}

Pointing your editor at .happyview/types/ is the language server’s own setting: workspace.library in .luarc.json for LuaLS, and include or typeRoots in tsconfig.json.

The dashboard’s script editor reads the same declarations, rendered for the whole instance through GET /admin/editor/declarations. They cover every installed library and every lexicon the instance serves.

  • Lua: the editor completes the members of a required library and of what its calls return. It types input and ctx from the script’s trigger, so a handler needs no annotations there, and shows each member’s type and description on hover.
  • TypeScript and JavaScript: import type from happyview:ctx and happyview:lexicons/<nsid> resolve as they do in an editor.