diff --git a/civet.dev/.vitepress/components/Hero.vue b/civet.dev/.vitepress/components/Hero.vue
index ef2f1f2b..51134bee 100644
--- a/civet.dev/.vitepress/components/Hero.vue
+++ b/civet.dev/.vitepress/components/Hero.vue
@@ -4,6 +4,11 @@ import VPHero from 'vitepress/dist/client/theme-default/components/VPHero.vue';
const actions = [
{
theme: 'brand',
+ text: 'Reference',
+ link: '/reference',
+ },
+ {
+ theme: 'alt',
text: 'Cheatsheet',
link: '/cheatsheet',
},
diff --git a/civet.dev/.vitepress/config.js b/civet.dev/.vitepress/config.mjs
similarity index 93%
rename from civet.dev/.vitepress/config.js
rename to civet.dev/.vitepress/config.mjs
index 5271c0ca..3771e741 100644
--- a/civet.dev/.vitepress/config.js
+++ b/civet.dev/.vitepress/config.mjs
@@ -1,6 +1,6 @@
import pkg from '../../package.json';
-import { head } from './head.js';
-import { getContributors } from './utils/getContributors.js';
+import { head } from './head.mjs';
+import { getContributors } from './utils/getContributors.mjs';
import { defineConfig } from 'vitepress';
import { compileCivet } from './utils/compileCivet';
import { getHighlighter } from './utils/getHighlighter';
@@ -26,7 +26,8 @@ export default async function vitePressConfig() {
siteTitle: 'Civet',
nav: [
{ text: 'Getting started', link: '/getting-started' },
- { text: 'Cheatsheet', link: '/cheatsheet' },
+ { text: 'Reference', link: '/reference' },
+ { text: 'Cheatsheet', link: '/cheatsheet'},
{ text: 'Comparison', link: '/comparison' },
{ text: 'Integrations', link: '/integrations' },
{ text: 'Config', link: '/config' },
diff --git a/civet.dev/.vitepress/head.js b/civet.dev/.vitepress/head.mjs
similarity index 100%
rename from civet.dev/.vitepress/head.js
rename to civet.dev/.vitepress/head.mjs
diff --git a/civet.dev/.vitepress/utils/getContributors.js b/civet.dev/.vitepress/utils/getContributors.mjs
similarity index 100%
rename from civet.dev/.vitepress/utils/getContributors.js
rename to civet.dev/.vitepress/utils/getContributors.mjs
diff --git a/civet.dev/cheatsheet.md b/civet.dev/cheatsheet.md
index a3a387aa..dea4cc9b 100644
--- a/civet.dev/cheatsheet.md
+++ b/civet.dev/cheatsheet.md
@@ -5,124 +5,218 @@ aside: false
# {{ $frontmatter.title }}
-Civet code on the left top ,
-compiled TypeScript output on
-the right bottom .
+Here's a quick overview of the language. For more detailed information take a look at the [Reference](/reference).
+
+
+
+
+
+```ts
+// Declarations
+const x = 1
+let y: number = 2
+var z: string = "3"
+x := 1 // const x = 1
+y .= 2 // let y = 2
+
+// Destructuring
+[ a, b ] := x
+[ ..., last ] := x
+[ first, ...rest ] := x
+[ first, ..., last ] := x
+[ first, ...middle, last] := x
+
+{ a, b } := c
-In most cases, the Civet code on
-
the left top
-is optional shorthand.
-The TypeScript code on
-
the right bottom
-(and most TypeScript code) is almost always also valid Civet input.
+```
-[[toc]]
+```ts
+// Function application
+f(x)
+f(a, g(x))
+f(...args, cb)
-## Variable Declaration
+// Implicit application
+f x // f(x)
+f a, b, c // f(a, b, c)
+f g x // f(g(x))
+f a, b c // f(a, b(c))
-By default, you are responsible for declaring your variables
-via `var`, `let`, `const`, or their shorthands:
+```
-
-a := 10
-b .= 10
-c: number | string .= 0
-let d: boolean
-var v: any
-
+```ts
+// Conditionals
+x && y
+x and y // x && y
+x || y
+x or y // x || y
+
+// relationals
+x === y
+x is y // x === y
+x < y
+x > y
+// Chained relationals
+x < y < z // x < y && y < z
+```
-Alternatively, you can use a `"civet"` directive at the beginning of your file
-to specify one of two automatic variable declaration modes:
+```ts
+// this
+this
+// shorthand
+@ // this
+@x // this.x
+
+// instance of and typeof shorthand
+x instanceof y
+x Y // x instanceof y
+typeof x === "string"
+x "string" // typeof x === "string"
+```
-### `autoVar`
+`````ts
+// strings
+"I'm a string"
+'I\'m also a string'
+`I'm a ${template} string`
-
-"civet autoVar"
-sos = 0
-for item of iterable
- square = item * item
- sos += square
-
+// Block Strings
+"""
+ Block strings
+ will dedent
+"""
-### `autoLet`
+'''
+ They work with all kinds of
+ strings
+'''
-
-"civet autoLet"
-sos = 0
-for item of iterable
- square = item * item
- sos += square
-
+```
+ I will dedent by removing
+ common indentation
+```
-### Declarations in Conditions and Loops
+`````
-
-if match := regex.exec string
- console.log match[1], match[2]
-
+```ts
+// if conditions
+if x < 3
+ "it's small"
-
-if [, dir, base] := /^(.*\/)?([^/]*)$/.exec file
- console.log dir, base
-
+if x > 11
+ "it's big"
-
-if {x, y} := getLocation()
- console.log `At ${x}, ${y}`
-else
- console.log "Not anywhere"
-
+unless paused
+ run()
-
-node .= linkedList.head
-while {data, next} := node
- console.log data
- node = next
-
+// loops
+while x < 10
+ f(x)
+ x++
-## Objects
+for item of items
+ update item
-### Unbraced Literals
+for key in object
+ log key
-When every property has a value, braces can be omitted.
+for own key in object
+ log `my ${key}`
+```
+
+```ts
+// Postfix loops/conditionals
+f(x) if x
+log name for name of names
+
+```
-
-person := name: 'Henry', age: 4
-obj :=
- a: 1
- b: 2
- c:
- x: 'pretty'
- y: 'cool'
-
+```ts
+// Arrow Functions
+inc := (x) => x + 1
+add :=
(a, b): T => a + b
+
+// Thin arrow -> is equivalent to `function`
+f := (this: ctx, a, b) ->
+ ctx.log a, b if ctx.debug
+
+```
-`$:` behaves specially for Svelte compatibility. If you want a key of `$`,
-wrap it in quotes or use explicit braces.
+```ts
+// Block shorthand
+people.map .name // people.map($ => $.name)
+numbers.filter & % 2 is 0
+// numbers.filter($ => $ % 2 === 0)
-
-$: document.title = title
-"$": "dollar"
-{$: "dollar"}
-
+// Conditional declarations
+throw error if { error } := result
+
+if [, dir, base] := /^(.*\/)?([^/]*)$/.exec file
+ console.log dir, base
+```
+
+```ts
+// Switch
+switch dir
+ when '>' then civet.x++
+ when '<'
+ civet.x--
+ civet.x = 0 if civet.x < 0
+ else
+ civet.waiting += 5
+```
-### Braced Literals
+```ts
+// Pattern Matching
+switch s
+ ""
+ console.log "nothing"
+ /\s+/
+ console.log "whitespace"
+ "hi"
+ console.log "greeting"
+```
-With braces, the `{x}` shorthand generalizes to any
-sequence of member accesses and/or calls:
+```ts
+// Pattern destructuring
+switch x
+ [{type: "text", content: /\s+/}, ...rest]
+ console.log "leading whitespace"
+ [{type: "text", content}, ...rest]
+ console.log "leading text:", content
+ [{type}, ...rest]
+ console.log "leading type:", type
+```
-
-another := {person.name, obj?.c?.x}
-computed := {foo(), bar()}
-named := {lookup[x+y]}
-templated := {`${prefix}${suffix}`: result}
-
+```ts
+// JSX
+// Better binding
+ Click Me
+ Click Me Also
-### Object Globs
+// Closing is optional
+
+
Click Me
-Inspired by
-[brace expansion in shell globs](https://en.wikipedia.org/wiki/Bash_(Unix_shell)#Brace_expansion):
+// class shorthand
+<.items>
+ <.item>
+```
-
+```ts
+// Object globs
point = data{x,y}
point = data.{x,y};
point.{x,y} = data
@@ -130,1513 +224,78 @@ point3D = { point.{x,y}, z: 0 }
complex := obj.{x:a, b.c()?.y}
merged := data.{...global, ...user};
data.{a, b, ...rest} = result
-
-
-### Flagging Shorthand
-
-Inspired by [LiveScript](https://livescript.net/#literals-objects):
-
-
-config := {
- +debug
- -live
- !verbose
-}
-
-
-### Methods and Getters/Setters
-
-Braced objects support methods and getters/setters:
-
-
-p := {
- name: 'Mary'
- say(msg)
- console.log @name, 'says', msg
- setName(@name);
- get NAME()
- @name.toUpperCase()
-}
-p.say p.NAME
-
-
-::: tip
-
-Methods need a body, or they get treated as literal shorthand.
-To specify a blank body, use `;` or `{}`.
-
-:::
-
-### Property Access
-
-Many more literals can appear after a `.` to access an object property:
+```
-
+```ts
+// Property Access
+json.x.y
json.'long property'
json.`${movie} name`
matrix.0.0
array.-1
-
-
-You can also write property access as an English possessive
-(inspired by [_hyperscript](https://hyperscript.org/expressions/possessive/)):
-
-
-mario's brother's name
-mario?'s name
-json's "long property"'s `${movie} name`
-
-
-## Arrays
-
-Commas are optional at the ends of lines.
-
-
-rotate := [
- c, -s
- s, c
-]
-
-
-
-func.apply @, [
- arg1
- arg2
-]
-
-
-
-people := [
- name: "Alice"
- id: 7
-,
- name: "Bob"
- id: 9
-]
-
-
-### Rest
-
-Rest properties/parameters/elements are no longer limited to the final position.
-You may use them in their first or middle positions as well.
-
-
-[...head, last] = [1, 2, 3, 4, 5]
-
-
-
-{a, ...rest, b} = {a: 7, b: 8, x: 0, y: 1}
-
-
-
-function justDoIt(a, ...args, cb) {
- cb.apply(a, args)
-}
-
-
-You can also omit the name of the rest component:
-
-
-[first, ..., last] = array
-
-
-### Range Literals
+```
-`[x..y]` includes `x` and `y`, while `[x...y]` includes `x` but not `y`.
+```ts
+// Await operators
+await.allSettled promises
+await.all promises
+await.race promises
+```
-
+```ts
+// Range literals
letters := ['a'..'f']
numbers := [1..10]
reversed := [10..1]
indices := [0...array.length]
-
-
-### Array/String Slicing
-
-`[i..j]` includes `i` and `j`, while `[i...j]` includes `i` but not `j`.
-`i` and/or `j` can be omitted when slicing.
+```
-
+```ts
+// slicing and splicing
start := numbers[..2]
mid := numbers[3...-2]
end := numbers[-2..]
numbers[1...-1] = []
-
-
-## Strings
-
-Strings can span multiple lines:
-
-
-console.log "Hello,
-world!"
-
-
-
-### Triple-Quoted Strings
-
-Leading indentation is removed.
-
-
-console.log '''
-
- Civet
-
-'''
-
-
-
-console.log """
-
- Civet #{version}
-
-"""
-
-
-
-console.log ```
-
- Civet ${version}
-
```
-
-
-## Operators
-
-### All JavaScript/TypeScript Operators
-
-
-center := min + length / 2
-name := user?.name ?? defaultName
-typeof x === "string" && x += "!"
-result! as string | number
-
-
-### Late Assignment
-
-
-a + b = c
-
-
-### Multi Assignment
-
-
-(count[key] ?= 0)++
-(count[key] ?= 0) += 1
-++count *= 2
-
-
-### Humanized Operators
-
-
-a is b
-a is not b
-a and b
-a or b
-a not in b
-a not instanceof b
-a?
-
-
-### Includes Operator
-
-
-item is in array
-item is not in array
-substring is in string
-item1 ∈ container ∌ item2 // Unicode
-
-
-### Assignment Operators
-
-
-a and= b
-a or= b
-a ?= b
-obj.key ?= "civet"
-
-### Optional Chaining
-
-
-obj?[key]
-fun?(arg)
-
-
-## Existence Checking
-
-
-x?
-x.y[z]?
-
-
-### Chained Comparisons
-
-
-a < b <= c
-a ≤ b ≤ c // Unicode
-a ≡ b ≣ c ≠ d ≢ e
-a is b is not c
-a instanceof b not instanceof c
-x? instanceof Function
-
-
-### `instanceof` shorthand
-
-
-a b
-a ! b
-a b ! c
-
-
-### `typeof` shorthand
-
-
-a "string"
-a ! "string"
-a instanceof "number"
-a not instanceof "number"
-
-
-### Logical XOR Operator
-
-
-a ^^ b
-a xor b
-a ^^= b
-a xor= b
-
-
-
-a !^ b
-a xnor b
-a !^= b
-a xnor= b
-
-
-### Modulo Operator
-
-`%` can return negative values, while `%%` is always between 0 and the divisor.
-
-
-let a = -3
-let b = 5
-let rem = a % b
-let mod = a %% b
-console.log rem, mod
-
-
-### `Object.is`
-
-The `"civet objectIs"` directive changes the behavior of the `is` operator to
-[`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is),
-which is a bit better behaved than `===`.
-The plan is to make this the default behavior, once TypeScript supports
-type narrowing with `Object.is` as well as it does for `===`.
-(Currently, `a is b` will not correctly narrow `b` in some edge cases.)
-
-
-"civet objectIs"
-a is b
-a is not b
-
-
-### Pipe Operator
-
-Based on
-[F# pipes](https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/symbol-and-operator-reference/#function-symbols-and-operators) and
-[TC39 Proposal: Pipe Operator](https://github.com/tc39/proposal-pipeline-operator).
-
-
+```ts
+// Pipe operator
data
- |> Object.keys
- |> console.log
-
+|> Object.keys
+|> console.log
-Pairs particularly well with
-[single-argument function shorthand](#single-argument-function-shorthand):
+x.length
+|> & + 1
+|> .toString()
-
-x.length |> & + 1 |> .toString()
-
-
-Use `await`, `yield`, or `return` in your pipeline:
-
-
-fetch url |> await
-|> .json() |> await
+fetch url
+|> await
+|> .json()
+|> await
|> return
-
-Pipe assignment:
-
-
+// Pipe assignment
data |>= .content
-
-
-Fat pipes `||>` pass the left-hand value to the next two steps in the pipeline
-(ignoring the output from the right-hand side):
+```
-
+```ts
+// Thick Pipes
array
||> .pop()
||> .push 5
||> .sort()
||> .reverse()
-
-
count |> & + 1
||> console.log
|> & * 2
||> console.log
-
-
url |> fetch |> await
||> (response) => console.log response.status
|> .json() |> await
||> (json) => console.log "json:", json
|> callback
-
-
-Unicode forms:
-
-
-data ▷= func1 |▷ func2 ▷ func3
-
-
-### Await Operators
-
-[TC39 proposal: `await` operations](https://github.com/tc39/proposal-await.ops)
-
-
-await.allSettled promises
-
-
-
-await.all
- for url of urls
- fetch url
-
-
-
-await.all
- for url of urls
- async do
- fetch url |> await |> .json() |> await
-
-
-### Custom Infix Operators
-
-You can also define your own infix operators;
-see [Functions as Infix Operators](#functions-as-infix-operators) below.
-
-## Functions
-
-### Function Calls
-
-The parentheses in a function call are usually optional.
-If present, there should be no space between the function and the open paren.
-
-
-console.log x, f(x), (f g x), g f x
-
-
-### `function`
-
-
-function abort
- process.exit 1
-
-
-
-function circle(degrees: number): {x: number, y: number}
- radians := degrees * Math.PI / 180
- x: Math.cos radians
- y: Math.sin radians
-
-
-::: info
-Implicit return of the last value in a function can be avoided by
-specifying a `void` return type (or `Promise` for async functions),
-adding a final semicolon or explicit `return`,
-or globally using the directive `"civet -implicitReturns"`.
-:::
-
-
-function abort
- process.exit 1;
-
-
-
-function abort: void
- process.exit 1
-
-
-
-function run(command: string): Promise
- await exec command
-
-
-### One-Line Functions
-
-
-function do console.log "Anonymous"
-function f do console.log "Named"
-function f(x) do console.log x
-
-
-### Function Overloading
-
-
-function add(a: string, b: string): string
-function add(a: number, b: number): number
- a+b
-
-
-### Arrow Functions
-
-::: info
-Unlike ECMAScript, zero-argument arrows do not need a `()` prefix,
-but one-argument arrows do need parentheses around the argument.
-:::
-
-
-abort := => process.exit 1
-
-
-
-createEffect => console.log data()
-greet := (name) => console.log "Hello", name
-
-
-::: info
-`=>` makes arrow functions as usual, while
-`->` makes `function`s (which can have `this` assigned via `.call`).
-:::
-
-
-add := (a: number, b: number) => a + b
-
-
-
-add := (a: number, b: number) -> a + b
-
-
-::: info
-Unlike ECMAScript, even multi-line arrow functions implicitly return their
-last value. See [above](#function) for how to avoid this behavior.
-:::
-
-
-circle := (degrees: number): {x: number, y: number} =>
- radians := degrees * Math.PI / 180
- x: Math.cos radians
- y: Math.sin radians
-
-
-You can also use Unicode arrows:
-
-
-curryAdd := (a: number) → (b: number) ⇒ a + b
-
-
-### `return.value`
-
-Instead of specifying a function's return value when it returns,
-you can prepare it ahead of time using `return.value`
-(or its shorthand, assigning to `return`).
-Using this feature disables implicit `return` for that function.
-
-
-function sum(list: number[])
- return .= 0
- for item of list
- return += item
-
-
-
-function search(list: T[]): T | undefined
- return unless list
- for item of list
- if match item
- return = item
- return++ if return.value
- list.destroy()
-
-
-### Single-Argument Function Shorthand
-
-
-x.map &.name
-x.map &.profile?.name[0...3]
-x.map &.callback a, b
-x.map +&
-
-
-::: info
-Short function block syntax like [Ruby symbol to proc](https://ruby-doc.org/core-3.1.2/Symbol.html#method-i-to_proc),
-[Crystal](https://crystal-lang.org/reference/1.6/syntax_and_semantics/blocks_and_procs.html#short-one-parameter-syntax),
-or [Elm record access](https://elm-lang.org/docs/records#access).
-:::
-
-You can also omit `&` when starting with a `.` or `?.` property access:
-
-
-x.map .name
-x.map ?.profile?.name[0...3]
-
-
-### Functions as Infix Operators
-
-You can "bless" an existing function to behave as an infix operator
-(and a negated form) like so:
-
-
-operator contains
-x contains y
-x not contains y
-
-
-You can combine this with a [variable declaration](#variable-declaration):
-
-
-operator {min, max} := Math
-value min ceiling max floor
-
-
-You can also define an operator with a function body:
-
-
-operator calls(t: T, f: (this: T) => R): R
- f.call(t)
-this calls callback
-
-
-Operators are just functions in the end, and behave as such when used
-unambiguously:
-
-
-operator foo
-x foo foo(y, z)
-x (foo) y
-
-
-You can also `import` functions from another module as operators
-(independent of whether they are declared as operators in the other module):
-
-
-import { operator contains } from 'bar'
-x contains y
-export operator has(x, y)
- y contains x
-
-
-### Operator Assignment
-
-Even without blessing a function as an `operator`, you can use it in
-an assignment form:
-
-
-{min, max} := Math
-smallest .= Infinity
-largest .= -Infinity
-for item in items
- smallest min= item
- largest max= item
-
-
-## Conditions
-
-### If/Else
-
-
-if coffee or relaxed
- code()
-else
- sleep()
-
-
-### One-Line If/Else
-
-
-if coffee or relaxed then code() else sleep()
-
-
-### If/Else Expressions
-
-
-name :=
- if power === Infinity
- "Saitama"
- else if power > 9000
- "Goku"
-caps := if name? then name.toUpperCase() else 'ANON'
-
-
-### Unless
-
-
-unless tired
- code()
-
-
-### Postfix If/Unless
-
-
-civet.speed = 15 if civet.rested
-
-
-### Switch
-
-
-switch dir
- when '>' then civet.x++
- when '<'
- civet.x--
- civet.x = 0 if civet.x < 0
- else civet.waiting += 5
-
-
-With implicit `return`:
-
-
-getX := (civet: Civet, dir: Dir) =>
- switch dir
- when '>' then civet.x + 3
- when '<' then civet.x - 1
- when '^' then civet.x + 0.3
-
-
-### Pattern Matching
-
-
-switch s
- ""
- console.log "nothing"
- /\s+/
- console.log "whitespace"
- "hi"
- console.log "greeting"
-
-
-
-switch a
- []
- console.log "empty"
- [item]
- console.log "one", item
- [first, ...middle, last]
- console.log "multiple", first, "...", last
- else
- console.log "not array"
-
-
-::: info
-Array patterns are exact; object patterns allow unmatched properties
-(similar to TypeScript types).
-:::
-
-
-switch x
- {type: "text", content}
- console.log `"${content}"`
- {type, ...rest}
- console.log `unknown type ${type}`
- else
- console.log 'unknown'
-
-
-
-switch x
- [{type: "text", content: /\s+/}, ...rest]
- console.log "leading whitespace"
- [{type: "text", content}, ...rest]
- console.log "leading text:", content
- [{type}, ...rest]
- console.log "leading type:", type
-
-
-::: info
-You can also use condition fragments as patterns.
-:::
-
-
-switch x
- < 0
- console.log "it's negative"
- > 0
- console.log "it's positive"
- is 0
- console.log "it's zero"
- else
- console.log "it's something else"
-
-
-
-switch x
- % 15 is 0
- console.log "fizzbuzz"
- % 3 is 0
- console.log "fizz"
- % 5 is 0
- console.log "buzz"
- else
- console.log x
-
-
-::: info
-Aliasing object properties works the same as destructuring.
-:::
-
-
-switch e
- {type, key: eventKey}
- return [type, eventKey]
-
-
-::: info
-Patterns can aggregate duplicate bindings.
-:::
-
-
-switch x
- [{type}, {type}]
- type
-
-
-## Loops
-
-All JavaScript loops are available,
-with optional parentheses around the clause.
-
-
-for let i = 0; i < 100; i++
- console.log i
-
-
-### for..of
-
-Looping over an iterator via `for..of` defaults to `const`:
-
-
-for item of list
- console.log item
-
-
-
-for let item of list
- item *= item
- console.log item
-
-
-You can also keep track of the current index of the iteration
-by specifying a comma and a second variable (also defaulting to `const`):
-
-
-for item, index of list
- console.log `${index}th item is ${item}`
-
-
-### for each..of
-
-For Arrays and other objects implementing `.length` and `[i]` indexing,
-you can use `for each..of` as an optimized form of `for..of`
-(without building an iterator):
-
-
-for each item of list
- console.log item
-
-
-
-for each let item of list
- item *= item
- console.log item
-
-
-
-for each item, index of list
- console.log `${index}th item is ${item}`
-
-
-`for each` loops are similar to `Array.prototype.forEach` (hence the name),
-but are more efficient and allow for e.g. `break` and `continue`.
-
-### for..in
-
-Looping over properties of an object via `for..in` defaults to `const`:
-
-
-for key in object
- console.log key
-
-
-
-for var key in object
- console.log key
-console.log `Last key is ${key}`
-
-
-You can also retrieve the corresponding value
-by specifying a comma and a second variable (also defaulting to `const`):
-
-
-for key, value in object
- console.log `${key} maps to ${value}`
-
-
-If your object might have a prototype with enumerable properties,
-you can skip them with `own`:
-
-
-for own key in object
- console.log key
-
-
-### Loop Expressions
-
-If needed, loops automatically assemble an Array of the last value
-within the body of the loop for each completed iteration.
-
-
-squares :=
- for item of list
- item * item
-
-
-
-evenSquares :=
- for item of list
- continue unless item % 2 == 0
- item * item
-
-
-
-function parities(list: number[]): string[]
- for item of list
- if item % 2 === 0
- "even"
- else
- "odd"
-
-
-::: info
-Because loop expressions wrap in an
-[IIFE](https://developer.mozilla.org/en-US/docs/Glossary/IIFE),
-you cannot use `return` inside such a loop,
-nor can you `break` or `continue` any outer loop.
-:::
-
-Loops that use `await` automatically get `await`ed.
-If you'd rather obtain the promise for the results so you can `await` them
-yourself, use `async for`.
-
-
-results :=
- for url of urls
- await fetch url
-
-
-
-promise :=
- async for url of urls
- await fetch url
-
-
-### Postfix Loop
-
-
-console.log item for item of array
-
-
-### Infinite Loop
-
-
-i .= 0
-loop
- i++
- break if i > 5
-
-
-### Range Loop
-
-
-for i of [0...array.length]
- array[i] = array[i].toString()
-
-
-
-for [1..5]
- attempt()
-
-
-### Until Loop
-
-
-i .= 0
-until i > 5
- i++
-
-
-### Do...While/Until Loop
-
-
-total .= 0
-item .= head
-do
- total += item.value
- item = item.next
-while item?
-
-
-### Do Blocks
-
-To put multiple lines in a scope and possibly an expression,
-you can use `do` without a `while`/`until` suffix, similar to
-[TC39 proposal: `do` expressions](https://github.com/tc39/proposal-do-expressions).
-
-
-x := 5
-do
- x := 10
- console.log x
-console.log x
-
-
-
-x := do
- y := f()
- y*y
-
-
-::: info
-Because `do` expressions wrap in an
-[IIFE](https://developer.mozilla.org/en-US/docs/Glossary/IIFE),
-you cannot use `return`, `break`, or `continue` within them.
-:::
-
-### Async Do Blocks
-
-You can create a promise using `await` notation with `async do`:
-
-
-promise := async do
- result := await fetch url
- await result.json()
-
-
-
-await Promise.allSettled for url of urls
- async do
- result := await fetch url
- await result.json()
-
-
-### Labels
-
-
-:outer while (list = next())?
- for item of list
- if finale item
- break outer
- continue :outer
-
-
-::: info
-Labels have the colon on the left to avoid conflict with implicit object
-literals. The colons are optional in `break` and `continue`.
-As a special case, Svelte's `$:` can be used with the colon on the right.
-:::
-
-
-$: document.title = title
-
-
-## Classes
-
-
-class Animal
- sound = "Woof!"
- bark(): void
- console.log @sound
- wiki()
- fetch 'https://en.wikipedia.org/wiki/Animal'
-
-
-### This
-
-
-@
-id := @id
-obj := { @id }
-
-
-### Bind
-
-
-bound := object@.method
-bound := object@method
-bound := @@method
-
-
-### Private Fields
-
-[Private class fields](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields)
-do not need an explicit `this.` or `@` prefix.
-
-
-class Counter
- #count = 0
- increment(): void
- #count++
- add(other: Counter): void
- #count += other.#count if #count in other
- set(#count)
-
-
-### Static Fields
-
-
-class A
- @a = 'civet'
-
-
-### Readonly Fields
-
-
-class B
- b := 'civet'
-
-
-### Typed Fields
-
-
-class C
- size: number | undefined
- @root: Element = document.body
-
-
-### Constructor
-
-
-class Rectangle
- @(@width: number, @height: number)
-
-
-
-class Rectangle
- @(public width: number, public height: number)
-
-
-### Static Block
-
-
-class Civet
- @
- try
- this.colors = getCivetColors()
-
-
-### Extends
-
-
-class Civet < Animal
-
-
-### Implements
-
-
-class Civet < Animal <: Named
-class Civet <: Animal, Named
-
-
-### Decorators
-
-
-@@Object.seal
-class Civet
- @name = "Civet"
-
-
-## Types
-
-### Unknown
-
-`???` is shorthand for the type `unknown`.
-
-
-declare function jsonParse(json: string): ???
-
-
-### Import
-
-
-type { Civet, Cat } from animals
-
-
-
-{ type Civet, meow } from animals
-
-
-### Aliases
-
-
-type ID = number | string
-
-
-
-type Point = x: number, y: number
-
-
-The `=` is optional if the content is indented:
-
-
-type ID
- | number
- | string
-type Point
- x: number
- y: number
-
-
-### Interfaces
-
-
-interface Point
- x: number
- y: number
-
-
-
-interface Point3D < Point
- z: number
-
-
-
-interface Signal
- listen(callback: =>): void
-
-
-
-interface Node
- value: T
- next: Node
-
-
-### Enum
-
-
-enum Direction
- Up
- Down
- Left = 2 * Down
- Right = 2 * Left
-
-
-### Assertions
-
-
-elt as HTMLInputElement
-
-
-## Modules
-
-### `from` Shorthand
-
-If you have `from` in your `import`, you can omit `import`.
-You can also omit quotes around most filenames.
-
-
-fs from fs
-{basename, dirname} from path
-metadata from ./package.json assert type: 'json'
-
-
-### Import Like Object Destructuring
-
-
-import {X: LocalX, Y: LocalY} from "./util"
-{X: LocalX, Y: LocalY} from "./util"
-
-
-### Dynamic Import
-
-If it's not the start of a statement,
-dynamic `import` does not require parentheses.
-
-
-{x} = await import url
-
-
-### Export Shorthand
-
-
-export a, b, c from "./cool.js"
-export x = 3
-
-
-## Comments
-
-### JavaScript Comments
-
-
-// one-line comment
-/** Block comment
- */
-const i /* inline comment */ : number
-
-
-### Block Comments
-
-
-###
-block comment
-/* nested comment */
-###
-
-
-### `#` Comments
-
-If you do not need
-[private class fields](#private-fields),
-you can enable `#` one-line comments (as in many other languages)
-via a `"civet"` directive at the beginning of your file:
-
-
-"civet coffee-comment"
-# one-line comment
-
-
-## JSX
-
-Enhancements, inspired by [solid-dsl discussions](https://github.com/solidjs-community/solid-dsl/discussions)
-and [jsx spec issues](https://github.com/facebook/jsx/issues)
-
-### Element id
-
-
-Civet
-
Civet
-
-
-### Class
-
-
-Civet
-
Civet
-
Civet
-
-
-
-### Implicit Element
-
-
-<.foo>Civet
-
-
-
-"civet defaultElement=span"
-<.foo>Civet
-
-
-::: info
-Implicit elements must start with `id` or `class` shorthand (`#` or `.`).
-:::
-
-### Boolean Toggles
-
-
-
-
-
-::: tip
-
-`!` is synonymous with `-` and both say "set the attribute value to false".
-
-:::
-
-### Attributes
-
-Attribute values without whitespace or suitably wrapped (parenthesized expressions, strings and template strings, regular expressions, array literals, braced object literals) do not need braces:
-
-
-
- Civet
-
-
-Arbitrary [braced literals](#braced-literals) convert to equivalent JSX:
-
-
-Civet
-
Civet
-
Civet
-
-
-Call/member/glob/spread expressions without unwrapped whitespace
-do not need braces
-(but note that simple identifiers remain empty attributes):
-
-
-Civet
-
Civet
-
Civet
-
Civet
-
Civet
-
Civet
-
Civet
-
-
-Computed property names:
-
-
-Civet
-
Civet
-
-
-### Comments
-
-
-
-
- Civet
-
-
-### Indentation
-
-Closing tags are optional if JSX uses indentation.
-
-
-return
- <>
-
- Hello {name}!
- {svg}
-
-
-### Implicit Fragments
-
-Adjacent elements/fragments get implicitly combined into one fragment,
-unless they are items in an array.
-
-
-return
- Hello World!
- Body
-
-
-
-[
- Hello World!
- Body
-]
-
-
-### Function Children
-
-
-
- (item) =>
- {item}
-
-
-## [SolidJS](https://www.solidjs.com/)
-
-`link` automatically typed as `HTMLAnchorElement`
-
-
-"civet solid"
-link := Civet
-
-
-## [CoffeeScript](https://coffeescript.org/) Compatibility
-
-Turn on full [CoffeeScript](https://coffeescript.org/) compatibility mode
-with a `"civet coffeeCompat"` directive at the top of your file,
-or use more specific directive(s) as listed below.
-You can also selectively remove features, such as
-`"civet coffeeCompat -coffeeForLoops -autoVar"`.
-
-### CoffeeScript For Loops
-
-
-"civet coffeeForLoops autoVar"
-for item, index in array
- console.log item, index
-for key, value of object
- console.log key, value
-for own key, value of object
- console.log key, value
-for item from iterable
- console.log item
-
-
-### Double-Quoted Strings
-
-
-"civet coffeeInterpolation"
-console.log "Hello #{name}!"
-
-
-### CoffeeScript Operators
-
-
-"civet coffeeEq"
-x == y != z
-
-
-
-"civet coffeeIsnt"
-x isnt y
-
-
-
-"civet coffeeNot"
-not (x == y)
-not x == y
-
-
-
-"civet coffeeBinaryExistential"
-x ? y
-
-
-
-"civet coffeeOf"
-item in array
-key of object
-
-
-
-"civet coffeePrototype"
-X::
-X::a
-
-
-### CoffeeScript Booleans
-
-
-"civet coffeeBooleans"
-on
-off
-yes
-no
-
-
-### CoffeeScript Comments
-
-If you don't need [private class fields](#private-fields),
-you can enable `#` for single-line comments:
-
-
-"civet coffeeComment"
-# one-line comment
-
+```
-[`###...###` block comments](#block-comments) are always available.
+
diff --git a/civet.dev/comparison.md b/civet.dev/comparison.md
index e66681c9..e147715c 100644
--- a/civet.dev/comparison.md
+++ b/civet.dev/comparison.md
@@ -165,7 +165,7 @@ $: document.title = title
## Decorators
Civet uses `@` as
-[shorthand for `this`, `static`, and `constructor`](/cheatsheet#this).
+[shorthand for `this`, `static`, and `constructor`](/reference#this).
Decorators need to be written with `@@`:
diff --git a/civet.dev/index.md b/civet.dev/index.md
index 0837051d..a1d4d74d 100644
--- a/civet.dev/index.md
+++ b/civet.dev/index.md
@@ -18,7 +18,7 @@ so you can [use existing tooling](/integrations)
but enable concise and powerful syntax.
In addition to 99% JS/TS [compatibility](/comparison), there are many
features, with some highlights below and more comprehensive examples
-on the [cheatsheet](/cheatsheet).
+in the [reference](/reference).
See also Civet's [design philosophy](/philosophy).
## Highlights: Beyond TC39
@@ -174,7 +174,7 @@ export a, b, c from "./cool.js"
export x = 3
-### [JSX](/cheatsheet#jsx)
+### [JSX](/reference#jsx)
function Listing(props)
diff --git a/civet.dev/reference.md b/civet.dev/reference.md
new file mode 100644
index 00000000..8843c4c5
--- /dev/null
+++ b/civet.dev/reference.md
@@ -0,0 +1,1642 @@
+---
+title: Reference
+aside: false
+---
+
+# {{ $frontmatter.title }}
+
+Civet code on the left top ,
+compiled TypeScript output on
+the right bottom .
+
+In most cases, the Civet code on
+the left top
+is optional shorthand.
+The TypeScript code on
+the right bottom
+(and most TypeScript code) is almost always also valid Civet input.
+
+[[toc]]
+
+## Variable Declaration
+
+By default, you are responsible for declaring your variables
+via `var`, `let`, `const`, or their shorthands:
+
+
+a := 10
+b .= 10
+c: number | string .= 0
+let d: boolean
+var v: any
+
+
+Alternatively, you can use a `"civet"` directive at the beginning of your file
+to specify one of two automatic variable declaration modes:
+
+### `autoVar`
+
+
+"civet autoVar"
+sos = 0
+for item of iterable
+ square = item * item
+ sos += square
+
+
+### `autoLet`
+
+
+"civet autoLet"
+sos = 0
+for item of iterable
+ square = item * item
+ sos += square
+
+
+### Declarations in Conditions and Loops
+
+
+if match := regex.exec string
+ console.log match[1], match[2]
+
+
+
+if [, dir, base] := /^(.*\/)?([^/]*)$/.exec file
+ console.log dir, base
+
+
+
+if {x, y} := getLocation()
+ console.log `At ${x}, ${y}`
+else
+ console.log "Not anywhere"
+
+
+
+node .= linkedList.head
+while {data, next} := node
+ console.log data
+ node = next
+
+
+## Objects
+
+### Unbraced Literals
+
+When every property has a value, braces can be omitted.
+
+
+person := name: 'Henry', age: 4
+obj :=
+ a: 1
+ b: 2
+ c:
+ x: 'pretty'
+ y: 'cool'
+
+
+`$:` behaves specially for Svelte compatibility. If you want a key of `$`,
+wrap it in quotes or use explicit braces.
+
+
+$: document.title = title
+"$": "dollar"
+{$: "dollar"}
+
+
+### Braced Literals
+
+With braces, the `{x}` shorthand generalizes to any
+sequence of member accesses and/or calls:
+
+
+another := {person.name, obj?.c?.x}
+computed := {foo(), bar()}
+named := {lookup[x+y]}
+templated := {`${prefix}${suffix}`: result}
+
+
+### Object Globs
+
+Inspired by
+[brace expansion in shell globs](https://en.wikipedia.org/wiki/Bash_(Unix_shell)#Brace_expansion):
+
+
+point = data{x,y}
+point = data.{x,y};
+point.{x,y} = data
+point3D = { point.{x,y}, z: 0 }
+complex := obj.{x:a, b.c()?.y}
+merged := data.{...global, ...user};
+data.{a, b, ...rest} = result
+
+
+### Flagging Shorthand
+
+Inspired by [LiveScript](https://livescript.net/#literals-objects):
+
+
+config := {
+ +debug
+ -live
+ !verbose
+}
+
+
+### Methods and Getters/Setters
+
+Braced objects support methods and getters/setters:
+
+
+p := {
+ name: 'Mary'
+ say(msg)
+ console.log @name, 'says', msg
+ setName(@name);
+ get NAME()
+ @name.toUpperCase()
+}
+p.say p.NAME
+
+
+::: tip
+
+Methods need a body, or they get treated as literal shorthand.
+To specify a blank body, use `;` or `{}`.
+
+:::
+
+### Property Access
+
+Many more literals can appear after a `.` to access an object property:
+
+
+json.'long property'
+json.`${movie} name`
+matrix.0.0
+array.-1
+
+
+You can also write property access as an English possessive
+(inspired by [_hyperscript](https://hyperscript.org/expressions/possessive/)):
+
+
+mario's brother's name
+mario?'s name
+json's "long property"'s `${movie} name`
+
+
+## Arrays
+
+Commas are optional at the ends of lines.
+
+
+rotate := [
+ c, -s
+ s, c
+]
+
+
+
+func.apply @, [
+ arg1
+ arg2
+]
+
+
+
+people := [
+ name: "Alice"
+ id: 7
+,
+ name: "Bob"
+ id: 9
+]
+
+
+### Rest
+
+Rest properties/parameters/elements are no longer limited to the final position.
+You may use them in their first or middle positions as well.
+
+
+[...head, last] = [1, 2, 3, 4, 5]
+
+
+
+{a, ...rest, b} = {a: 7, b: 8, x: 0, y: 1}
+
+
+
+function justDoIt(a, ...args, cb) {
+ cb.apply(a, args)
+}
+
+
+You can also omit the name of the rest component:
+
+
+[first, ..., last] = array
+
+
+### Range Literals
+
+`[x..y]` includes `x` and `y`, while `[x...y]` includes `x` but not `y`.
+
+
+letters := ['a'..'f']
+numbers := [1..10]
+reversed := [10..1]
+indices := [0...array.length]
+
+
+### Array/String Slicing
+
+`[i..j]` includes `i` and `j`, while `[i...j]` includes `i` but not `j`.
+`i` and/or `j` can be omitted when slicing.
+
+
+start := numbers[..2]
+mid := numbers[3...-2]
+end := numbers[-2..]
+numbers[1...-1] = []
+
+
+## Strings
+
+Strings can span multiple lines:
+
+
+console.log "Hello,
+world!"
+
+
+
+### Triple-Quoted Strings
+
+Leading indentation is removed.
+
+
+console.log '''
+
+ Civet
+
+'''
+
+
+
+console.log """
+
+ Civet #{version}
+
+"""
+
+
+
+console.log ```
+
+ Civet ${version}
+
+```
+
+
+## Operators
+
+### All JavaScript/TypeScript Operators
+
+
+center := min + length / 2
+name := user?.name ?? defaultName
+typeof x === "string" && x += "!"
+result! as string | number
+
+
+### Late Assignment
+
+
+a + b = c
+
+
+### Multi Assignment
+
+
+(count[key] ?= 0)++
+(count[key] ?= 0) += 1
+++count *= 2
+
+
+### Humanized Operators
+
+
+a is b
+a is not b
+a and b
+a or b
+a not in b
+a not instanceof b
+a?
+
+
+### Includes Operator
+
+
+item is in array
+item is not in array
+substring is in string
+item1 ∈ container ∌ item2 // Unicode
+
+
+### Assignment Operators
+
+
+a and= b
+a or= b
+a ?= b
+obj.key ?= "civet"
+
+
+### Optional Chaining
+
+
+obj?[key]
+fun?(arg)
+
+
+## Existence Checking
+
+
+x?
+x.y[z]?
+
+
+### Chained Comparisons
+
+
+a < b <= c
+a ≤ b ≤ c // Unicode
+a ≡ b ≣ c ≠ d ≢ e
+a is b is not c
+a instanceof b not instanceof c
+x? instanceof Function
+
+
+### `instanceof` shorthand
+
+
+a b
+a ! b
+a b ! c
+
+
+### `typeof` shorthand
+
+
+a "string"
+a ! "string"
+a instanceof "number"
+a not instanceof "number"
+
+
+### Logical XOR Operator
+
+
+a ^^ b
+a xor b
+a ^^= b
+a xor= b
+
+
+
+a !^ b
+a xnor b
+a !^= b
+a xnor= b
+
+
+### Modulo Operator
+
+`%` can return negative values, while `%%` is always between 0 and the divisor.
+
+
+let a = -3
+let b = 5
+let rem = a % b
+let mod = a %% b
+console.log rem, mod
+
+
+### `Object.is`
+
+The `"civet objectIs"` directive changes the behavior of the `is` operator to
+[`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is),
+which is a bit better behaved than `===`.
+The plan is to make this the default behavior, once TypeScript supports
+type narrowing with `Object.is` as well as it does for `===`.
+(Currently, `a is b` will not correctly narrow `b` in some edge cases.)
+
+
+"civet objectIs"
+a is b
+a is not b
+
+
+### Pipe Operator
+
+Based on
+[F# pipes](https://learn.microsoft.com/en-us/dotnet/fsharp/language-reference/symbol-and-operator-reference/#function-symbols-and-operators) and
+[TC39 Proposal: Pipe Operator](https://github.com/tc39/proposal-pipeline-operator).
+
+
+data
+ |> Object.keys
+ |> console.log
+
+
+Pairs particularly well with
+[single-argument function shorthand](#single-argument-function-shorthand):
+
+
+x.length |> & + 1 |> .toString()
+
+
+Use `await`, `yield`, or `return` in your pipeline:
+
+
+fetch url |> await
+|> .json() |> await
+|> return
+
+
+Pipe assignment:
+
+
+data |>= .content
+
+
+Fat pipes `||>` pass the left-hand value to the next two steps in the pipeline
+(ignoring the output from the right-hand side):
+
+
+array
+||> .pop()
+||> .push 5
+||> .sort()
+||> .reverse()
+
+
+
+count |> & + 1
+||> console.log
+|> & * 2
+||> console.log
+
+
+
+url |> fetch |> await
+||> (response) => console.log response.status
+|> .json() |> await
+||> (json) => console.log "json:", json
+|> callback
+
+
+Unicode forms:
+
+
+data ▷= func1 |▷ func2 ▷ func3
+
+
+### Await Operators
+
+[TC39 proposal: `await` operations](https://github.com/tc39/proposal-await.ops)
+
+
+await.allSettled promises
+
+
+
+await.all
+ for url of urls
+ fetch url
+
+
+
+await.all
+ for url of urls
+ async do
+ fetch url |> await |> .json() |> await
+
+
+### Custom Infix Operators
+
+You can also define your own infix operators;
+see [Functions as Infix Operators](#functions-as-infix-operators) below.
+
+## Functions
+
+### Function Calls
+
+The parentheses in a function call are usually optional.
+If present, there should be no space between the function and the open paren.
+
+
+console.log x, f(x), (f g x), g f x
+
+
+### `function`
+
+
+function abort
+ process.exit 1
+
+
+
+function circle(degrees: number): {x: number, y: number}
+ radians := degrees * Math.PI / 180
+ x: Math.cos radians
+ y: Math.sin radians
+
+
+::: info
+Implicit return of the last value in a function can be avoided by
+specifying a `void` return type (or `Promise` for async functions),
+adding a final semicolon or explicit `return`,
+or globally using the directive `"civet -implicitReturns"`.
+:::
+
+
+function abort
+ process.exit 1;
+
+
+
+function abort: void
+ process.exit 1
+
+
+
+function run(command: string): Promise
+ await exec command
+
+
+### One-Line Functions
+
+
+function do console.log "Anonymous"
+function f do console.log "Named"
+function f(x) do console.log x
+
+
+### Function Overloading
+
+
+function add(a: string, b: string): string
+function add(a: number, b: number): number
+ a+b
+
+
+### Arrow Functions
+
+::: info
+Unlike ECMAScript, zero-argument arrows do not need a `()` prefix,
+but one-argument arrows do need parentheses around the argument.
+:::
+
+
+abort := => process.exit 1
+
+
+
+createEffect => console.log data()
+greet := (name) => console.log "Hello", name
+
+
+::: info
+`=>` makes arrow functions as usual, while
+`->` makes `function`s (which can have `this` assigned via `.call`).
+:::
+
+
+add := (a: number, b: number) => a + b
+
+
+
+add := (a: number, b: number) -> a + b
+
+
+::: info
+Unlike ECMAScript, even multi-line arrow functions implicitly return their
+last value. See [above](#function) for how to avoid this behavior.
+:::
+
+
+circle := (degrees: number): {x: number, y: number} =>
+ radians := degrees * Math.PI / 180
+ x: Math.cos radians
+ y: Math.sin radians
+
+
+You can also use Unicode arrows:
+
+
+curryAdd := (a: number) → (b: number) ⇒ a + b
+
+
+### `return.value`
+
+Instead of specifying a function's return value when it returns,
+you can prepare it ahead of time using `return.value`
+(or its shorthand, assigning to `return`).
+Using this feature disables implicit `return` for that function.
+
+
+function sum(list: number[])
+ return .= 0
+ for item of list
+ return += item
+
+
+
+function search(list: T[]): T | undefined
+ return unless list
+ for item of list
+ if match item
+ return = item
+ return++ if return.value
+ list.destroy()
+
+
+### Single-Argument Function Shorthand
+
+
+x.map &.name
+x.map &.profile?.name[0...3]
+x.map &.callback a, b
+x.map +&
+
+
+::: info
+Short function block syntax like [Ruby symbol to proc](https://ruby-doc.org/core-3.1.2/Symbol.html#method-i-to_proc),
+[Crystal](https://crystal-lang.org/reference/1.6/syntax_and_semantics/blocks_and_procs.html#short-one-parameter-syntax),
+or [Elm record access](https://elm-lang.org/docs/records#access).
+:::
+
+You can also omit `&` when starting with a `.` or `?.` property access:
+
+
+x.map .name
+x.map ?.profile?.name[0...3]
+
+
+### Functions as Infix Operators
+
+You can "bless" an existing function to behave as an infix operator
+(and a negated form) like so:
+
+
+operator contains
+x contains y
+x not contains y
+
+
+You can combine this with a [variable declaration](#variable-declaration):
+
+
+operator {min, max} := Math
+value min ceiling max floor
+
+
+You can also define an operator with a function body:
+
+
+operator calls(t: T, f: (this: T) => R): R
+ f.call(t)
+this calls callback
+
+
+Operators are just functions in the end, and behave as such when used
+unambiguously:
+
+
+operator foo
+x foo foo(y, z)
+x (foo) y
+
+
+You can also `import` functions from another module as operators
+(independent of whether they are declared as operators in the other module):
+
+
+import { operator contains } from 'bar'
+x contains y
+export operator has(x, y)
+ y contains x
+
+
+### Operator Assignment
+
+Even without blessing a function as an `operator`, you can use it in
+an assignment form:
+
+
+{min, max} := Math
+smallest .= Infinity
+largest .= -Infinity
+for item in items
+ smallest min= item
+ largest max= item
+
+
+## Conditions
+
+### If/Else
+
+
+if coffee or relaxed
+ code()
+else
+ sleep()
+
+
+### One-Line If/Else
+
+
+if coffee or relaxed then code() else sleep()
+
+
+### If/Else Expressions
+
+
+name :=
+ if power === Infinity
+ "Saitama"
+ else if power > 9000
+ "Goku"
+caps := if name? then name.toUpperCase() else 'ANON'
+
+
+### Unless
+
+
+unless tired
+ code()
+
+
+### Postfix If/Unless
+
+
+civet.speed = 15 if civet.rested
+
+
+### Switch
+
+
+switch dir
+ when '>' then civet.x++
+ when '<'
+ civet.x--
+ civet.x = 0 if civet.x < 0
+ else civet.waiting += 5
+
+
+With implicit `return`:
+
+
+getX := (civet: Civet, dir: Dir) =>
+ switch dir
+ when '>' then civet.x + 3
+ when '<' then civet.x - 1
+ when '^' then civet.x + 0.3
+
+
+### Pattern Matching
+
+
+switch s
+ ""
+ console.log "nothing"
+ /\s+/
+ console.log "whitespace"
+ "hi"
+ console.log "greeting"
+
+
+
+switch a
+ []
+ console.log "empty"
+ [item]
+ console.log "one", item
+ [first, ...middle, last]
+ console.log "multiple", first, "...", last
+ else
+ console.log "not array"
+
+
+::: info
+Array patterns are exact; object patterns allow unmatched properties
+(similar to TypeScript types).
+:::
+
+
+switch x
+ {type: "text", content}
+ console.log `"${content}"`
+ {type, ...rest}
+ console.log `unknown type ${type}`
+ else
+ console.log 'unknown'
+
+
+
+switch x
+ [{type: "text", content: /\s+/}, ...rest]
+ console.log "leading whitespace"
+ [{type: "text", content}, ...rest]
+ console.log "leading text:", content
+ [{type}, ...rest]
+ console.log "leading type:", type
+
+
+::: info
+You can also use condition fragments as patterns.
+:::
+
+
+switch x
+ < 0
+ console.log "it's negative"
+ > 0
+ console.log "it's positive"
+ is 0
+ console.log "it's zero"
+ else
+ console.log "it's something else"
+
+
+
+switch x
+ % 15 is 0
+ console.log "fizzbuzz"
+ % 3 is 0
+ console.log "fizz"
+ % 5 is 0
+ console.log "buzz"
+ else
+ console.log x
+
+
+::: info
+Aliasing object properties works the same as destructuring.
+:::
+
+
+switch e
+ {type, key: eventKey}
+ return [type, eventKey]
+
+
+::: info
+Patterns can aggregate duplicate bindings.
+:::
+
+
+switch x
+ [{type}, {type}]
+ type
+
+
+## Loops
+
+All JavaScript loops are available,
+with optional parentheses around the clause.
+
+
+for let i = 0; i < 100; i++
+ console.log i
+
+
+### for..of
+
+Looping over an iterator via `for..of` defaults to `const`:
+
+
+for item of list
+ console.log item
+
+
+
+for let item of list
+ item *= item
+ console.log item
+
+
+You can also keep track of the current index of the iteration
+by specifying a comma and a second variable (also defaulting to `const`):
+
+
+for item, index of list
+ console.log `${index}th item is ${item}`
+
+
+### for each..of
+
+For Arrays and other objects implementing `.length` and `[i]` indexing,
+you can use `for each..of` as an optimized form of `for..of`
+(without building an iterator):
+
+
+for each item of list
+ console.log item
+
+
+
+for each let item of list
+ item *= item
+ console.log item
+
+
+
+for each item, index of list
+ console.log `${index}th item is ${item}`
+
+
+`for each` loops are similar to `Array.prototype.forEach` (hence the name),
+but are more efficient and allow for e.g. `break` and `continue`.
+
+### for..in
+
+Looping over properties of an object via `for..in` defaults to `const`:
+
+
+for key in object
+ console.log key
+
+
+
+for var key in object
+ console.log key
+console.log `Last key is ${key}`
+
+
+You can also retrieve the corresponding value
+by specifying a comma and a second variable (also defaulting to `const`):
+
+
+for key, value in object
+ console.log `${key} maps to ${value}`
+
+
+If your object might have a prototype with enumerable properties,
+you can skip them with `own`:
+
+
+for own key in object
+ console.log key
+
+
+### Loop Expressions
+
+If needed, loops automatically assemble an Array of the last value
+within the body of the loop for each completed iteration.
+
+
+squares :=
+ for item of list
+ item * item
+
+
+
+evenSquares :=
+ for item of list
+ continue unless item % 2 == 0
+ item * item
+
+
+
+function parities(list: number[]): string[]
+ for item of list
+ if item % 2 === 0
+ "even"
+ else
+ "odd"
+
+
+::: info
+Because loop expressions wrap in an
+[IIFE](https://developer.mozilla.org/en-US/docs/Glossary/IIFE),
+you cannot use `return` inside such a loop,
+nor can you `break` or `continue` any outer loop.
+:::
+
+Loops that use `await` automatically get `await`ed.
+If you'd rather obtain the promise for the results so you can `await` them
+yourself, use `async for`.
+
+
+results :=
+ for url of urls
+ await fetch url
+
+
+
+promise :=
+ async for url of urls
+ await fetch url
+
+
+### Postfix Loop
+
+
+console.log item for item of array
+
+
+### Infinite Loop
+
+
+i .= 0
+loop
+ i++
+ break if i > 5
+
+
+### Range Loop
+
+
+for i of [0...array.length]
+ array[i] = array[i].toString()
+
+
+
+for [1..5]
+ attempt()
+
+
+### Until Loop
+
+
+i .= 0
+until i > 5
+ i++
+
+
+### Do...While/Until Loop
+
+
+total .= 0
+item .= head
+do
+ total += item.value
+ item = item.next
+while item?
+
+
+### Do Blocks
+
+To put multiple lines in a scope and possibly an expression,
+you can use `do` without a `while`/`until` suffix, similar to
+[TC39 proposal: `do` expressions](https://github.com/tc39/proposal-do-expressions).
+
+
+x := 5
+do
+ x := 10
+ console.log x
+console.log x
+
+
+
+x := do
+ y := f()
+ y*y
+
+
+::: info
+Because `do` expressions wrap in an
+[IIFE](https://developer.mozilla.org/en-US/docs/Glossary/IIFE),
+you cannot use `return`, `break`, or `continue` within them.
+:::
+
+### Async Do Blocks
+
+You can create a promise using `await` notation with `async do`:
+
+
+promise := async do
+ result := await fetch url
+ await result.json()
+
+
+
+await Promise.allSettled for url of urls
+ async do
+ result := await fetch url
+ await result.json()
+
+
+### Labels
+
+
+:outer while (list = next())?
+ for item of list
+ if finale item
+ break outer
+ continue :outer
+
+
+::: info
+Labels have the colon on the left to avoid conflict with implicit object
+literals. The colons are optional in `break` and `continue`.
+As a special case, Svelte's `$:` can be used with the colon on the right.
+:::
+
+
+$: document.title = title
+
+
+## Classes
+
+
+class Animal
+ sound = "Woof!"
+ bark(): void
+ console.log @sound
+ wiki()
+ fetch 'https://en.wikipedia.org/wiki/Animal'
+
+
+### This
+
+
+@
+id := @id
+obj := { @id }
+
+
+### Bind
+
+
+bound := object@.method
+bound := object@method
+bound := @@method
+
+
+### Private Fields
+
+[Private class fields](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields)
+do not need an explicit `this.` or `@` prefix.
+
+
+class Counter
+ #count = 0
+ increment(): void
+ #count++
+ add(other: Counter): void
+ #count += other.#count if #count in other
+ set(#count)
+
+
+### Static Fields
+
+
+class A
+ @a = 'civet'
+
+
+### Readonly Fields
+
+
+class B
+ b := 'civet'
+
+
+### Typed Fields
+
+
+class C
+ size: number | undefined
+ @root: Element = document.body
+
+
+### Constructor
+
+
+class Rectangle
+ @(@width: number, @height: number)
+
+
+
+class Rectangle
+ @(public width: number, public height: number)
+
+
+### Static Block
+
+
+class Civet
+ @
+ try
+ this.colors = getCivetColors()
+
+
+### Extends
+
+
+class Civet < Animal
+
+
+### Implements
+
+
+class Civet < Animal <: Named
+class Civet <: Animal, Named
+
+
+### Decorators
+
+
+@@Object.seal
+class Civet
+ @name = "Civet"
+
+
+## Types
+
+### Unknown
+
+`???` is shorthand for the type `unknown`.
+
+
+declare function jsonParse(json: string): ???
+
+
+### Import
+
+
+type { Civet, Cat } from animals
+
+
+
+{ type Civet, meow } from animals
+
+
+### Aliases
+
+
+type ID = number | string
+
+
+
+type Point = x: number, y: number
+
+
+The `=` is optional if the content is indented:
+
+
+type ID
+ | number
+ | string
+type Point
+ x: number
+ y: number
+
+
+### Interfaces
+
+
+interface Point
+ x: number
+ y: number
+
+
+
+interface Point3D < Point
+ z: number
+
+
+
+interface Signal
+ listen(callback: =>): void
+
+
+
+interface Node
+ value: T
+ next: Node
+
+
+### Enum
+
+
+enum Direction
+ Up
+ Down
+ Left = 2 * Down
+ Right = 2 * Left
+
+
+### Assertions
+
+
+elt as HTMLInputElement
+
+
+## Modules
+
+### `from` Shorthand
+
+If you have `from` in your `import`, you can omit `import`.
+You can also omit quotes around most filenames.
+
+
+fs from fs
+{basename, dirname} from path
+metadata from ./package.json assert type: 'json'
+
+
+### Import Like Object Destructuring
+
+
+import {X: LocalX, Y: LocalY} from "./util"
+{X: LocalX, Y: LocalY} from "./util"
+
+
+### Dynamic Import
+
+If it's not the start of a statement,
+dynamic `import` does not require parentheses.
+
+
+{x} = await import url
+
+
+### Export Shorthand
+
+
+export a, b, c from "./cool.js"
+export x = 3
+
+
+## Comments
+
+### JavaScript Comments
+
+
+// one-line comment
+/** Block comment
+ */
+const i /* inline comment */ : number
+
+
+### Block Comments
+
+
+###
+block comment
+/* nested comment */
+###
+
+
+### `#` Comments
+
+If you do not need
+[private class fields](#private-fields),
+you can enable `#` one-line comments (as in many other languages)
+via a `"civet"` directive at the beginning of your file:
+
+
+"civet coffee-comment"
+# one-line comment
+
+
+## JSX
+
+Enhancements, inspired by [solid-dsl discussions](https://github.com/solidjs-community/solid-dsl/discussions)
+and [jsx spec issues](https://github.com/facebook/jsx/issues)
+
+### Element id
+
+
+Civet
+
Civet
+
+
+### Class
+
+
+Civet
+
Civet
+
Civet
+
+
+
+### Implicit Element
+
+
+<.foo>Civet
+
+
+
+"civet defaultElement=span"
+<.foo>Civet
+
+
+::: info
+Implicit elements must start with `id` or `class` shorthand (`#` or `.`).
+:::
+
+### Boolean Toggles
+
+
+
+
+
+::: tip
+
+`!` is synonymous with `-` and both say "set the attribute value to false".
+
+:::
+
+### Attributes
+
+Attribute values without whitespace or suitably wrapped (parenthesized expressions, strings and template strings, regular expressions, array literals, braced object literals) do not need braces:
+
+
+
+ Civet
+
+
+Arbitrary [braced literals](#braced-literals) convert to equivalent JSX:
+
+
+Civet
+
Civet
+
Civet
+
+
+Call/member/glob/spread expressions without unwrapped whitespace
+do not need braces
+(but note that simple identifiers remain empty attributes):
+
+
+Civet
+
Civet
+
Civet
+
Civet
+
Civet
+
Civet
+
Civet
+
+
+Computed property names:
+
+
+Civet
+
Civet
+
+
+### Comments
+
+
+
+
+ Civet
+
+
+### Indentation
+
+Closing tags are optional if JSX uses indentation.
+
+
+return
+ <>
+
+ Hello {name}!
+ {svg}
+
+
+### Implicit Fragments
+
+Adjacent elements/fragments get implicitly combined into one fragment,
+unless they are items in an array.
+
+
+return
+ Hello World!
+ Body
+
+
+
+[
+ Hello World!
+ Body
+]
+
+
+### Function Children
+
+
+
+ (item) =>
+ {item}
+
+
+## [SolidJS](https://www.solidjs.com/)
+
+`link` automatically typed as `HTMLAnchorElement`
+
+
+"civet solid"
+link := Civet
+
+
+## [CoffeeScript](https://coffeescript.org/) Compatibility
+
+Turn on full [CoffeeScript](https://coffeescript.org/) compatibility mode
+with a `"civet coffeeCompat"` directive at the top of your file,
+or use more specific directive(s) as listed below.
+You can also selectively remove features, such as
+`"civet coffeeCompat -coffeeForLoops -autoVar"`.
+
+### CoffeeScript For Loops
+
+
+"civet coffeeForLoops autoVar"
+for item, index in array
+ console.log item, index
+for key, value of object
+ console.log key, value
+for own key, value of object
+ console.log key, value
+for item from iterable
+ console.log item
+
+
+### Double-Quoted Strings
+
+
+"civet coffeeInterpolation"
+console.log "Hello #{name}!"
+
+
+### CoffeeScript Operators
+
+
+"civet coffeeEq"
+x == y != z
+
+
+
+"civet coffeeIsnt"
+x isnt y
+
+
+
+"civet coffeeNot"
+not (x == y)
+not x == y
+
+
+
+"civet coffeeBinaryExistential"
+x ? y
+
+
+
+"civet coffeeOf"
+item in array
+key of object
+
+
+
+"civet coffeePrototype"
+X::
+X::a
+
+
+### CoffeeScript Booleans
+
+
+"civet coffeeBooleans"
+on
+off
+yes
+no
+
+
+### CoffeeScript Comments
+
+If you don't need [private class fields](#private-fields),
+you can enable `#` for single-line comments:
+
+
+"civet coffeeComment"
+# one-line comment
+
+
+[`###...###` block comments](#block-comments) are always available.