scriptflow

package
v1.138.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 29, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

Documentation

Overview

Package scriptflow derives a managed script's flow graph from its source (#1906): what the script reads, what it writes, what it produces, and which results feed which calls. The script page draws it on its Flow tab.

Nobody authors the graph. It is read from the parse tree, so a new version of a script has a new graph with nobody updating it, and the graph cannot disagree with the code. That is possible because the dialect is small (internal/platform/scriptdialect): no imports, no classes, no exceptions and no while, so every loop is a for over a value. Recursion is refused by the interpreter when a recursive call is made, so the walk expands a user function at every place it is called except inside its own expansion, where a run would fail.

The rules the graph is built by:

  • Every platform.* call is a step, except platform.progress.
  • Edges follow values. A value carries the set of steps (and run.state) it was computed from, and a step's inputs are the origins of its arguments. The user functions a value passed through on the way are recorded on the edge.
  • A user function is expanded at each call site, so a helper called for three purposes is three steps, each rendered with its caller's arguments.
  • A function holding steps is one box per enclosing box, captioned with its author's comment. A function whose only effect is one platform call is not a box: it is folded into the step and named on it.
  • Names are rendered from the source: literals and module constants by value, string building with each computed part as {its source}.
  • An edge a longer path already implies is removed.
  • Parameters are not drawn. Each is listed with the steps its value reaches.
  • A connection, destination, tool, table or target the source computes marks its step computed; the graph never names a guessed one.

Index

Constants

View Source
const (
	RoleInput  = "input"
	RoleReads  = "reads"
	RoleWrites = "writes"
	RoleOutput = "output"
)

Roles a step plays, which the diagram colors it by.

View Source
const (
	KindQuery       = "query"
	KindAPI         = "api"
	KindTool        = "tool"
	KindWrite       = "write"
	KindExport      = "export"
	KindTable       = "table"
	KindPublishData = "publish_data"
	KindSaveState   = "save_state"
	KindNotify      = "notify"
	KindPublish     = "publish"
	KindResult      = "result"
	KindState       = "state"
)

Kinds of step, which name what the step is.

View Source
const (
	EdgeData  = "data"
	EdgeState = "state"
)

Edge kinds: a value passed from one step to the next, or this run saving state for the next run.

View Source
const (
	ChangeAdded   = "added"
	ChangeChanged = "changed"
	ChangeRemoved = "removed"
)

Change marks on a compared graph's nodes (#1908).

View Source
const (
	StructStart  = "start"
	StructEnd    = "end"
	StructStop   = "stop"
	StructReturn = "return"
	StructIf     = "if"
	StructStep   = "step"
)

Kinds of structure node.

View Source
const (
	BoxLoop     = "loop"
	BoxFunction = "function"
)

Kinds of structure box.

View Source
const (
	ArmYes = "yes"
	ArmNo  = "no"
)

Arm labels on the edges out of an if.

View Source
const StateNodeID = "state"

StateNodeID is the id of the node standing for run.state.

Variables

This section is empty.

Functions

This section is empty.

Types

type Edge

type Edge struct {
	From string `json:"from"`
	To   string `json:"to"`
	// Via names the functions that reshaped the value on the way.
	Via  []string `json:"via"`
	Kind string   `json:"kind" example:"data"`
	// Change is "removed" on an edge of a compared graph that only the older
	// version had.
	Change string `json:"change,omitempty"`
}

Edge is one value passed from a step to another, or the state saved for the next run.

type FuncSpan added in v1.138.1

type FuncSpan struct {
	Name    string `json:"name"`
	Line    int    `json:"line"`
	EndLine int    `json:"end_line"`
}

FuncSpan is one def and the lines it covers.

type Function added in v1.138.1

type Function struct {
	Name string `json:"name" example:"last_week"`
	// Params is each parameter as the source writes it, a default included.
	Params []string `json:"params" example:"today,days=7"`
	// Doc is the first sentence of the function's docstring.
	Doc  string `json:"doc,omitempty" example:"The seven days before today."`
	Line int    `json:"line" example:"12"`
}

Function is one function a library defines at its top level.

type Graph

