moonscratch 0.1.1 → 0.1.2
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/dist/chunk-DQk6qfdC.mjs +18 -0
- package/dist/index.d.mts +1173 -0
- package/dist/index.mjs +27135 -0
- package/package.json +6 -1
- package/.agents/skills/moonbit-agent-guide/LICENSE +0 -202
- package/.agents/skills/moonbit-agent-guide/SKILL.mbt.md +0 -1126
- package/.agents/skills/moonbit-agent-guide/SKILL.md +0 -1126
- package/.agents/skills/moonbit-agent-guide/ide.md +0 -116
- package/.agents/skills/moonbit-agent-guide/references/advanced-moonbit-build.md +0 -106
- package/.agents/skills/moonbit-agent-guide/references/moonbit-language-fundamentals.mbt.md +0 -422
- package/.agents/skills/moonbit-agent-guide/references/moonbit-language-fundamentals.md +0 -422
- package/.agents/skills/moonbit-practice/SKILL.md +0 -258
- package/.agents/skills/moonbit-practice/assets/ci.yaml +0 -25
- package/.agents/skills/moonbit-practice/reference/agents.md +0 -1469
- package/.agents/skills/moonbit-practice/reference/configuration.md +0 -228
- package/.agents/skills/moonbit-practice/reference/ffi.md +0 -229
- package/.agents/skills/moonbit-practice/reference/ide.md +0 -189
- package/.agents/skills/moonbit-practice/reference/performance.md +0 -217
- package/.agents/skills/moonbit-practice/reference/refactor.md +0 -154
- package/.agents/skills/moonbit-practice/reference/stdlib.md +0 -351
- package/.agents/skills/moonbit-practice/reference/testing.md +0 -228
- package/.agents/skills/moonbit-refactoring/LICENSE +0 -21
- package/.agents/skills/moonbit-refactoring/SKILL.md +0 -323
- package/.githooks/README.md +0 -23
- package/.githooks/pre-commit +0 -3
- package/.github/workflows/copilot-setup-steps.yml +0 -40
- package/AGENTS.md +0 -91
- package/PLAN.md +0 -64
- package/TODO.md +0 -120
- package/benchmarks/calc.bench.ts +0 -144
- package/benchmarks/draw.bench.ts +0 -215
- package/benchmarks/load.bench.ts +0 -28
- package/benchmarks/render.bench.ts +0 -53
- package/benchmarks/run.bench.ts +0 -8
- package/benchmarks/types.d.ts +0 -15
- package/docs/scratch-vm-specs/eventloop.md +0 -103
- package/docs/scratch-vm-specs/moonscratch-time-separation.md +0 -50
- package/index.html +0 -91
- package/js/AGENTS.md +0 -5
- package/js/a.ts +0 -52
- package/js/assets/AGENTS.md +0 -5
- package/js/assets/base64.test.ts +0 -14
- package/js/assets/base64.ts +0 -21
- package/js/assets/build-asset.test.ts +0 -26
- package/js/assets/build-asset.ts +0 -28
- package/js/assets/create.test.ts +0 -142
- package/js/assets/create.ts +0 -122
- package/js/assets/index.test.ts +0 -15
- package/js/assets/index.ts +0 -2
- package/js/assets/types.ts +0 -26
- package/js/assets/validation.test.ts +0 -34
- package/js/assets/validation.ts +0 -25
- package/js/assets.test.ts +0 -14
- package/js/assets.ts +0 -1
- package/js/index.test.ts +0 -26
- package/js/index.ts +0 -3
- package/js/render/index.test.ts +0 -65
- package/js/render/index.ts +0 -13
- package/js/render/sharp.ts +0 -87
- package/js/render/svg.ts +0 -68
- package/js/render/types.ts +0 -35
- package/js/render/utils.ts +0 -108
- package/js/render/webgl.ts +0 -274
- package/js/sharp-optional.d.ts +0 -16
- package/js/test/helpers.ts +0 -116
- package/js/test/hikkaku-sample.test.ts +0 -37
- package/js/test/rubik-components.input-motion.test.ts +0 -60
- package/js/test/rubik-components.lists.test.ts +0 -49
- package/js/test/rubik-components.operators.test.ts +0 -104
- package/js/test/rubik-components.pen.test.ts +0 -112
- package/js/test/rubik-components.procedures-loops.test.ts +0 -72
- package/js/test/rubik-components.variables-branches.test.ts +0 -57
- package/js/test/rubik-components.visibility-entry.test.ts +0 -31
- package/js/test/test-projects.ts +0 -598
- package/js/test/variable.ts +0 -200
- package/js/test/warp.test.ts +0 -59
- package/js/vm/AGENTS.md +0 -6
- package/js/vm/README.md +0 -183
- package/js/vm/bindings.test.ts +0 -13
- package/js/vm/bindings.ts +0 -5
- package/js/vm/compare-operators.test.ts +0 -145
- package/js/vm/constants.test.ts +0 -11
- package/js/vm/constants.ts +0 -4
- package/js/vm/effect-guards.test.ts +0 -68
- package/js/vm/effect-guards.ts +0 -44
- package/js/vm/factory.test.ts +0 -486
- package/js/vm/factory.ts +0 -615
- package/js/vm/headless-vm.test.ts +0 -131
- package/js/vm/headless-vm.ts +0 -342
- package/js/vm/index.test.ts +0 -28
- package/js/vm/index.ts +0 -5
- package/js/vm/internal-types.ts +0 -32
- package/js/vm/json.test.ts +0 -40
- package/js/vm/json.ts +0 -273
- package/js/vm/normalize.test.ts +0 -48
- package/js/vm/normalize.ts +0 -65
- package/js/vm/options.test.ts +0 -30
- package/js/vm/options.ts +0 -55
- package/js/vm/pen-transparency.test.ts +0 -115
- package/js/vm/program-wasm.ts +0 -322
- package/js/vm/scheduler-render.test.ts +0 -401
- package/js/vm/scratch-assets.test.ts +0 -136
- package/js/vm/scratch-assets.ts +0 -202
- package/js/vm/types.ts +0 -358
- package/js/vm/value-guards.test.ts +0 -25
- package/js/vm/value-guards.ts +0 -18
- package/moon.mod.json +0 -10
- package/scripts/preinstall.ts +0 -4
- package/src/AGENTS.md +0 -6
- package/src/api.mbt +0 -161
- package/src/api_aot_commands.mbt +0 -184
- package/src/api_effects_json.mbt +0 -72
- package/src/api_options.mbt +0 -60
- package/src/api_program_wasm.mbt +0 -1647
- package/src/api_program_wat.mbt +0 -2206
- package/src/api_snapshot_json.mbt +0 -44
- package/src/cmd/AGENTS.md +0 -5
- package/src/cmd/main/AGENTS.md +0 -5
- package/src/cmd/main/main.mbt +0 -29
- package/src/cmd/main/moon.pkg +0 -7
- package/src/cmd/main/pkg.generated.mbti +0 -13
- package/src/json_helpers.mbt +0 -176
- package/src/moon.pkg +0 -65
- package/src/moonscratch.mbt +0 -3
- package/src/moonscratch_wbtest.mbt +0 -40
- package/src/parser_sb3.mbt +0 -890
- package/src/pkg.generated.mbti +0 -479
- package/src/runtime_eval.mbt +0 -2844
- package/src/runtime_exec.mbt +0 -3850
- package/src/runtime_render.mbt +0 -2550
- package/src/runtime_state.mbt +0 -870
- package/src/test/AGENTS.md +0 -3
- package/src/test/projects/AGENTS.md +0 -6
- package/src/test/projects/moon.pkg +0 -4
- package/src/test/projects/moonscratch_compat_test.mbt +0 -642
- package/src/test/projects/moonscratch_core_test.mbt +0 -1332
- package/src/test/projects/moonscratch_runtime_test.mbt +0 -1087
- package/src/test/projects/pkg.generated.mbti +0 -13
- package/src/test/projects/test_support.mbt +0 -35
- package/src/types_effects.mbt +0 -20
- package/src/types_error.mbt +0 -4
- package/src/types_options.mbt +0 -31
- package/src/types_runtime_structs.mbt +0 -254
- package/src/types_vm.mbt +0 -109
- package/tsconfig.json +0 -29
- package/viewer/index.ts +0 -399
- package/viewer/vite.d.ts +0 -1
- package/viewer/worker.ts +0 -161
- package/vite.config.ts +0 -61
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: 'MoonBit Testing Reference'
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# MoonBit Testing Reference
|
|
6
|
-
|
|
7
|
-
## Doc Tests
|
|
8
|
-
|
|
9
|
-
Doc tests can be written in `.mbt.md` files or inline docstrings.
|
|
10
|
-
|
|
11
|
-
### Code Block Types
|
|
12
|
-
|
|
13
|
-
| Block | Behavior |
|
|
14
|
-
| ---------------- | ------------------------------------ |
|
|
15
|
-
| ` ```mbt check ` | Type-checked by LSP and `moon check` |
|
|
16
|
-
| ` ```mbt test ` | Executed as `test {...}` block |
|
|
17
|
-
| ` ```moonbit ` | Display only (not executed) |
|
|
18
|
-
|
|
19
|
-
### Inline Docstring Example
|
|
20
|
-
|
|
21
|
-
````moonbit
|
|
22
|
-
///|
|
|
23
|
-
/// Get the largest element of a non-empty `Array`.
|
|
24
|
-
///
|
|
25
|
-
/// # Example
|
|
26
|
-
/// ```mbt test
|
|
27
|
-
/// test {
|
|
28
|
-
/// inspect(sum_array([1, 2, 3, 4, 5, 6]), content="21")
|
|
29
|
-
/// }
|
|
30
|
-
/// ```
|
|
31
|
-
///
|
|
32
|
-
/// # Panics
|
|
33
|
-
/// Panics if the `xs` is empty.
|
|
34
|
-
pub fn sum_array(xs : Array[Int]) -> Int {
|
|
35
|
-
xs.fold(init=0, fn(a, b) { a + b })
|
|
36
|
-
}
|
|
37
|
-
````
|
|
38
|
-
|
|
39
|
-
### README.mbt.md
|
|
40
|
-
|
|
41
|
-
Create `README.mbt.md` in your package directory with tested code examples:
|
|
42
|
-
|
|
43
|
-
````markdown
|
|
44
|
-
# My Package
|
|
45
|
-
|
|
46
|
-
## Usage
|
|
47
|
-
|
|
48
|
-
```mbt test
|
|
49
|
-
test {
|
|
50
|
-
inspect(@mypackage.hello(), content="Hello, World!")
|
|
51
|
-
}
|
|
52
|
-
```
|
|
53
|
-
````
|
|
54
|
-
|
|
55
|
-
Symlink to `README.md` for GitHub compatibility:
|
|
56
|
-
|
|
57
|
-
```bash
|
|
58
|
-
ln -s README.mbt.md README.md
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
## Snapshot Tests
|
|
62
|
-
|
|
63
|
-
Use `inspect()` for snapshot testing. Run `moon test -u` to auto-update.
|
|
64
|
-
|
|
65
|
-
```moonbit
|
|
66
|
-
test "snapshot" {
|
|
67
|
-
inspect([1, 2, 3], content="") // Empty initially
|
|
68
|
-
}
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
After `moon test -u`:
|
|
72
|
-
|
|
73
|
-
```moonbit
|
|
74
|
-
test "snapshot" {
|
|
75
|
-
inspect([1, 2, 3], content="[1, 2, 3]")
|
|
76
|
-
}
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
### inspect vs @json.inspect
|
|
80
|
-
|
|
81
|
-
- `inspect()` - Uses `Show` trait, good for simple values
|
|
82
|
-
- `@json.inspect()` - Uses `ToJson` trait, better for complex nested structures
|
|
83
|
-
|
|
84
|
-
```moonbit
|
|
85
|
-
test "complex structure" {
|
|
86
|
-
let data = { "name": "Alice", "scores": [90, 85, 92] }
|
|
87
|
-
@json.inspect(data, content={"name":"Alice","scores":[90,85,92]})
|
|
88
|
-
}
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
## Benchmarks with moon bench
|
|
92
|
-
|
|
93
|
-
### Basic Benchmark
|
|
94
|
-
|
|
95
|
-
```moonbit
|
|
96
|
-
///|
|
|
97
|
-
bench "array_sum" {
|
|
98
|
-
let arr = Array::make(1000, 1)
|
|
99
|
-
arr.fold(init=0, fn(a, b) { a + b })
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
///|
|
|
103
|
-
bench "array_sum_iter" {
|
|
104
|
-
let arr = Array::make(1000, 1)
|
|
105
|
-
let mut sum = 0
|
|
106
|
-
for v in arr {
|
|
107
|
-
sum = sum + v
|
|
108
|
-
}
|
|
109
|
-
sum
|
|
110
|
-
}
|
|
111
|
-
```
|
|
112
|
-
|
|
113
|
-
### Running Benchmarks
|
|
114
|
-
|
|
115
|
-
```bash
|
|
116
|
-
moon bench # Run all benchmarks
|
|
117
|
-
moon bench --target js # JS backend
|
|
118
|
-
moon bench --target wasm-gc # Wasm backend
|
|
119
|
-
```
|
|
120
|
-
|
|
121
|
-
### Benchmark Best Practices
|
|
122
|
-
|
|
123
|
-
1. **Isolate the operation**: Only measure the code you want to benchmark
|
|
124
|
-
2. **Use realistic data sizes**: Small inputs may not reveal performance issues
|
|
125
|
-
3. **Compare alternatives**: Benchmark multiple approaches side by side
|
|
126
|
-
4. **Consider different backends**: Performance varies between JS, Wasm, and Native
|
|
127
|
-
|
|
128
|
-
## QuickCheck (Property-Based Testing)
|
|
129
|
-
|
|
130
|
-
QuickCheck generates random test inputs automatically.
|
|
131
|
-
|
|
132
|
-
### Setup
|
|
133
|
-
|
|
134
|
-
Add to `moon.pkg.json`:
|
|
135
|
-
|
|
136
|
-
```json
|
|
137
|
-
{
|
|
138
|
-
"test-import": ["moonbitlang/quickcheck"]
|
|
139
|
-
}
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
### Basic Usage
|
|
143
|
-
|
|
144
|
-
```moonbit
|
|
145
|
-
///|
|
|
146
|
-
test "reverse twice is identity" {
|
|
147
|
-
@quickcheck.check(fn(arr : Array[Int]) {
|
|
148
|
-
arr.rev().rev() == arr
|
|
149
|
-
})
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
///|
|
|
153
|
-
test "sort is idempotent" {
|
|
154
|
-
@quickcheck.check(fn(arr : Array[Int]) {
|
|
155
|
-
let sorted = arr.copy()
|
|
156
|
-
sorted.sort()
|
|
157
|
-
let sorted_again = sorted.copy()
|
|
158
|
-
sorted_again.sort()
|
|
159
|
-
sorted == sorted_again
|
|
160
|
-
})
|
|
161
|
-
}
|
|
162
|
-
```
|
|
163
|
-
|
|
164
|
-
### Custom Generators
|
|
165
|
-
|
|
166
|
-
```moonbit
|
|
167
|
-
///|
|
|
168
|
-
test "custom generator" {
|
|
169
|
-
// Generate positive integers only
|
|
170
|
-
@quickcheck.check(fn(n : Int) {
|
|
171
|
-
let positive = n.abs() + 1
|
|
172
|
-
positive > 0
|
|
173
|
-
})
|
|
174
|
-
}
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
### Shrinking
|
|
178
|
-
|
|
179
|
-
QuickCheck automatically shrinks failing inputs to find minimal counterexamples:
|
|
180
|
-
|
|
181
|
-
```moonbit
|
|
182
|
-
///|
|
|
183
|
-
test "finds minimal counterexample" {
|
|
184
|
-
// If this fails, QuickCheck will find the smallest failing input
|
|
185
|
-
@quickcheck.check(fn(arr : Array[Int]) {
|
|
186
|
-
arr.length() < 100 // Will fail and shrink to length=100
|
|
187
|
-
})
|
|
188
|
-
}
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
## Test Organization
|
|
192
|
-
|
|
193
|
-
### File Naming
|
|
194
|
-
|
|
195
|
-
- `*_test.mbt` - Black-box tests (only public API)
|
|
196
|
-
- `*_wbtest.mbt` - White-box tests (can access private members)
|
|
197
|
-
- `*.mbt.md` - Documentation with tested examples
|
|
198
|
-
|
|
199
|
-
### Test Filtering
|
|
200
|
-
|
|
201
|
-
```bash
|
|
202
|
-
moon test --filter "Array::*" # Run tests matching pattern
|
|
203
|
-
moon test src/parser_test.mbt # Run specific file
|
|
204
|
-
moon test -v # Verbose output
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
### Panic Tests
|
|
208
|
-
|
|
209
|
-
Name tests with `panic` prefix:
|
|
210
|
-
|
|
211
|
-
```moonbit
|
|
212
|
-
///|
|
|
213
|
-
test "panic on empty array" {
|
|
214
|
-
ignore(@mypackage.head([])) // Should panic
|
|
215
|
-
}
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
### Error Tests
|
|
219
|
-
|
|
220
|
-
Use `try?` to convert errors to `Result`:
|
|
221
|
-
|
|
222
|
-
```moonbit
|
|
223
|
-
///|
|
|
224
|
-
test "parse error" {
|
|
225
|
-
let result = try? parse("invalid")
|
|
226
|
-
inspect(result, content="Err(ParseError::InvalidInput)")
|
|
227
|
-
}
|
|
228
|
-
```
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 bobzhang
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
@@ -1,323 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: moonbit-refactoring
|
|
3
|
-
description: 'Refactor MoonBit code to be idiomatic: shrink public APIs, convert functions to methods, use pattern matching with views, add loop invariants, and ensure test coverage without regressions. Use when updating MoonBit packages or refactoring MoonBit APIs, modules, or tests.'
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# MoonBit Refactoring Skill
|
|
7
|
-
|
|
8
|
-
## Intent
|
|
9
|
-
|
|
10
|
-
- Preserve behavior and public contracts unless explicitly changed.
|
|
11
|
-
- Minimize the public API to what callers require.
|
|
12
|
-
- Prefer declarative style and pattern matching over incidental mutation.
|
|
13
|
-
- Use view types (ArrayView/StringView/BytesView) to avoid copies.
|
|
14
|
-
- Add tests and docs alongside refactors.
|
|
15
|
-
|
|
16
|
-
## Workflow
|
|
17
|
-
|
|
18
|
-
**Start broad, then refine locally:**
|
|
19
|
-
|
|
20
|
-
1. **Architecture first**: Review package structure, dependencies, and API boundaries.
|
|
21
|
-
2. **Inventory** public APIs and call sites (`moon doc`, `moon ide find-references`).
|
|
22
|
-
3. **Pick one refactor theme** (API minimization, package splits, pattern matching, loop style).
|
|
23
|
-
4. **Apply the smallest safe change**.
|
|
24
|
-
5. **Update docs/tests** in the same patch.
|
|
25
|
-
6. **Run `moon check`, then `moon test`**.
|
|
26
|
-
7. **Use coverage** to target missing branches.
|
|
27
|
-
|
|
28
|
-
Avoid local cleanups (renaming, pattern matching) until the high-level structure is sound.
|
|
29
|
-
|
|
30
|
-
## Improve Package Architecture
|
|
31
|
-
|
|
32
|
-
- Keep packages focused: aim for <10k lines per package.
|
|
33
|
-
- Keep files manageable: aim for <2k lines per file.
|
|
34
|
-
- Keep functions focused: aim for <200 lines per function.
|
|
35
|
-
|
|
36
|
-
### Splitting Files
|
|
37
|
-
|
|
38
|
-
Treat files in MoonBit as organizational units; move code freely within a package as long as each file stays focused on one concept.
|
|
39
|
-
|
|
40
|
-
### Splitting Packages
|
|
41
|
-
|
|
42
|
-
When spinning off package `A` into `A` and `B`:
|
|
43
|
-
|
|
44
|
-
1. Create the new package and re-export temporarily:
|
|
45
|
-
|
|
46
|
-
```mbt
|
|
47
|
-
// In package B
|
|
48
|
-
using @A { ... } // re-export A's APIs
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
Ensure `moon check` passes before proceeding.
|
|
52
|
-
|
|
53
|
-
2. Find and update all call sites:
|
|
54
|
-
|
|
55
|
-
```bash
|
|
56
|
-
moon ide find-references <symbol>
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
Replace bare `f` with `@B.f`.
|
|
60
|
-
|
|
61
|
-
3. Remove the `use` statement once all call sites are updated.
|
|
62
|
-
|
|
63
|
-
4. Audit and remove newly-unused `pub` APIs from both packages.
|
|
64
|
-
|
|
65
|
-
### Guidelines
|
|
66
|
-
|
|
67
|
-
- Prefer acyclic dependencies: lower-level packages should not import higher-level ones.
|
|
68
|
-
- Only expose what downstream packages actually need.
|
|
69
|
-
- Consider an `internal/` package for helpers that shouldn't leak.
|
|
70
|
-
|
|
71
|
-
## Minimize Public API and Modularize
|
|
72
|
-
|
|
73
|
-
- Remove `pub` from helpers; keep only required exports.
|
|
74
|
-
- Move helpers into `internal/` packages to block external imports.
|
|
75
|
-
- Split large files by feature; files do not define modules in MoonBit.
|
|
76
|
-
|
|
77
|
-
## Local refactoring
|
|
78
|
-
|
|
79
|
-
### Convert Free Functions to Methods + Chaining
|
|
80
|
-
|
|
81
|
-
- Move behavior onto the owning type for discoverability.
|
|
82
|
-
- Use `..` for fluent, mutating chains when it reads clearly.
|
|
83
|
-
|
|
84
|
-
Example:
|
|
85
|
-
|
|
86
|
-
```mbt nocheck
|
|
87
|
-
// Before
|
|
88
|
-
fn reader_next(r : Reader) -> Char? { ... }
|
|
89
|
-
let ch = reader_next(r)
|
|
90
|
-
|
|
91
|
-
// After
|
|
92
|
-
#as_free_fn(reader_next, deprecated="Use Reader::next instead")
|
|
93
|
-
fn Reader::next(self : Reader) -> Char? { ... }
|
|
94
|
-
let ch = r.next()
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
To make the transition smooth, place `#as_free_fn(old_name, ...)` on the method; it emits a deprecated free function
|
|
98
|
-
`old_name` that forwards to the method.
|
|
99
|
-
Then you can check call sites and update them gradually by looking at warnings.
|
|
100
|
-
Example (chaining):
|
|
101
|
-
|
|
102
|
-
```mbt nocheck
|
|
103
|
-
buf..write_string("#\\")..write_char(ch)
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
### Prefer Explicit Qualification
|
|
107
|
-
|
|
108
|
-
- Use `@pkg.fn` instead of `using` when clarity matters.
|
|
109
|
-
- Keep call sites explicit during wide refactors.
|
|
110
|
-
|
|
111
|
-
Example:
|
|
112
|
-
|
|
113
|
-
```mbt nocheck
|
|
114
|
-
let n = @parser.parse_number(token)
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
### Simplify Enum Constructors When Type Is Known
|
|
118
|
-
|
|
119
|
-
When the expected type is known from context, you can omit the full package path for enum constructors:
|
|
120
|
-
|
|
121
|
-
- **Pattern matching**: Annotate the matched value; constructors need no path.
|
|
122
|
-
- **Nested constructors**: Only the outermost needs the full path.
|
|
123
|
-
- **Return values**: The return type provides context for constructors in the body.
|
|
124
|
-
- **Collections**: Type-annotate the collection; elements inherit the type.
|
|
125
|
-
|
|
126
|
-
Examples:
|
|
127
|
-
|
|
128
|
-
```mbt
|
|
129
|
-
// Pattern matching - annotate the value being matched
|
|
130
|
-
let tree : @pkga.Tree = ...
|
|
131
|
-
match tree {
|
|
132
|
-
Leaf(x) => x
|
|
133
|
-
Node(left~, x, right~) => left.sum() + x + right.sum()
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// Nested constructors - only outer needs full path
|
|
137
|
-
let x = @pkga.Tree::Node(left=Leaf(1), x=2, right=Leaf(3))
|
|
138
|
-
|
|
139
|
-
// Return type provides context
|
|
140
|
-
fn make_tree() -> @pkga.Tree {
|
|
141
|
-
Node(left=Leaf(1), x=2, right=Leaf(3))
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
// Collections - type annotation on the array
|
|
145
|
-
let trees : Array[@pkga.Tree] = [Leaf(1), Node(left=Leaf(2), x=3, right=Leaf(4))]
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
### Pattern Matching and Views
|
|
149
|
-
|
|
150
|
-
- Pattern match arrays directly; the compiler inserts ArrayView implicitly.
|
|
151
|
-
- Use `..` in the middle to match prefix and suffix at once.
|
|
152
|
-
- Pattern match strings directly; avoid converting to `Array[Char]`.
|
|
153
|
-
- `String`/`StringView` indexing yields `UInt16` code units. Use `for ch in s` for Unicode-aware iteration.
|
|
154
|
-
|
|
155
|
-
#### we prefer pattern matching over small functions
|
|
156
|
-
|
|
157
|
-
For example,
|
|
158
|
-
|
|
159
|
-
```mbt
|
|
160
|
-
match gen_results.get(0) {
|
|
161
|
-
Some(value) => Iter::singleton(value)
|
|
162
|
-
None => Iter::empty()
|
|
163
|
-
}
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
We can pattern match directly, it is more efficient and as readable:
|
|
167
|
-
|
|
168
|
-
```mbt
|
|
169
|
-
match gen_results {
|
|
170
|
-
[value, ..] => Iter::singleton(value)
|
|
171
|
-
[] => Iter::empty()
|
|
172
|
-
}
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
MoonBit pattern matching is pretty expressive, here are some more examples:
|
|
176
|
-
|
|
177
|
-
```mbt
|
|
178
|
-
match items {
|
|
179
|
-
[] => ()
|
|
180
|
-
[head, ..tail] => handle(head, tail)
|
|
181
|
-
[..prefix, mid, ..suffix] => handle_mid(prefix, mid, suffix)
|
|
182
|
-
}
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
```mbt
|
|
186
|
-
match s {
|
|
187
|
-
"" => ()
|
|
188
|
-
[.."let", ..rest] => handle_let(rest)
|
|
189
|
-
_ => ()
|
|
190
|
-
}
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
#### Char literal matching
|
|
194
|
-
|
|
195
|
-
Use char literal overloading for `Char`, `UInt16`, and `Int`; the examples below rely on it. This is handy when matching `String` indexing results (`UInt16`) against a char range.
|
|
196
|
-
|
|
197
|
-
```mbt
|
|
198
|
-
test {
|
|
199
|
-
let a_int : Int = 'b'
|
|
200
|
-
if (a_int is 'a'..<'z') { () } else { () }
|
|
201
|
-
let a_u16 : UInt16 = 'b'
|
|
202
|
-
if (a_u16 is 'a'..<'z') { () } else { () }
|
|
203
|
-
let a_char : Char = 'b'
|
|
204
|
-
if (a_char is 'a'..<'z') { () } else { () }
|
|
205
|
-
}
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
#### Use Nested Patterns and `is`
|
|
209
|
-
|
|
210
|
-
- Use `is` patterns inside `if`/`guard` to keep branches concise.
|
|
211
|
-
|
|
212
|
-
Example:
|
|
213
|
-
|
|
214
|
-
```mbt
|
|
215
|
-
match token {
|
|
216
|
-
Some(Ident([.."@", ..rest])) if process(rest) is Some(x) => handle_at(rest)
|
|
217
|
-
Some(Ident(name)) => handle_ident(name)
|
|
218
|
-
None => ()
|
|
219
|
-
}
|
|
220
|
-
```
|
|
221
|
-
|
|
222
|
-
#### Prefer Range Loops for Simple Indexing
|
|
223
|
-
|
|
224
|
-
- Use `for i in start..<end { ... }`, `for i in start..<=end { ... }`, `for i in large>..small`, or `for i in large>=..small` for simple index loops.
|
|
225
|
-
- Keep functional-state `for` loops for algorithms that update state.
|
|
226
|
-
|
|
227
|
-
Example:
|
|
228
|
-
|
|
229
|
-
```mbt
|
|
230
|
-
// Before
|
|
231
|
-
for i = 0; i < len; {
|
|
232
|
-
items.push(fill)
|
|
233
|
-
continue i + 1
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// After
|
|
237
|
-
for i in 0..<len {
|
|
238
|
-
items.push(fill)
|
|
239
|
-
}
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
## Loop Specs (Dafny-Style Comments)
|
|
243
|
-
|
|
244
|
-
- Add specs for functional-state loops.
|
|
245
|
-
- Skip invariants for simple `for x in xs` loops.
|
|
246
|
-
- Add TODO when a decreases clause is unclear (possible bug).
|
|
247
|
-
|
|
248
|
-
Example:
|
|
249
|
-
|
|
250
|
-
```mbt
|
|
251
|
-
for i = 0, acc = 0; i < xs.length(); {
|
|
252
|
-
acc = acc + xs[i]
|
|
253
|
-
i = i + 1
|
|
254
|
-
} else { acc }
|
|
255
|
-
where {
|
|
256
|
-
invariant: 0 <= i <= xs.length(),
|
|
257
|
-
reasoning: (
|
|
258
|
-
#| ... rigorous explanation ...
|
|
259
|
-
#| ...
|
|
260
|
-
)
|
|
261
|
-
}
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
### Tests and Docs
|
|
265
|
-
|
|
266
|
-
- Prefer black-box tests in `*_test.mbt` or `*.mbt.md`.
|
|
267
|
-
- Add docstring tests with `mbt check` for public APIs.
|
|
268
|
-
|
|
269
|
-
Example:
|
|
270
|
-
|
|
271
|
-
````mbt
|
|
272
|
-
///|
|
|
273
|
-
/// Return the last element of a non-empty array.
|
|
274
|
-
///
|
|
275
|
-
/// # Example
|
|
276
|
-
/// ```mbt check
|
|
277
|
-
/// test {
|
|
278
|
-
/// inspect(last([1, 2, 3]), content="3")
|
|
279
|
-
/// }
|
|
280
|
-
/// ```
|
|
281
|
-
pub fn last(xs : Array[Int]) -> Int { ... }
|
|
282
|
-
````
|
|
283
|
-
|
|
284
|
-
## Coverage-Driven Refactors
|
|
285
|
-
|
|
286
|
-
- Use coverage to target missing branches through public APIs.
|
|
287
|
-
- Prefer small, focused tests over white-box checks.
|
|
288
|
-
|
|
289
|
-
Commands:
|
|
290
|
-
|
|
291
|
-
```bash
|
|
292
|
-
moon coverage analyze -- -f summary
|
|
293
|
-
moon coverage analyze -- -f caret -F path/to/file.mbt
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
## Moon IDE Commands
|
|
297
|
-
|
|
298
|
-
```bash
|
|
299
|
-
moon doc "<query>"
|
|
300
|
-
moon ide outline <dir|file>
|
|
301
|
-
moon ide find-references <symbol>
|
|
302
|
-
moon ide peek-def <symbol>
|
|
303
|
-
moon ide rename <symbol> -new-name <new_name>
|
|
304
|
-
moon check
|
|
305
|
-
moon test
|
|
306
|
-
moon info
|
|
307
|
-
```
|
|
308
|
-
|
|
309
|
-
Use these commands for reliable refactoring.
|
|
310
|
-
|
|
311
|
-
Example: spinning off `package_b` from `package_a`.
|
|
312
|
-
|
|
313
|
-
Temporary import in `package_b`:
|
|
314
|
-
|
|
315
|
-
```mbt
|
|
316
|
-
using @package_a { a, type B }
|
|
317
|
-
```
|
|
318
|
-
|
|
319
|
-
Steps:
|
|
320
|
-
|
|
321
|
-
1. Use `moon ide find-references <symbol>` to find all call sites of `a` and `B`.
|
|
322
|
-
2. Replace them with `@package_a.a` and `@package_a.B`.
|
|
323
|
-
3. Remove the `using` statement and run `moon check`.
|
package/.githooks/README.md
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# Git Hooks
|
|
2
|
-
|
|
3
|
-
## Pre-commit Hook
|
|
4
|
-
|
|
5
|
-
This pre-commit hook performs automatic checks before finalizing your commit.
|
|
6
|
-
|
|
7
|
-
### Usage Instructions
|
|
8
|
-
|
|
9
|
-
To use this pre-commit hook:
|
|
10
|
-
|
|
11
|
-
1. Make the hook executable if it isn't already:
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
chmod +x .githooks/pre-commit
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
2. Configure Git to use the hooks in the .githooks directory:
|
|
18
|
-
|
|
19
|
-
```bash
|
|
20
|
-
git config core.hooksPath .githooks
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
3. The hook will automatically run when you execute `git commit`
|
package/.githooks/pre-commit
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
# Reference: https://docs.github.com/en/copilot/how-tos/use-copilot-agents/coding-agent/customize-the-agent-environment
|
|
2
|
-
name: 'Copilot Setup Steps'
|
|
3
|
-
|
|
4
|
-
# Automatically run the setup steps when they are changed to allow for easy validation, and
|
|
5
|
-
# allow manual testing through the repository's "Actions" tab
|
|
6
|
-
on:
|
|
7
|
-
workflow_dispatch:
|
|
8
|
-
push:
|
|
9
|
-
paths:
|
|
10
|
-
- .github/workflows/copilot-setup-steps.yml
|
|
11
|
-
pull_request:
|
|
12
|
-
paths:
|
|
13
|
-
- .github/workflows/copilot-setup-steps.yml
|
|
14
|
-
|
|
15
|
-
jobs:
|
|
16
|
-
# The job MUST be called `copilot-setup-steps` or it will not be picked up by Copilot.
|
|
17
|
-
copilot-setup-steps:
|
|
18
|
-
runs-on: ubuntu-latest
|
|
19
|
-
|
|
20
|
-
# Set the permissions to the lowest permissions possible needed for your steps.
|
|
21
|
-
# Copilot will be given its own token for its operations.
|
|
22
|
-
permissions:
|
|
23
|
-
# If you want to clone the repository as part of your setup steps, for example to install dependencies, you'll need the `contents: read` permission. If you don't clone the repository in your setup steps, Copilot will do this for you automatically after the steps complete.
|
|
24
|
-
contents: read
|
|
25
|
-
|
|
26
|
-
# You can define any steps you want, and they will run before the agent starts.
|
|
27
|
-
# If you do not check out your code, Copilot will do this for you.
|
|
28
|
-
steps:
|
|
29
|
-
- name: Checkout code
|
|
30
|
-
uses: actions/checkout@v5
|
|
31
|
-
|
|
32
|
-
- name: Set up MoonBit
|
|
33
|
-
run: |
|
|
34
|
-
curl -fsSL https://cli.moonbitlang.com/install/unix.sh | bash
|
|
35
|
-
echo "$HOME/.moon/bin" >> $GITHUB_PATH
|
|
36
|
-
|
|
37
|
-
- name: Update MoonBit dependencies
|
|
38
|
-
run: |
|
|
39
|
-
moon version --all
|
|
40
|
-
moon update
|