Documentation
¶
Overview ¶
Package script runs user Go scripts with the yaegi interpreter, exposing the sdb API plus the Go standard library.
Index ¶
- Constants
- func FitPluginName(text, file string, taken func(name string) bool) (out, from, to string)
- func HasError(diags []Diag) bool
- func LoadPluginFile(path string) *pipeline.PluginProblem
- func LoadPlugins(dir string) []pipeline.PluginProblem
- func PluginNameFor(file string) string
- func PluginNameTaken(name string) bool
- func Run(path string, s *sdb.S) error
- func RunSource(name, src string, s *sdb.S) error
- func SyncPlugins(dir string) bool
- func WrapSnippet(code string) (src string, headerLines int)
- type Diag
- type Edit
- type Span
- type Symbol
Constants ¶
const ( SevError = "error" SevWarning = "warning" )
The two severities. An error means Run would fail (or never start); a warning is legal Go that probably does not do what was meant.
const NotOnSymbol = "rename works on a name the script declares: a variable, constant, type, function, method, field, label or import"
NotOnSymbol is the sentence for a caret on nothing renamable, shared with the editor's rename box so both say it in the same words.
Variables ¶
This section is empty.
Functions ¶
func FitPluginName ¶ added in v0.13.0
FitPluginName returns text with its Plugin.Name rewritten to file's own name when the Name it has is taken (taken: another plugin, built in or a file's, already has it); from and to say what changed, both "" when nothing did. The new name is made free with -2, -3 … when the file's own is taken too.
func HasError ¶ added in v0.9.0
HasError reports whether any diag is an error rather than a warning.
func LoadPluginFile ¶ added in v0.13.0
func LoadPluginFile(path string) *pipeline.PluginProblem
LoadPluginFile loads one plugin file on its own — compiled, var Plugin read and checked, its funcs bound — without registering it, and says why it cannot be a plugin, or nil. Its name is checked against the built-ins, not against other plugin files. For `dbc plugins --check`.
func LoadPlugins ¶ added in v0.13.0
func LoadPlugins(dir string) []pipeline.PluginProblem
LoadPlugins loads every plugin file in dir now, whatever changed, and returns the files that did not load. A missing directory is no plugins and no problem.
func PluginNameFor ¶ added in v0.13.0
PluginNameFor is the plugin name a file's name suggests, as the examples pair them: the stem, its underscores as dots ("mask_email.go" → "mask.email", "gen_series-2.go" → "gen.series-2"). A stem that would make no valid name (a trailing "_") keeps its underscores.
func PluginNameTaken ¶ added in v0.13.0
PluginNameTaken says whether a plugin is already called name: one built into dbc, one a file loaded, or one a file declares that did not load (its problem names it), which would take the name back once fixed. The hosts' taken for FitPluginName.
func RunSource ¶ added in v0.9.0
RunSource is Run for a script that is text rather than a file: a sample built into the binary, run by `dbc script NAME` without being copied out first. name stands in for the path in errors.
func SyncPlugins ¶ added in v0.13.0
SyncPlugins loads the plugin files in dir when the directory changed since the last load (or nothing was loaded yet, or dir is another directory), and reports whether it did. Cheap when nothing changed: one directory read and a stat per file.
func WrapSnippet ¶ added in v0.13.0
WrapSnippet makes a whole script of a snippet: with a package clause it is returned as it is (and headerLines is 0); without one, "package main" and an import block of the known packages it names go before it, and headerLines says how many lines that added, so a diag's line can be mapped back to the snippet's. A snippet that does not parse gets every known import, and the compile pass says what is wrong.
Types ¶
type Diag ¶ added in v0.9.0
type Diag struct {
Line int `json:"line"`
Col int `json:"col"`
Severity string `json:"severity"` // SevError or SevWarning
Msg string `json:"msg"`
}
Diag is one problem Check found, at a 1-based line and column (column 0 when only the line is known).
func Check ¶ added in v0.9.0
Check finds what is wrong with a script without running it, so an editor can mark errors on their lines as the user types, and `dbc script --check` can gate a scripts repo in CI. It never executes the script: not Run, not init(), not a package-level initializer.
src ─► 1. parse (go/parser) ── syntax errors? ──► those, and stop
│ (the passes below need a tree)
├► 2. signature: package main, func Run(s *sdb.S) error, from the AST
├► 3. lint: m[k], _ = … (yaegi drops the write)
└► 4. compile (yaegi, newInterp + Compile, no Execute)
Why each pass:
- go/parser first, because its positions are exact and it reports up to ten errors; yaegi stops at its first and words it less helpfully.
- Run's signature from the AST, not the interpreter: asking yaegi for main.Run needs Execute first, which runs init() and the package's var initializers — exactly what a check must never do.
- The lint is the one case that has cost real time: yaegi compiles and runs a two-value assignment into a map element and stores nothing (traefik/yaegi#1655). Without types it cannot tell a map from a slice, so it flags both and says so; a slice there is rare.
- yaegi's compile pass (type analysis and control flow, no code run) catches what the parser cannot: an undefined name, a type mismatch, an import a script cannot have. It is the same interpreter Run builds (newInterp), so the two agree on what a script may import. It reports only its first error, and does not catch everything the Go compiler would (an unused variable passes).
Diags come back sorted by position. A clean script is nil.
func CheckPlugin ¶ added in v0.13.0
CheckPlugin finds what is wrong with a plugin file without running it — the plugin file's script.Check, for the web's markers, the TUI's check when $EDITOR exits and `dbc plugins --check`:
- parse syntax errors (and stop)
- shape, from the AST package main; var Plugin = sdb.Plugin{…}; its Name and Kind when written as literals; the funcs that Kind calls, with their signatures
- lint m[k], _ = … (yaegi drops the write)
- compile yaegi's compile pass: undefined names, types
Like Check it never executes the file — not var Plugin's initializer either — so what it can say about the descriptor is what the source spells out literally; the loader, which does run it, has the last word.
type Edit ¶ added in v0.12.0
Edit replaces [From, To) of the script with Text. From == To inserts.
func Rename ¶ added in v0.12.0
Rename is the edits that rename the symbol at byte offset caret of src to name. The error is a sentence for the user: nothing renamable there, the symbol cannot be renamed (Symbol.Fixed), the name is not a Go name, or the renamed script would mean something else.
A snippet (a pipeline's go field) is renamed in as its node runs it, with WrapSnippet's header before it (symbol.go, A SNIPPET); the edits come back in the snippet's own offsets.
type Symbol ¶ added in v0.11.0
type Symbol struct {
Kind string `json:"kind"` // var, const, type, func, method, field, package, label, builtin
Name string `json:"name"`
At Span `json:"at"` // the occurrence under the caret
Def *Span `json:"def"` // nil: declared outside the script
Uses []Span `json:"uses"`
// Fixed says why F2 cannot rename it; "" when it can (rename.go).
Fixed string `json:"fixed,omitempty"`
}
Symbol is what the caret is on. Kind "" means nothing that resolves (a keyword, a literal, white space): the editor has nowhere to go. Def is nil when the declaration is not in the script (a builtin such as len or error, or a member of an imported package); Uses then still lists every occurrence. Uses includes the declaration itself, in buffer order.
func Resolve ¶ added in v0.11.0
Resolve finds the symbol at byte offset caret of src. A caret just past a name (where it rests after typing one) counts as on it.
A script with syntax errors still resolves: go/parser hands back the tree it could build, and the checker binds what is in it. A panic deep in the checker over odd input is a symbol with no kind, never a crash of the server that asked.