Introduction
EZMAScript is a statically typed, multi-purpose scripting language, primarily used for developing native applications through the ZoneGFX platform.
EZMAScript uses the ES file extension.
(EZMA stands for "Elegant-Zone Modular Applicable")
Equivalence
EZMAScript is equivalent to the TypeScript language and implemented using the TypeScript Compiler API, although with different coding conventions.
Hello World
The following prints a hello-world message to the console:
trace("Hello, world!");
Modules
Module structure usually looks as follows:
<project>
├── src/
│ ├── equations/
│ │ ├── __mod__.es
│ │ └── RungeKutta.es
│ ├── sat/
│ │ ├── __mod__.es
│ │ └── FineSAT.es
│ └── __mod__.es
└── zonegfx.toml
Given the project is a package identified as org.generalrelativity.foam and the source path is the default (src/), this results in three modules:
org.generalrelativity.foam- This would besrc/__mod__.esorg.generalrelativity.foam.equationsorg.generalrelativity.foam.sat
And two item-like modules:
org.generalrelativity.foam.equations::RungeKuttaorg.generalrelativity.foam.sat::FineSAT
Further explanation:
- The
__mod__.esfile is the entry point of a module. - The
RungeKutta.esandFineSAT.esfiles are item-like modules.
A module source looks as follows:
// src/sat/__mod__.es
export * from "./FineSAT";
// src/sat/FineSAT.es
export class FineSAT {
//
}
Imports
Here are some snippets on how import declarations look for importing items from a package:
// <source-path>/equations/__mod__.es
import * as equations from "org.generalrelativity.foam.equations";
// <source-path>/sat/__mod__.es
import { FineSAT } from "org.generalrelativity.foam.sat";
Internal imports
A package may import an item of itself in different ways. The most basic is using relative imports:
import { A } from "./A";
import { B } from "../B";
However, for convenience or for avoiding the ../../.. hell, you can use the actual package ID, and, if needing to resolve to an item-like module, use a trailing :: followed by the item name.
import { Account } from "com.ea.n4s.account::Account";
For example, this could be equivalent to importing from src/account/Account.es.
ESDoc
Tags
@default
Specifies a plain EZMAScript expression assumed as the default value of an item.
@default val
@deprecated
@deprecated Optional message
@event
Indicates that a property is an event handler.
@event
Example usage:
type ButtonProperties = {
/**
* @event
*/
click?: (e: MouseEvent) => void,
};
@example
Attaches an example. If an @example tag contains no code blocks, then it is entirely treated as code.
@example
trace("hi");
@example
Example description.
```
trace("hi")
```
@hidden
Equivalent to @private.
@hidden
@package
Indicates that the ESDoc comment belongs to the file rather than to the item following it.
@package
@param
@param paramName Description
@private
Equivalent to @hidden.
@private
@return
@return Description
@see
@see [Display text](https://google.com)
@see {@link itemReference}
@throws
@throws {RangeError} Optional description
References
Include a link to a EZMAScript declaration anywhere by using {@link ...}.
{@link a.B}
{@link a.B | Display text}
Events
Class-based EventRecord
Here is a code snippet demonstrating how to structure a simple class with a compile-time event record.
/**
* Example signalizer.
*/
class Example extends EventTarget {
//
declare [EventRecord]: {
/**
* Example event.
*/
example: Event,
};
}
Class trees should explicitly inherit the supertype's event record through intersection types A & B:
class A extends EventTarget {
declare [EventRecord]: {
ready: Event,
};
}
class B extends A {
declare [EventRecord]: A[typeof EventRecord] & {
updated: CustomEvent<number>,
};
}
class C extends B {
declare [EventRecord]: B[typeof EventRecord] & {
beep: CustomEvent<boolean>,
};
}
Embed
The global Embed() function is a compiler-processed function that is used for embedding files into the program. It may only resolve to files under either the main source path or the target artifact directory.
- The following results into an external
app:URL ordata:URL for short files:
Embed("thumb.webp")
- The following results into a string from an UTF-8 encoded text:
Embed("data.txt", "text/plain")
- The following results into a
ByteArray:
Embed("data.bin", "application/octet-stream")
- The following results into
anyobtained from parsing a JSON file:
Embed("data.json", "application/json")
- The following embeds a file from artifacts. For example, these files may result from a build script that writes to the
import.meta.env.TARGETdirectory in ZoneGFX applications.
Embed("{target}/data.bin", "application/octet-stream")
- For the ZoneGFX platform, the following results into an
import("zone.skins").StyleSheetFilethat may be used in<z:Style>tags with thefile=attribute.
Embed("Application.css", "text/css")
Enumerations
General enumerations
For general enumerations, just use a pattern like:
type Enum1 =
| "variantA"
| "variantB"
;
If the need ever arises, you can change it to a complex enumeration using the Enum() helper, detailed below.
Implementing complex enumerations
Use the Enum() helper to designate simple enumerations quickly.
Here is a basic enumeration:
const Enum1 = Enum({
variantA: 0,
variantB: 1,
});
type Enum1 = Parameters<typeof Enum1>[0];
// ===== usage =====
const x: Enum1 = "variantA";
const y: string = Enum1("variantB");
trace(Enum1.valueOf(x)) // 0
trace(Enum1.from(0)) // "variantA"
trace(Enum1.from("variantWrong")) // null
Here is an enumeration with a custom method:
const Enum1 = Enum({
variantA: 0,
variantB: 1,
}, {
plus(e: Enum1, inc: number): number {
return Enum1.valueOf(e) + inc;
},
});
type Enum1 = Parameters<typeof Enum1>[0];
// ===== usage =====
trace(Enum1.plus("variantA", 1)) // 1
Type operator
Satisfies operator
type A = "a" | "b";
let a: string;
a = "a" satisfies A; // ok
a = "c" satisfies A; // ERROR
Structural versus nominal typing
EZMAScript compile-time types are fully structural, including classes.
Defining a nominal class
To define a nominal class, declare a virtual private field:
class A {
declare private __nominal__: undefined;
}
E4X
The EZMAScript for XML (E4X) feature provides APIs for working efficiently with the XML data format. It is not be mistaken with XML-like expressions used by the ZoneDS feature of the ZoneGFX framework.
Examples
Constructing a XML object
XML(`
<f:document>
<f:page>
<f:title>SínTitulo1</f:title>
</f:page>
</f:document>
`, [
Namespace("f", "http://example.com/ezmascript/facade/2009"),
])