Перейти к содержимому

Приложение D: Шпаргалка

Для случая, когда вы знаете, чего хотите, и вам нужен синтаксис. Каждая строка — полная конструкция; главы и другие приложения связаны для полного контекста.

Простой module — строительный блок по умолчанию; конкретный тип (service, …) — это сахар, к которому прибегают, когда он окупается.

module Orders { rest_create createOrder } // plain module — the default
service Orders { // a typed module (sugar)
aspect team: "Commerce"
rest_create createOrder
} // type + name + body
service #k7f2 Orders { ... } // with stable ID (random, meaningless)
service AuthService in Platform { ... } // attach to a parent declared elsewhere
service Notifications // empty body, no braces

См. гл. 4.

Простой interface — соединение по умолчанию; тип на уровне протокола (rest_create, kafka, …) — это сахар. Называйте интерфейсы по глаголу/ресурсу протокола.

interface authorize // plain interface — the default
rest_create authorize // typed leaf (sugar)
rest_create authorize { // with body
"Description"
timeout: "5s"
}
kafka paymentEvents // async event interface (no subscribes:)
// an event is an async interface reached by a normal `>` process edge — the edge IS the subscription

См. гл. 5.

surface ordersResource { // generic surface
base: "/orders"
rest_create createOrder
}
resource ordersResource { base: "/orders" } // user-defined surface type
surface outer { surface inner { ... } } // nested surfaces

resource — пользовательский тип, который команды определяют через type surface resource { ... }; стандартная библиотека поставляет только обобщённый surface. См. гл. 6 и гл. 16.

process Checkout {
order = Customer > Orders.createOrder // step, with result binding
Orders > Payments.authorize(order) // step with arg list
| > Ledger.record // fan: owner = previous line's HEAD (Orders)
\ > Audit.log // snake: owner = previous line's TAIL (Ledger)
"wait for fraud review" // bare note step (no edge)
Orders "ops team double-checks the total" // actor-anchored note
Payments if "stripe-customer" { // exclusive conditional (free-form head)
Payments > Stripe.charge
} else {
Payments > PayPal.charge
}
Orders select "payment method" { // multi-way, inclusive (every match runs)
stripe: Payments > Ledger.record
applepay: Payments > Ledger.record
}
Shipping parallel race { // concurrent branches; race = first wins
branch: Shipping > Notifications.sendEmail
branch: Shipping > Notifications.sendSMS
}
Orders try { // error path (guard, continue forward)
Orders > Payments.authorize
} catch "declined" {
Orders > Notifications.sendEmail
}
Orders each item in order.items: Orders > Inventory.reserve(item) // iteration (one-liner body)
Order reversible { // saga: completed steps roll back
Order > Inventory.reserve unwind Order > Inventory.release // each step compensates itself
Order > Payments.charge unwind Order > Payments.refund
}
do NotifyCustomer(order) // splice subprocess (ownerless)
finish "checkout complete" // terminate: success
}
process Checkout in Orders { ... } // attach to a module
subprocess NotifyCustomer(arg) { Orders > Ledger.record } // reusable helper (args intent-only)

Анонимность — минимальный черновик (каждая анонимная часть — это TODO):

module Orders {
> Payments // bare step: anon process, implicit caller = Orders
> Cart.add // name the interface; caller still implicit
}
A > B. // trailing dot: B is a module, interface unspecified (TODO)
A > B.x > C.y // chain (ordered): desugars to A > B.x ; B > C.y

Голые шаги неупорядочены (порядок даёт только обёртка process { }); цепочка — это один упорядоченный анонимный процесс; вызываемый-модуль синтезирует анонимный интерфейс. Ссылайтесь на модули, интерфейсы и подпроцессы, которых ещё нет, — компилятор синтезирует пунктирную заглушку и отслеживает каждый пробел как TODO (черновое проектирование «процесс сначала»), вместо того чтобы выдавать ошибку. archlang validate --complete гейтит модель с нулём TODO. См. гл. 7.