type Graph struct {
	// OK is false when the source does not parse or resolve. Findings then
	// says why, and the diagram is empty.
	OK       bool                `json:"ok"`
	Findings []scriptrun.Finding `json:"findings"`
	Nodes    []Node              `json:"nodes"`
	Edges    []Edge              `json:"edges"`
	Groups   []Group             `json:"groups"`
	Params   []Param             `json:"params"`
	// Lines is the source's line count, for the reader's scale.
	Lines int `json:"lines" example:"136"`
	// Truncated is true when the script expands into more steps than one
	// diagram draws; the graph holds the first ones.
	Truncated bool `json:"truncated"`
	// Structure is the script drawn in the order it runs (#1972), the Flow
	// tab's default view.
	Structure Structure `json:"structure"`
	// ComparedWith is the older version this graph is compared against
	// (#1908), zero when it is not a comparison.
	ComparedWith int `json:"compared_with,omitempty"`
	// Library is present when the script is a library (#1970): the functions
	// it defines for another script to load. Derive does not set it: whether
	// a script is a library is recorded when it is created, and a source with
	// no main() saved before libraries existed is not one, so the caller that
	// holds the script attaches it with LibraryOf.
	Library *Library `json:"library,omitempty"`
}

Graph is one script version's flow.

func Derive

func Derive(source string) Graph

Derive returns the flow graph of one source. The graph depends on the source alone, so it is computed once per distinct source and served from memory after that.

type Group

type Group struct {
	ID      string `json:"id" example:"/load_orders"`
	Label   string `json:"label" example:"load_orders(day)"`
	Caption string `json:"caption,omitempty"`
	// Parent is the id of the enclosing box, empty at the top level.
	Parent     string `json:"parent,omitempty"`
	DefLine    int    `json:"def_line" example:"12"`
	CalledFrom []int  `json:"called_from"`
}

Group is a function box.

type Library added in v1.138.1

type Library struct {
	// Functions is every function a load can name, in source order.
	Functions []Function `json:"functions"`
	// Load is the statement that loads every one of them from this version,
	// empty when there is none to load.
	Load string `json:"load,omitempty" example:"load(\"lib:date-windows@2\", \"last_week\")"`
}

