@alloy-js/core 0.7.0 → 0.8.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 +26 -0
- package/babel.config.cjs +1 -4
- package/dist/src/binder.d.ts +13 -12
- package/dist/src/binder.d.ts.map +1 -1
- package/dist/src/binder.js +11 -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 +6 -0
- 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 +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/jsx-runtime.d.ts +91 -0
- package/dist/src/jsx-runtime.d.ts.map +1 -1
- package/dist/src/jsx-runtime.js +46 -1
- 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 +20 -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 +10 -3
- 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 +1 -0
- package/src/jsx-runtime.ts +158 -0
- package/src/stc.ts +35 -56
- package/src/sti.ts +63 -0
- package/src/tap.ts +69 -6
- package/src/{utils.ts → utils.tsx} +45 -0
- package/temp/api.json +1509 -428
- 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/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
|
/**
|
|
@@ -370,15 +376,11 @@ export interface Binder {
|
|
|
370
376
|
* When we resolve the refkey for `bar` from within `namespace scope 2`, we will get the following
|
|
371
377
|
* resolution result:
|
|
372
378
|
*
|
|
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.
|
|
379
|
+
* * **targetDeclaration**: symbol bar, the symbol we resolved.
|
|
380
|
+
* * **commonScope**: global scope, because this is the most specific scope that contains both the declaration and the reference.
|
|
381
|
+
* * **pathUp**: [namespace scope 2], because this is the scope between the reference and the common scope.
|
|
382
|
+
* * **pathDown**: [namespace scope 1], because this is the scope between the common scope and the declaration
|
|
383
|
+
* * **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
384
|
*/
|
|
383
385
|
export interface ResolutionResult<
|
|
384
386
|
TScope extends OutputScope,
|
|
@@ -467,6 +469,7 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
|
|
|
467
469
|
parent,
|
|
468
470
|
owner,
|
|
469
471
|
flags = OutputScopeFlags.None,
|
|
472
|
+
metadata = {},
|
|
470
473
|
...rest
|
|
471
474
|
} = args;
|
|
472
475
|
|
|
@@ -499,6 +502,7 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
|
|
|
499
502
|
flags,
|
|
500
503
|
owner,
|
|
501
504
|
binder,
|
|
505
|
+
metadata,
|
|
502
506
|
...rest,
|
|
503
507
|
getSymbolNames: symbolNames(symbols),
|
|
504
508
|
}) as T;
|
|
@@ -525,19 +529,12 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
|
|
|
525
529
|
name,
|
|
526
530
|
scope = useDefaultScope(args.flags),
|
|
527
531
|
refkey,
|
|
528
|
-
refkeys,
|
|
529
532
|
flags = OutputSymbolFlags.None,
|
|
533
|
+
metadata = {},
|
|
530
534
|
...rest
|
|
531
535
|
} = args;
|
|
532
536
|
|
|
533
|
-
const allRefkeys = [];
|
|
534
|
-
if (refkey) {
|
|
535
|
-
allRefkeys.push(refkey);
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
if (refkeys) {
|
|
539
|
-
allRefkeys.push(...refkeys);
|
|
540
|
-
}
|
|
537
|
+
const allRefkeys = [refkey ?? []].flat();
|
|
541
538
|
|
|
542
539
|
if (!scope) {
|
|
543
540
|
throw new Error(
|
|
@@ -570,6 +567,7 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
|
|
|
570
567
|
refkeys: allRefkeys,
|
|
571
568
|
binder,
|
|
572
569
|
flags,
|
|
570
|
+
metadata,
|
|
573
571
|
...rest,
|
|
574
572
|
}) as T;
|
|
575
573
|
|
|
@@ -634,8 +632,7 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
|
|
|
634
632
|
createSymbol({
|
|
635
633
|
name: sym.name,
|
|
636
634
|
scope: target.instanceMemberScope!,
|
|
637
|
-
|
|
638
|
-
refkeys: [refkey(target.refkeys[0], sym.refkeys[0])],
|
|
635
|
+
refkey: [refkey(target.refkeys[0], sym.refkeys[0])],
|
|
639
636
|
flags: sym.flags | OutputSymbolFlags.InstanceMember,
|
|
640
637
|
});
|
|
641
638
|
}
|
|
@@ -709,12 +706,6 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
|
|
|
709
706
|
targetDeclarationBase: TSymbol,
|
|
710
707
|
): ResolutionResult<TScope, TSymbol> {
|
|
711
708
|
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
709
|
// todo: handle referencing nested objects by refkey
|
|
719
710
|
return {
|
|
720
711
|
pathUp: [],
|
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>
|
|
@@ -27,6 +27,13 @@ export interface ForProps<
|
|
|
27
27
|
* A function to call for each item.
|
|
28
28
|
*/
|
|
29
29
|
children: (...args: [...ForCallbackArgs<T>, index: number]) => U;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Whether to skip falsy values. By default, falsy values are mapped. However,
|
|
33
|
+
* when mapping children, it is useful to skip falsy values, as it enables
|
|
34
|
+
* omitting list elements via patterns like `{condition && <ListItem />}`.
|
|
35
|
+
*/
|
|
36
|
+
skipFalsy?: boolean;
|
|
30
37
|
}
|
|
31
38
|
|
|
32
39
|
export type ForSupportedCollections = any[] | Map<any, any> | Set<any>;
|
|
@@ -66,7 +73,7 @@ export function For<
|
|
|
66
73
|
>(props: ForProps<T, U>) {
|
|
67
74
|
const cb = props.children;
|
|
68
75
|
const options = baseListPropsToMapJoinArgs(props);
|
|
69
|
-
options.skipFalsy =
|
|
76
|
+
options.skipFalsy = props.skipFalsy;
|
|
70
77
|
return memo(() => {
|
|
71
78
|
const maybeRef = props.each;
|
|
72
79
|
|
|
@@ -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
|
+
}
|
package/src/components/Scope.tsx
CHANGED
|
@@ -4,21 +4,61 @@ import { BinderContext } from "../context/binder.js";
|
|
|
4
4
|
import { ScopeContext } from "../context/scope.js";
|
|
5
5
|
import { Children } from "../jsx-runtime.js";
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
/**
|
|
8
|
+
* Declare a scope by providing an already created scope. The scope is merely
|
|
9
|
+
* exposed via {@link ScopeContext}.
|
|
10
|
+
*/
|
|
11
|
+
export interface ScopePropsWithValue {
|
|
12
|
+
/**
|
|
13
|
+
* The scope to use. If not provided, a new scope will be created.
|
|
14
|
+
*/
|
|
15
|
+
value: OutputScope;
|
|
16
|
+
|
|
17
|
+
children?: Children;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Create a scope by providing a name and optional metadata.
|
|
22
|
+
*/
|
|
23
|
+
export interface ScopePropsWithInfo {
|
|
24
|
+
/**
|
|
25
|
+
* The kind of scope. This may be used by application code to determine how
|
|
26
|
+
* to handle symbols in this scope. It is not used by the core framework.
|
|
27
|
+
*/
|
|
8
28
|
kind?: string;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* The name of this scope.
|
|
32
|
+
*/
|
|
9
33
|
name?: string;
|
|
10
|
-
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Additional metadata for the scope.
|
|
37
|
+
*/
|
|
38
|
+
metadata?: Record<string, unknown>;
|
|
39
|
+
|
|
11
40
|
children?: Children;
|
|
12
41
|
}
|
|
13
42
|
|
|
43
|
+
export type ScopeProps = ScopePropsWithValue | ScopePropsWithInfo;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Declare a scope for this component's children. Any symbols and scopes
|
|
47
|
+
* declared in the children of this component will be in this scope.
|
|
48
|
+
*
|
|
49
|
+
* @see {@link ScopeContext}
|
|
50
|
+
*/
|
|
14
51
|
export function Scope(props: ScopeProps) {
|
|
15
52
|
let scope: OutputScope;
|
|
16
|
-
if (props
|
|
53
|
+
if ("value" in props) {
|
|
17
54
|
scope = props.value;
|
|
18
55
|
} else {
|
|
19
|
-
const kind = props.kind ?? "file";
|
|
20
56
|
const binder = useContext(BinderContext)!;
|
|
21
|
-
scope = binder.createScope({
|
|
57
|
+
scope = binder.createScope({
|
|
58
|
+
kind: props.kind,
|
|
59
|
+
metadata: props.metadata,
|
|
60
|
+
name: props.name ?? "",
|
|
61
|
+
});
|
|
22
62
|
}
|
|
23
63
|
|
|
24
64
|
return (
|