view PaymentsLandscape {
"Description — first line is the header zone"
show @@domain:"Payments" or @@security.zone:"PCI" // union selectors; @@ = aspect axis
show in Payments or in Gateway // subtree membership
hide database // subtract after the show-union
group by @@team // cluster by an aspect getter (by VALUE)
group by in Payments // by CONTAINMENT — one frame per container
style * { color: colorize(@@security.zone) } // colour; explicit cast feeds the legend
style violating PciIsolation { color: crimson } // policy findings drive visuals
}
// one representation clause replaces the board:
// table { column @name; sort by @name }
// matrix { axis @@team; order by cluster } — or `rows`/`cols` for a rectangular one
// grid { rows @@team; cols @@security.zone; color @kind } — cross-tab, cells list modules
// flow <Proc> [sequence | bpmn] — `bpmn` opens { lane by @@team | pool by @@team | … }
// no layout clause — layout is the solver's; pin per node with `style X { pin <x>, <y> }`.

См. гл. 8.

История — направляемый обход проекции; не представление, поэтому сочетается с любым из них, и инертна, пока просмотрщик не открыт с ?present=1:

view PaymentsStory {
show @@team:"payments"
story { // at most FIVE chapters (hard grammar rule)
chapter "Order comes in" {
"Leading string is the chapter's note — optional, and it must come first."
Web, Checkout, Orders // any node selector; written order IS the narration
}
chapter "Money moves" {
Payments, Bank, Ledger
}
}
}
// beats, the relation each crosses, the sentence, the camera window and the
// chapter handoff are all DERIVED. Doesn't compose with `focus`; one per view.

См. гл. 36.

Поля = структурированные данные. Аспекты = связи между плоскостями (key: "x" — классификация, key: X — членство). Описания = неструктурированная проза.

service Orders {
region: euWest // identifier value (a plain field)
repo.url: "https://..." // dotted key + string (structured property)
version: 2 // number
enabled: true // boolean
"Description goes here as a bare string."
aspect {
domain: "Orders" // string value = classification (a (key, value) tag)
broker: KafkaBroker // bare module ref = membership (KafkaBroker becomes a place)
}
}

См. гл. 9.

