@marko/language-tools 1.0.0

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.
@@ -0,0 +1,520 @@
1
+ // This is a typescript file which defines utilities used in the output of the typescript extractor.
2
+ declare global {
3
+ namespace Marko {
4
+ // Extend the Body type to keep track of what is yielded (used for scope hoisted types).
5
+ export interface Body<
6
+ in Params extends readonly any[] = [],
7
+ out Return = void
8
+ > {
9
+ (...params: Params): MarkoReturn<Return>;
10
+ }
11
+
12
+ /**
13
+ * Do not use or you will be fired.
14
+ */
15
+ namespace _ {
16
+ export const voidReturn: MarkoReturn<void>;
17
+ export const scope: unique symbol;
18
+ export const out: Marko.Out;
19
+ export const never: never;
20
+ export const any: any;
21
+
22
+ export function attrTagNames<Input, Keys extends keyof Input>(
23
+ input: Input
24
+ ): Record<string, never> & {
25
+ [Key in Keys as `@${Input[Key] extends infer Value
26
+ ? Value extends { renderBody?: any }
27
+ ? Key
28
+ : never
29
+ : never}`]: Input[Key];
30
+ };
31
+
32
+ export const rendered: {
33
+ scopes: Record<number, never>;
34
+ returns: Record<number, never>;
35
+ };
36
+
37
+ export const Template: new <Overrides = unknown>() => {
38
+ [K in Exclude<
39
+ keyof Marko.Template,
40
+ keyof Overrides
41
+ >]: Marko.Template[K];
42
+ } & Overrides;
43
+
44
+ export function noop(value: any): void;
45
+
46
+ export function tuple<T extends readonly any[]>(...v: T): T;
47
+
48
+ export function interpolated(
49
+ strs: TemplateStringsArray,
50
+ ...exprs: (string | number | void | null | false)[]
51
+ ): string;
52
+
53
+ export function state<Component>(
54
+ component: Component
55
+ ): Component extends {
56
+ state: infer State extends object;
57
+ }
58
+ ? State
59
+ : never;
60
+
61
+ export type ReturnWithScope<Input, Return> = ReturnAndScope<
62
+ Scopes<Input>,
63
+ Return
64
+ >;
65
+
66
+ export function instance<Constructor>(
67
+ constructor: Constructor
68
+ ): Constructor extends abstract new (...args: any) => infer Instance
69
+ ? Instance
70
+ : never;
71
+
72
+ export function readScopes<Rendered>(
73
+ rendered: Rendered
74
+ ): MergeScopes<
75
+ Rendered extends { scopes: Record<any, infer Scope> } ? Scope : never
76
+ > &
77
+ Record<any, never>;
78
+
79
+ export function assertRendered<Index extends number, Rendered, Result>(
80
+ rendered: Rendered,
81
+ index: Index,
82
+ result: Result
83
+ ): asserts rendered is Rendered & {
84
+ scopes: Record<
85
+ Index,
86
+ MergeOptionalScopes<
87
+ Result extends { scope: infer Scope } ? Scope : undefined
88
+ >
89
+ >;
90
+ returns: Result extends { return?: infer Return }
91
+ ? Record<Index, Return>
92
+ : Record<Index, never>;
93
+ };
94
+
95
+ export function mutable<Lookup>(lookup: Lookup): UnionToIntersection<
96
+ Lookup extends readonly (infer Item)[]
97
+ ? Item extends
98
+ | readonly [infer LocalName extends string, infer Data]
99
+ | readonly [infer LocalName, infer SourceName, infer Data]
100
+ ? Data extends {
101
+ [K in `${SourceName extends string
102
+ ? SourceName
103
+ : LocalName}Change`]: (value: infer V, ...args: any[]) => any;
104
+ }
105
+ ? { [K in LocalName]: V }
106
+ : { readonly [K in LocalName]: unknown }
107
+ : never
108
+ : never
109
+ >;
110
+
111
+ export function bind<
112
+ Owner extends Marko.Component,
113
+ OwnerHandlers extends ComponentEventHandlers<Owner>,
114
+ Handler extends
115
+ | keyof OwnerHandlers
116
+ | ((...args: any) => any)
117
+ | false
118
+ | void,
119
+ Args extends readonly any[]
120
+ >(
121
+ owner: Owner,
122
+ handler: Handler,
123
+ ...args: Args
124
+ ): Args extends readonly []
125
+ ? Handler extends keyof OwnerHandlers
126
+ ? OwnerHandlers[Handler]
127
+ : Handler
128
+ : (...args: any) => any; // If typescript ever actually supports partial application maybe we do this.
129
+
130
+ export function renderTemplate<Name extends Marko.Template>(
131
+ imported: Promise<{ default: Name }>
132
+ ): TemplateRenderer<Name>;
133
+ export function renderNativeTag<Name extends string>(
134
+ tag: Name
135
+ ): NativeTagRenderer<Name>;
136
+ export const missingTag: DefaultRenderer;
137
+ export function renderPreferLocal<Name, Fallback>(
138
+ name: Name,
139
+ fallback: Fallback
140
+ ): 0 extends 1 & Name ? Fallback : DynamicRenderer<Name>;
141
+ export function renderDynamicTag<Name>(tag: Name): DynamicRenderer<Name>;
142
+
143
+ export function returnTag<
144
+ Input extends { value: unknown; valueChange?: (value: any) => void }
145
+ >(input: Input): Input;
146
+
147
+ export function forTag<
148
+ Value,
149
+ RenderBody extends Marko.Body<
150
+ [
151
+ value: Value extends readonly (infer Item)[] | Iterable<infer Item>
152
+ ? Item
153
+ : unknown,
154
+ index: number,
155
+ all: Value
156
+ ],
157
+ void
158
+ >
159
+ >(input: {
160
+ of: Value;
161
+ renderBody: RenderBody;
162
+ }): ReturnAndScope<RenderBodyScope<RenderBody>, void>;
163
+
164
+ export function forTag<
165
+ Value,
166
+ RenderBody extends Marko.Body<
167
+ [key: keyof Value, value: Value[keyof Value]],
168
+ void
169
+ >
170
+ >(input: {
171
+ in: Value;
172
+ renderBody: RenderBody;
173
+ }): ReturnAndScope<RenderBodyScope<RenderBody>, void>;
174
+
175
+ export function forTag<
176
+ From extends void | number,
177
+ To extends number,
178
+ Step extends void | number,
179
+ RenderBody extends Marko.Body<[index: number], void>
180
+ >(input: {
181
+ from?: From;
182
+ to: To;
183
+ step?: Step;
184
+ renderBody: RenderBody;
185
+ }): ReturnAndScope<RenderBodyScope<RenderBody>, void>;
186
+
187
+ export function forTag<RenderBody extends AnyMarkoBody>(
188
+ input: (
189
+ | {
190
+ from?: number;
191
+ to: number;
192
+ step?: number;
193
+ }
194
+ | {
195
+ in: unknown;
196
+ }
197
+ | {
198
+ of: readonly unknown[] | Iterable<unknown>;
199
+ }
200
+ ) & { renderBody?: RenderBody }
201
+ ): ReturnAndScope<RenderBodyScope<RenderBody>, void>;
202
+
203
+ export function forAttrTag<
204
+ Value extends Iterable<any> | readonly any[],
205
+ Return
206
+ >(
207
+ input: {
208
+ of: Value;
209
+ },
210
+ renderBody: (
211
+ value: Value extends readonly (infer Item)[] | Iterable<infer Item>
212
+ ? Item
213
+ : unknown,
214
+ index: number,
215
+ all: Value
216
+ ) => Return
217
+ ): {
218
+ [Key in keyof Return]: Return[Key] extends
219
+ | readonly (infer Item)[]
220
+ | infer Item
221
+ ? AttrTagByListSize<Value, Item>
222
+ : never;
223
+ };
224
+
225
+ export function forAttrTag<Value extends object, Return>(
226
+ input: {
227
+ in: Value;
228
+ },
229
+ renderBody: (key: keyof Value, value: Value[keyof Value]) => Return
230
+ ): {
231
+ [Key in keyof Return]: Return[Key] extends
232
+ | readonly (infer Item)[]
233
+ | infer Item
234
+ ? AttrTagByObjectSize<Value, Item>
235
+ : never;
236
+ };
237
+
238
+ export function forAttrTag<
239
+ From extends void | number,
240
+ To extends number,
241
+ Step extends void | number,
242
+ Return
243
+ >(
244
+ input: {
245
+ from?: From;
246
+ to: To;
247
+ step?: Step;
248
+ },
249
+ renderBody: (index: number) => Return
250
+ ): {
251
+ [Key in keyof Return]: Return[Key] extends
252
+ | readonly (infer Item)[]
253
+ | infer Item
254
+ ? number extends From | To | Step
255
+ ? MaybeRepeatable<Item>
256
+ : Step extends 0
257
+ ? never
258
+ : [To] extends [From extends void ? 0 : From]
259
+ ? undefined
260
+ : Repeatable<Item>
261
+ : never;
262
+ };
263
+
264
+ export function forAttrTag<Return>(attrs: {
265
+ input:
266
+ | {
267
+ of: any;
268
+ }
269
+ | {
270
+ in: any;
271
+ }
272
+ | {
273
+ from?: any;
274
+ to: any;
275
+ step?: any;
276
+ };
277
+ renderBody: (index: number) => Return;
278
+ }): {
279
+ [Key in keyof Return]: Return[Key] extends
280
+ | readonly (infer Item)[]
281
+ | infer Item
282
+ ? MaybeRepeatable<Item>
283
+ : never;
284
+ };
285
+
286
+ export function mergeAttrTags<Attrs extends readonly any[]>(
287
+ ...attrs: Attrs
288
+ ): MergeAttrTags<Attrs>;
289
+
290
+ // TODO: this could be improved.
291
+ // currently falls back to DefaultRenderer too eagerly.
292
+ export type DynamicRenderer<Name> = 0 extends 1 & Name
293
+ ? DefaultRenderer
294
+ : [Name] extends [Marko.Template]
295
+ ? TemplateRenderer<Name>
296
+ : [Name] extends [string]
297
+ ? NativeTagRenderer<Name>
298
+ : [Name] extends [AnyMarkoBody]
299
+ ? BodyRenderer<Name>
300
+ : [Name] extends [{ renderBody?: AnyMarkoBody }]
301
+ ? [Name["renderBody"]] extends [AnyMarkoBody]
302
+ ? BodyRenderer<Name["renderBody"]>
303
+ : BaseRenderer<
304
+ RenderBodyInput<BodyParameters<Exclude<Name["renderBody"], void>>>
305
+ >
306
+ : DefaultRenderer;
307
+
308
+ export type TemplateRenderer<Template> = Template extends {
309
+ _: infer Renderer;
310
+ }
311
+ ? Renderer
312
+ : Template extends Marko.Template<
313
+ infer Input extends Record<string, unknown>,
314
+ infer Return
315
+ >
316
+ ? BaseRenderer<Input, Return>
317
+ : never;
318
+
319
+ export interface NativeTagRenderer<Name extends string> {
320
+ (): () => <Input extends Marko.NativeTags[Name]["input"]>(
321
+ input: Input
322
+ ) => ReturnAndScope<Scopes<Input>, Marko.NativeTags[Name]["return"]>;
323
+ }
324
+
325
+ export interface BodyRenderer<Body extends AnyMarkoBody> {
326
+ (): () => <Args extends BodyParameters<Body>>(
327
+ input: RenderBodyInput<Args>
328
+ ) => ReturnAndScope<Scopes<Args>, BodyReturnType<Body>>;
329
+ }
330
+
331
+ export interface BaseRenderer<
332
+ Input extends Record<PropertyKey, unknown>,
333
+ Return = void
334
+ > {
335
+ (): () => (input: Input) => ReturnAndScope<Scopes<Input>, Return>;
336
+ }
337
+
338
+ export interface DefaultRenderer {
339
+ (): () => <Input extends Record<PropertyKey, unknown>>(
340
+ input: Input
341
+ ) => ReturnAndScope<Scopes<Input>, void>;
342
+ }
343
+
344
+ export type Relate<A, B> = B extends A ? A : B;
345
+ }
346
+ }
347
+ }
348
+
349
+ declare abstract class MarkoReturn<Return> {
350
+ return: Return;
351
+ }
352
+
353
+ type AnyMarkoBody = Marko.Body<any, any>;
354
+
355
+ type RenderBodyScope<RenderBody> = RenderBody extends (...params: any) => {
356
+ [Marko._.scope]: infer Scope;
357
+ }
358
+ ? Scope
359
+ : never;
360
+
361
+ type ReturnAndScope<Scope, Return> = {
362
+ return: Return;
363
+ scope: Scope;
364
+ };
365
+
366
+ type RenderBodyInput<Args extends readonly unknown[]> = Args extends {
367
+ length: infer Length;
368
+ }
369
+ ? number extends Length
370
+ ? { value?: Args }
371
+ : 0 extends Length
372
+ ? { value?: [] }
373
+ : { value: Args }
374
+ : never;
375
+
376
+ type Scopes<Input> = 0 extends 1 & Input
377
+ ? never
378
+ : Input extends Record<any, unknown>
379
+ ? MergeScopes<FlatScopes<Input>>
380
+ : never;
381
+
382
+ type ComponentEventHandlers<Component extends Marko.Component> = {
383
+ [K in Exclude<
384
+ keyof Component,
385
+ Exclude<
386
+ keyof Marko.Component,
387
+ "emit" | "setState" | "setStateDirty" | "forceUpdate"
388
+ >
389
+ >]: Component[K] extends (...args: any) => any ? Component[K] : never;
390
+ };
391
+
392
+ type FlatScopes<
393
+ Input extends object,
394
+ Objects = Input
395
+ > = Input[keyof Input] extends infer Prop
396
+ ? Prop extends (...args: any) => { [Marko._.scope]: infer Scope }
397
+ ? unknown extends Scope
398
+ ? never
399
+ : Scope
400
+ : 0 extends 1 & Prop
401
+ ? never
402
+ : Prop extends object
403
+ ? Prop extends Extract<Objects, Prop>
404
+ ? never
405
+ : FlatScopes<Prop, Objects | Prop>
406
+ : never
407
+ : never;
408
+
409
+ type MergeScopes<Scopes> = {
410
+ [K in Scopes extends Scopes ? keyof Scopes : never]: Scopes extends Scopes
411
+ ? Scopes[K & keyof Scopes]
412
+ : never;
413
+ };
414
+
415
+ type MergeOptionalScopes<Scopes> = {
416
+ [K in Scopes extends Scopes ? keyof Scopes : never]: Scopes extends Scopes
417
+ ? K extends keyof Scopes
418
+ ? Scopes[K]
419
+ : undefined
420
+ : never;
421
+ };
422
+
423
+ type MergeAttrTags<Attrs extends readonly any[]> = Attrs extends readonly [
424
+ infer A,
425
+ infer B,
426
+ ...infer Rest
427
+ ]
428
+ ? MergeAttrTags<[MergeAttrTag<A, B>, ...Rest]>
429
+ : Attrs extends readonly [infer A]
430
+ ? A
431
+ : never;
432
+
433
+ type MergeAttrTag<A, B> = {
434
+ [K in keyof A | keyof B]: K extends keyof A
435
+ ? K extends keyof B
436
+ ? MergeAttrTagValue<A[K], B[K]>
437
+ : A[K]
438
+ : K extends keyof B
439
+ ? B[K]
440
+ : never;
441
+ };
442
+
443
+ type MergeAttrTagValue<A, B> = A extends readonly any[]
444
+ ? B extends readonly any[]
445
+ ? [...A, ...B]
446
+ : B extends void
447
+ ? A
448
+ : [...A, B]
449
+ : A extends void
450
+ ? B
451
+ : B extends void
452
+ ? A
453
+ : [A, B];
454
+
455
+ type AttrTagByListSize<T, Item> = T extends
456
+ | readonly [any, any, ...any[]]
457
+ | readonly [...any[], any, any]
458
+ | readonly [any, ...any[], any]
459
+ ? Repeated<Item>
460
+ : T extends readonly [any]
461
+ ? Item
462
+ : T extends readonly [any, ...any[]] | readonly [...any[], any]
463
+ ? Repeatable<Item>
464
+ : T extends readonly []
465
+ ? undefined
466
+ : MaybeRepeatable<Item>;
467
+
468
+ type AttrTagByObjectSize<
469
+ Value,
470
+ Item,
471
+ Keys = RecordKeys<Value>,
472
+ KnownKeys = KnownRecordKeys<Value>
473
+ > = CheckNever<
474
+ Keys,
475
+ undefined,
476
+ CheckUnionSize<
477
+ KnownKeys,
478
+ [Keys] extends [KnownKeys] ? Item : Repeatable<Item>,
479
+ Repeated<Item>,
480
+ MaybeRepeatable<Item>
481
+ >
482
+ >;
483
+
484
+ type CheckUnionSize<T, IfOne, IfMany, Else, Copy = T> = CheckNever<
485
+ T,
486
+ Else,
487
+ T extends T
488
+ ? (Copy extends T ? never : true) extends never
489
+ ? IfOne
490
+ : IfMany
491
+ : never
492
+ >;
493
+
494
+ type RecordKeys<T> = keyof {
495
+ [K in keyof T as CheckNever<T[K], never, K>]: 0;
496
+ };
497
+
498
+ type KnownRecordKeys<T> = keyof {
499
+ [Key in keyof T as string extends Key
500
+ ? never
501
+ : number extends Key
502
+ ? never
503
+ : symbol extends Key
504
+ ? never
505
+ : CheckNever<T[Key], never, Key>]: 0;
506
+ };
507
+
508
+ type CheckNever<T, If, Else> = [T] extends [never] ? If : Else;
509
+
510
+ type UnionToIntersection<T> = (T extends any ? (_: T) => any : never) extends (
511
+ _: infer U
512
+ ) => any
513
+ ? U
514
+ : never;
515
+
516
+ type Repeated<T> = [T, T, ...T[]];
517
+ type Repeatable<T> = T | Repeated<T>;
518
+ type MaybeRepeatable<T> = undefined | Repeatable<T>;
519
+
520
+ export {};
package/package.json ADDED
@@ -0,0 +1,56 @@
1
+ {
2
+ "name": "@marko/language-tools",
3
+ "description": "Marko Language Tools",
4
+ "version": "1.0.0",
5
+ "bugs": "https://github.com/marko-js/language-server/issues/new?template=Bug_report.md",
6
+ "dependencies": {
7
+ "@babel/helper-validator-identifier": "^7.19.1",
8
+ "@babel/parser": "^7.21.2",
9
+ "htmljs-parser": "^5.2.4",
10
+ "relative-import-path": "^1.0.0"
11
+ },
12
+ "devDependencies": {
13
+ "@babel/code-frame": "^7.18.6",
14
+ "@marko/compiler": "^5.23.6",
15
+ "@types/babel__code-frame": "^7.0.3",
16
+ "@types/babel__helper-validator-identifier": "^7.15.0",
17
+ "@typescript/vfs": "^1.4.0",
18
+ "marko": "^5.22.7",
19
+ "mitata": "^0.1.6",
20
+ "tsx": "^3.12.3"
21
+ },
22
+ "exports": {
23
+ ".": {
24
+ "import": "./dist/index.mjs",
25
+ "default": "./dist/index.js"
26
+ },
27
+ "./marko.internal.d.ts": "./marko.internal.d.ts"
28
+ },
29
+ "files": [
30
+ "dist",
31
+ "!**/__tests__",
32
+ "!**/*.tsbuildinfo",
33
+ "marko.internal.d.ts"
34
+ ],
35
+ "homepage": "https://github.com/marko-js/language-server/tree/main/packages/language-tools/README.md",
36
+ "keywords": [
37
+ "analysis",
38
+ "analyze",
39
+ "language",
40
+ "marko",
41
+ "tools"
42
+ ],
43
+ "license": "MIT",
44
+ "main": "./dist/index.js",
45
+ "module": "./dist/index.mjs",
46
+ "repository": {
47
+ "type": "git",
48
+ "url": "https://github.com/marko-js/language-server/tree/main/packages/language-tools"
49
+ },
50
+ "scripts": {
51
+ "bench": "BENCH=1 mocha './src/**/__tests__/*.test.ts'",
52
+ "build": "tsc -b && tsx build.mts",
53
+ "test": "mocha './src/**/__tests__/*.test.ts'",
54
+ "test:update": "mocha './src/**/__tests__/*.test.ts' --update"
55
+ }
56
+ }