-
-
Notifications
You must be signed in to change notification settings - Fork 419
Writing Algorithms
Specifications define normative behavior through algorithms — numbered step sequences that unambiguously describe what a user agent must do. ReSpec provides markup support for algorithm authoring.
<section data-dfn-for="Widget">
<h2>The <code>activate()</code> method</h2>
<pre class="idl">
interface Widget {
undefined activate(optional WidgetOptions options = {});
};
</pre>
<p>The <dfn>activate(options)</dfn> method steps are:</p>
<ol class="algorithm">
<li>If [=this=]'s [=Widget/active flag=] is true, return.</li>
<li>Let |opts:WidgetOptions| be the result of [=converting=] |options|.</li>
<li>Set [=this=]'s [=Widget/active flag=] to true.</li>
<li>[=Fire an event=] named `activate` at [=this=].</li>
<li>Return undefined.</li>
</ol>
</section>The class="algorithm" on <ol> enables:
- Variable highlighting (when
highlightVarsis enabled) - Unused variable detection (when the
no-unused-varslinting rule is enabled) - Assert step detection (steps starting "Assert:" get a special style)
These conventions are used throughout W3C and WHATWG specifications. Following them makes your spec consistent with the broader ecosystem.
Use |variable:Type| for typed variables, or |variable| for untyped:
<ol class="algorithm">
<li>Let |request:Request| be a new [=request=].</li>
<li>Let |url:URL| be the result of [=URL parser|parsing=] |input|.</li>
<li>Let |n| be 0.</li>
</ol>- Declare with "Let |x| be …"
- Assign with "Set |x| to …"
- Types are informational — use the IDL interface name or a descriptive type
Use these consistently:
| Verb | Use for |
|---|---|
| Let x be y | Declaring a new variable |
| Set x to y | Reassigning an existing variable |
| Return x | Returning a value (ends execution) |
| Throw x | Throwing an exception (ends execution) |
| Assert: condition | Invariant that must hold (starts with "Assert:") |
| If condition, then | Conditional (inline or block) |
| For each x of list | Iteration |
| Append x to list | Adding to a list |
Use [=this=] to refer to the object the method is called on. This links to the Infra definition of "this":
<ol class="algorithm">
<li>If [=this=]'s [=Widget/active flag=] is true, then throw an
{{InvalidStateError}}.</li>
<li>Set [=this=]'s [=Widget/name=] to |name|.</li>
<li>Return [=this=].</li>
</ol>Steps starting with "Assert:" are assertions — conditions that must be true at that point. ReSpec links "Assert" to the Infra definition automatically and styles them distinctively:
<ol class="algorithm">
<li>Assert: |request|'s [=request/URL=] is not null.</li>
<li>Assert: |options| [=map/contains=] "method".</li>
</ol>Indent using nested <ol class="algorithm"> for sub-steps:
<ol class="algorithm">
<li>For each |header| of |request|'s [=request/header list=]:
<ol>
<li>If |header|'s [=header/name=] is `authorization`, then return failure.</li>
</ol>
</li>
<li>Return success.</li>
</ol>Use [=term=] and {{IDL}} shorthands as normal. For scoped members, use [=Interface/member=]:
<ol class="algorithm">
<li>Let |url| be the result of [=URL parser|parsing=] |input| with |base|.</li>
<li>If |url| is failure, then [=throw=] a {{TypeError}}.</li>
<li>Set [=this=]'s [=Request/url=] to |url|.</li>
</ol>Define reusable sub-algorithms as abstract operations:
<section>
<h3>To <dfn data-dfn-type="abstract-op">validate a widget</dfn>, given a |widget:Widget|:</h3>
<ol class="algorithm">
<li>If |widget|'s [=Widget/name=] is the empty string, return false.</li>
<li>Return true.</li>
</ol>
</section>Reference abstract operations with [=validate a widget=]:
<ol class="algorithm">
<li>If [=validate a widget=] with |w| returns false, throw a {{TypeError}}.</li>
</ol>Methods that return a {{Promise}} follow a standard structure. The primitives are defined in WEBIDL:
<p>The <dfn>load(url)</dfn> method steps are:</p>
<ol class="algorithm">
<li>Let |p:Promise| be [=a new promise=].</li>
<li>If |url| is not [=valid=], then [=reject=] |p| with a {{TypeError}}
and return |p|.</li>
<li>Run [=fetch the resource=] with |url| and |p|.</li>
<li>Return |p|.</li>
</ol>Key promise primitives from WEBIDL — enable with xref: ["WEBIDL"] or xref: "web-platform":
| Phrase | Meaning |
|---|---|
[=a new promise=] |
Create a new pending Promise |
[=a promise resolved with=] |value| |
Create an already-resolved Promise |
[=a promise rejected with=] |reason| |
Create an already-rejected Promise |
[=resolve=] |p| with |value| |
Settle an existing Promise as resolved |
[=reject=] |p| with |reason| |
Settle an existing Promise as rejected |
[=upon fulfillment=] of |p| |
Run steps when promise resolves |
[=upon rejection=] of |p| |
Run steps when promise rejects |
[=promise/react=] to |p| |
Run steps on fulfillment and/or rejection |
[=wait for all=] with |promises| |
Wait for a list of promises |
[=a promise resolved with=] vs [=resolve=]:
-
[=a promise resolved with=] x— creates and returns a new already-resolved promise. Use when returning immediately:return [=a promise resolved with=] undefined. -
[=resolve=] |p| with x— settles an existing pending promise. Use with[=In parallel=]after doing work asynchronously.
For operations that run asynchronously (most network and I/O operations), use [=In parallel=] from HTML:
<p>The <dfn>fetch(request)</dfn> method steps are:</p>
<ol class="algorithm">
<li>Let |p:Promise| be [=a new promise=].</li>
<li>[=In parallel=]:
<ol>
<li>Let |response| be the result of [=fetching=] |request|.</li>
<li>If |response| is a failure, then [=queue a global task=] on
the [=networking task source=] with [=this=]'s [=relevant global object=]
to [=reject=] |p| with a {{TypeError}}.</li>
<li>Otherwise, [=queue a global task=] to [=resolve=] |p|
with |response|.</li>
</ol>
</li>
<li>Return |p|.</li>
</ol>Key HTML primitives — available with xref: "web-platform":
| Phrase | Meaning |
|---|---|
[=In parallel=] |
Run the following steps concurrently |
[=Queue a task=] |
Schedule work on the event loop |
[=Queue a global task=] |
Schedule work on a specific global's event loop |
[=Fire an event=] |
Dispatch a DOM event |
WebIDL dictionary members are accessed using Infra map operations — enable with xref: ["INFRA"] or xref: "web-platform":
<ol class="algorithm">
<li>If |options|["signal"] [=map/exists=], then:
<ol>
<li>If |options|["signal"] is [=AbortSignal/aborted=], return
[=a promise rejected with=] |options|["signal"]'s
[=AbortSignal/abort reason=].</li>
</ol>
</li>
<li>Let |timeout| be |options|["timeout"] if it [=map/exists=],
otherwise 5000.</li>
</ol>Key Infra map operations — available with xref: "web-platform":
| Operation | Linking text | Meaning |
|---|---|---|
| ` | map | ["key"]` |
[=map/exist=] or [=map/contain=]
|
exist | contain
|
Check if a key is present |
[=map/set=] |
set |
Set a value at key |
[=map/remove=] |
remove |
Remove an entry |
[=map/for each=] |
for each |
Iterate over entries |
[=map/size=] |
size |
Number of entries |
[=map/is empty=] |
is empty |
True if no entries |
Key Infra list operations:
| Operation | Linking text | Meaning |
|---|---|---|
[=list/append=] |
append |
Add item to end |
[=list/contain=] |
contain |
Check membership |
[=list/remove=] |
remove |
Remove item(s) |
[=list/for each=] |
for each |
Iterate |
[=list/size=] |
size |
Number of items |
[=list/is empty=] |
is empty |
True if no items |
For operations that support cancellation via {{AbortSignal}}:
<ol class="algorithm">
<li>If |options|["signal"] [=map/exists=]:
<ol>
<li>If |options|["signal"] is [=AbortSignal/aborted=], return
[=a promise rejected with=] |options|["signal"]'s
[=AbortSignal/abort reason=].</li>
<li>[=AbortSignal/add=] the following abort steps to
|options|["signal"]:
<ol>
<li>[=Reject=] |p| with |options|["signal"]'s
[=AbortSignal/abort reason=].</li>
</ol>
</li>
</ol>
</li>
</ol>When defining prose descriptions for IDL enum values, use data-dfn-type="enum-value" and data-dfn-for:
<p>The <dfn data-dfn-type="enum-value" data-dfn-for="WidgetState">"idle"</dfn>
state means the widget has not yet been activated.</p>
<p>The <dfn data-dfn-type="enum-value" data-dfn-for="WidgetState">"active"</dfn>
state means the widget is currently active.</p>These can then be linked as {{WidgetState/"idle"}} in algorithm steps.
Mark an algorithm with a name using data-algorithm:
<ol class="algorithm" data-algorithm="fetch">
<li>...</li>
</ol>This is useful for cross-referencing specific algorithms by name.
- One action per step — don't combine unrelated operations in a single step
- Terminate explicitly — every path should end with "return", "throw", or similar
-
Use Infra for primitives — it defines lists, maps, strings, and common operations used across W3C/WHATWG specs. Enable with
xref: ["INFRA"]. -
Use WebIDL for promises — all promise creation and settling language comes from WebIDL. Enable with
xref: ["WEBIDL"]. - Link everything — terms, types, and operations should link to their definitions
- Keep it deterministic — algorithms must have one unambiguous outcome for every input
💖 Support ReSpec by becoming a sponsor via Open Collective. 💖
✨ View rendered version of this documentation at https://respec.org/docs/ ✨
- Getting Started
- How Do I…
- Spec Editor's Guide
- Writing Algorithms
- WebIDL Guide
- Configuring ReSpec
- Developers Guide
- Shorthands
- addSectionLinks
- authors
- caniuse
- edDraftURI
- editors
- format (markdown)
- formerEditors
- github
- highlightVars
- isPreview
- license
- lint
- localBiblio
- logos
- maxTocLevel
- mdn
- modificationDate
- monetization
- noTOC
- otherLinks
- pluralize
- postProcess
- preProcess
- previousDiffURI
- previousMaturity
- previousPublishDate
- prevRecShortname
- prevRecURI
-
processVersion(Removed) - publishDate
- shortName
- specStatus
- subjectPrefix
- subtitle
- testSuiteURI
- xref
- additionalCopyrightHolders
-
addPatentNote(Removed) - alternateFormats
- canonicalURI
- charterDisclosureURI
- copyrightStart
- crEnd
- dark mode
- doJsonLd
- errata
- group
- implementationReportURI
- level
- noRecTrack
- prevED
- prEnd
- submissionCommentNumber
-
wg(Deprecated — usegroup) -
wgId(Deprecated — usegroup) -
wgPatentURI(Deprecated — usegroup) -
wgPublicList(Deprecated — usegroup) -
wgURI(Deprecated — usegroup)
a11ycheck-charsetcheck-internal-slotscheck-punctuationinformative-dfnlocal-refs-existno-captionless-tablesno-headingless-sectionsno-http-propsno-link-warningsno-unused-dfnsno-unused-varsprivsec-sectionwpt-tests-exist
Handled by ReSpec for you.
- conformance
- idl-index
- index
- issue-summary
- references
- tof (Table of Figures)
- data-abbr
- data-cite
- data-dfn-for
- data-dfn-type
- data-export
- data-format
- data-include
- data-include-format
- data-include-replace
- data-link-for
- data-link-type
- data-local-lt
- data-lt
- data-lt-no-plural
- data-lt-noDefault
- data-max-toc
- data-number
- data-oninclude
- data-sort
- data-tests
-
data-transform(Deprecated) - data-type
- dir
- lang