You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/src/modules/1-getting-started/6-troubleshooting.md
+2Lines changed: 2 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,6 +3,7 @@
3
3
## Installation Troubleshooting
4
4
5
5
### ESBuild Error
6
+
6
7
If you encounter errors with esbuild dependencies like the following while building:
7
8
8
9
```txt
@@ -17,6 +18,7 @@ Especially if you've worked with other Javascript/Typescript projects before, yo
17
18
does not seem to work (or work permanently) for you.
18
19
19
20
Things to check for:
21
+
20
22
- Remove any errant `package.json` or `.yarnrc.yml` files in places like your home directory or elsewhere.
21
23
- Run `npm uninstall -g yarn` if you previously installed Yarn using installed `npm`.
22
24
- For people running Windows, `corepack enable` is a command that needs to be run using administrator privileges. If this is not possible for you, there are [workarounds](https://github.com/nodejs/corepack?tab=readme-ov-file#corepack-enable--name).
Copy file name to clipboardExpand all lines: docs/src/modules/2-bundle/1-overview.md
+14-3Lines changed: 14 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,11 +2,12 @@
2
2
3
3
Similar to regular Javascript modules, Source allows developers to export functions and constants to users for importing into their programs.
4
4
5
-
For example, the `binary_tree` module may want to provide an abstraction for Source programs to interact with the Binary Tree data structure. Thus, the `binary_tree` module would expose functions such as `make_tree`, `left_branch` and `right_branch` to be used in Source programs.
5
+
For example, the `binary_tree` module may want to provide an abstraction for Source programs to interact with the Binary Tree data structure. Thus, the `binary_tree` module would expose functions such as `make_tree`, `left_branch` and `right_branch` to be used in Source programs.
6
6
7
7
## Bundle Directory Structure Overview
8
8
9
9
The typical bundle structure for a bundle is shown below. Each section will have its own explanation.
10
+
10
11
```dirtree
11
12
name: bundle_name
12
13
children:
@@ -65,12 +66,14 @@ export function createDrawFunction(
65
66
// implementation hidden...
66
67
}
67
68
```
69
+
68
70
Note that `curve/functions.ts` exports both `createDrawFunction` and `make_point`.
69
71
70
72
```ts
71
73
// curve/index.ts
72
74
export { make_point } from'./functions';
73
75
```
76
+
74
77
However, only `make_point` is exported at the bundle's entry point however `createDrawFunction` is not, so cadets will not be able to access it, identical to how ES modules behave.
75
78
76
79
```js
@@ -87,6 +90,7 @@ It is not recommended that you use default exports in your code as default expor
87
90
:::
88
91
89
92
## `package.json`
93
+
90
94
The `package.json` file follows the same format as your typical `package.json` used with the likes of `npm` or `yarn`. If you use the template creation command, it should already have been created for you.
91
95
92
96
```jsonc
@@ -101,21 +105,27 @@ The `package.json` file follows the same format as your typical `package.json` u
101
105
}
102
106
}
103
107
```
108
+
104
109
You can find more information about each of the fields and what they mean [here](https://docs.npmjs.com/cli/v11/configuring-npm/package-json#devdependencies).
105
110
106
111
> [!WARNING] Bundle vs Package Name
107
112
> The `name` field in `package.json` is the package name and must follow the format `@sourceacademy/bundle-[your bundle name]`.
108
113
> The bundle name is what users will actually use to import your bundle from within Source code:
114
+
>
109
115
> ```ts
110
116
>import { whatever } from'bundle_name';
111
117
>```
118
+
>
112
119
> However, people consuming your bundle from regular Javascript and Typescript need to use the full (scoped) package name:
`manifest.json` contains the information required by `js-slang` to load your bundle.
128
+
119
129
```jsonc
120
130
{
121
131
"tabs": ["Curve"], // String array of the names of the tabs that will be loaded alongside your bundle
@@ -133,7 +143,9 @@ Your bundle may rely on features that are only present in later Source Chapters.
133
143
> You can use the `buildtools list bundle` command to check that your bundle can be properly detected and has the correct format.
134
144
135
145
## `tsconfig.json`
146
+
136
147
This file controls the behaviour of Typescript. By default, it should look like this:
148
+
137
149
```json
138
150
{
139
151
"extends": "../tsconfig.json",
@@ -148,10 +160,9 @@ This file controls the behaviour of Typescript. By default, it should look like
148
160
}
149
161
}
150
162
```
163
+
151
164
In general, there should not be a need for you to modify this file. A full explanation on how to use `tsconfig.json` can be found [here](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html). Note that the `typedocOptions` field is a custom field used by `typedoc` for its configuration. Refer to [here](https://typedoc.org/documents/Options.Configuration.html#compileroptions) for more information.
152
165
153
166
> [!WARNING]
154
167
> You should not remove or modify the `typedocOptions` section from your `tsconfig.json` unless you provide the name of your bundle to Typedoc via its other configuration methods. Generating documentation for your bundle
155
168
> requires that the name of your bundle be set correctly.
Copy file name to clipboardExpand all lines: docs/src/modules/2-bundle/3-editing.md
+13Lines changed: 13 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,23 +1,29 @@
1
1
# Editing an Existing Bundle
2
+
2
3
This page contains instructions for modifying an existing bundle. If you are creating a new bundle from scratch, refer to [these](./2-creating/2-creating) instructions instead.
3
4
4
5
## Installing Dependencies
6
+
5
7
To install **only** the dependencies required by the bundle you are modifying, use the command below:
Copy file name to clipboardExpand all lines: docs/src/modules/2-bundle/4-conventions/1-basic.md
+11Lines changed: 11 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,8 +1,10 @@
1
1
# Basic Conventions
2
2
3
3
## 1. Cadet facing functions should not have default or rest parameters
4
+
4
5
The function signature below takes in two booleans, the second of which is optional. This is not supported for Module functions in Source, but is fine if your function
5
6
isn't being exposed to cadets.
7
+
6
8
```ts
7
9
// Don't expose this to cadets!
8
10
function configure_options(option_1:boolean, option_2:boolean=false) {
@@ -26,22 +28,28 @@ Neither default nor rest parameters are currently supported due to an [issue](ht
26
28
:::
27
29
28
30
## 2. If your bundle requires specific Source features, make sure to indicate it in the manifest
31
+
29
32
Consider the bundle function below:
33
+
30
34
```ts
31
35
exportfunction sum(args:numbers[]) {
32
36
returnargs.reduce((res, each) =>res+each, 0);
33
37
}
34
38
```
39
+
35
40
It takes an an input an array of `number`s. However, arrays are only available in Source 3 onward. This means that you should indicate in your bundle's manifest:
41
+
36
42
```jsonc
37
43
{
38
44
"requires":3
39
45
}
40
46
```
47
+
41
48
to let `js-slang` know that your bundle can't be loaded with Source 1 and 2.
42
49
43
50
::: details Which data structure to use?
44
51
In the above example, the array can actually be replaced with a Source `List`:
@@ -59,11 +67,13 @@ export function sum(args: List) {
59
67
returntotal;
60
68
}
61
69
```
70
+
62
71
Lists are actually introduced in Source 1, which would make the above function compatible with Source 1 instead of requiring Source 3. If your bundle doesn't need
63
72
functionality specific to arrays, then consider using Source Lists instead.
64
73
:::
65
74
66
75
## 3. Making use of `js-slang/stdlib`
76
+
67
77
Bundles, where necessary, should use the implementations of libraries such as `list` or `stream` from the `js-slang` standard library:
68
78
69
79
```ts
@@ -77,6 +87,7 @@ export function is_sound(obj: unknown): obj is Sound {
77
87
);
78
88
}
79
89
```
90
+
80
91
These libraries get externalized and are then provided to bundles at runtime, so not only does this make your bundle size smaller, but it also
81
92
ensures that you are using the same version of the `stdlib` as the version being used by `js-slang` while running your bundle code.
Copy file name to clipboardExpand all lines: docs/src/modules/2-bundle/4-conventions/2-abstractions.md
+28-1Lines changed: 28 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -9,13 +9,15 @@ primitive and non primitive objects (`Wave`s are `(t: number) => number` while `
9
9
Instead of passing around the type in terms of primitives, you should make it such that cadets interact directly with the abstraction instead. Take the `sound` bundle for example.
10
10
11
11
`Sound`s are defined as a `pair`, where the head is a `Wave` and the tail is a number representing the duration of that sound:
Functionally, `Sound` behaves like a primitive type: as far as a cadet using the `sound` bundle is concerned, the bundle allows them to make and manipulate `Sound`s.
32
34
33
35
## Breaking Abstractions with `display` and `stringify`
36
+
34
37
`js-slang` provides a built-in function for converting any value into a string: `stringify()`. `display()` behaves like the typical `console.log` and prints the string representation
35
38
as returned by `stringify` to the REPL. Under the hood, `stringify` uses the default Javascript `toString` functionality to convert primitive types to their string representations. This does
36
39
mean that for "primitives" that are actually objects, `js-slang`'s default implementation will end up exposing implementation details.
37
40
38
41
Taking an example from the `curve` bundle, `RenderFunction`s are considered a type of primitive. Without any further changes, calling `display` on a `RenderFunction` produces the following
39
42
output:
43
+
40
44
```js
41
45
// Partial toString() representation of a RenderFunction
42
46
curve=> {
@@ -47,11 +51,14 @@ curve => {
47
51
return curveDrawn;
48
52
}
49
53
```
54
+
50
55
This exposes implementation details to the cadet and "breaks" the `RenderFunction` abstraction. Thus, there is a need for such objects to be able to override the default `toString`
51
56
implementation.
52
57
53
58
## The `ReplResult` interface
59
+
54
60
To allow objects to provide their own `toString` implementations, objects can implement the `ReplResult` interface:
61
+
55
62
```ts
56
63
interfaceReplResult {
57
64
toReplString: () =>string
@@ -69,22 +76,28 @@ but if your circumstances can't support it you can refer to the second method wh
69
76
70
77
> [!TIP]
71
78
> Source automatically hides the implementation for all functions at the top-level of a bundle. Running the code below
79
+
>
72
80
> ```ts
73
81
>import { show } from'rune';
74
82
>display(show);
75
83
>```
84
+
>
76
85
> produces the following string output:
86
+
>
77
87
> ```txt
78
88
>function show {
79
-
> [Functionfromrune
89
+
> [Functionfromrune
80
90
>Implementationhidden]
81
91
> }
82
92
>```
93
+
>
83
94
> This means that is is unnecessary to implement `ReplResult` for any of your top-level functions. You can still override this automatic functionality by implementing
84
95
> `ReplResult`.
85
96
86
97
### Implementing `ReplResult` directly
98
+
87
99
The simplest way to implement the interface is to do it in Typescript. For example, the `curve` bundle has a `Point` class, which is an abstraction of a point in 3D space with a color value:
100
+
88
101
```ts
89
102
/** Encapsulates 3D point with RGB values. */
90
103
exportclassPointimplementsReplResult {
@@ -105,9 +118,11 @@ would result in the infamous `[object Object]` being printed.
105
118
The benefit of implementing the interface this way in Typescript is that it enables type-checking to ensure that the interface is properly implemented.
106
119
107
120
### Implementing `ReplResult` indirectly
121
+
108
122
The `ReplResult` type is only just a Typescript interface. So long as `toReplString` property is present on the object/function, `js-slang` will be able to call it.
109
123
110
124
Referring back to the `curve` bundle's `RenderFunction`s, the type `RenderFunction` is really just a plain Javascript function with some extra properties attached to it:
125
+
111
126
```ts
112
127
typeRenderFunction= {
113
128
(func:Curve):CurveDrawn
@@ -119,6 +134,7 @@ type RenderFunction = {
119
134
```
120
135
121
136
This type doesn't implement the `ReplResult` interface, but before `RenderFunction`s are returned, they have the `toReplString` property set:
137
+
122
138
```ts
123
139
// curve/src/functions.ts
124
140
@@ -156,13 +172,15 @@ function createDrawFunction(
156
172
// This has type (points: number) => RenderFunction
> Notice in this case that they abstraction is being applied to the return type of `draw_connected` and not to the return type of `createDrawFunction`. The latter
161
178
> is just a factory function for creating the different `draw_connected` function variants, each of which return `RenderFunction`s.
162
179
>
163
180
> As mentioned earlier, since `draw_connected` is exported at the top-level of the `curve` bundle, `ReplResult` is automatically implemented for it.
164
181
165
182
We've seen the result of the default `toString` implementation. By providing `toReplString`, `js-slang` can instead return a user-friendly stringified representation of a `RenderFunction`:
183
+
166
184
```js
167
185
import { draw_connected } from'curve';
168
186
display(draw_connected(200));
@@ -179,23 +197,30 @@ provide compile time validation that the property has been set correctly.
179
197
> interface, so there should be no need for this, but this section is here as a "just in case".
180
198
181
199
## Simple Abstractions
200
+
182
201
There may be cases where you intend for your abstraction to be "decomposable" by cadets. The `Sound` type is just a wrapper around a `js-slang` pair:
202
+
183
203
```ts
184
204
typeWave= (t:number) =>number
185
205
typeSound=Pair<Wave, number>
186
206
```
207
+
187
208
For both of these types, the default `toString` behaviour closely follows their definitions:
209
+
188
210
```ts
189
211
const s =make_sound(t=>0, 1000);
190
212
display(s);
191
213
// Produces the output below
192
214
// [t => t >= duration ? 0 : wave(t), 100]
193
215
```
216
+
194
217
Calling `display` on a `Sound` prints out a pair consisting of a function and a number. In this case, then, it becomes unnecessary to apply abstractions and implement the `ReplResult` interface.
195
218
196
219
## Avoid using raw object literals
220
+
197
221
Object literals are not supported in Source, but might be required in bundle code. For example, in the case where your bundle might have several configurable options that the cadet can change,
198
222
you should have a function for each option rather than a single function that takes all the options:
0 commit comments