@alloy-js/core 0.7.0 → 0.9.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.
- package/CHANGELOG.md +36 -0
- package/babel.config.cjs +1 -4
- package/dist/src/binder.d.ts +14 -12
- package/dist/src/binder.d.ts.map +1 -1
- package/dist/src/binder.js +26 -23
- package/dist/src/binder.js.map +1 -1
- package/dist/src/code.d.ts +11 -2
- package/dist/src/code.d.ts.map +1 -1
- package/dist/src/code.js +27 -2
- package/dist/src/code.js.map +1 -1
- package/dist/src/components/Block.d.ts +2 -2
- package/dist/src/components/Block.d.ts.map +1 -1
- package/dist/src/components/Block.js +6 -5
- package/dist/src/components/Block.js.map +1 -1
- package/dist/src/components/Declaration.d.ts +31 -7
- package/dist/src/components/Declaration.d.ts.map +1 -1
- package/dist/src/components/Declaration.js +15 -7
- package/dist/src/components/Declaration.js.map +1 -1
- package/dist/src/components/For.d.ts +8 -2
- package/dist/src/components/For.d.ts.map +1 -1
- package/dist/src/components/For.js +2 -3
- package/dist/src/components/For.js.map +1 -1
- package/dist/src/components/Indent.d.ts +29 -1
- package/dist/src/components/Indent.d.ts.map +1 -1
- package/dist/src/components/Indent.js +7 -2
- package/dist/src/components/Indent.js.map +1 -1
- package/dist/src/components/List.d.ts +7 -3
- package/dist/src/components/List.d.ts.map +1 -1
- package/dist/src/components/List.js +1 -16
- package/dist/src/components/List.js.map +1 -1
- package/dist/src/components/MemberDeclaration.d.ts +35 -5
- package/dist/src/components/MemberDeclaration.d.ts.map +1 -1
- package/dist/src/components/MemberDeclaration.js +18 -7
- package/dist/src/components/MemberDeclaration.js.map +1 -1
- package/dist/src/components/MemberScope.d.ts +2 -0
- package/dist/src/components/MemberScope.d.ts.map +1 -1
- package/dist/src/components/MemberScope.js +2 -0
- package/dist/src/components/MemberScope.js.map +1 -1
- package/dist/src/components/Prose.d.ts +10 -0
- package/dist/src/components/Prose.d.ts.map +1 -0
- package/dist/src/components/Prose.js +23 -0
- package/dist/src/components/Prose.js.map +1 -0
- package/dist/src/components/Scope.d.ts +33 -2
- package/dist/src/components/Scope.d.ts.map +1 -1
- package/dist/src/components/Scope.js +20 -4
- package/dist/src/components/Scope.js.map +1 -1
- package/dist/src/components/SourceFile.d.ts +5 -0
- package/dist/src/components/SourceFile.d.ts.map +1 -1
- package/dist/src/components/SourceFile.js +10 -1
- package/dist/src/components/SourceFile.js.map +1 -1
- package/dist/src/components/index.d.ts +1 -0
- package/dist/src/components/index.d.ts.map +1 -1
- package/dist/src/components/index.js +1 -0
- package/dist/src/components/index.js.map +1 -1
- package/dist/src/components/stc/index.d.ts +19 -95
- package/dist/src/components/stc/index.d.ts.map +1 -1
- package/dist/src/components/stc/index.js +3 -6
- package/dist/src/components/stc/index.js.map +1 -1
- package/dist/src/components/stc/sti.d.ts +9 -0
- package/dist/src/components/stc/sti.d.ts.map +1 -0
- package/dist/src/components/stc/sti.js +10 -0
- package/dist/src/components/stc/sti.js.map +1 -0
- package/dist/src/context/assignment.d.ts +6 -0
- package/dist/src/context/assignment.d.ts.map +1 -1
- package/dist/src/context/assignment.js +7 -0
- package/dist/src/context/assignment.js.map +1 -1
- package/dist/src/context.d.ts +2 -0
- package/dist/src/context.d.ts.map +1 -1
- package/dist/src/context.js +12 -9
- package/dist/src/context.js.map +1 -1
- package/dist/src/index.d.ts +2 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/jsx-runtime.d.ts +93 -2
- package/dist/src/jsx-runtime.d.ts.map +1 -1
- package/dist/src/jsx-runtime.js +51 -3
- package/dist/src/jsx-runtime.js.map +1 -1
- package/dist/src/stc.d.ts +5 -7
- package/dist/src/stc.d.ts.map +1 -1
- package/dist/src/stc.js +11 -23
- package/dist/src/stc.js.map +1 -1
- package/dist/src/sti.d.ts +11 -0
- package/dist/src/sti.d.ts.map +1 -0
- package/dist/src/sti.js +31 -0
- package/dist/src/sti.js.map +1 -0
- package/dist/src/tap.d.ts +69 -6
- package/dist/src/tap.d.ts.map +1 -1
- package/dist/src/tap.js +70 -0
- package/dist/src/tap.js.map +1 -1
- package/dist/src/utils.d.ts +5 -0
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/src/utils.js +20 -0
- package/dist/src/utils.js.map +1 -1
- package/dist/test/components/prose.test.d.ts +2 -0
- package/dist/test/components/prose.test.d.ts.map +1 -0
- package/dist/test/props-with-defaults.test.d.ts +2 -0
- package/dist/test/props-with-defaults.test.d.ts.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/binder.ts +44 -29
- package/src/code.ts +37 -3
- package/src/components/Block.tsx +3 -6
- package/src/components/Declaration.tsx +43 -11
- package/src/components/For.tsx +16 -4
- package/src/components/Indent.tsx +38 -5
- package/src/components/List.tsx +14 -40
- package/src/components/MemberDeclaration.tsx +51 -12
- package/src/components/MemberScope.tsx +2 -0
- package/src/components/Prose.tsx +35 -0
- package/src/components/Scope.tsx +45 -5
- package/src/components/SourceFile.tsx +10 -0
- package/src/components/index.tsx +1 -0
- package/src/components/stc/index.ts +3 -6
- package/src/components/stc/sti.ts +10 -0
- package/src/context/assignment.ts +7 -1
- package/src/context.ts +15 -11
- package/src/index.ts +3 -0
- package/src/jsx-runtime.ts +168 -3
- package/src/stc.ts +38 -59
- package/src/sti.ts +63 -0
- package/src/tap.ts +69 -6
- package/src/{utils.ts → utils.tsx} +45 -0
- package/temp/api.json +1657 -440
- package/test/components/declaration.test.tsx +1 -1
- package/test/components/prose.test.tsx +36 -0
- package/test/components/source-file.test.tsx +17 -0
- package/test/control-flow/for.test.tsx +17 -0
- package/test/props-with-defaults.test.ts +97 -0
- package/test/symbols.test.ts +0 -25
- package/vitest.config.ts +2 -10
package/src/binder.ts
CHANGED
|
@@ -127,6 +127,11 @@ export interface OutputSymbol {
|
|
|
127
127
|
* one static member symbol in the output (i.e., the symbol is unique).
|
|
128
128
|
*/
|
|
129
129
|
staticMemberScope?: OutputScope;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Additional custom metadata about this symbol.
|
|
133
|
+
*/
|
|
134
|
+
metadata: Record<string, unknown>;
|
|
130
135
|
}
|
|
131
136
|
|
|
132
137
|
/**
|
|
@@ -175,7 +180,7 @@ export interface OutputScope {
|
|
|
175
180
|
* The kind of scope. Subtypes will likely provide a set of known scope kinds.
|
|
176
181
|
* The kind is not used by the binder itself.
|
|
177
182
|
*/
|
|
178
|
-
kind
|
|
183
|
+
kind?: string;
|
|
179
184
|
|
|
180
185
|
/**
|
|
181
186
|
* The name of the scope.
|
|
@@ -227,9 +232,9 @@ export interface OutputScope {
|
|
|
227
232
|
export type CreateSymbolOptions<T extends OutputSymbol = OutputSymbol> = {
|
|
228
233
|
name: string;
|
|
229
234
|
scope?: OutputScope;
|
|
230
|
-
refkey?: Refkey;
|
|
231
|
-
refkeys?: Refkey[];
|
|
235
|
+
refkey?: Refkey | Refkey[];
|
|
232
236
|
flags?: OutputSymbolFlags;
|
|
237
|
+
metadata?: Record<string, unknown>;
|
|
233
238
|
} & Omit<T, keyof OutputSymbol>;
|
|
234
239
|
|
|
235
240
|
export type CreateScopeOptions<T extends OutputScope = OutputScope> = {
|
|
@@ -238,6 +243,7 @@ export type CreateScopeOptions<T extends OutputScope = OutputScope> = {
|
|
|
238
243
|
parent?: OutputScope | undefined;
|
|
239
244
|
flags?: OutputScopeFlags;
|
|
240
245
|
owner?: OutputSymbol;
|
|
246
|
+
metadata?: Record<string, unknown>;
|
|
241
247
|
} & Omit<T, keyof OutputScope>;
|
|
242
248
|
|
|
243
249
|
/**
|
|
@@ -311,6 +317,10 @@ export interface Binder {
|
|
|
311
317
|
key: Refkey,
|
|
312
318
|
): Ref<ResolutionResult<TScope, TSymbol> | undefined>;
|
|
313
319
|
|
|
320
|
+
getSymbolForRefkey<TSymbol extends OutputSymbol>(
|
|
321
|
+
refkey: Refkey,
|
|
322
|
+
): Ref<TSymbol | undefined>;
|
|
323
|
+
|
|
314
324
|
/**
|
|
315
325
|
* Find a symbol with a given name in the given scope. Returns a ref
|
|
316
326
|
* for the symbol, such that when the symbol is available, the ref value
|
|
@@ -370,15 +380,11 @@ export interface Binder {
|
|
|
370
380
|
* When we resolve the refkey for `bar` from within `namespace scope 2`, we will get the following
|
|
371
381
|
* resolution result:
|
|
372
382
|
*
|
|
373
|
-
* **targetDeclaration**: symbol bar, the symbol we resolved.
|
|
374
|
-
*
|
|
375
|
-
* **
|
|
376
|
-
*
|
|
377
|
-
* **
|
|
378
|
-
*
|
|
379
|
-
* **pathDown**: [namespace scope 1], because this is the scope between the common scope and the declaration
|
|
380
|
-
*
|
|
381
|
-
* **memberPath**: [foo, bar], because we resolved a member symbol and these are the symbols that lead from the base declaration to the member symbol.
|
|
383
|
+
* * **targetDeclaration**: symbol bar, the symbol we resolved.
|
|
384
|
+
* * **commonScope**: global scope, because this is the most specific scope that contains both the declaration and the reference.
|
|
385
|
+
* * **pathUp**: [namespace scope 2], because this is the scope between the reference and the common scope.
|
|
386
|
+
* * **pathDown**: [namespace scope 1], because this is the scope between the common scope and the declaration
|
|
387
|
+
* * **memberPath**: [foo, bar], because we resolved a member symbol and these are the symbols that lead from the base declaration to the member symbol.
|
|
382
388
|
*/
|
|
383
389
|
export interface ResolutionResult<
|
|
384
390
|
TScope extends OutputScope,
|
|
@@ -424,6 +430,7 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
|
|
|
424
430
|
createSymbol,
|
|
425
431
|
deleteSymbol,
|
|
426
432
|
resolveDeclarationByKey,
|
|
433
|
+
getSymbolForRefkey,
|
|
427
434
|
addStaticMembersToSymbol,
|
|
428
435
|
addInstanceMembersToSymbol,
|
|
429
436
|
instantiateSymbolInto,
|
|
@@ -467,6 +474,7 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
|
|
|
467
474
|
parent,
|
|
468
475
|
owner,
|
|
469
476
|
flags = OutputScopeFlags.None,
|
|
477
|
+
metadata = {},
|
|
470
478
|
...rest
|
|
471
479
|
} = args;
|
|
472
480
|
|
|
@@ -499,6 +507,7 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
|
|
|
499
507
|
flags,
|
|
500
508
|
owner,
|
|
501
509
|
binder,
|
|
510
|
+
metadata,
|
|
502
511
|
...rest,
|
|
503
512
|
getSymbolNames: symbolNames(symbols),
|
|
504
513
|
}) as T;
|
|
@@ -525,19 +534,12 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
|
|
|
525
534
|
name,
|
|
526
535
|
scope = useDefaultScope(args.flags),
|
|
527
536
|
refkey,
|
|
528
|
-
refkeys,
|
|
529
537
|
flags = OutputSymbolFlags.None,
|
|
538
|
+
metadata = {},
|
|
530
539
|
...rest
|
|
531
540
|
} = args;
|
|
532
541
|
|
|
533
|
-
const allRefkeys = [];
|
|
534
|
-
if (refkey) {
|
|
535
|
-
allRefkeys.push(refkey);
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
if (refkeys) {
|
|
539
|
-
allRefkeys.push(...refkeys);
|
|
540
|
-
}
|
|
542
|
+
const allRefkeys = [refkey ?? []].flat();
|
|
541
543
|
|
|
542
544
|
if (!scope) {
|
|
543
545
|
throw new Error(
|
|
@@ -570,6 +572,7 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
|
|
|
570
572
|
refkeys: allRefkeys,
|
|
571
573
|
binder,
|
|
572
574
|
flags,
|
|
575
|
+
metadata,
|
|
573
576
|
...rest,
|
|
574
577
|
}) as T;
|
|
575
578
|
|
|
@@ -634,8 +637,7 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
|
|
|
634
637
|
createSymbol({
|
|
635
638
|
name: sym.name,
|
|
636
639
|
scope: target.instanceMemberScope!,
|
|
637
|
-
|
|
638
|
-
refkeys: [refkey(target.refkeys[0], sym.refkeys[0])],
|
|
640
|
+
refkey: [refkey(target.refkeys[0], sym.refkeys[0])],
|
|
639
641
|
flags: sym.flags | OutputSymbolFlags.InstanceMember,
|
|
640
642
|
});
|
|
641
643
|
}
|
|
@@ -709,12 +711,6 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
|
|
|
709
711
|
targetDeclarationBase: TSymbol,
|
|
710
712
|
): ResolutionResult<TScope, TSymbol> {
|
|
711
713
|
if (targetDeclarationBase.flags & OutputSymbolFlags.InstanceMember) {
|
|
712
|
-
if (targetDeclarationBase.scope !== currentMemberScope) {
|
|
713
|
-
throw new Error(
|
|
714
|
-
"Cannot resolve member symbols from a different member scope",
|
|
715
|
-
);
|
|
716
|
-
}
|
|
717
|
-
|
|
718
714
|
// todo: handle referencing nested objects by refkey
|
|
719
715
|
return {
|
|
720
716
|
pathUp: [],
|
|
@@ -810,6 +806,25 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
|
|
|
810
806
|
}
|
|
811
807
|
}
|
|
812
808
|
|
|
809
|
+
function getSymbolForRefkey<TSymbol extends OutputSymbol>(
|
|
810
|
+
refkey: Refkey,
|
|
811
|
+
): Ref<TSymbol | undefined> {
|
|
812
|
+
const symbol = knownDeclarations.get(refkey);
|
|
813
|
+
if (symbol) {
|
|
814
|
+
return shallowRef(symbol as TSymbol);
|
|
815
|
+
} else {
|
|
816
|
+
if (waitingDeclarations.has(refkey)) {
|
|
817
|
+
return waitingDeclarations.get(refkey)! as ShallowRef<
|
|
818
|
+
TSymbol | undefined
|
|
819
|
+
>;
|
|
820
|
+
} else {
|
|
821
|
+
const declSignal = shallowRef();
|
|
822
|
+
waitingDeclarations.set(refkey, declSignal);
|
|
823
|
+
return declSignal;
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
|
|
813
828
|
function waitForRefkey<
|
|
814
829
|
TScope extends OutputScope,
|
|
815
830
|
TSymbol extends OutputSymbol,
|
package/src/code.ts
CHANGED
|
@@ -1,17 +1,51 @@
|
|
|
1
1
|
// this code is split into a tokenizer and a parser of sorts because I feel like
|
|
2
|
-
// it should be
|
|
2
|
+
// it should be possible to share logic between this and the babel transform, but
|
|
3
3
|
// this is an exercise for the future.
|
|
4
|
-
import { hbr, indent } from "./components/stc/
|
|
4
|
+
import { hbr, indent } from "./components/stc/sti.js";
|
|
5
5
|
import { Child, Children } from "./jsx-runtime.js";
|
|
6
|
+
|
|
7
|
+
export function text(
|
|
8
|
+
template: TemplateStringsArray,
|
|
9
|
+
...substitutions: Children[]
|
|
10
|
+
): Children {
|
|
11
|
+
const children = [];
|
|
12
|
+
// push the literal parts and the substitutions into the children array. The
|
|
13
|
+
// first part has all leading whitespace removed, the last part has all
|
|
14
|
+
// trailing whitespace removed, and each part in the middle replaces any
|
|
15
|
+
// amount of whitespace with a single space.
|
|
16
|
+
|
|
17
|
+
for (let i = 0; i < template.length; i++) {
|
|
18
|
+
let part = template[i];
|
|
19
|
+
part = part
|
|
20
|
+
.replace(/(^(\s*\r?\n\s*)+)|((\s*\r?\n\s*)+$)/g, "")
|
|
21
|
+
.replace(/(\s*\r?\n\s*)+/g, " ");
|
|
22
|
+
children.push(part);
|
|
23
|
+
if (i < substitutions.length) {
|
|
24
|
+
children.push(substitutions[i]);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return children;
|
|
29
|
+
}
|
|
30
|
+
|
|
6
31
|
interface IndentLevelData {
|
|
7
32
|
kind: "indent";
|
|
8
33
|
children: (string | Children | IndentLevelData)[];
|
|
9
34
|
pendingLines: string[];
|
|
10
35
|
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Turn the provided string template into Children by replacing literal line
|
|
39
|
+
* breaks with hardlines and automatically indenting indented content. Similar
|
|
40
|
+
* in spirit to the `<code>` element in HTML.
|
|
41
|
+
*
|
|
42
|
+
* @see {@link text} for a similar function which treats whitespace similar to
|
|
43
|
+
* JSX template bodies.
|
|
44
|
+
*/
|
|
11
45
|
export function code(
|
|
12
46
|
template: TemplateStringsArray,
|
|
13
47
|
...substitutions: Children[]
|
|
14
|
-
) {
|
|
48
|
+
): Children {
|
|
15
49
|
const indentNodes: IndentLevelData[] = [
|
|
16
50
|
{
|
|
17
51
|
kind: "indent",
|
package/src/components/Block.tsx
CHANGED
|
@@ -23,8 +23,8 @@ export interface BlockProps {
|
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* Create an indented block of source text. The block has `opener` text which is
|
|
26
|
-
* added prior to the block, which defaults to "
|
|
27
|
-
* added after the block, which defaults to "
|
|
26
|
+
* added prior to the block, which defaults to `"{"`, and `closer` text which is
|
|
27
|
+
* added after the block, which defaults to `"}"`.
|
|
28
28
|
*/
|
|
29
29
|
export function Block(props: BlockProps) {
|
|
30
30
|
const childCount = computed(() => childrenArray(() => props.children).length);
|
|
@@ -32,12 +32,9 @@ export function Block(props: BlockProps) {
|
|
|
32
32
|
<group>
|
|
33
33
|
{props.newline && <br />}
|
|
34
34
|
{props.opener ?? "{"}
|
|
35
|
-
<Indent
|
|
35
|
+
<Indent softline={childCount.value === 0} trailingBreak>
|
|
36
36
|
{props.children}
|
|
37
37
|
</Indent>
|
|
38
|
-
{childCount.value > 0 ?
|
|
39
|
-
<hbr />
|
|
40
|
-
: <sbr />}
|
|
41
38
|
{props.closer ?? "}"}
|
|
42
39
|
</group>
|
|
43
40
|
);
|
|
@@ -3,15 +3,48 @@ import { useContext } from "../context.js";
|
|
|
3
3
|
import { BinderContext } from "../context/binder.js";
|
|
4
4
|
import { DeclarationContext } from "../context/declaration.js";
|
|
5
5
|
import { Children, onCleanup } from "../jsx-runtime.js";
|
|
6
|
-
import { Refkey
|
|
6
|
+
import { Refkey } from "../refkey.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Create a declaration by providing an already created symbol. The symbol is
|
|
10
|
+
* merely exposed via {@link DeclarationContext}.
|
|
11
|
+
*/
|
|
12
|
+
export interface DeclarationPropsWithSymbol {
|
|
13
|
+
/**
|
|
14
|
+
* The symbol being declared. When provided, the name, refkey, and metadata
|
|
15
|
+
* props are ignored.
|
|
16
|
+
*/
|
|
17
|
+
symbol: OutputSymbol;
|
|
18
|
+
|
|
19
|
+
children?: Children;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Create a declaration by providing a symbol name and optional symbol metadata.
|
|
24
|
+
*/
|
|
25
|
+
export interface DeclarationPropsWithInfo {
|
|
26
|
+
/**
|
|
27
|
+
* The name of this declaration.
|
|
28
|
+
*/
|
|
29
|
+
name: string;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The unique key or array of unique keys for this declaration.
|
|
33
|
+
*/
|
|
34
|
+
refkey?: Refkey | Refkey[];
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Additional metadata for the declared symbol.
|
|
38
|
+
*/
|
|
39
|
+
metadata?: Record<string, unknown>;
|
|
7
40
|
|
|
8
|
-
export interface DeclarationProps {
|
|
9
|
-
name?: string;
|
|
10
|
-
refkey?: Refkey;
|
|
11
|
-
symbol?: OutputSymbol;
|
|
12
41
|
children?: Children;
|
|
13
42
|
}
|
|
14
43
|
|
|
44
|
+
export type DeclarationProps =
|
|
45
|
+
| DeclarationPropsWithSymbol
|
|
46
|
+
| DeclarationPropsWithInfo;
|
|
47
|
+
|
|
15
48
|
/**
|
|
16
49
|
* Declares a symbol in the current scope for this component's children.
|
|
17
50
|
*
|
|
@@ -20,11 +53,10 @@ export interface DeclarationProps {
|
|
|
20
53
|
* This component must be called in one of two ways: with a name and an optional
|
|
21
54
|
* refkey, or else passing in the symbol. When called with a name and refkey, a
|
|
22
55
|
* symbol will be created in the current scope (provided by
|
|
23
|
-
* {@link ScopeContext}) with that name and refkey.
|
|
24
|
-
* `refkey(props.name)` is used.
|
|
56
|
+
* {@link ScopeContext}) with that name and refkey.
|
|
25
57
|
*
|
|
26
58
|
* When called with a symbol, that symbol is merely exposed via
|
|
27
|
-
* {@link DeclarationContext
|
|
59
|
+
* {@link DeclarationContext}. It is assumed that the caller of this component
|
|
28
60
|
* has created the symbol with the `createSymbol` API on the
|
|
29
61
|
* {@link BinderContext }.
|
|
30
62
|
*
|
|
@@ -37,13 +69,13 @@ export function Declaration(props: DeclarationProps) {
|
|
|
37
69
|
}
|
|
38
70
|
|
|
39
71
|
let declaration;
|
|
40
|
-
if (props
|
|
72
|
+
if ("symbol" in props) {
|
|
41
73
|
declaration = props.symbol;
|
|
42
74
|
} else {
|
|
43
|
-
const rk = props.refkey ? props.refkey : refkey(props.name);
|
|
44
75
|
declaration = binder.createSymbol({
|
|
45
76
|
name: props.name!,
|
|
46
|
-
refkey:
|
|
77
|
+
refkey: props.refkey,
|
|
78
|
+
metadata: props.metadata,
|
|
47
79
|
});
|
|
48
80
|
|
|
49
81
|
onCleanup(() => {
|
package/src/components/For.tsx
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Children, memo } from "@alloy-js/core/jsx-runtime";
|
|
2
2
|
import { isRef, Ref } from "@vue/reactivity";
|
|
3
|
-
import { mapJoin } from "../utils.js";
|
|
4
|
-
import { BaseListProps
|
|
3
|
+
import { baseListPropsToMapJoinArgs, mapJoin } from "../utils.js";
|
|
4
|
+
import { BaseListProps } from "./List.jsx";
|
|
5
5
|
|
|
6
6
|
export type ForCallbackArgs<T> =
|
|
7
7
|
T extends Ref<infer U> ? ForCallbackArgs<U>
|
|
@@ -9,6 +9,7 @@ export type ForCallbackArgs<T> =
|
|
|
9
9
|
: T extends (infer U)[] ? [value: U]
|
|
10
10
|
: T extends Map<infer U, infer V> ? [key: U, value: V]
|
|
11
11
|
: T extends Set<infer U> ? [value: U]
|
|
12
|
+
: T extends IterableIterator<infer U> ? [value: U]
|
|
12
13
|
: [];
|
|
13
14
|
|
|
14
15
|
export interface ForProps<
|
|
@@ -27,9 +28,20 @@ export interface ForProps<
|
|
|
27
28
|
* A function to call for each item.
|
|
28
29
|
*/
|
|
29
30
|
children: (...args: [...ForCallbackArgs<T>, index: number]) => U;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Whether to skip falsy values. By default, falsy values are mapped. However,
|
|
34
|
+
* when mapping children, it is useful to skip falsy values, as it enables
|
|
35
|
+
* omitting list elements via patterns like `{condition && <ListItem />}`.
|
|
36
|
+
*/
|
|
37
|
+
skipFalsy?: boolean;
|
|
30
38
|
}
|
|
31
39
|
|
|
32
|
-
export type ForSupportedCollections =
|
|
40
|
+
export type ForSupportedCollections =
|
|
41
|
+
| any[]
|
|
42
|
+
| Map<any, any>
|
|
43
|
+
| Set<any>
|
|
44
|
+
| IterableIterator<any>;
|
|
33
45
|
/**
|
|
34
46
|
* The For component iterates over the provided array and invokes the child
|
|
35
47
|
* callback for each item. It can optionally be provided with a `joiner` which
|
|
@@ -66,7 +78,7 @@ export function For<
|
|
|
66
78
|
>(props: ForProps<T, U>) {
|
|
67
79
|
const cb = props.children;
|
|
68
80
|
const options = baseListPropsToMapJoinArgs(props);
|
|
69
|
-
options.skipFalsy =
|
|
81
|
+
options.skipFalsy = props.skipFalsy;
|
|
70
82
|
return memo(() => {
|
|
71
83
|
const maybeRef = props.each;
|
|
72
84
|
|
|
@@ -2,17 +2,50 @@ import { Children } from "@alloy-js/core/jsx-runtime";
|
|
|
2
2
|
|
|
3
3
|
export interface IndentProps {
|
|
4
4
|
children: Children;
|
|
5
|
+
/**
|
|
6
|
+
* Don't include a line break. The new indentation level will start after the
|
|
7
|
+
* first linebreak within the children.
|
|
8
|
+
*/
|
|
5
9
|
nobreak?: boolean;
|
|
6
|
-
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Use a regular line (`<br />`) to start (and optionally end with
|
|
13
|
+
* `trailingBreak`) the new indentation level.
|
|
14
|
+
*/
|
|
15
|
+
line?: boolean;
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Use a soft line (`<sbr />`) to start (and optionally end with
|
|
19
|
+
* `trailingBreak`) the new indentation level.
|
|
20
|
+
*/
|
|
21
|
+
softline?: boolean;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Use a hard line (`<hbr />`) to start (and optionally end with
|
|
25
|
+
* `trailingBreak`) the new indentation level.
|
|
26
|
+
*/
|
|
27
|
+
hardline?: boolean;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Place the configured line break at the end of the block after restoring the
|
|
31
|
+
* indentation level.
|
|
32
|
+
*/
|
|
7
33
|
trailingBreak?: boolean;
|
|
8
34
|
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Create an indented block of source text. The indented block starts a new line
|
|
38
|
+
* at the new indentation level and, with `trailingBreak`, ends with a new line
|
|
39
|
+
* after restoring the indentation level. The default line break is a hard line
|
|
40
|
+
* break suitable for typical blocks of statements but can be configured.
|
|
41
|
+
*/
|
|
9
42
|
export function Indent(props: IndentProps) {
|
|
10
|
-
const breakStyle = props.break ?? "hard";
|
|
11
43
|
const breakElem =
|
|
12
44
|
props.nobreak ? ""
|
|
13
|
-
:
|
|
14
|
-
:
|
|
15
|
-
: <br
|
|
45
|
+
: props.hardline ? <hbr />
|
|
46
|
+
: props.softline ? <sbr />
|
|
47
|
+
: props.line ? <br />
|
|
48
|
+
: <hbr />;
|
|
16
49
|
|
|
17
50
|
return (
|
|
18
51
|
<>
|
package/src/components/List.tsx
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { Children, memo, splitProps } from "@alloy-js/core/jsx-runtime";
|
|
2
|
-
import { childrenArray
|
|
2
|
+
import { childrenArray } from "../utils.js";
|
|
3
3
|
import { For } from "./For.jsx";
|
|
4
4
|
|
|
5
|
-
export type BreakKind = "none" | "space" | "soft" | "hard" | "literal";
|
|
6
|
-
|
|
7
5
|
export interface BaseListProps {
|
|
8
6
|
/** Text to place between each element */
|
|
9
7
|
joiner?: Children;
|
|
@@ -14,10 +12,22 @@ export interface BaseListProps {
|
|
|
14
12
|
/** Place a semicolon between each element */
|
|
15
13
|
semicolon?: boolean;
|
|
16
14
|
|
|
15
|
+
/** Place a regular line (`<br />`) between each element */
|
|
17
16
|
line?: boolean;
|
|
17
|
+
|
|
18
|
+
/** Place a softline (`<sbr />`) between each element */
|
|
18
19
|
softline?: boolean;
|
|
20
|
+
|
|
21
|
+
/** Place a hardline (`<hbr />`) between each element */
|
|
19
22
|
hardline?: boolean;
|
|
23
|
+
|
|
24
|
+
/** Place two hardlines between each element */
|
|
25
|
+
doubleHardline?: boolean;
|
|
26
|
+
|
|
27
|
+
/** Place a literal line (`<lbr />`) between each element */
|
|
20
28
|
literalline?: boolean;
|
|
29
|
+
|
|
30
|
+
/** Place a space between each element */
|
|
21
31
|
space?: boolean;
|
|
22
32
|
|
|
23
33
|
/**
|
|
@@ -32,42 +42,6 @@ export interface BaseListProps {
|
|
|
32
42
|
enderPunctuation?: boolean;
|
|
33
43
|
}
|
|
34
44
|
|
|
35
|
-
export function baseListPropsToMapJoinArgs(props: BaseListProps): JoinOptions {
|
|
36
|
-
let joiner, punctuation;
|
|
37
|
-
if ("joiner" in props) {
|
|
38
|
-
joiner = props.joiner;
|
|
39
|
-
} else {
|
|
40
|
-
punctuation =
|
|
41
|
-
props.comma ? ","
|
|
42
|
-
: props.semicolon ? ";"
|
|
43
|
-
: "";
|
|
44
|
-
|
|
45
|
-
joiner = (
|
|
46
|
-
<>
|
|
47
|
-
{punctuation}
|
|
48
|
-
{props.softline ?
|
|
49
|
-
<sbr />
|
|
50
|
-
: props.hardline ?
|
|
51
|
-
<hbr />
|
|
52
|
-
: props.literalline ?
|
|
53
|
-
<lbr />
|
|
54
|
-
: props.line ?
|
|
55
|
-
<br />
|
|
56
|
-
: props.space ?
|
|
57
|
-
<> </>
|
|
58
|
-
: <hbr />}
|
|
59
|
-
</>
|
|
60
|
-
);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const ender =
|
|
64
|
-
"ender" in props ? props.ender
|
|
65
|
-
: props.enderPunctuation ? punctuation
|
|
66
|
-
: undefined;
|
|
67
|
-
|
|
68
|
-
return { joiner, ender };
|
|
69
|
-
}
|
|
70
|
-
|
|
71
45
|
export interface ListProps extends BaseListProps {
|
|
72
46
|
children?: Children;
|
|
73
47
|
}
|
|
@@ -87,7 +61,7 @@ export function List(props: ListProps) {
|
|
|
87
61
|
}),
|
|
88
62
|
);
|
|
89
63
|
return (
|
|
90
|
-
<For each={resolvedChildren} {...forProps}>
|
|
64
|
+
<For each={resolvedChildren} {...forProps} skipFalsy>
|
|
91
65
|
{(child) => child}
|
|
92
66
|
</For>
|
|
93
67
|
);
|
|
@@ -3,16 +3,54 @@ import { useContext } from "../context.js";
|
|
|
3
3
|
import { BinderContext } from "../context/binder.js";
|
|
4
4
|
import { MemberDeclarationContext } from "../context/member-declaration.js";
|
|
5
5
|
import { Children } from "../jsx-runtime.js";
|
|
6
|
-
import { Refkey
|
|
6
|
+
import { Refkey } from "../refkey.js";
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Create a member declaration by providing a symbol name and optional symbol
|
|
10
|
+
* metadata.
|
|
11
|
+
*/
|
|
12
|
+
export interface MemberDeclarationPropsWithInfo {
|
|
13
|
+
/**
|
|
14
|
+
* The name of this declaration.
|
|
15
|
+
*/
|
|
16
|
+
name: string;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The refkey or array refkeys for this declaration.
|
|
20
|
+
*/
|
|
21
|
+
refkey?: Refkey | Refkey[];
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Additional metadata for the declared symbol.
|
|
25
|
+
*/
|
|
26
|
+
metadata?: Record<string, unknown>;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Whether this is a static member. If not provided, the member is an instance
|
|
30
|
+
* member.
|
|
31
|
+
*/
|
|
13
32
|
static?: boolean;
|
|
33
|
+
children?: Children;
|
|
14
34
|
}
|
|
15
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Create a declaration by providing an already created symbol. The symbol is
|
|
38
|
+
* merely exposed via {@link DeclarationContext}.
|
|
39
|
+
*/
|
|
40
|
+
export interface MemberDeclarationPropsWithSymbol {
|
|
41
|
+
/**
|
|
42
|
+
* The symbol being declared. When provided, the name, refkey, and metadata
|
|
43
|
+
* props are ignored.
|
|
44
|
+
*/
|
|
45
|
+
symbol: OutputSymbol;
|
|
46
|
+
|
|
47
|
+
children?: Children;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export type MemberDeclarationProps =
|
|
51
|
+
| MemberDeclarationPropsWithInfo
|
|
52
|
+
| MemberDeclarationPropsWithSymbol;
|
|
53
|
+
|
|
16
54
|
/**
|
|
17
55
|
* Declares a symbol in the current member scope for this component's children.
|
|
18
56
|
*
|
|
@@ -38,20 +76,21 @@ export function MemberDeclaration(props: MemberDeclarationProps) {
|
|
|
38
76
|
}
|
|
39
77
|
|
|
40
78
|
let declaration;
|
|
41
|
-
if (props.symbol) {
|
|
79
|
+
if ("symbol" in props && props.symbol) {
|
|
42
80
|
declaration = props.symbol;
|
|
43
81
|
} else {
|
|
44
|
-
|
|
82
|
+
const infoProps = props as MemberDeclarationPropsWithInfo;
|
|
83
|
+
if (!infoProps.name) {
|
|
45
84
|
throw new Error(
|
|
46
85
|
"Must provide a member name, or else provide a member symbol",
|
|
47
86
|
);
|
|
48
87
|
}
|
|
49
|
-
const rk = props.refkey ? props.refkey : refkey(props.name);
|
|
50
88
|
declaration = binder.createSymbol({
|
|
51
|
-
name:
|
|
52
|
-
refkey:
|
|
89
|
+
name: infoProps.name!,
|
|
90
|
+
refkey: infoProps.refkey,
|
|
91
|
+
metadata: infoProps.metadata,
|
|
53
92
|
flags:
|
|
54
|
-
|
|
93
|
+
infoProps.static ?
|
|
55
94
|
OutputSymbolFlags.StaticMember
|
|
56
95
|
: OutputSymbolFlags.InstanceMember,
|
|
57
96
|
});
|
|
@@ -28,6 +28,8 @@ export interface MemberScopeProps {
|
|
|
28
28
|
*
|
|
29
29
|
* The member scope contains scopes for both instance and static members.
|
|
30
30
|
* However, it does not affect the resolution of static members.
|
|
31
|
+
*
|
|
32
|
+
* @see {@link (MemberScopeContext:variable)}
|
|
31
33
|
*/
|
|
32
34
|
export function MemberScope(props: MemberScopeProps) {
|
|
33
35
|
const context: MemberScopeContext = {
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { childrenArray, computed } from "@alloy-js/core";
|
|
2
|
+
import { Children } from "@alloy-js/core/jsx-runtime";
|
|
3
|
+
|
|
4
|
+
export interface Prose {
|
|
5
|
+
children: Children;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Create a block of text which will break once a word exceeds the configured line width.
|
|
10
|
+
* The children are expected to be strings, and a <br /> is added between each word.
|
|
11
|
+
*/
|
|
12
|
+
export function Prose(props: Prose) {
|
|
13
|
+
const brokenChildren = computed(() => {
|
|
14
|
+
const children = childrenArray(() => props.children);
|
|
15
|
+
return children
|
|
16
|
+
.map((child) => {
|
|
17
|
+
if (typeof child === "string") {
|
|
18
|
+
return child
|
|
19
|
+
.trim()
|
|
20
|
+
.split(/\s+/)
|
|
21
|
+
.map((word) => (
|
|
22
|
+
<>
|
|
23
|
+
{word}
|
|
24
|
+
<br />
|
|
25
|
+
</>
|
|
26
|
+
));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return child;
|
|
30
|
+
})
|
|
31
|
+
.flat(2);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
return <fill>{brokenChildren.value}</fill>;
|
|
35
|
+
}
|