marko 5.22.7 → 5.22.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -10,8 +10,4 @@ exports.register = function (id, component) {
10
10
  registry.r(id, function () {
11
11
  return component;
12
12
  });
13
- };
14
-
15
- window.Marko = {
16
- Component: function () {}
17
13
  };
@@ -270,8 +270,4 @@ exports.writeInitComponentsCode = writeInitComponentsCode;
270
270
  */
271
271
  exports.getRenderedComponents = function (out) {
272
272
  return warp10.stringifyPrepare(getInitComponentsDataFromOut(out));
273
- };
274
-
275
- globalThis.Marko = {
276
- Component: function () {}
277
273
  };
@@ -1,5 +1,9 @@
1
1
  "use strict";
2
2
 
3
+ globalThis.Marko = {
4
+ Component: function () {}
5
+ };
6
+
3
7
  /**
4
8
  * Method is for internal usage only. This method
5
9
  * is invoked by code in a compiled Marko template and
@@ -1,5 +1,9 @@
1
1
  "use strict";
2
2
 
3
+ window.Marko = {
4
+ Component: function () {}
5
+ };
6
+
3
7
  /**
4
8
  * Method is for internal usage only. This method
5
9
  * is invoked by code in a compiled Marko template and
@@ -0,0 +1,4 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 630 630">
2
+ <rect width="630" height="630" fill="#f7df1e"/>
3
+ <path d="m423.2 492.19c12.69 20.72 29.2 35.95 58.4 35.95 24.53 0 40.2-12.26 40.2-29.2 0-20.3-16.1-27.49-43.1-39.3l-14.8-6.35c-42.72-18.2-71.1-41-71.1-89.2 0-44.4 33.83-78.2 86.7-78.2 37.64 0 64.7 13.1 84.2 47.4l-46.1 29.6c-10.15-18.2-21.1-25.37-38.1-25.37-17.34 0-28.33 11-28.33 25.37 0 17.76 11 24.95 36.4 35.95l14.8 6.34c50.3 21.57 78.7 43.56 78.7 93 0 53.3-41.87 82.5-98.1 82.5-54.98 0-90.5-26.2-107.88-60.54zm-209.13 5.13c9.3 16.5 17.76 30.45 38.1 30.45 19.45 0 31.72-7.61 31.72-37.2v-201.3h59.2v202.1c0 61.3-35.94 89.2-88.4 89.2-47.4 0-74.85-24.53-88.81-54.075z"/>
4
+ </svg>
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="512" viewBox="0 0 2560 1400"><path fill="url(#a)" d="M427 0h361L361 697l427 697H427L0 698z"/><linearGradient id="a" x2="0" y2="1"><stop offset="0" stop-color="hsl(181, 96.3%, 38.8%)"/><stop offset=".25" stop-color="hsl(186, 94.9%, 46.1%)"/><stop offset=".5" stop-color="hsl(191, 93.3%, 60.8%)"/><stop offset=".5" stop-color="hsl(195, 94.3%, 50.8%)"/><stop offset=".75" stop-color="hsl(199, 95.9%, 48.0%)"/><stop offset="1" stop-color="hsl(203, 94.9%, 38.6%)"/></linearGradient><path fill="url(#b)" d="M854 697h361L788 0H427z"/><linearGradient id="b" x2="0" y2="1"><stop offset="0" stop-color="hsl(170, 80.3%, 50.8%)"/><stop offset=".5" stop-color="hsl(161, 79.1%, 47.3%)"/><stop offset="1" stop-color="hsl(157, 78.1%, 38.9%)"/></linearGradient><path fill="url(#c)" d="M1281 0h361l-427 697H854z"/><linearGradient id="c" x2="0" y2="1"><stop offset="0" stop-color="hsl(86, 95.9%, 37.1%)"/><stop offset=".5" stop-color="hsl(86, 91.9%, 45.0%)"/><stop offset="1" stop-color="hsl(90, 82.1%, 51.2%)"/></linearGradient><path fill="url(#d)" d="M1642 0h-361l428 697-428 697h361l428-697z"/><linearGradient id="d" x2="0" y2="1"><stop offset="0" stop-color="hsl(55, 99.9%, 53.1%)"/><stop offset=".25" stop-color="hsl(51, 99.9%, 50.0%)"/><stop offset=".5" stop-color="hsl(47, 99.2%, 49.8%)"/><stop offset=".5" stop-color="hsl(39, 99.9%, 50.0%)"/><stop offset=".75" stop-color="hsl(35, 99.9%, 50.0%)"/><stop offset="1" stop-color="hsl(29, 99.9%, 46.9%)"/></linearGradient><path fill="url(#e)" d="M2132 0h-361l427 697-428 697h361l428-697z"/><linearGradient id="e" x2="0" y2="1"><stop offset="0" stop-color="hsl(352, 99.9%, 62.9%)"/><stop offset=".25" stop-color="hsl(345, 90.3%, 51.8%)"/><stop offset=".5" stop-color="hsl(341, 88.3%, 51.8%)"/><stop offset=".5" stop-color="hsl(336, 80.9%, 45.4%)"/><stop offset=".75" stop-color="hsl(332, 80.3%, 44.8%)"/><stop offset="1.1" stop-color="hsl(328, 78.1%, 35.9%)"/></linearGradient></svg>
@@ -0,0 +1 @@
1
+ <svg fill="none" height="512" viewBox="0 0 512 512" width="512" xmlns="http://www.w3.org/2000/svg"><rect fill="#3178c6" height="512" rx="50" width="512"/><rect fill="#3178c6" height="512" rx="50" width="512"/><path clip-rule="evenodd" d="m316.939 407.424v50.061c8.138 4.172 17.763 7.3 28.875 9.386s22.823 3.129 35.135 3.129c11.999 0 23.397-1.147 34.196-3.442 10.799-2.294 20.268-6.075 28.406-11.342 8.138-5.266 14.581-12.15 19.328-20.65s7.121-19.007 7.121-31.522c0-9.074-1.356-17.026-4.069-23.857s-6.625-12.906-11.738-18.225c-5.112-5.319-11.242-10.091-18.389-14.315s-15.207-8.213-24.18-11.967c-6.573-2.712-12.468-5.345-17.685-7.9-5.217-2.556-9.651-5.163-13.303-7.822-3.652-2.66-6.469-5.476-8.451-8.448-1.982-2.973-2.974-6.336-2.974-10.091 0-3.441.887-6.544 2.661-9.308s4.278-5.136 7.512-7.118c3.235-1.981 7.199-3.52 11.894-4.615 4.696-1.095 9.912-1.642 15.651-1.642 4.173 0 8.581.313 13.224.938 4.643.626 9.312 1.591 14.008 2.894 4.695 1.304 9.259 2.947 13.694 4.928 4.434 1.982 8.529 4.276 12.285 6.884v-46.776c-7.616-2.92-15.937-5.084-24.962-6.492s-19.381-2.112-31.066-2.112c-11.895 0-23.163 1.278-33.805 3.833s-20.006 6.544-28.093 11.967c-8.086 5.424-14.476 12.333-19.171 20.729-4.695 8.395-7.043 18.433-7.043 30.114 0 14.914 4.304 27.638 12.912 38.172 8.607 10.533 21.675 19.45 39.204 26.751 6.886 2.816 13.303 5.579 19.25 8.291s11.086 5.528 15.415 8.448c4.33 2.92 7.747 6.101 10.252 9.543 2.504 3.441 3.756 7.352 3.756 11.733 0 3.233-.783 6.231-2.348 8.995s-3.939 5.162-7.121 7.196-7.147 3.624-11.894 4.771c-4.748 1.148-10.303 1.721-16.668 1.721-10.851 0-21.597-1.903-32.24-5.71-10.642-3.806-20.502-9.516-29.579-17.13zm-84.159-123.342h64.22v-41.082h-179v41.082h63.906v182.918h50.874z" fill="#fff" fill-rule="evenodd"/></svg>
@@ -10,6 +10,7 @@
10
10
  "Styles",
11
11
  "Events",
12
12
  "Body content",
13
+ "TypeScript",
13
14
  "Marko 5 upgrade",
14
15
  "Troubleshooting Streaming"
15
16
  ]
@@ -0,0 +1,359 @@
1
+ # TypeScript in Marko
2
+
3
+ > **Note:** Types are supported in Marko v5.22.7+ and Marko v4.24.6+
4
+
5
+ Marko’s TypeScript support offers in-editor error checking, makes refactoring less scary, verifies that data matches expectations, and even helps with API design.
6
+
7
+ Or maybe you just want more autocomplete in VSCode. That works too.
8
+
9
+ ## Enabling TypeScript in your Marko project
10
+
11
+ There are two (non-exclusive) ways to add TypeScript to a Marko project:
12
+
13
+ - **For sites and web apps**, you can place [a `tsconfig.json` file](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html) at the project root:
14
+ <pre>
15
+ 📁 components/
16
+ 📁 node_modules/
17
+ <img src="./icons/marko.svg" width=16> index.marko
18
+ 📦 package.json
19
+ <mark><img src="./icons/ts.svg" width=16> tsconfig.json</mark>
20
+ </pre>
21
+ - **If you’re [publishing packages of Marko tags](https://markojs.com/docs/custom-tags/#publishing-tags-to-npm)**, add the following to [your `marko.json`](https://markojs.com/docs/marko-json/):
22
+ ```json
23
+ "script-lang": "ts"
24
+ ```
25
+ This will automatically expose type-checking and autocomplete for the published tags.
26
+
27
+ > **ProTip**: You can also use the `script-lang` method for sites and apps.
28
+
29
+ ## Typing a tag's `input`
30
+
31
+ A `.marko` file will use any exported `Input` type for [that file’s `input` object](https://markojs.com/docs/class-components/#input).
32
+
33
+ This can be `export type Input` or `export interface Input`.
34
+
35
+ ### Example
36
+
37
+ _PriceField.marko_
38
+
39
+ ```marko
40
+ export interface Input {
41
+ currency: string;
42
+ amount: number;
43
+ }
44
+
45
+ <label>
46
+ Price in ${input.currency}:
47
+ <input type="number" value=input.amount min=0 step=0.01>
48
+ </label>
49
+ ```
50
+
51
+ You can also import, reuse, and extend `Input` interfaces from other `.marko` or `.ts` files:
52
+
53
+ ```marko
54
+ import { Input as PriceInput } from "<PriceField>";
55
+ import { ExtraTypes } from "lib/utils.ts";
56
+ export type Input = { ...PriceInput, ...ExtraTypes };
57
+ ```
58
+
59
+ ```marko
60
+ import { Input as PriceInput } from "<PriceField>";
61
+ export interface Input extends PriceInput {
62
+ discounted: boolean;
63
+ expiresAt: Date;
64
+ };
65
+ ```
66
+
67
+ ### Generic `Input`s
68
+
69
+ [Generic Types and Type Parameters](https://www.typescriptlang.org/docs/handbook/2/generics.html) on `Input` are recognized throughout the entire `.marko` template (excluding [static statements](https://markojs.com/docs/syntax/#static-javascript)).
70
+
71
+ For example, if you set up a component like this:
72
+
73
+ _components/my-select.marko_
74
+
75
+ ```marko
76
+ export interface Input<T> {
77
+ options: T[];
78
+ onSelect: (newVal: T) => unknown;
79
+ }
80
+
81
+ static function staticFn() {
82
+ // can NOT use `T` here
83
+ }
84
+
85
+ $ const instanceFn = (val: T) => {
86
+ // can use `T` here
87
+ }
88
+
89
+ // can use `as T` here
90
+ <select on-input(evt => input.onSelect(options[evt.target.value] as T))>
91
+ <for|value, i| of=input.options>
92
+ <option value=i>${value}</option>
93
+ </for>
94
+ </select>
95
+ ```
96
+
97
+ …then your editor will figure out the types of inputs to that component:
98
+
99
+ ```marko
100
+ <my-select options=[1,2,3] onSelect=val => {}/>
101
+ // ^^^ number
102
+
103
+ <my-select options=["M","K","O"] onSelect=val => {}/>
104
+ // ^^^ string
105
+ ```
106
+
107
+ ## Built-in Marko Types
108
+
109
+ Marko exposes [type definitions](https://github.com/marko-js/marko/blob/main/packages/marko/index.d.ts) you can reuse in [a TypeScript namespace](https://www.typescriptlang.org/docs/handbook/namespaces.html) called `Marko`:
110
+
111
+ - **`Marko.Template<Input, Return>`**
112
+ - The type of a `.marko` file
113
+ - `typeof import("./template.marko")`
114
+ - **`Marko.TemplateInput<Input>`**
115
+ - The object accepted by the render methods of a template. It includes the template's `Input` as well as `$global` values.
116
+ - **`Marko.Body<Params, Return>`**
117
+ - The type of the [body content](https://markojs.com/docs/body-content/) of a tag (`renderBody`)
118
+ - **`Marko.Component<Input, State>`**
119
+ - The base class for a [class component](https://markojs.com/docs/class-components/)
120
+ - **`Marko.Renderable`**
121
+ - Values accepted by the [`<${dynamic}/>` tag](https://markojs.com/docs/syntax/#dynamic-tagname)
122
+ - `string | Marko.Template | Marko.Body | { renderBody: Marko.Body}`
123
+ - **`Marko.Out`**
124
+ - The render context with methods like `write`, `beginAsync`, etc.
125
+ - `ReturnType<template.render>`
126
+ - **`Marko.Global`**
127
+ - The type of the object on `out.global` that can be passed to a template's render methods as the `$global` property
128
+ - **`Marko.RenderResult`**
129
+ - The [result](https://markojs.com/docs/rendering/#renderresult) of rendering a Marko template
130
+ - `ReturnType<template.renderSync>`
131
+ - `Awaited<ReturnType<template.render>>`
132
+ - **`Marko.Emitter`**
133
+ - `EventEmitter` from `@types/node`
134
+ - **`Marko.NativeTags`**
135
+ - `Marko.NativeTags`: An object containing all native tags and their types
136
+ - **`Marko.NativeTagInput<TagName>`** and **`Marko.NativeTagReturn<TagName>`**
137
+ - Helpers to extract the input and return types for the specified `keyof Marko.NativeTag`
138
+ - **`Marko.BodyParameters<Body>`** and **`Marko.BodyReturnType<Body>`**
139
+ - Helpers to extract the parameters and return types from the specified `Marko.Body`
140
+ - **`Marko.Repeated<T>`** and **`Marko.Repeatable<T>`**
141
+ - Used to represent types for attributes tags which can have one or many instances
142
+ - `Marko.Repeated<T>`: `[T, T, ...T[]]` (array with at least two items)
143
+ - `Marko.Repeatable<T>`: `T | Marko.Repeated<T>`
144
+
145
+ ### Typing `renderBody`
146
+
147
+ The most commonly used type from the `Marko` namespace is `Marko.Body` which can be used to type `input.renderBody`:
148
+
149
+ _child.marko_
150
+
151
+ ```marko
152
+ export interface Input {
153
+ renderBody?: Marko.Body;
154
+ }
155
+ ```
156
+
157
+ Here, the following will be acceptable values:
158
+
159
+ _index.marko_
160
+
161
+ ```marko
162
+ <child/>
163
+ <child>Text in render body</child>
164
+ <child>
165
+ <div>Any combination of components</div>
166
+ </child>
167
+ ```
168
+
169
+ Passing other values (including components) will cause a type error:
170
+
171
+ _index.marko_
172
+
173
+ ```marko
174
+ import OtherTag from "<other-tag>";
175
+ <child renderBody=OtherTag/>
176
+ ```
177
+
178
+ ### Typing Tag Parameters
179
+
180
+ Tag parameters are passed to the `renderBody` by the child tag. For this reason, `Marko.Body` also allows typing of its parameters:
181
+
182
+ _for-by-two.marko_
183
+
184
+ ```marko
185
+ export interface Input {
186
+ to: number;
187
+ renderBody: Marko.Body<[number]>
188
+ }
189
+
190
+ <for|i| from=0 to=input.to by=2>
191
+ <${input.renderBody}(i)/>
192
+ </for>
193
+ ```
194
+
195
+ _index.marko_
196
+
197
+ ```marko
198
+ <for-by-two|i| to=10>
199
+ <div>${i}</div>
200
+ </for-by-two>
201
+ ```
202
+
203
+ ### Extending a native tag type
204
+
205
+ The types for native tags are accessed via the global `Marko.NativeTags` type. Here's an example of a component that adds a feature to the `button` element:
206
+
207
+ _color-button.marko_
208
+
209
+ ```marko
210
+ export interface Input extends Marko.NativeTagInput<"button"> {
211
+ color: string;
212
+ renderBody?: Marko.Body;
213
+ }
214
+
215
+ $ const { color, renderBody, ...restOfInput } = input;
216
+
217
+ <button style=`color: ${color}` ...restOfInput>
218
+ <${renderBody}/>
219
+ </button>
220
+ ```
221
+
222
+ ## TypeScript Syntax in `.marko`
223
+
224
+ Any [JavaScript expression in Marko](https://markojs.com/docs/syntax/#inline-javascript) can also be written as a TypeScript expression.
225
+
226
+ ### Tag Type Parameters
227
+
228
+ ```marko
229
+ <child <T>|value: T|>
230
+ ...
231
+ </child>
232
+ ```
233
+
234
+ ### Tag Type Arguments
235
+
236
+ _components/child.marko_
237
+
238
+ ```marko
239
+ export interface Input<T> {
240
+ value: T;
241
+ }
242
+ ```
243
+
244
+ _index.marko_
245
+
246
+ ```marko
247
+ // number would be inferred in this case, but we can be explicit
248
+ <child<number> value=1 />
249
+ ```
250
+
251
+ ### Method Shorthand Type Parameters
252
+
253
+ ```marko
254
+ <child process<T>() { /* ... */ } />
255
+ ```
256
+
257
+ ### Attribute Type Assertions
258
+
259
+ The types of attribute values can _usually_ be inferred. When needed, you can assert values to be more specific with [TypeScript’s `as` keyword](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#type-assertions):
260
+
261
+ ```marko
262
+ <some-component
263
+ number=1 as const
264
+ names=[] as string[]
265
+ />
266
+ ```
267
+
268
+ # JSDoc Support
269
+
270
+ For existing projects that want to incrementally add type safety, adding full TypeScript support is a big leap. This is why Marko also includes full support for [incremental typing via JSDoc](https://www.typescriptlang.org/docs/handbook/intro-to-js-ts.html).
271
+
272
+ ## Setup
273
+
274
+ You can enable type checking in an existing `.marko` file by adding a `// @ts-check` comment at the top:
275
+
276
+ ```js
277
+ // @ts-check
278
+ ```
279
+
280
+ If you want to enable type checking for all Marko & JavaScript files in a JavaScript project, you can switch to using a [`jsconfig.json`](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html#using-tsconfigjson-or-jsconfigjson). You can skip checking some files by adding a `// @ts-nocheck` comment to files.
281
+
282
+ Once that has been enabled, you can start by typing the input with JSDoc. Here's an example component with typed `input`:
283
+
284
+ ```marko
285
+ // @ts-check
286
+
287
+ /**
288
+ * @typedef {{
289
+ * firstName: string,
290
+ * lastName: string,
291
+ * }} Input
292
+ */
293
+
294
+ <div>${firstName} ${lastName}</div>
295
+ ```
296
+
297
+ ## With a separate `component.js` file
298
+
299
+ Many components in existing projects adhere to the following structure:
300
+
301
+ <pre>
302
+ 📁 components/
303
+ 📁 color-rotate-button/
304
+ <img src="./icons/marko.svg" width=16> index.marko
305
+ <img src="./icons/js.svg" width=16> component.js
306
+ </pre>
307
+
308
+ The `color-rotate-button` takes a list of colors and moves to the next one each time the button is clicked:
309
+
310
+ ```marko
311
+ <color-rotate-button colors=["red", "blue", "yellow"]>
312
+ Next Color
313
+ </color-rotate-button>
314
+ ```
315
+
316
+ Here is an example of how this `color-rotate-button` component could be typed:
317
+
318
+ _components/color-rotate-button/component.js_
319
+
320
+ ```js
321
+ // @ts-check
322
+
323
+ /**
324
+ * @typedef {{
325
+ * colors: string[],
326
+ * renderBody: Marko.Renderable
327
+ * }} Input
328
+ * @typedef {{
329
+ * colorIndex: number
330
+ * }} State
331
+ * @extends {Marko.Component<Input, State>}
332
+ */
333
+ export default class extends Marko.Component {
334
+ onCreate() {
335
+ this.state = {
336
+ colorIndex: 0
337
+ };
338
+ }
339
+
340
+ rotateColor() {
341
+ this.state.colorIndex =
342
+ (this.state.colorIndex + 1) % this.input.colors.length;
343
+ }
344
+ }
345
+ ```
346
+
347
+ _components/color-rotate-button/index.marko_
348
+
349
+ ```marko
350
+ // @ts-check
351
+
352
+ /* Input will be automatically imported from `component.js`! */
353
+
354
+ <button
355
+ onClick('rotateColor')
356
+ style=`color: ${input.colors[state.colorIndex]}`>
357
+ <${input.renderBody}/>
358
+ </button>
359
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "marko",
3
- "version": "5.22.7",
3
+ "version": "5.22.9",
4
4
  "license": "MIT",
5
5
  "description": "UI Components + streaming, async, high performance, HTML templating for Node.js and the browser.",
6
6
  "dependencies": {
@@ -11,7 +11,3 @@ exports.register = function (id, component) {
11
11
  return component;
12
12
  });
13
13
  };
14
-
15
- window.Marko = {
16
- Component: function () {}
17
- };
@@ -271,7 +271,3 @@ exports.writeInitComponentsCode = writeInitComponentsCode;
271
271
  exports.getRenderedComponents = function (out) {
272
272
  return warp10.stringifyPrepare(getInitComponentsDataFromOut(out));
273
273
  };
274
-
275
- globalThis.Marko = {
276
- Component: function () {}
277
- };
@@ -1,5 +1,9 @@
1
1
  "use strict";
2
2
 
3
+ globalThis.Marko = {
4
+ Component: function () {}
5
+ };
6
+
3
7
  /**
4
8
  * Method is for internal usage only. This method
5
9
  * is invoked by code in a compiled Marko template and
@@ -1,5 +1,9 @@
1
1
  "use strict";
2
2
 
3
+ window.Marko = {
4
+ Component: function () {}
5
+ };
6
+
3
7
  /**
4
8
  * Method is for internal usage only. This method
5
9
  * is invoked by code in a compiled Marko template and