Library is what a library defines for another script to load (#1970). A library makes no platform calls, so its diagram is empty by definition; what a reader of one needs is the functions it offers and how to load them.

func LibraryOf added in v1.138.1

func LibraryOf(ref scriptlib.Ref, source string) *Library

LibraryOf is what one version of a library offers a load: the functions its source defines and the statement that loads them from that version. A source that does not parse offers none; its graph already says why.

type Node

type Node struct {
	ID   string `json:"id" example:"op:3"`
	Role string `json:"role" example:"reads"`
	Kind string `json:"kind" example:"query"`
	// Title is the action and where it goes; Subtitle the operation, name or
	// path; Purpose the purpose sentence the author wrote on the call.
	Title    string `json:"title" example:"Query warehouse"`
	Subtitle string `json:"subtitle,omitempty"`
	Purpose  string `json:"purpose,omitempty"`
	// Detail is the tables, paths or keys the step touches.
	Detail []string `json:"detail"`
	// Computed is true when what the step reaches is only known at run time;
	// the computed part is written as {its source} in the text above.
	Computed bool `json:"computed"`
	// Group is the id of the function box the step is drawn in, empty at the
	// top level.
	Group string `json:"group,omitempty"`
	// Line and EndLine are the platform call's lines. Site is the line the
	// folded wrapper named in Wrapper is called from.
	Line    int    `json:"line" example:"42"`
	EndLine int    `json:"end_line" example:"44"`
	Site    int    `json:"site,omitempty"`
	Wrapper string `json:"wrapper,omitempty"`
	// Loops are the for statements the step repeats in, outermost first.
	Loops []string `json:"loops"`
	// CallSite is the position of every call on the stack that makes this
	// step's call, outermost first, as "line:col": what a run records on the
	// step's audited calls and outputs (#1907), so a run is drawn on the card
	// that made each call.
	CallSite []string `json:"call_site,omitempty"`
	// Change and Was mark a node of a compared graph (#1908): added, changed
	// (with what it said before) or removed (carried over from the older
	// version).
	Change string `json:"change,omitempty"`
	Was    *Was   `json:"was,omitempty"`
}

Node is one step, or the run.state input.

type Param

type Param struct {
	Name string `json:"name" example:"day"`
	// Line is where the source first reads it.
	Line int `json:"line" example:"3"`
	// Reaches lists the steps whose arguments the parameter's value reaches.
	Reaches []string `json:"reaches"`
	// Decides is true when the value is read by a condition, so it decides
	// which steps run.
	Decides bool `json:"decides"`
}

Param is one run parameter the source reads, with the steps its value reaches.

type StructBox added in v1.138.1

type StructBox struct {
	ID   string `json:"id" example:"b:2"`
	Kind string `json:"kind" example:"loop"`
	// Label is a loop's header or a function's signature; Caption the
	// function's first comment sentence.
	Label   string `json:"label"`
	Caption string `json:"caption,omitempty"`
	Parent  string `json:"parent,omitempty"`
	Line    int    `json:"line" example:"12"`
	// CallSite is where this expansion of a function was called from, the
	// prefix every call made inside it carries.
	CallSite []string `json:"call_site,omitempty"`
}

StructBox is a loop or a helper function around the nodes it runs.

type StructEdge added in v1.138.1

type StructEdge struct {
	From  string `json:"from"`
	To    string `json:"to"`
	Label string `json:"label,omitempty" example:"yes"`
}

StructEdge is "runs next". Label is yes or no on an if's arms.

type StructNode added in v1.138.1

type StructNode struct {
	ID   string `json:"id" example:"s:3"`
	Kind string `json:"kind" example:"if"`
	// Label is the if's condition and the fail()'s message, as the source
	// writes them.
	Label string `json:"label,omitempty" example:"len(rows) < 1000"`
	// Step is the value graph's node for a platform call.
	Step string `json:"step,omitempty" example:"op:3"`
	// Box is the loop or function box the node is drawn in.
	Box  string `json:"box,omitempty"`
	Line int    `json:"line" example:"42"`
	// CallSite is a platform call's or a fail()'s position on the stack, as
	// a run records it (#1907).
	CallSite []string `json:"call_site,omitempty"`
}

StructNode is one node of the structure.

type Structure added in v1.138.1

type Structure struct {
	Nodes []StructNode `json:"nodes"`
	Edges []StructEdge `json:"edges"`
	Boxes []StructBox  `json:"boxes"`
	// Functions is every def with its span, so a call site's frames can be
	// named by the function each line is in.
	Functions []FuncSpan `json:"functions"`
	// Truncated is true when the script expands into more nodes than one
	// diagram draws.
	Truncated bool `json:"truncated"`
}

Structure is the script drawn in the order it runs (#1972): one Start, the statements that matter in sequence, a decision for every if that holds one, a box for every loop and helper function that holds one, and an exit for the normal end, every fail() and every early return from main(). It is the Flow tab's default view; the value graph (Graph.Nodes and Graph.Edges) is the Calls view.

The graph is acyclic by construction: a loop is a box around its body, and run.state is read at the top and saved at the bottom rather than drawn as an edge back. A platform call is a node whose Step names the value graph's card for the same call, so a run's calls, which are attributed to cards by call site, land on the same node in both views.

type Was

type Was struct {
	Title    string   `json:"title"`
	Subtitle string   `json:"subtitle,omitempty"`
	Purpose  string   `json:"purpose,omitempty"`
	Detail   []string `json:"detail"`
}

Was is what a changed node said in the older version.

Directories

Path Synopsis
Package flowcompare compares two versions of a script's flow graph (#1908): the newer version's diagram marked with what it reads, writes and produces that the older did not, which is what a reviewer approving a change asks first.
Package flowcompare compares two versions of a script's flow graph (#1908): the newer version's diagram marked with what it reads, writes and produces that the older did not, which is what a reviewer approving a change asks first.
Package flowrun draws one run of a script on the flow graph of the version it executed (#1907): which cards the run reached, the audited calls each made and how long they took, what each wrote, and the card the run failed at.
Package flowrun draws one run of a script on the flow graph of the version it executed (#1907): which cards the run reached, the audited calls each made and how long they took, what each wrote, and the card the run failed at.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL