Skip to content

Civet

A Programming Language for the New Millenium

Code More with Less in a TypeScript Superset

Civet logo

Civet is a programming language that compiles to TypeScript or JavaScript, so you can use existing tooling (including VSCode type checking, hints, completion, etc.) while enabling concise and powerful syntax. It starts with 99% JS/TS compatibility, making it easy to transition existing code bases. Then it adds many features and syntactic sugar, with some highlights below and more comprehensive examples in the reference. See also Civet's design philosophy and changelog.

Highlights: Beyond TC39

Civet code on the lefttop, compiled TypeScript output on the rightbottom.

Pattern Matching

TC39 Proposal: Pattern Matching

switch x
  0
    console.log("zero")
  /^\s+$/
    console.log("whitespace")
  [{type: "text", content}, ...rest]
    console.log("leading text", content)
Edit inline or edit in the Playground!
if (x === 0) {
  console.log("zero");
} else if (
  typeof x === "string" &&
  /^\s+$/.test(x)
) {
  console.log("whitespace");
} else if (
  Array.isArray(x) &&
  x.length >= 1 &&
  typeof x[0] === "object" &&
  x[0] != null &&
  "type" in x[0] &&
  x[0].type === "text" &&
  "content" in x[0]
) {
  const [{ type, content }, ...rest] = x;
  console.log("leading text", content);
}

Pipelines

TC39 Proposal: Pipe Operator

data
  |> Object.keys
  |> console.log
Edit inline or edit in the Playground!
console.log(Object.keys(data));

Fat pipes manipulate the same object repeatedly:

document.createElement('div')
||> .className = 'civet'
||> .appendChild document.createTextNode 'Civet'
Edit inline or edit in the Playground!
let ref;
((ref = document.createElement("div")).className =
  "civet"),
  ref.appendChild(
    document.createTextNode("Civet"),
  ),
  ref;

Pipe expression with shorthand functions:

a |> & + 1 |> bar
Edit inline or edit in the Playground!
bar(a + 1);

Single-Argument Function Shorthand

x.map .name
x.map &.profile?.name[0...3]
x.map &.callback a, b
x.map &+1
x.map -&
x.map [&, &.toUpperCase()]
Edit inline or edit in the Playground!
x.map(($) => $.name);
x.map(($1) => $1.profile?.name.slice(0, 3));
x.map(($2) => $2.callback(a, b));
x.map(($3) => $3 + 1);
x.map(($4) => -$4);
x.map(($5) => [$5, $5.toUpperCase()]);

Custom Infix Operators

operator {min, max} := Math
value min ceiling max floor
Edit inline or edit in the Playground!
const { min, max } = Math;
max(min(value, ceiling), floor);

Declarations in Conditions and Loops

if match := regex.exec string
  console.log match
Edit inline or edit in the Playground!
let ref;
if ((ref = regex.exec(string))) {
  const match = ref;
  console.log(match);
}

Everything is an Expression

items = for item of items
  if item.length
    item.toUpperCase()
  else
    "<empty>"
Edit inline or edit in the Playground!
const results = [];
for (const item of items) {
  if (item.length) {
    results.push(item.toUpperCase());
  } else {
    results.push("<empty>");
  }
}
items = results;
return
  if x == null
    throw "x is null"
  else
    log `received x of ${x}`
    x.value()
Edit inline or edit in the Playground!
return (() => {
  if (x == null) {
    throw "x is null";
  } else {
    log(`received x of ${x}`);
    return x.value();
  }
})();
const fs = import {readFile, writeFile} from "fs"
Edit inline or edit in the Playground!
let ref;
const fs =
  ((ref = await import("fs")),
  {
    readFile: ref.readFile,
    writeFile: ref.writeFile,
  });

TC39 proposal: do expressions

x = do
  const tmp = f()
  tmp * tmp + 1
Edit inline or edit in the Playground!
let ref;
{
  const tmp = f();
  ref = tmp * tmp + 1;
}
x = ref;

Bulleted Lists and Unbraced Object Literals

projects:
  . name: "Civet"
    url: "https://civet.dev"
  . name: "TypeScript"
    url: "https://www.typescriptlang.org"
colorPairs:
  . . "red"
    . "#f00"
  . . "green"
    . "#0f0"
  . . "blue"
    . "#00f"
Edit inline or edit in the Playground!
({
  projects: [
    { name: "Civet", url: "https://civet.dev" },
    {
      name: "TypeScript",
      url: "https://www.typescriptlang.org",
    },
  ],
  colorPairs: [
    ["red", "#f00"],
    ["green", "#0f0"],
    ["blue", "#00f"],
  ],
});

Dedented Strings and Templates

TC39 Proposal: String Dedent

text = """
  This text is a string that doesn't include
  the leading whitespace.
"""
Edit inline or edit in the Playground!
text = `This text is a string that doesn't include
the leading whitespace.`;
text = ```
  Also works for
  ${templates}!
```
Edit inline or edit in the Playground!
text = `Also works for
${templates}!`;

Chained Comparisons

a < b <= c
value > min?
a is b is not c
a instanceof b not instanceof c
Edit inline or edit in the Playground!
a < b && b <= c;
min != null && value > min;
a === b && b !== c;
a instanceof b && !(b instanceof c);

Default to const for Iteration Items

for (item of [1, 2, 3, 4, 5]) {
  console.log(item * item);
}
Edit inline or edit in the Playground!
for (const item of [1, 2, 3, 4, 5]) {
  console.log(item * item);
}

Spread in Any Position

Spreads in first or middle position:

[...head, last] = [1, 2, 3, 4, 5]
Edit inline or edit in the Playground!
([...head] = [1, 2, 3, 4, 5]),
  ([last] = head.splice(-1));
{a, ...rest, b} = {a: 7, b: 8, x: 0, y: 1}
Edit inline or edit in the Playground!
({ a, b, ...rest } = { a: 7, b: 8, x: 0, y: 1 });
function justDoIt(a, ...args, cb) {
  cb.apply(a, args)
}
Edit inline or edit in the Playground!
function justDoIt(a, ...args) {
  let [cb] = args.splice(-1);
  return cb.apply(a, args);
}

Import Syntax Matches Destructuring

import {X: LocalX, Y: LocalY} from "./util"
Edit inline or edit in the Playground!
import { X as LocalX, Y as LocalY } from "./util";

Export Convenience

export a, b, c from "./cool.js"
export x = 3
Edit inline or edit in the Playground!
export { a, b, c } from "./cool.js";
export var x = 3;

JSX

function Listing(props)
  <h1 #heading>Hello Civet!
  <ul .items>
    <For each=props.items>
      (item) =>
        <li .item {props.style}><Item {item}>
Edit inline or edit in the Playground!
function Listing(props) {
  return (
    <>
      <h1 id="heading">Hello Civet!</h1>
      <ul class="items">
        <For each={props.items}>
          {(item) => {
            return (
              <li
                class="item"
                style={props.style}
              >
                <Item item={item} />
              </li>
            );
          }}
        </For>
      </ul>
    </>
  );
}

Sponsors

Thank you to all of our sponsors for your invaluable support and contribution to the Civet language!

Support the future development of Civet!

Contributors

Thank you for your work and dedication to the Civet project!