Externals
use external "Units.ssp" gives a file another project's export, checked by shot check and run by shot run.
use external "Station.ssp"use external "Units.ssp"kind GenericUse external
Station.ssp uses Units.ssp, the Generic project beside it:
Units/Types.shot
doc { A temperature in degrees Celsius }
public type Celsius = numberUnits/Units.shot
types script.Parent.Types
doc { Converts temperatures and rounds numbers }
module Units = {
doc { The Celsius temperature for a Fahrenheit one }
function CelsiusOf(fahrenheit : number) : Celsius
return (fahrenheit - 32) * 5 / 9
end
doc { x rounded to the given number of decimal places }
function Round(x : number, places : number) : number
local scale = 10 ^ places
return math.floor(x * scale + 0.5) / scale
end
}Station/Station.shot
types script.Parent.Types
use FileService
use JsonService
use external "Units.ssp"
doc { Temperature readings in Celsius, kept in a JSON file }
class Station = {
doc { The readings, oldest first }
public Readings : {Celsius}
doc { Adds a reading taken in Fahrenheit }
public AddFahrenheit(fahrenheit : number)
table.insert(self.Readings, Units.Round(Units.CelsiusOf(fahrenheit), 1))
end
...
}use external "<path>"goes whereusegoes, above a.shotfile's declaration.- The local is named after the export, Units;
as Unames it U. - Only the export is reachable (One-file projects, MISTAKES AND THEIR ERRORS), and it can't be a program (THE ERRORS).
shot checktypes every use.Units.CelsiusOf("hot")gave:
Station.ssp/Station/Station.shot:23:59 TypeError: Expected this to be 'number', but got 'string'At run time
shot run runs used code too: Forecast runs Station, which runs Units (Overview, THE EXAMPLES). With Units.CelsiusOf("hot") in Station, Forecast still checked clean; its run stopped in Units:
error: Units.ssp/Units/Units.shot:8: attempt to perform arithmetic (sub) on string and number
at Units.ssp/Units/Units.shot:8 function CelsiusOf
at Station.ssp/Station/Station.shot:23 function AddFahrenheit
at Main/Main.shot:9- A run checks no used project: check each one.
- Relative paths in used code start at the running project's folder.
- A run reads used projects' saved files, written a moment after each change:
shot saveone before running or checking its users at once. - A run finds used projects by the header's external lines (THE RECORDED INTERFACE). Forecast without one:
error: Main/Main.shot:3: require("@Station"): Forecast.ssp has no external of that name (a string require is @<Alias> from the project's header, or @shotsystem/<Service>)
at Main/Main.shot:3Other run errors: Running a project, WHAT STOPS A RUN.
Checked paths
- From the folder of the using project's file:
"../libs/Units.ssp"is inlibs, beside that folder. - Quoted, forward slashes, ending
.ssp(or an older.shotsystem).
The alias
Each used project gets an alias in the header: its file name, numbered on a clash. Using "Units.ssp" and "../libs/Units.ssp" as LibUnits gave:
recorded external "Units.ssp" as Units interface 62f942db347c in .shotsystem: check reports any later change to that interface
recorded external "../libs/Units.ssp" as Units2 interface 62f942db347c in .shotsystem: check reports any later change to that interfaceas only names the local; the header keeps as Units. Plain Luau requires the alias (PLAIN LUAU).
Import external
Station/Types.shot
import external "Units.ssp"gives every file of Station's folder the public types of Units, like {Celsius} (Types). Only in a Types.shot:
Demo.ssp/Main.shot:1 import external goes in a system's Types.shot: it brings that project's public types into the system's types (use external "Units.ssp" gives a file the export itself)A name clash with the system's own types is an error:
Station.ssp/Station/Types.shot:1 import external "Units.ssp" brings the type Celsius, and Station/Types.shot:3 declares Celsius in this system: a system's types are one flat set, so rename one of themSo is a name two imports both bring (Units2.ssp copies Units.ssp):
Station.ssp/Station/Types.shot:2 | import external "Units2.ssp" brings the type Celsius, and import external "Units.ssp" on line 1 brings Celsius too: a system's types are one flat set, so import one of them only |
Station.ssp/Station/Types.shot:2 | import external "Units2.ssp" brings the type Units, and import external "Units.ssp" on line 1 brings Units too: a system's types are one flat set, so import one of them only |
The kinds rule
Generic uses Generic; System uses System and Generic; Roblox uses Roblox and Generic. Anything else is an error at its line:
Units.ssp/Units/Units.shot:3 "Station.ssp" is a System project, and a Generic project can only use Generic projects
Units.ssp/Units/Units.shot:4 "Demo.ssp" is a Roblox project, and a Generic project can only use Generic projects
Station.ssp/Station/Station.shot:6 "Demo.ssp" is a Roblox project, and a System project can only use System and Generic projects
Demo.ssp/Demo/Demo.shot:3 "Station.ssp" is a System project, and a Roblox project can only use Roblox and Generic projectsshot external accept doesn't lift the rule. Put shared code in a Generic project.
The recorded interface
The first use external line records the project in the header:
created Station/Station.shot (52 lines)
recorded external "Units.ssp" as Units interface 62f942db347c in .shotsystem: check reports any later change to that interfaceImported from a folder without that line:
Station.ssp/Station/Station.shot:5 use external "Units.ssp": the .shotsystem header has no line for that project; shot external accept "Units.ssp" adds it with its interface
Station.ssp/Station/Types.shot:1 import external "Units.ssp": the .shotsystem header has no line for that project; shot external accept "Units.ssp" adds it with its interfaceshot external accept "Units.ssp" --project Station.ssp records it and checks:
accepted "Units.ssp": interface 62f942db347c is recorded in .shotsystem as Units
check:
0 errors (2 files checked, 0.5 s)The header then holds:
external "Units.ssp" as Units interface 62f942db347c
.CelsiusOf(fahrenheit : number) -> Celsius
.Round(x : number, places : number) -> number
module Units
type Celsius = number- Under it: the export's interface as
shot apiprints it, sorted, without bodies, docs or internal members. 62f942db347cis the first 12 hex digits of their SHA-256.- shot writes these lines; leave them alone.
Unchanged, accept writes nothing:
"Units.ssp": the recorded interface 62f942db347c is the current one; nothing to acceptWhen a used project changes
A new body or doc keeps the interface. A new signature is an error in each direct user, at each line naming it:
Station.ssp/Station/Station.shot:5 use external "Units.ssp": its interface changed since it was recorded in .shotsystem (interface 62f942db347c, now 5cb27f16afa9):
- .Round(x : number, places : number) -> number
+ .Round(x : number, places : number?) -> number
once this project's code fits it, shot external accept "Units.ssp" records the new interfaceshot map says so too:
external Units: "Units.ssp", interface 62f942db347c, now 5cb27f16afa9: it changed (shot check shows how; shot external accept "Units.ssp" records it)Fix the user's code, then accept:
accepted "Units.ssp": interface 5cb27f16afa9 is recorded in .shotsystem (was 62f942db347c)
- .Round(x : number, places : number) -> number
+ .Round(x : number, places : number?) -> number
check:
0 errors (2 files checked, 0.5 s)Forecast, using only Station, stayed clean and kept running.
A loop
A project can't use one that uses it back. Each project in or using the loop gets the error:
Station.ssp/Station/Station.shot:6 external loop: Station.ssp -> Demo.ssp -> Station.ssp: a project can't use one that uses it back
Demo.ssp/Demo/Demo.shot:3 external loop: Demo.ssp -> Station.ssp -> Demo.ssp: a project can't use one that uses it back
Outer.ssp/Main.shot:1 external loop: Station.ssp -> Demo.ssp -> Station.ssp: a project can't use one that uses it backRuns aren't refused: in Outer's, Station was nil. Move shared code into a third project.
The errors
Demo.ssp/Main.shot:1 | use external "Units": the path names a .ssp project file (.shotsystem works too), like "../Signals.ssp" |
Demo.ssp/Main.shot:1 | use external "..\Units.ssp": write the path with forward slashes, like "../Signals.ssp" |
Demo.ssp/Main.shot:1 | use external needs the project's path in quotes, with forward slashes: use external "Signals.ssp" or use external "Signals.ssp" as Name |
Demo.ssp/Main.shot:1 | use external "Demo.ssp": that is this project itself, and a project can't use itself |
Demo.ssp/Main.shot:1 | "Forecast.ssp" exports the script Main.Main, and a script can't be used from another project: only a module, a class or a func can |
A missing project: use external "Missing.ssp": no project there, then the full path it tried.
Plain Luau
A .luau file requires a used project by its alias:
Main.luau
--!strict
local Units = require("@Units")
print(Units.Round(Units.CelsiusOf(212), 1))- The alias needs a
.shotfile naming the project: here Demo's Types.shot,import external "Units.ssp". shot run Demo.sspprinted100.shot checktypes it.Units.CelsiusOf("hot")gave:
Demo.ssp/Main.luau:4:35 TypeError: Expected this to be 'number', but got 'string'With no .shot file naming Units, check reports the require, though it runs:
Demo.ssp/Main.luau:2:15 Unknown require "@Units": a System project's services are EncodingService, FileService, HttpService, JsonService, PageService, ProcessService, ProgramService, RunService and TimeService, and its built-in modules Mop, QuickSignal and QuickValue (local FileService = require("@shotsystem/FileService")); its own modules come by path (require(script.Parent.Mop)), and another project by its alias (require("@Log")) once a .shot file of the project names it with use external "Log.ssp"