@maligator/cli 0.1.0-alpha.1 → 0.1.0-alpha.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,14 +1,287 @@
1
1
  # @maligator/cli
2
2
 
3
- The native Maligator compiler CLI.
3
+ [Maligator](https://github.com/dirkdev98/maligator) is a lean
4
+ ahead-of-time JavaScript-to-C compiler and native runtime. It turns a JavaScript or
5
+ erasable TypeScript entry point into a standalone native executable.
4
6
 
5
- Install the alpha globally:
7
+ This package is the npm launcher for the prebuilt Maligator CLI. The project is
8
+ pre-1.0; install prereleases through the `alpha` channel.
9
+
10
+ ## Install
11
+
12
+ Install the current alpha globally:
6
13
 
7
14
  ```shell
8
15
  npm install --global @maligator/cli@alpha
9
16
  ```
10
17
 
11
- The package selects a platform-specific native binary included with that alpha
12
- release. The initial alpha includes macOS and Linux on arm64 and x64; subsequent
13
- local alpha releases currently default to Apple Silicon macOS. Windows is not
14
- supported.
18
+ Or keep it in a project and invoke it through `npx`:
19
+
20
+ ```shell
21
+ npm install --save-dev @maligator/cli@alpha
22
+ npx maligator --version
23
+ ```
24
+
25
+ The npm launcher requires Node.js 20 or newer. The native CLI and applications
26
+ produced by it do not require Node.js.
27
+
28
+ ## Quick start
29
+
30
+ From the root of an application project:
31
+
32
+ ```shell
33
+ maligator init
34
+ maligator doctor
35
+ maligator build
36
+ maligator run -- first-argument "two words"
37
+ ```
38
+
39
+ `maligator init` creates `maligator.build.ts`. If it cannot find an existing entry
40
+ point, it also creates `src/index.ts`. `doctor` checks the native build toolchain,
41
+ `build` produces a development executable, and `run` builds and launches it while
42
+ forwarding everything after `--` to the application.
43
+
44
+ Useful commands:
45
+
46
+ ```text
47
+ maligator --help
48
+ maligator --version
49
+ maligator init
50
+ maligator doctor [--verbose] [--target rust-triple]
51
+ maligator build [entry] [--production] [--artifact directory] [--target rust-triple] [--config path]
52
+ maligator run [entry] [--config path] [-- args...]
53
+ maligator dev [entry] [--config path] [-- args...]
54
+ maligator test [path ...] [--run name] [--shuffle [seed]] [--repeat count] [--bail]
55
+ ```
56
+
57
+ Run commands from the project root. Maligator does not search parent directories
58
+ for configuration.
59
+
60
+ `run` and `dev` use the runtime embedded in the platform package for the supported
61
+ single-process, asset-free, Intl-disabled development profile, so they do not need
62
+ a local native toolchain. `dev` retains compiler identities between edits and
63
+ restarts a fresh application VM after every successful rebuild. Build failures keep
64
+ the watcher alive for recovery on the next edit.
65
+
66
+ ## Testing
67
+
68
+ `maligator test` discovers conventional JavaScript and erasable-TypeScript test
69
+ files and runs them through Maligator's embedded interpreter. Test runs do not
70
+ generate C or invoke the native toolchain. Import the Maligator-owned API from
71
+ `maligator:test`:
72
+
73
+ ```typescript
74
+ import { beforeEach, describe, expect, test } from "maligator:test";
75
+ import { createRouter, RouteError, type Router } from "./router.ts";
76
+
77
+ describe("router", () => {
78
+ let router: Router;
79
+
80
+ beforeEach(() => {
81
+ router = createRouter();
82
+ });
83
+
84
+ test("matches parameters", async () => {
85
+ await expect(router.match("/users/42")).resolves.toMatchObject({
86
+ id: expect.any(Number),
87
+ });
88
+ });
89
+
90
+ test("rejects malformed parameters", async () => {
91
+ await expect(router.match("/users/nope")).rejects.toThrow(RouteError);
92
+ });
93
+ });
94
+ ```
95
+
96
+ By default, discovery includes `*.test.js`, `*.test.mjs`, `*.test.ts`,
97
+ `*.test.mts`, and the corresponding `*.spec.*` names. Pass files, directories,
98
+ or both:
99
+
100
+ ```shell
101
+ maligator test
102
+ maligator test src/router
103
+ maligator test src/router/router.test.ts
104
+ maligator test --run "router > parameters"
105
+ maligator test --shuffle
106
+ maligator test --shuffle 18492
107
+ maligator test --repeat 10
108
+ maligator test --bail
109
+ ```
110
+
111
+ `--run` filters hierarchical suite and test names. `--shuffle [seed]` changes
112
+ execution order reproducibly and always prints the seed. `--repeat` executes the
113
+ selected tests again while reusing unchanged compilation artifacts. The default
114
+ policy completes the selected suite; `--bail` stops scheduling after the first
115
+ failure.
116
+
117
+ The authoring API includes nested `describe` suites, `beforeAll`, `afterAll`,
118
+ `beforeEach`, `afterEach`, synchronous and promise-returning callbacks,
119
+ `test.skip`, `test.todo`, `test.only`, and `test.each`. A committed `.only`
120
+ focuses execution and prints a warning. Matchers include identity, structural
121
+ equality, truthiness, containment, length, string/regular-expression matching,
122
+ partial-object matching, throwing, `.not`, `.resolves`, `.rejects`, and the
123
+ `expect.any`, `expect.anything`, `expect.stringMatching`,
124
+ `expect.objectContaining`, and `expect.arrayContaining` asymmetric helpers.
125
+ Maligator owns this API and does not claim Jest, Vitest, or `node:test`
126
+ compatibility.
127
+
128
+ Test files currently execute serially in one Realm. Registration and lifecycle
129
+ state are separated by test file, but globals, prototypes, imported module
130
+ singletons, host state, and asynchronous work left running by a test can be
131
+ shared. Do not rely on process-per-file isolation.
132
+
133
+ Frontend bytecode is content-addressed by source, transitive dependencies,
134
+ resolved module identities, relevant build configuration, and compiler/runtime
135
+ format versions. A warm run restores a shared base plus independently cached
136
+ test-file registration fragments. Test results are never cached: every selected
137
+ test executes on every invocation.
138
+
139
+ The package ships documented declarations for `maligator:test`. Projects whose
140
+ TypeScript configuration does not include `maligator.build.ts` should load the
141
+ package declarations explicitly:
142
+
143
+ ```json
144
+ {
145
+ "compilerOptions": {
146
+ "types": ["@maligator/cli"]
147
+ }
148
+ }
149
+ ```
150
+
151
+ ## Build cache
152
+
153
+ Normal `maligator build`, `maligator run`, and `maligator test` commands share a
154
+ content-addressed portable VM definition store. On a valid hit, Maligator skips
155
+ parsing, module-graph construction, semantic analysis, optimization, register
156
+ allocation, and VM lowering. For the single-process, asset-free, Intl-disabled
157
+ development profile, `run` executes the restored definition with the isolated
158
+ runtime embedded in the platform CLI; it does not generate C or invoke a native
159
+ toolchain. Normal and production `build` commands emit
160
+ native translation units from the same restored definition. Those units and the native driver are
161
+ compiled into independently content-addressed objects, so unchanged objects can
162
+ be relinked without repeating C compilation. The final link still runs, and
163
+ native runtime and Rust archives remain separately content-addressed.
164
+
165
+ Build cache invalidation includes source and transitive dependency content,
166
+ package-resolution metadata, relevant configuration, the TypeScript erasure
167
+ frontend, and compiler/wire versions. Generated-object identity additionally
168
+ includes the exact C source, source identity, native headers/runtime artifact,
169
+ compiler/toolchain, target, flags, and build environment. Compiler diagnostic
170
+ dump flags deliberately recompile the frontend because they require live
171
+ semantic and IR objects.
172
+
173
+ ## Production builds
174
+
175
+ Use production mode for a deployable binary:
176
+
177
+ ```shell
178
+ maligator build --production
179
+ ```
180
+
181
+ Production builds use optimized native compilation, add LTO when the toolchain
182
+ supports it, and strip native symbols when possible. To create a self-contained
183
+ artifact directory with a manifest, license, checksum, and binary:
184
+
185
+ ```shell
186
+ maligator build --production --artifact dist/my-application
187
+ ```
188
+
189
+ The artifact destination must be absent or empty. Launch the reported binary
190
+ directly; neither Node.js nor the Maligator CLI is needed at runtime.
191
+
192
+ ## Configuration
193
+
194
+ `maligator.build.ts` is trusted TypeScript configuration. A small configuration
195
+ looks like this:
196
+
197
+ ```typescript
198
+ import { defineBuild } from "@maligator/cli";
199
+
200
+ export default defineBuild({
201
+ entry: "src/index.ts",
202
+ outputName: "my-application",
203
+ engine: {
204
+ eval: false,
205
+ intl: { enabled: false },
206
+ },
207
+ surface: {
208
+ webPlatform: false,
209
+ node: false,
210
+ },
211
+ });
212
+ ```
213
+
214
+ All fields are optional. Maligator excludes optional engine and host surfaces unless
215
+ the configuration requests them. See the
216
+ [full configuration reference](https://github.com/dirkdev98/maligator#configuration)
217
+ for assets, Intl features, Node compatibility, web-platform support, and target
218
+ selection.
219
+
220
+ ## TypeScript
221
+
222
+ The package includes declarations for `maligator.build.ts` and Maligator's runtime
223
+ globals. Keeping the generated build file inside your TypeScript project makes the
224
+ types available automatically:
225
+
226
+ ```typescript
227
+ const path = mal.assets.materialize("templates", {
228
+ baseDirectory: ".cache/my-application",
229
+ });
230
+
231
+ const server = Mal.serve({
232
+ hostname: "127.0.0.1",
233
+ port: 3000,
234
+ async fetch(request) {
235
+ return new Response(`Hello from ${request.url}`);
236
+ },
237
+ });
238
+
239
+ console.log(path, server.port);
240
+ ```
241
+
242
+ `mal` is present when `surface.maligator` is enabled. `Mal` and `Mal.serve` are
243
+ present when `surface.webPlatform` is enabled. The declarations describe both
244
+ optional surfaces, while `maligator.build.ts` controls which globals exist in the
245
+ compiled application.
246
+
247
+ If your `tsconfig.json` excludes `maligator.build.ts`, load the declarations
248
+ explicitly:
249
+
250
+ ```json
251
+ {
252
+ "compilerOptions": {
253
+ "types": ["@maligator/cli"]
254
+ }
255
+ }
256
+ ```
257
+
258
+ ## Build toolchain
259
+
260
+ `maligator test` and supported `maligator run` profiles use the development runtime
261
+ embedded in the platform CLI and do not require a native toolchain. Native `build`
262
+ commands—and development runs using bundled assets, Intl, or multiprocessing—require:
263
+
264
+ - A C23 compiler and archive tool: Apple clang, clang 19 or newer, or GCC 15 or
265
+ newer
266
+ - Rustup with the `cargo` and `rustc` toolchain selected by Maligator
267
+ - A C++ compiler/runtime only when `surface.webPlatform` is enabled
268
+
269
+ On macOS, install Apple command-line tools with `xcode-select --install`. On Linux,
270
+ install a recent compiler and set `CC` and `CXX` when it is not your system default.
271
+ Run `maligator doctor --verbose` for resolved tool paths, versions, capabilities,
272
+ and installation hints. The
273
+ [native toolchain guide](https://github.com/dirkdev98/maligator#native-toolchain)
274
+ has the full requirements and cross-compilation instructions.
275
+
276
+ ## Alpha support
277
+
278
+ `0.1.0-alpha.1` provides native packages for macOS and glibc-based Linux on arm64
279
+ and x64. Later alpha releases currently default to Apple Silicon macOS; consult the
280
+ release notes before upgrading on another host. Windows is not supported.
281
+
282
+ There is no source-build fallback for the CLI package. The alpha binaries are
283
+ unsigned, and macOS binaries are not notarized. APIs, configuration, and supported
284
+ hosts may change before 1.0.
285
+
286
+ Please report problems through the
287
+ [Maligator issue tracker](https://github.com/dirkdev98/maligator/issues).
package/index.d.ts ADDED
@@ -0,0 +1,93 @@
1
+ /// <reference lib="dom" />
2
+
3
+ import "./test-api.d.ts";
4
+
5
+ export type MaligatorIntlFeature =
6
+ | "collator"
7
+ | "number-format"
8
+ | "date-time-format"
9
+ | "plural-rules"
10
+ | "list-format"
11
+ | "segmenter"
12
+ | "display-names"
13
+ | "relative-time-format"
14
+ | "duration-format";
15
+
16
+ export type AssetInclusion =
17
+ | { type: "file"; path: string }
18
+ | { type: "directory"; path: string; include: Array<string> };
19
+
20
+ export interface MaligatorBuildConfig {
21
+ entry?: string;
22
+ outputName?: string;
23
+ assets?: Record<string, AssetInclusion>;
24
+ engine?: {
25
+ /**
26
+ * `true` embeds the runtime compiler. `false` keeps eval/Function present
27
+ * but makes dynamic compilation throw at runtime. `"compile-check"` also
28
+ * rejects statically visible eval/Function calls during the build.
29
+ */
30
+ eval?: boolean | "compile-check";
31
+ realms?: boolean;
32
+ regexp?: boolean;
33
+ /** Include the Temporal global and its calendar/time-zone data. */
34
+ temporal?: boolean;
35
+ intl?: {
36
+ enabled?: boolean;
37
+ features?: Array<MaligatorIntlFeature>;
38
+ languages?: Array<string>;
39
+ };
40
+ };
41
+ host?: {
42
+ scheduler?: "single" | "multiprocessing";
43
+ };
44
+ surface?: {
45
+ webPlatform?: boolean;
46
+ node?: boolean;
47
+ maligator?: boolean;
48
+ };
49
+ }
50
+
51
+ export declare function defineBuild<const Config extends MaligatorBuildConfig>(
52
+ config: Config,
53
+ ): Config;
54
+
55
+ export interface MaligatorMaterializeOptions {
56
+ baseDirectory?: string;
57
+ }
58
+
59
+ export interface MaligatorAssets {
60
+ materialize(name: string, options?: MaligatorMaterializeOptions): string;
61
+ }
62
+
63
+ export interface MaligatorRuntime {
64
+ readonly assets: MaligatorAssets;
65
+ }
66
+
67
+ export interface MaligatorServeOptions {
68
+ hostname?: string;
69
+ port?: number;
70
+ fetch(request: Request): Response | PromiseLike<Response>;
71
+ }
72
+
73
+ export interface MaligatorServer {
74
+ readonly port: number;
75
+ }
76
+
77
+ export interface MaligatorWebRuntime {
78
+ serve(options: MaligatorServeOptions): MaligatorServer;
79
+ }
80
+
81
+ declare global {
82
+ /**
83
+ * Maligator's core runtime namespace. Present when
84
+ * `surface.maligator` is enabled.
85
+ */
86
+ var mal: MaligatorRuntime;
87
+
88
+ /**
89
+ * Maligator's web-host extension namespace. Present when
90
+ * `surface.webPlatform` is enabled.
91
+ */
92
+ var Mal: MaligatorWebRuntime;
93
+ }
package/index.js ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * @template T
3
+ * @param {T} config
4
+ * @returns {T}
5
+ */
6
+ export function defineBuild(config) {
7
+ return config;
8
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maligator/cli",
3
- "version": "0.1.0-alpha.1",
3
+ "version": "0.1.0-alpha.11",
4
4
  "description": "Ahead-of-time JavaScript compiler and native runtime",
5
5
  "license": "MIT",
6
6
  "homepage": "https://github.com/dirkdev98/maligator#readme",
@@ -19,7 +19,8 @@
19
19
  "runtime"
20
20
  ],
21
21
  "publishConfig": {
22
- "access": "public"
22
+ "access": "public",
23
+ "tag": "alpha"
23
24
  },
24
25
  "type": "module",
25
26
  "engines": {
@@ -27,16 +28,23 @@
27
28
  },
28
29
  "files": [
29
30
  "bin/maligator.js",
31
+ "index.js",
32
+ "index.d.ts",
33
+ "test-api.d.ts",
30
34
  "README.md",
31
35
  "LICENSE"
32
36
  ],
33
37
  "bin": {
34
38
  "maligator": "bin/maligator.js"
35
39
  },
40
+ "types": "./index.d.ts",
41
+ "exports": {
42
+ ".": {
43
+ "types": "./index.d.ts",
44
+ "import": "./index.js"
45
+ }
46
+ },
36
47
  "optionalDependencies": {
37
- "@maligator/cli-darwin-arm64": "0.1.0-alpha.1",
38
- "@maligator/cli-darwin-x64": "0.1.0-alpha.1",
39
- "@maligator/cli-linux-arm64": "0.1.0-alpha.1",
40
- "@maligator/cli-linux-x64": "0.1.0-alpha.1"
48
+ "@maligator/cli-darwin-arm64": "0.1.0-alpha.11"
41
49
  }
42
50
  }
package/test-api.d.ts ADDED
@@ -0,0 +1,167 @@
1
+ declare module "maligator:test" {
2
+ /**
3
+ * A test or hook body. Maligator waits for a returned promise or thenable
4
+ * before advancing the lifecycle.
5
+ */
6
+ export type TestCallback = () => unknown;
7
+ /** A lifecycle hook body, with the same async completion contract as a test. */
8
+ export type HookCallback = TestCallback;
9
+ /** A constructable value accepted by {@link expect.any}. */
10
+ export type Constructor = abstract new (...args: Array<never>) => unknown;
11
+
12
+ /**
13
+ * Opaque partial-match value produced by helpers such as
14
+ * {@link expect.objectContaining}. It may be nested inside `toEqual`,
15
+ * `toStrictEqual`, and `toMatchObject` expectations.
16
+ */
17
+ export interface AsymmetricMatcher {
18
+ readonly __maligator_asymmetric__: string;
19
+ }
20
+
21
+ /** Matchers for a synchronously received value. */
22
+ export interface Matchers {
23
+ /** Negate the following matcher. */
24
+ readonly not: Matchers;
25
+ /** Wait for the received promise to fulfill, then match its value. */
26
+ readonly resolves: AsyncMatchers;
27
+ /** Wait for the received promise to reject, then match its reason. */
28
+ readonly rejects: AsyncMatchers;
29
+ /** Require ECMAScript `Object.is` identity. */
30
+ toBe(expected: unknown): void;
31
+ /** Recursively compare enumerable object properties and array elements. */
32
+ toEqual(expected: unknown): void;
33
+ /**
34
+ * Recursively compare values while also requiring matching prototypes and
35
+ * matching sparse-array holes.
36
+ */
37
+ toStrictEqual(expected: unknown): void;
38
+ /** Require a value other than `undefined`. */
39
+ toBeDefined(): void;
40
+ /** Require `undefined`. */
41
+ toBeUndefined(): void;
42
+ /** Require `null`. */
43
+ toBeNull(): void;
44
+ /** Require a truthy value. */
45
+ toBeTruthy(): void;
46
+ /** Require a falsy value. */
47
+ toBeFalsy(): void;
48
+ /** Require a string substring or an array element matched by identity. */
49
+ toContain(expected: unknown): void;
50
+ /** Require a numeric `.length` equal to `expected`. */
51
+ toHaveLength(expected: number): void;
52
+ /** Match a string against a substring or regular expression. */
53
+ toMatch(expected: string | RegExp): void;
54
+ /** Recursively require the enumerable properties present in `expected`. */
55
+ toMatchObject(expected: object): void;
56
+ /**
57
+ * Invoke the received function and require it to throw. The optional
58
+ * expectation may be a message substring, regular expression, error
59
+ * constructor, or error instance.
60
+ */
61
+ toThrow(
62
+ expected?:
63
+ | string
64
+ | RegExp
65
+ | Error
66
+ | (abstract new (...args: Array<never>) => Error),
67
+ ): void;
68
+ }
69
+
70
+ /**
71
+ * Promise-returning matcher surface exposed by {@link Matchers.resolves} and
72
+ * {@link Matchers.rejects}. Await these calls so the test cannot finish before
73
+ * the assertion.
74
+ */
75
+ export interface AsyncMatchers {
76
+ /** Negate the following asynchronous matcher. */
77
+ readonly not: AsyncMatchers;
78
+ toBe(expected: unknown): Promise<void>;
79
+ toEqual(expected: unknown): Promise<void>;
80
+ toStrictEqual(expected: unknown): Promise<void>;
81
+ toBeDefined(): Promise<void>;
82
+ toBeUndefined(): Promise<void>;
83
+ toBeNull(): Promise<void>;
84
+ toBeTruthy(): Promise<void>;
85
+ toBeFalsy(): Promise<void>;
86
+ toContain(expected: unknown): Promise<void>;
87
+ toHaveLength(expected: number): Promise<void>;
88
+ toMatch(expected: string | RegExp): Promise<void>;
89
+ toMatchObject(expected: object): Promise<void>;
90
+ toThrow(
91
+ expected?:
92
+ | string
93
+ | RegExp
94
+ | Error
95
+ | (abstract new (...args: Array<never>) => Error),
96
+ ): Promise<void>;
97
+ }
98
+
99
+ /** Assertion entrypoint and Maligator-owned asymmetric matcher factories. */
100
+ export interface ExpectFunction {
101
+ /** Create matchers for `received`. The assertion position is captured here. */
102
+ (received: unknown): Matchers;
103
+ /** Match a primitive of the corresponding built-in kind or an instance. */
104
+ any(constructorValue: Constructor): AsymmetricMatcher;
105
+ /** Match any value except `null` and `undefined`. */
106
+ anything(): AsymmetricMatcher;
107
+ /** Match a string containing `pattern` or satisfying the regular expression. */
108
+ stringMatching(pattern: string | RegExp): AsymmetricMatcher;
109
+ /** Match an object containing all recursively matched properties in `value`. */
110
+ objectContaining(value: object): AsymmetricMatcher;
111
+ /** Match an array containing a match for every element in `value`. */
112
+ arrayContaining(value: Array<unknown>): AsymmetricMatcher;
113
+ }
114
+
115
+ /** Register tests in the current suite during module evaluation. */
116
+ export interface TestFunction {
117
+ /** Register a test. Returned promises are awaited by the runner. */
118
+ (name: string, callback: TestCallback): void;
119
+ /** Register a skipped test without invoking its callback. */
120
+ skip(name: string, callback: TestCallback): void;
121
+ /** Register a named placeholder with no callback. */
122
+ todo(name: string): void;
123
+ /**
124
+ * Register a focused test. When any `.only` exists, non-focused tests are
125
+ * skipped and the runner emits a warning.
126
+ */
127
+ only(name: string, callback: TestCallback): void;
128
+ /**
129
+ * Register one test for each row. Use `%#` in `name` for the zero-based row
130
+ * index. Array rows are spread into callback parameters.
131
+ */
132
+ each<const Row extends ReadonlyArray<unknown>>(
133
+ rows: ReadonlyArray<Row>,
134
+ ): (name: string, callback: (...values: [...Row]) => unknown) => void;
135
+ }
136
+
137
+ /** Register nested suites synchronously during module evaluation. */
138
+ export interface DescribeFunction {
139
+ /** Register a suite. Suite callbacks must not return a promise. */
140
+ (name: string, callback: () => void): void;
141
+ /** Register a suite whose descendants are skipped. */
142
+ skip(name: string, callback: () => void): void;
143
+ /** Register a focused suite and emit the runner's focused-test warning. */
144
+ only(name: string, callback: () => void): void;
145
+ }
146
+
147
+ /** Register a test in the current suite. */
148
+ export const test: TestFunction;
149
+ /** Register a nested suite in the current suite. */
150
+ export const describe: DescribeFunction;
151
+ /** Create fluent matchers for a received value. */
152
+ export const expect: ExpectFunction;
153
+ /** Run once before tests in the current suite. */
154
+ export function beforeAll(callback: HookCallback): void;
155
+ /** Run once after tests in the current suite, including after test failures. */
156
+ export function afterAll(callback: HookCallback): void;
157
+ /**
158
+ * Run before every selected descendant test. Ancestor hooks run before hooks
159
+ * declared by a nested suite.
160
+ */
161
+ export function beforeEach(callback: HookCallback): void;
162
+ /**
163
+ * Run after every selected descendant test. Nested-suite hooks run before
164
+ * ancestor hooks.
165
+ */
166
+ export function afterEach(callback: HookCallback): void;
167
+ }