"Plain markdown plus archlang extensions.
**bold**, *italic*, ~~strike~~, `code`, [link](https://...), tables, lists.
[[#stable_id]] / [[Name]] link to a declaration
[[@@key]] / [[@@key:value]] link to an aspect plane / a specific classification
[[Doc#section]] link to a heading inside an .md document
@@aspectPath substitute an aspect value from THIS node (descriptions only)
[[ref]]@@aspectPath read an aspect value on a REFERENCED node (works in .md too)"

Каждый элемент также получает автоматические обратные ссылки («упоминается в»). Файлы .md рендерятся той же флавор-разметкой и являются первоклассной поверхностью архпространства. См. гл. 10 и гл. 10a.

package: acme.shop // package root (opaque unit)
version: "1.0.0"
widgets: "./widgets.js"
repo: "https://github.com/acme/shop" // evidence pin — the repo `sources:` is checked against
commit: "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0" // required whenever `repo:` is set
dependencies {
acme.shared: "../shared"
}
use database, frontend from arch.backend // explicit, pick-and-choose (never use *)
use relational_db as managed_db from acme.shared // local rename
export use payments_provider from acme.payments // re-export

Вложенный манифест пространства несёт name: вместо package::

name: acme.shop.loans // a space within the package

См. гл. 12.

Привязки к исходному коду — обычное поле, называющее код, который свидетельствует о модуле; проверяется по закреплению repo:/commit: пакета:

module Checkout {
sources: "src/checkout/index.ts:12-88", "src/tax.ts:5-40", "src/whole-file.ts"
}
// entries are repo-root-relative; ranges are 1-based and INCLUSIVE.
// verdicts: verified | broken | unverified — `unverified` is never a pass and draws no badge.

См. гл. 37.

Идентификаторы бессмысленны и постоянны — случайные, никогда не кодируют домен, никогда не меняются (пусть их выдаёт инструментарий).

service #q8m3 Payments { ... } // module ID
type #b9k1 module service { ... } // type ID
process #x4t7 Checkout { ... } // process ID
view #h2w5 Landscape { ... } // view ID
// Surfaces and interfaces do NOT carry IDs.

См. гл. 13.

Простые модули/интерфейсы — вариант по умолчанию; определяйте пользовательский тип только тогда, когда нужно ввести подтип, прикрепить виджеты, добавить пользовательские поля/требования или утвердить тип.

type module service {
required cascade version // mandatory cascading blank field
required aspect domain // mandatory blank aspect
component metrics { rest_create emit } // pre-filled sub-declaration
required database PrimaryStore // mandatory blank sub-declaration
cascade widget: arch-service // default cascading field
append base // append-mode field (path/list/object compose)
}
type service paymentsService { version: "2.1" } // subtype
export type service internal_service { ... } // visible to importers

См. гл. 15 и гл. 16.

// Two and only two ways to address an inherited `required` blank:
field: value // fulfill
drop field // remove entirely

См. гл. 17.

Режимы распространения (задаются на типе)

Заголовок раздела «Режимы распространения (задаются на типе)»
МодификаторПоведение
(нет)локальноОстаётся там, где задано, не растекается
cascadeРастекается к потомкам; переопределение на ходу
cascade *Объявляет корень каскад-группы — подполя под этим путём участвуют в той же группе; замена корня сбрасывает группу; переопределение листа его сохраняет
appendРастекается и композируется (пути конкатенируются, списки добавляются, объекты сливаются)

Каскад-группы позволяют связать родственные подполя (например, widget, widget.icon, widget.color) так, что замена корневого тега автоматически очищает унаследованные подполя — без церемонии drop для каждого листа:

type module service {
cascade * widget: arch-module {
icon: service
color: info
}
}
type service custom {
widget: my-element // drops icon, color
}
type service tweaked {
widget.color: green // keeps icon
}

Аспекты всегда каскадируют с семантикой переопределения; модификатор на аспектах не нужен (и не разрешён). См. гл. 18.

Уточнение / override / drop (единообразно на уровне типа и экземпляра)

Заголовок раздела «Уточнение / override / drop (единообразно на уровне типа и экземпляра)»
// Refine — same type or subtype, merges:
component metrics { rest_create emitV2 }
// Override — switch to non-subtype type, requires keyword:
override database metrics { db_read read }
// Drop — remove entirely:
drop metrics
drop metrics.emit // remove a child

Набор операций против унаследованного required пустого слота:

ЦельСинтаксис
Уточнить до типа-подтипа, слот пустойrequired <subtype> Name
Уточнить до типа-подтипа, заполнить<subtype> Name { ... }
Переключить на тип не-подтип, слот пустойoverride required <new-type> Name
Переключить на тип не-подтип, заполнитьoverride <new-type> Name { ... }
Заполнить, сохраняя унаследованный типName: value или Name { ... }
Удалить полностьюdrop Name

См. гл. 19.

widget: arch-service // custom-element form
widget.icon: server // widget prop
widget.accent: accent
widget: "<div class='card'>{{name}}</div>" // inline template form
widget: """<archui-card>{{name}}</archui-card>""" // triple-quoted, raw

См. гл. 20.

Окно терминала
archlang validate <path> # validate; exit non-zero on errors
archlang validate --watch <path>
archlang validate --complete <path> # fail (exit 3) if any TODO remains
archlang info <path> # summarize a package
archlang check <path> # validate + policy-check + format --check + evidence
archlang check <path> --against=main # + change-gate dry run vs a git ref
archlang format <file.arch> # canonical formatting (whitespace, indent, ID minting)
archlang format --check # exit non-zero if format would change anything
archlang format --diff # print what would change
archlang set <path> <target> <field> <value> [--aspect] # headless field/aspect write
archlang set <path> <target> <text> --description # headless description write
archlang policy-check <path> # evaluate policies; error/warning/advisory findings
archlang evidence <path> [--repo=<path>] # check `sources:` bindings; exit 1 only on BROKEN
archlang export json <path> [-o <file>] # dump the resolved model as JSON
archlang export html <path> -o <file> # one self-contained HTML file, opens offline
archlang render <path> --out=<f.svg|f.png> [--view=board|bpmn|flow|sequence] [--process=<name>]
# headless diagram export (PNG via bundled resvg)
archlang serve <path> [--port=<n>] [--web-root=<path>] # HTTP API + optional web UI
archlang lsp # language server on stdio
archlang conform <path> --source=jaeger|tempo --endpoint=<url> # check telemetry vs the model

См. гл. 21.

<archlang-viewer
src="./diagram.arch"
style="width: 100%; height: 480px"></archlang-viewer>

Размеры задаются через CSS (style, class); элемент не принимает атрибуты width/height. См. гл. 23.

my-project/
├── package.archspace # manifest (required for non-anonymous package)
├── widgets.js # custom-element registrations (optional)
├── types.arch # type declarations
├── orders.arch # instance declarations
└── packages/shared/ # nested package (its own boundary)
├── package.archspace
└── ...