Plugins
A plugin brings a format or a framework to archec in one folder. It holds three kinds of declarations:
- a generator adds a code target (
archec gen --target <id>, see generators); - an importer reads a file of another tool into arche-lang
(
archec import <file>); - an exporter writes the model as a file of another tool
(
archec export <main.arche> --format <id>).
plugins/acme/
library.arche library acme "Acme tools" { version "0.1.0"; kind plugin }
plugin.arche its generators, importers and exporters
kv/import.ts
kv/export.ts
cpp/generate.ts
README.md
importer kv "Key-value files" {
script "kv/import.ts"
extensions ".kv"
reads "../.."
}
exporter kv "Key-value files" {
script "kv/export.ts"
extension ".kv"
}
generator acme-cpp "Acme C++" {
script "cpp/generate.ts"
option framework "The runtime" { type string; values acme, stl; default acme }
}
archec import settings.kv -o settings.arche
archec export main.arche --format kv -o settings.kv
archec gen main.arche --target acme-cpp --option framework=stl
archec plugin list main.arche
These are not the Arche app's plugins (plugin records, plugins.yaml):
those run in the app.
Where archec finds plugins#
| Where | Source | Runs its code |
|---|---|---|
plugins/<name>/plugin.arche beside the main file |
the project's own | at once |
a library of kind plugin that the project uses (from the Store, git or a folder) |
library, store |
once approved |
ARCHE_PLUGINS, a path list of plugin folders (or folders of them) |
the user's | at once |
lib/plugins/<name>/ beside archec |
built in | at once |
When two declare the same id, the nearer wins: the project's own
declarations first, then the order of the table. A project needs no
include: uses acme "^1" is enough. A plugin's declarations are read
on their own. Only the commands that run them see them, and a project's
generator x from <a plugin's>.
A built-in plugin's hooks (after c) do not run: what archec ships does not
change every project's files.
archec plugin list [main.arche] lists the plugins, where each comes from,
and what each brings, with their options. It also says what is wrong in a
plugin's own declarations. Without a project, it lists the built-in plugins
and those of ./plugins.
Importers#
archec import <file> picks the importer whose extensions end the file's
name, the longest ending first. A built-in importer keeps its own endings
(.dbc, .sysml, .urdf, …); a plugin's importer takes them only when it is
named: archec import bus.dbc --importer mydbc.
Without --project, archec import sees the plugins of main.arche in the
current folder, else only the built-in ones and those of ./plugins. A
library's plugin needs its project: --project main.arche.
A script#
export default function importFile(input, ctx) {
// input: { api: 1, importer, file, name, text, options }
const names = [...input.text.matchAll(/identifier="(\w+)"/g)].map((m) => m[1]);
if (!names.length) ctx.warn({ line: 1 }, 'no identifier');
return { files: { 'main.arche': names.map((n) => `component ${n}`).join('\n') + '\n' } };
}
export function importFile and module.exports = function … work too. It
returns { files, notes, warnings, errors }:
files:{ "path": "text" }, or[{ path, text }]. Paths are relative to the output, and never leave it.notes: plain strings.warnings,errors: strings, or{ where, message }.whereis a line of the imported file ({ line: 12 }) or of another one ({ file, line }).
ctx gives:
options: the importer's options, with--option k=vfor a run;readFile(rel),exists(rel),listFiles(rel): files beside the imported file, relative to its folder;readOwn(rel): a file of the plugin's folder (its tables, its library models);render(template, data),filters: the template language;note(msg),warn(where, msg),error(where, msg).
What a script may read#
A script runs in the generators' sandbox: no process, no network, no
module but the plugin's own (import … from './core/view'). It reads, and only reads:
- the imported file's folder and what is under it;
- the plugin's own folder;
- the folders the importer names with
reads, relative to the imported file's folder. A format whose files name others two folders up saysreads "../.."; - the folders given with
--allow-read <dir>for one run.
A read outside them, or through a link that leads out, is an error.
A command#
importer kv "Key-value files" { command "python3 kv.py"; extensions ".kv" }
The command runs in the plugin's folder. It reads the input as JSON on its
stdin — { "api": 1, "importer", "file", "name", "text", "options" } — and
writes the result as JSON on its stdout. What it writes on stderr is shown as
notes. A command is not sandboxed: it is code, approved like a script.
What archec does with the result#
- No
-o: one file goes to stdout; several are an error. -o x.arche: the one file.-o folder: the files, under it.
Then archec checks what it wrote, as archec build would: the main.arche
written, else the first .arche. An error there fails the import (exit 1).
Exporters#
An exporter is a generator whose files are another tool's: it reads the same
generator model (version 1), and comes
as templates, a script (function generate(model, ctx)) or a command. Its
options, typed options, from, needs deployment and errors at the
elements' at work as a generator's.
archec export <main.arche> --format <id> runs it. Without --format, -o
picks the exporter whose extension ends its name; -o model.json stays the
model's JSON.
- One file:
-ois that file, whatever the exporter calls it. Without-o, it goes to stdout. - Several files:
-ois a folder.
Plugins as packages#
A Store package of kind plugin is a plugin: its library.arche, its
plugin.arche, and the files they need. Scripts are TypeScript (.ts):
a package holds no .js. Templates may end in .tpl.
archec store check ./acme # kind plugin needs a plugin.arche
archec add main.arche acme/acme@^0.1
archec plugin approve main.arche acme
archec store seed publishes the built-in plugins as arche/<name>.
Approval#
A library's templates run as they are. Its scripts and commands run on the machine of whoever builds the project, so they run only once approved:
archec plugin approve main.arche acme # lists its code, then records it
archec plugin approve main.arche acme --revoke
Each script or command is recorded in arche.lock at the library's
fingerprint: acme/importer:kv, acme/exporter:kv, and
acme/acme-cpp for a generator (archec generator approve approves
one generator). When the library changes, it is refused until it is approved
again. The project's own plugins, the user's and the built-in ones need no
approval.
What is checked#
The codes are the generators': generator and generator-option.
- An importer is a
scriptor acommand, not templates. - An importer without
extensionsruns only with--importer(a warning). - An importer or an exporter has no
after, and an importer nobuiltins. - Options are held as a generator's.