nomen-lang 0.0.7 → 0.0.8
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/NOMEN_AGENTS.md +235 -0
- package/core/System/Ansi.nm +150 -0
- package/core/System/Array.nm +358 -0
- package/core/System/BigInt.nm +887 -0
- package/core/System/Buffer.nm +526 -0
- package/core/System/Channel.nm +198 -0
- package/core/System/ClassBuffer.nm +229 -0
- package/core/System/Console.nm +211 -0
- package/core/System/Controls/Button.nm +138 -0
- package/core/System/Controls/CheckBox.nm +158 -0
- package/core/System/Controls/Container.nm +1562 -0
- package/core/System/Controls/Control.nm +28 -0
- package/core/System/Controls/Geometry.nm +101 -0
- package/core/System/Controls/Layout.nm +228 -0
- package/core/System/Controls/LayoutParams.nm +50 -0
- package/core/System/Controls/Text.nm +129 -0
- package/core/System/Controls/TextBox.nm +157 -0
- package/core/System/Controls/Window.nm +280 -0
- package/core/System/Disposable.nm +8 -0
- package/core/System/Enumerable.nm +10 -0
- package/core/System/Equatable.nm +10 -0
- package/core/System/Graph.nm +68 -0
- package/core/System/Hashable.nm +13 -0
- package/core/System/Init.nm +21 -0
- package/core/System/LinkedList.nm +64 -0
- package/core/System/List.nm +44 -0
- package/core/System/Map.nm +153 -0
- package/core/System/Math.nm +54 -0
- package/core/System/Mutex.nm +78 -0
- package/core/System/Nursery.nm +27 -0
- package/core/System/Sendable.nm +9 -0
- package/core/System/Set.nm +97 -0
- package/core/System/Stream/Directory.nm +176 -0
- package/core/System/Stream/File.nm +432 -0
- package/core/System/Stream/Http.nm +453 -0
- package/core/System/String.nm +154 -0
- package/core/System/StringBuilder.nm +249 -0
- package/core/System/Stringable.nm +8 -0
- package/core/System/Task.nm +263 -0
- package/core/System/Test.nm +241 -0
- package/core/System/Text/Json.nm +377 -0
- package/core/System/Text/JsonTree.nm +187 -0
- package/core/System/Text/Regex.nm +655 -0
- package/core/System/Time.nm +112 -0
- package/core/System/Tree.nm +70 -0
- package/core/System/Viewable.nm +27 -0
- package/core/System/bool.nm +66 -0
- package/core/System/char.nm +42 -0
- package/core/System/float.nm +43 -0
- package/core/System/int.nm +54 -0
- package/core/System/int64.nm +42 -0
- package/core/System/int8.nm +42 -0
- package/core/System/uint.nm +42 -0
- package/core/System/uint64.nm +42 -0
- package/core/System/uint8.nm +42 -0
- package/core/docs/System/Ansi.md +40 -0
- package/core/docs/System/Array.md +16 -0
- package/core/docs/System/BigInt.md +30 -0
- package/core/docs/System/Buffer.md +31 -0
- package/core/docs/System/Channel.md +10 -0
- package/core/docs/System/ClassBuffer.md +15 -0
- package/core/docs/System/Console.md +13 -0
- package/core/docs/System/Controls/Button.md +12 -0
- package/core/docs/System/Controls/CheckBox.md +15 -0
- package/core/docs/System/Controls/Container.md +82 -0
- package/core/docs/System/Controls/Control.md +5 -0
- package/core/docs/System/Controls/Geometry.md +26 -0
- package/core/docs/System/Controls/Layout.md +37 -0
- package/core/docs/System/Controls/LayoutParams.md +13 -0
- package/core/docs/System/Controls/Text.md +12 -0
- package/core/docs/System/Controls/TextBox.md +13 -0
- package/core/docs/System/Controls/Window.md +20 -0
- package/core/docs/System/Disposable.md +5 -0
- package/core/docs/System/Enumerable.md +5 -0
- package/core/docs/System/Graph.md +17 -0
- package/core/docs/System/Init.md +9 -0
- package/core/docs/System/LinkedList.md +16 -0
- package/core/docs/System/List.md +13 -0
- package/core/docs/System/Map.md +14 -0
- package/core/docs/System/Math.md +11 -0
- package/core/docs/System/Mutex.md +10 -0
- package/core/docs/System/Nursery.md +5 -0
- package/core/docs/System/Sendable.md +5 -0
- package/core/docs/System/Set.md +14 -0
- package/core/docs/System/Stream/Directory.md +12 -0
- package/core/docs/System/Stream/File.md +21 -0
- package/core/docs/System/String.md +14 -0
- package/core/docs/System/StringBuilder.md +12 -0
- package/core/docs/System/Stringable.md +5 -0
- package/core/docs/System/Task.md +15 -0
- package/core/docs/System/Text/Json.md +12 -0
- package/core/docs/System/Text/JsonTree.md +21 -0
- package/core/docs/System/Text/Regex.md +12 -0
- package/core/docs/System/Time.md +11 -0
- package/core/docs/System/Tree.md +18 -0
- package/core/docs/System/Viewable.md +5 -0
- package/core/docs/System/bool.md +9 -0
- package/core/docs/System/char.md +9 -0
- package/core/docs/System/float.md +9 -0
- package/core/docs/System/int.md +10 -0
- package/core/docs/System/int64.md +9 -0
- package/core/docs/System/int8.md +9 -0
- package/core/docs/System/uint.md +9 -0
- package/core/docs/System/uint64.md +9 -0
- package/core/docs/System/uint8.md +9 -0
- package/core/package.jsonc +4 -0
- package/dist/index.mjs +417 -5490
- package/package.json +33 -30
- package/src/args.ts +171 -0
- package/src/index.ts +53 -104
- package/src/init.ts +128 -0
- package/src/test.ts +6 -2
- package/test/fixtures/build/calc.test +0 -0
- package/test/fixtures/build/calc.test.c +0 -969
- package/test/fixtures/build/main.h +0 -170
- package/test/fixtures/calc.test.nm +0 -32
- package/tsconfig.json +0 -21
- package/vite.config.ts +0 -7
package/package.json
CHANGED
|
@@ -1,31 +1,34 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
2
|
+
"name": "nomen-lang",
|
|
3
|
+
"version": "0.0.8",
|
|
4
|
+
"description": "The CLI for the Nomen programming language.",
|
|
5
|
+
"keywords": [],
|
|
6
|
+
"license": "ISC",
|
|
7
|
+
"author": "",
|
|
8
|
+
"bin": {
|
|
9
|
+
"nomen": "dist/index.mjs"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"src",
|
|
14
|
+
"core",
|
|
15
|
+
"NOMEN_AGENTS.md"
|
|
16
|
+
],
|
|
17
|
+
"type": "module",
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"@types/node": "^26.1.2",
|
|
20
|
+
"chokidar": "^5.0.0",
|
|
21
|
+
"tsx": "^4.23.1",
|
|
22
|
+
"typescript": "^7.0.2",
|
|
23
|
+
"vite-plus": "0.2.7"
|
|
24
|
+
},
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "node scripts/bundle-assets.mjs && vp pack",
|
|
27
|
+
"dev": "node scripts/bundle-assets.mjs && vp pack --watch",
|
|
28
|
+
"test": "vp test",
|
|
29
|
+
"check": "vp check",
|
|
30
|
+
"format": "vp check --fix",
|
|
31
|
+
"go": "tsx src/index.ts",
|
|
32
|
+
"register": "pnpm build && pnpm add -g ."
|
|
33
|
+
}
|
|
34
|
+
}
|
package/src/args.ts
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
export interface Args {
|
|
2
|
+
command: string | undefined;
|
|
3
|
+
name?: string;
|
|
4
|
+
in?: string;
|
|
5
|
+
out?: string;
|
|
6
|
+
config?: string;
|
|
7
|
+
watch: boolean;
|
|
8
|
+
filter?: string;
|
|
9
|
+
arch: string;
|
|
10
|
+
platform?: string;
|
|
11
|
+
lib?: string;
|
|
12
|
+
audit: boolean;
|
|
13
|
+
audit_runtime?: string;
|
|
14
|
+
check: boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Canonical option name for each accepted long/short spelling.
|
|
18
|
+
const STRING_OPTIONS: Map<string, string> = new Map([
|
|
19
|
+
["in", "in"],
|
|
20
|
+
["i", "in"],
|
|
21
|
+
["out", "out"],
|
|
22
|
+
["o", "out"],
|
|
23
|
+
["config", "config"],
|
|
24
|
+
["c", "config"],
|
|
25
|
+
["filter", "filter"],
|
|
26
|
+
["f", "filter"],
|
|
27
|
+
["arch", "arch"],
|
|
28
|
+
["a", "arch"],
|
|
29
|
+
["platform", "platform"],
|
|
30
|
+
["p", "platform"],
|
|
31
|
+
["lib", "lib"],
|
|
32
|
+
["l", "lib"],
|
|
33
|
+
["audit-runtime", "audit_runtime"],
|
|
34
|
+
]);
|
|
35
|
+
|
|
36
|
+
const BOOLEAN_OPTIONS: Map<string, string> = new Map([
|
|
37
|
+
["watch", "watch"],
|
|
38
|
+
["w", "watch"],
|
|
39
|
+
["audit", "audit"],
|
|
40
|
+
["check", "check"],
|
|
41
|
+
]);
|
|
42
|
+
|
|
43
|
+
const DEFAULTS: Partial<Args> = {
|
|
44
|
+
arch: "aarch64",
|
|
45
|
+
watch: false,
|
|
46
|
+
audit: false,
|
|
47
|
+
check: false,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
function set(args: Args, key: string, value: string | boolean): void {
|
|
51
|
+
(args as unknown as Record<string, string | boolean>)[key] = value;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** Parse `argv` (excluding the node binary and script path) into an `Args` object. */
|
|
55
|
+
export function parse_args(argv: string[] = process.argv.slice(2)): Args {
|
|
56
|
+
const args: Args = { command: undefined, ...DEFAULTS } as Args;
|
|
57
|
+
const positional: string[] = [];
|
|
58
|
+
let only_positional = false;
|
|
59
|
+
|
|
60
|
+
const next_value = (i: number, spelling: string): string => {
|
|
61
|
+
if (i + 1 >= argv.length) throw new Error(`Option ${spelling} requires a value`);
|
|
62
|
+
return argv[i + 1];
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
for (let i = 0; i < argv.length; i++) {
|
|
66
|
+
const arg = argv[i];
|
|
67
|
+
|
|
68
|
+
if (only_positional) {
|
|
69
|
+
positional.push(arg);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (arg === "--") {
|
|
74
|
+
only_positional = true;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (arg === "-h" || arg === "--help") {
|
|
79
|
+
print_help();
|
|
80
|
+
process.exit(0);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Long option: --name, --name=value, or --name value
|
|
84
|
+
if (arg.startsWith("--") && arg.length > 2) {
|
|
85
|
+
const eq = arg.indexOf("=");
|
|
86
|
+
const name = eq === -1 ? arg.slice(2) : arg.slice(2, eq);
|
|
87
|
+
const inline = eq === -1 ? undefined : arg.slice(eq + 1);
|
|
88
|
+
|
|
89
|
+
if (STRING_OPTIONS.has(name)) {
|
|
90
|
+
const key = STRING_OPTIONS.get(name)!;
|
|
91
|
+
set(args, key, inline !== undefined ? inline : next_value(i, `--${name}`));
|
|
92
|
+
if (inline === undefined) i++;
|
|
93
|
+
} else if (BOOLEAN_OPTIONS.has(name)) {
|
|
94
|
+
const key = BOOLEAN_OPTIONS.get(name)!;
|
|
95
|
+
set(args, key, inline === undefined ? true : inline !== "false");
|
|
96
|
+
} else {
|
|
97
|
+
throw new Error(`Unknown option: --${name}`);
|
|
98
|
+
}
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// Short option(s): -i value, -ivalue, -i=value, or combined -wv
|
|
103
|
+
if (arg.startsWith("-") && arg.length > 1 && !/^-\d/.test(arg)) {
|
|
104
|
+
const chars = arg.slice(1);
|
|
105
|
+
for (let j = 0; j < chars.length; j++) {
|
|
106
|
+
const c = chars[j];
|
|
107
|
+
|
|
108
|
+
if (c === "h") {
|
|
109
|
+
print_help();
|
|
110
|
+
process.exit(0);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (STRING_OPTIONS.has(c)) {
|
|
114
|
+
const key = STRING_OPTIONS.get(c)!;
|
|
115
|
+
const rest = chars.slice(j + 1);
|
|
116
|
+
if (rest.length > 0) {
|
|
117
|
+
set(args, key, rest.startsWith("=") ? rest.slice(1) : rest);
|
|
118
|
+
} else {
|
|
119
|
+
set(args, key, next_value(i, `-${c}`));
|
|
120
|
+
i++;
|
|
121
|
+
}
|
|
122
|
+
break;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
if (BOOLEAN_OPTIONS.has(c)) {
|
|
126
|
+
set(args, BOOLEAN_OPTIONS.get(c)!, true);
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
throw new Error(`Unknown option: -${c}`);
|
|
131
|
+
}
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
positional.push(arg);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
args.command = positional[0];
|
|
139
|
+
args.name = positional[1];
|
|
140
|
+
return args;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function print_help(): void {
|
|
144
|
+
console.log(
|
|
145
|
+
[
|
|
146
|
+
"Usage:",
|
|
147
|
+
" nomen run --in [file/folder] Parse, check, build and run a program",
|
|
148
|
+
" nomen build --in [file/folder] Parse, check and build (no run)",
|
|
149
|
+
" nomen check --in [file/folder] Parse and check only",
|
|
150
|
+
" nomen format [--in folder] Reformat every .nm file",
|
|
151
|
+
" nomen docs [--in file] Generate markdown documentation",
|
|
152
|
+
" nomen test [--in folder] Discover and run *.test.nm files",
|
|
153
|
+
" nomen init <name> Scaffold a new project in ./<name>",
|
|
154
|
+
" nomen lib-path Print the bundled System library path",
|
|
155
|
+
"",
|
|
156
|
+
"Options:",
|
|
157
|
+
" --in, -i <path> Input file or folder",
|
|
158
|
+
" --out, -o <path> Output file",
|
|
159
|
+
" --config, -c <path> Path to a config file",
|
|
160
|
+
" --watch, -w Watch for file changes",
|
|
161
|
+
" --filter, -f <regex> Only run test files whose path matches this regex",
|
|
162
|
+
" --arch, -a <arch> Target architecture: aarch64 | c (default: aarch64)",
|
|
163
|
+
" --platform, -p <name> Target platform: macos, ios, linux, android, windows, web",
|
|
164
|
+
" --lib, -l <path> Path to System library directory (containing package.jsonc)",
|
|
165
|
+
" --audit Audit the generated program for memory issues",
|
|
166
|
+
" --audit-runtime <path> Path to audit_runtime.c, linked in when --audit is set",
|
|
167
|
+
" --check For `nomen format`: report files that would change",
|
|
168
|
+
" -h, --help Show this help",
|
|
169
|
+
].join("\n"),
|
|
170
|
+
);
|
|
171
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -4,16 +4,16 @@ import fs from "node:fs";
|
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
|
|
6
6
|
import chokidar from "chokidar";
|
|
7
|
-
import { hideBin } from "yargs/helpers";
|
|
8
|
-
import yargs from "yargs/yargs";
|
|
9
7
|
|
|
10
8
|
import build, { default_platform } from "../../src/build.ts";
|
|
11
9
|
import { format_source, type FormatOptions } from "../../src/format.ts";
|
|
12
10
|
import join from "../../src/join.ts";
|
|
13
11
|
import { get_library } from "../../src/lib.ts";
|
|
14
12
|
import parse from "../../src/parse.ts";
|
|
13
|
+
import { parse_args, print_help, type Args } from "./args.ts";
|
|
15
14
|
import { run_docs } from "./docs.ts";
|
|
16
15
|
import render_errors, { render_warnings } from "./format_errors.ts";
|
|
16
|
+
import { find_bundled, run_init } from "./init.ts";
|
|
17
17
|
import { runTests } from "./test.ts";
|
|
18
18
|
import type Config from "./types/Config.ts";
|
|
19
19
|
|
|
@@ -73,100 +73,48 @@ let build_root: string | undefined;
|
|
|
73
73
|
|
|
74
74
|
console.log("\n~ NOMEN ~\n");
|
|
75
75
|
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
"Usage:\n" +
|
|
79
|
-
" nomen run --in [file/folder] Parse, check, build and run a program\n" +
|
|
80
|
-
" nomen build --in [file/folder] Parse, check and build (no run)\n" +
|
|
81
|
-
" nomen check --in [file/folder] Parse and check only\n" +
|
|
82
|
-
" nomen format [--in folder] Reformat every .nm file\n" +
|
|
83
|
-
" nomen docs [--in file] Generate markdown documentation",
|
|
84
|
-
)
|
|
85
|
-
.command("run", "Parse, check, build and run a program")
|
|
86
|
-
.command("build", "Parse, check and build (compile and link, but do not run)")
|
|
87
|
-
.command("check", "Parse and check only")
|
|
88
|
-
.command("format", "Reformat every .nm file")
|
|
89
|
-
.command("docs", "Generate markdown documentation")
|
|
90
|
-
.command("test", "Discover and run *.test.nm files with the Tester harness")
|
|
91
|
-
.option("in", {
|
|
92
|
-
alias: "i",
|
|
93
|
-
describe: "Input file or folder",
|
|
94
|
-
type: "string",
|
|
95
|
-
})
|
|
96
|
-
.option("out", {
|
|
97
|
-
alias: "o",
|
|
98
|
-
describe: "Output file",
|
|
99
|
-
type: "string",
|
|
100
|
-
})
|
|
101
|
-
.option("config", {
|
|
102
|
-
alias: "c",
|
|
103
|
-
describe: "The path to a config file",
|
|
104
|
-
type: "string",
|
|
105
|
-
})
|
|
106
|
-
.option("watch", {
|
|
107
|
-
alias: "w",
|
|
108
|
-
describe: "Whether to watch for file changes",
|
|
109
|
-
type: "boolean",
|
|
110
|
-
})
|
|
111
|
-
.option("filter", {
|
|
112
|
-
alias: "f",
|
|
113
|
-
describe: "Only run test files whose path matches this regex",
|
|
114
|
-
type: "string",
|
|
115
|
-
})
|
|
116
|
-
.option("arch", {
|
|
117
|
-
alias: "a",
|
|
118
|
-
describe: "Target architecture (aarch64 or c)",
|
|
119
|
-
type: "string",
|
|
120
|
-
default: "aarch64",
|
|
121
|
-
})
|
|
122
|
-
.option("platform", {
|
|
123
|
-
alias: "p",
|
|
124
|
-
describe: "Target platform (macos, ios, linux, android, windows, web)",
|
|
125
|
-
type: "string",
|
|
126
|
-
})
|
|
127
|
-
.option("lib", {
|
|
128
|
-
alias: "l",
|
|
129
|
-
describe: "Path to System library directory (containing package.jsonc)",
|
|
130
|
-
type: "string",
|
|
131
|
-
})
|
|
132
|
-
.option("audit", {
|
|
133
|
-
describe: "Whether to audit the generated program for memory issues",
|
|
134
|
-
type: "boolean",
|
|
135
|
-
})
|
|
136
|
-
.option("audit-runtime", {
|
|
137
|
-
describe: "Path to audit_runtime.c, linked in when --audit is set",
|
|
138
|
-
type: "string",
|
|
139
|
-
})
|
|
140
|
-
.option("check", {
|
|
141
|
-
describe: "For `nomen format`: report files that would change without writing them",
|
|
142
|
-
type: "boolean",
|
|
143
|
-
})
|
|
144
|
-
.help(true);
|
|
145
|
-
|
|
146
|
-
const options = parser.parseSync();
|
|
147
|
-
|
|
148
|
-
const command = options._[0];
|
|
76
|
+
const args: Args = parse_args();
|
|
77
|
+
const command = args.command;
|
|
149
78
|
|
|
150
79
|
try {
|
|
80
|
+
// `nomen init <name>` scaffolds a new project under ./<name>.
|
|
81
|
+
if (command === "init") {
|
|
82
|
+
run_init(args.name);
|
|
83
|
+
process.exit(0);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// `nomen lib-path` prints the absolute path to the System library
|
|
87
|
+
// bundled with this CLI. Used by tooling (e.g. the VS Code extension)
|
|
88
|
+
// to locate the standard library for projects without a local one.
|
|
89
|
+
if (command === "lib-path") {
|
|
90
|
+
const lib = find_bundled("core");
|
|
91
|
+
if (lib) {
|
|
92
|
+
process.stdout.write(lib + "\n");
|
|
93
|
+
process.exit(0);
|
|
94
|
+
}
|
|
95
|
+
console.log("No bundled System library found alongside the CLI.");
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
|
|
151
99
|
// `nomen docs` generates markdown documentation instead of compiling.
|
|
152
100
|
if (command === "docs") {
|
|
153
|
-
run_docs(
|
|
101
|
+
run_docs(args.in);
|
|
154
102
|
process.exit(0);
|
|
155
103
|
}
|
|
156
104
|
|
|
157
105
|
// `nomen test` discovers and runs every `*.test.nm` file under --in (or
|
|
158
106
|
// the cwd), compiling each into a Tester harness and reporting results.
|
|
159
107
|
if (command === "test") {
|
|
160
|
-
const root =
|
|
161
|
-
const filter =
|
|
162
|
-
const arch =
|
|
108
|
+
const root = args.in ?? process.cwd();
|
|
109
|
+
const filter = args.filter ? new RegExp(args.filter) : undefined;
|
|
110
|
+
const arch = args.arch ?? "aarch64";
|
|
163
111
|
const ok = runTests(root, { arch, filter });
|
|
164
112
|
process.exit(ok ? 0 : 1);
|
|
165
113
|
}
|
|
166
114
|
|
|
167
115
|
// `nomen format` re-indents and tidies every .nm file under a folder.
|
|
168
116
|
if (command === "format") {
|
|
169
|
-
const root =
|
|
117
|
+
const root = args.in ?? process.cwd();
|
|
170
118
|
const format_options = load_format_options(root);
|
|
171
119
|
const files = collect_nm_files(root);
|
|
172
120
|
let changed = 0;
|
|
@@ -178,7 +126,7 @@ try {
|
|
|
178
126
|
continue;
|
|
179
127
|
}
|
|
180
128
|
if (result.changed) {
|
|
181
|
-
if (!
|
|
129
|
+
if (!args.check) fs.writeFileSync(file, result.code);
|
|
182
130
|
changed += 1;
|
|
183
131
|
console.log(`Formatted ${file}`);
|
|
184
132
|
}
|
|
@@ -196,59 +144,59 @@ try {
|
|
|
196
144
|
else if (command === "check") mode = "check";
|
|
197
145
|
|
|
198
146
|
if (!mode) {
|
|
199
|
-
|
|
147
|
+
print_help();
|
|
200
148
|
process.exit(1);
|
|
201
149
|
}
|
|
202
150
|
|
|
203
151
|
// An explicit --in wins; otherwise discover what to compile from the
|
|
204
152
|
// working folder — a package.jsonc `entry`, or a lone .nm file.
|
|
205
|
-
|
|
206
|
-
if (!
|
|
153
|
+
args.in = args.in ?? resolve_input();
|
|
154
|
+
if (!args.in) {
|
|
207
155
|
process.exit(0);
|
|
208
156
|
}
|
|
209
157
|
// For an explicit --in, build next to whatever was passed (the folder
|
|
210
158
|
// itself, or the file's folder). Discovery cases set build_root themselves.
|
|
211
159
|
if (!build_root) {
|
|
212
|
-
build_root = fs.lstatSync(
|
|
160
|
+
build_root = fs.lstatSync(args.in).isDirectory() ? args.in : path.dirname(args.in);
|
|
213
161
|
}
|
|
214
162
|
|
|
215
|
-
if (fs.existsSync(
|
|
163
|
+
if (fs.existsSync(args.in)) {
|
|
216
164
|
let config: Config = { arch: "aarch64", platform: default_platform() };
|
|
217
165
|
// Load the config from a file
|
|
218
|
-
if (
|
|
219
|
-
config = JSON.parse(fs.readFileSync(
|
|
166
|
+
if (args.config && fs.existsSync(args.config)) {
|
|
167
|
+
config = JSON.parse(fs.readFileSync(args.config, "utf-8"));
|
|
220
168
|
}
|
|
221
169
|
// Overwrite with args
|
|
222
|
-
if (
|
|
223
|
-
if (
|
|
224
|
-
if (
|
|
225
|
-
if (
|
|
226
|
-
if (
|
|
170
|
+
if (args.arch) config.arch = args.arch as "aarch64" | "c";
|
|
171
|
+
if (args.platform) config.platform = args.platform;
|
|
172
|
+
if (args.lib) config.lib = args.lib;
|
|
173
|
+
if (args.audit) config.audit = args.audit;
|
|
174
|
+
if (args.audit_runtime) config.audit_runtime = args.audit_runtime;
|
|
227
175
|
|
|
228
176
|
// Is the --in path a folder
|
|
229
|
-
if (fs.lstatSync(
|
|
230
|
-
if (
|
|
231
|
-
watchPath(
|
|
177
|
+
if (fs.lstatSync(args.in).isDirectory()) {
|
|
178
|
+
if (args.watch) {
|
|
179
|
+
watchPath(args.in, config, mode);
|
|
232
180
|
} else {
|
|
233
|
-
processFolder(
|
|
181
|
+
processFolder(args.in, config, mode);
|
|
234
182
|
}
|
|
235
183
|
} else {
|
|
236
184
|
// Process the supplied file
|
|
237
|
-
const extname = path.extname(
|
|
238
|
-
if (shouldProcessFile(
|
|
185
|
+
const extname = path.extname(args.in);
|
|
186
|
+
if (shouldProcessFile(args.in)) {
|
|
239
187
|
// NOTE: We get add notifications for all watched files immediately
|
|
240
188
|
// TODO: Is this the case on Windows etc too?
|
|
241
|
-
if (
|
|
242
|
-
watchPath(
|
|
189
|
+
if (args.watch) {
|
|
190
|
+
watchPath(args.in, config, mode);
|
|
243
191
|
} else {
|
|
244
|
-
processFile(
|
|
192
|
+
processFile(args.in, config, mode);
|
|
245
193
|
}
|
|
246
194
|
} else {
|
|
247
195
|
console.log("Unsupported file type: " + extname);
|
|
248
196
|
}
|
|
249
197
|
}
|
|
250
198
|
} else {
|
|
251
|
-
console.log("Path not found: " +
|
|
199
|
+
console.log("Path not found: " + args.in);
|
|
252
200
|
}
|
|
253
201
|
} catch (err) {
|
|
254
202
|
console.log("UH", err);
|
|
@@ -320,7 +268,8 @@ function resolve_lib(file_path: string): string | undefined {
|
|
|
320
268
|
if (parent === dir) break;
|
|
321
269
|
dir = parent;
|
|
322
270
|
}
|
|
323
|
-
|
|
271
|
+
// Nothing local — fall back to the System library bundled with the CLI.
|
|
272
|
+
return find_bundled("core");
|
|
324
273
|
}
|
|
325
274
|
|
|
326
275
|
function resolve_audit_runtime(config: Config, input_path: string): string | undefined {
|
package/src/init.ts
ADDED
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
|
|
5
|
+
// A name must be a portable folder name: letters, digits, underscore and
|
|
6
|
+
// hyphen only. Anything else (slashes, spaces, dots) would either break the
|
|
7
|
+
// filesystem layout or produce an invalid package name.
|
|
8
|
+
const NAME_RE = /^[A-Za-z][A-Za-z0-9_-]*$/;
|
|
9
|
+
|
|
10
|
+
const GITIGNORE = `build/
|
|
11
|
+
`;
|
|
12
|
+
|
|
13
|
+
function package_jsonc(name: string): string {
|
|
14
|
+
return `{
|
|
15
|
+
"name": "${name}",
|
|
16
|
+
"entry": "src/main.nm"
|
|
17
|
+
// The System library is resolved automatically from your nomen-lang
|
|
18
|
+
// install. To pin a local checkout instead, uncomment:
|
|
19
|
+
// "imports": { "System": "../core" }
|
|
20
|
+
}
|
|
21
|
+
`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const MAIN_NM = `import System
|
|
25
|
+
|
|
26
|
+
pub func main = (Init init) {
|
|
27
|
+
Console.write("Hello world!\\n")
|
|
28
|
+
}
|
|
29
|
+
`;
|
|
30
|
+
|
|
31
|
+
const TEST_NM = `import System
|
|
32
|
+
import System/Test
|
|
33
|
+
|
|
34
|
+
func add = (int a, int b, out int) => a + b
|
|
35
|
+
|
|
36
|
+
pub func test_smoke = (ref Tester t) {
|
|
37
|
+
t.expect(add(2, 2) == 4, "2 + 2 should equal 4")
|
|
38
|
+
}
|
|
39
|
+
`;
|
|
40
|
+
|
|
41
|
+
function readme(name: string): string {
|
|
42
|
+
return `# ${name}
|
|
43
|
+
|
|
44
|
+
A [Nomen](https://github.com/andrewjk/nomen) project.
|
|
45
|
+
|
|
46
|
+
## Build
|
|
47
|
+
|
|
48
|
+
\`\`\`bash
|
|
49
|
+
nomen build
|
|
50
|
+
\`\`\`
|
|
51
|
+
|
|
52
|
+
## Run
|
|
53
|
+
|
|
54
|
+
\`\`\`bash
|
|
55
|
+
nomen run
|
|
56
|
+
\`\`\`
|
|
57
|
+
|
|
58
|
+
## Test
|
|
59
|
+
|
|
60
|
+
\`\`\`bash
|
|
61
|
+
nomen test
|
|
62
|
+
\`\`\`
|
|
63
|
+
`;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Resolve a bundled asset (core/ or NOMEN_AGENTS.md) shipped alongside the
|
|
67
|
+
// CLI. In the published package these sit next to dist/; in the dev tree they
|
|
68
|
+
// live one level up (the repo root), so check both.
|
|
69
|
+
export function find_bundled(filename: string): string | undefined {
|
|
70
|
+
const here = path.dirname(fileURLToPath(import.meta.url));
|
|
71
|
+
const cli_root = path.dirname(here);
|
|
72
|
+
const candidates = [path.join(cli_root, filename), path.join(cli_root, "..", filename)];
|
|
73
|
+
for (const c of candidates) {
|
|
74
|
+
if (fs.existsSync(c)) return path.resolve(c);
|
|
75
|
+
}
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* `nomen init <name>`: scaffold a new project under `./<name>` with a sensible
|
|
81
|
+
* starting layout (package.jsonc, src/main.nm, a starter test, README and an
|
|
82
|
+
* AGENTS.md copied from the bundled NOMEN_AGENTS.md template).
|
|
83
|
+
*/
|
|
84
|
+
export function run_init(name: string | undefined): void {
|
|
85
|
+
if (!name) {
|
|
86
|
+
console.log("Usage: nomen init <name>");
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
if (!NAME_RE.test(name)) {
|
|
90
|
+
console.log(
|
|
91
|
+
`Invalid project name "${name}". Use letters, digits, '-' or '_' (must start with a letter).`,
|
|
92
|
+
);
|
|
93
|
+
process.exit(1);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const target = path.resolve(process.cwd(), name);
|
|
97
|
+
if (fs.existsSync(target)) {
|
|
98
|
+
console.log(`Already exists: ${target}`);
|
|
99
|
+
process.exit(1);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const agents_template = find_bundled("NOMEN_AGENTS.md");
|
|
103
|
+
if (!agents_template) {
|
|
104
|
+
console.log("Could not locate NOMEN_AGENTS.md template alongside the CLI.");
|
|
105
|
+
process.exit(1);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const src = path.join(target, "src");
|
|
109
|
+
const test = path.join(target, "test");
|
|
110
|
+
fs.mkdirSync(src, { recursive: true });
|
|
111
|
+
fs.mkdirSync(test, { recursive: true });
|
|
112
|
+
|
|
113
|
+
fs.writeFileSync(path.join(target, ".gitignore"), GITIGNORE);
|
|
114
|
+
fs.writeFileSync(path.join(target, "package.jsonc"), package_jsonc(name));
|
|
115
|
+
fs.writeFileSync(path.join(src, "main.nm"), MAIN_NM);
|
|
116
|
+
fs.writeFileSync(path.join(test, "smoke.test.nm"), TEST_NM);
|
|
117
|
+
fs.writeFileSync(path.join(target, "README.md"), readme(name));
|
|
118
|
+
fs.writeFileSync(path.join(target, "AGENTS.md"), fs.readFileSync(agents_template));
|
|
119
|
+
|
|
120
|
+
console.log(`Created ${name}/`);
|
|
121
|
+
console.log(` ${name}/.gitignore`);
|
|
122
|
+
console.log(` ${name}/package.jsonc`);
|
|
123
|
+
console.log(` ${name}/src/main.nm`);
|
|
124
|
+
console.log(` ${name}/test/smoke.test.nm`);
|
|
125
|
+
console.log(` ${name}/README.md`);
|
|
126
|
+
console.log(` ${name}/AGENTS.md`);
|
|
127
|
+
console.log(`\nNext: cd ${name} && nomen run`);
|
|
128
|
+
}
|
package/src/test.ts
CHANGED
|
@@ -7,6 +7,7 @@ import build from "../../src/build.ts";
|
|
|
7
7
|
import join from "../../src/join.ts";
|
|
8
8
|
import { get_library } from "../../src/lib.ts";
|
|
9
9
|
import parse from "../../src/parse.ts";
|
|
10
|
+
import { find_bundled } from "./init.ts";
|
|
10
11
|
|
|
11
12
|
const RECORD_PREFIX = "\\nomen|";
|
|
12
13
|
|
|
@@ -504,8 +505,10 @@ function resolve_lib_for(root: string): string | undefined {
|
|
|
504
505
|
}
|
|
505
506
|
}
|
|
506
507
|
}
|
|
508
|
+
// A bare `<dir>/System` is only the library if it has a package.jsonc;
|
|
509
|
+
// otherwise we'd match macOS's `/System` on the way to the root.
|
|
507
510
|
const systemDir = path.join(dir, "System");
|
|
508
|
-
if (fs.existsSync(systemDir)) return systemDir;
|
|
511
|
+
if (fs.existsSync(path.join(systemDir, "package.jsonc"))) return systemDir;
|
|
509
512
|
const globalSystem = path.join(dir, "core", "System");
|
|
510
513
|
if (fs.existsSync(globalSystem)) {
|
|
511
514
|
return path.join(dir, "core");
|
|
@@ -514,5 +517,6 @@ function resolve_lib_for(root: string): string | undefined {
|
|
|
514
517
|
if (parent === dir) break;
|
|
515
518
|
dir = parent;
|
|
516
519
|
}
|
|
517
|
-
|
|
520
|
+
// Nothing local — fall back to the System library bundled with the CLI.
|
|
521
|
+
return find_bundled("core");
|
|
518
522
|
}
|
|
Binary file
|