@alloy-js/core 0.6.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 +37 -0
- package/babel.config.cjs +1 -4
- package/dist/src/binder.d.ts +15 -13
- package/dist/src/binder.d.ts.map +1 -1
- package/dist/src/binder.js +34 -34
- 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 +98 -1
- 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/render.d.ts.map +1 -1
- package/dist/src/render.js +12 -0
- package/dist/src/render.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/src/write-output.js +3 -3
- package/dist/src/write-output.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 +46 -40
- 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 +162 -0
- package/src/render.ts +14 -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/src/write-output.ts +3 -3
- package/temp/api.json +1563 -393
- 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 +14 -33
- package/vitest.config.ts +2 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alloy-js/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./dist/src/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -42,12 +42,12 @@
|
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@babel/cli": "^7.24.7",
|
|
44
44
|
"@microsoft/api-extractor": "^7.47.7",
|
|
45
|
-
"@rollup/plugin-babel": "^6.0.4",
|
|
46
45
|
"@rollup/plugin-typescript": "^11.1.6",
|
|
47
46
|
"concurrently": "^8.2.2",
|
|
48
47
|
"typescript": "^5.7.3",
|
|
49
48
|
"vitest": "^3.0.4",
|
|
50
|
-
"vite": "^6.0.1"
|
|
49
|
+
"vite": "^6.0.1",
|
|
50
|
+
"@alloy-js/rollup-plugin": "~0.1.0"
|
|
51
51
|
},
|
|
52
52
|
"type": "module",
|
|
53
53
|
"scripts": {
|
package/src/binder.ts
CHANGED
|
@@ -99,9 +99,9 @@ export interface OutputSymbol {
|
|
|
99
99
|
binder: Binder;
|
|
100
100
|
|
|
101
101
|
/**
|
|
102
|
-
*
|
|
102
|
+
* The unique values that reference this symbol.
|
|
103
103
|
*/
|
|
104
|
-
|
|
104
|
+
refkeys: Refkey[];
|
|
105
105
|
|
|
106
106
|
/**
|
|
107
107
|
* The instance members available on this symbol.
|
|
@@ -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,8 +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;
|
|
235
|
+
refkey?: Refkey | Refkey[];
|
|
231
236
|
flags?: OutputSymbolFlags;
|
|
237
|
+
metadata?: Record<string, unknown>;
|
|
232
238
|
} & Omit<T, keyof OutputSymbol>;
|
|
233
239
|
|
|
234
240
|
export type CreateScopeOptions<T extends OutputScope = OutputScope> = {
|
|
@@ -237,6 +243,7 @@ export type CreateScopeOptions<T extends OutputScope = OutputScope> = {
|
|
|
237
243
|
parent?: OutputScope | undefined;
|
|
238
244
|
flags?: OutputScopeFlags;
|
|
239
245
|
owner?: OutputSymbol;
|
|
246
|
+
metadata?: Record<string, unknown>;
|
|
240
247
|
} & Omit<T, keyof OutputScope>;
|
|
241
248
|
|
|
242
249
|
/**
|
|
@@ -369,15 +376,11 @@ export interface Binder {
|
|
|
369
376
|
* When we resolve the refkey for `bar` from within `namespace scope 2`, we will get the following
|
|
370
377
|
* resolution result:
|
|
371
378
|
*
|
|
372
|
-
* **targetDeclaration**: symbol bar, the symbol we resolved.
|
|
373
|
-
*
|
|
374
|
-
* **
|
|
375
|
-
*
|
|
376
|
-
* **
|
|
377
|
-
*
|
|
378
|
-
* **pathDown**: [namespace scope 1], because this is the scope between the common scope and the declaration
|
|
379
|
-
*
|
|
380
|
-
* **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.
|
|
381
384
|
*/
|
|
382
385
|
export interface ResolutionResult<
|
|
383
386
|
TScope extends OutputScope,
|
|
@@ -466,6 +469,7 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
|
|
|
466
469
|
parent,
|
|
467
470
|
owner,
|
|
468
471
|
flags = OutputScopeFlags.None,
|
|
472
|
+
metadata = {},
|
|
469
473
|
...rest
|
|
470
474
|
} = args;
|
|
471
475
|
|
|
@@ -498,6 +502,7 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
|
|
|
498
502
|
flags,
|
|
499
503
|
owner,
|
|
500
504
|
binder,
|
|
505
|
+
metadata,
|
|
501
506
|
...rest,
|
|
502
507
|
getSymbolNames: symbolNames(symbols),
|
|
503
508
|
}) as T;
|
|
@@ -525,9 +530,12 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
|
|
|
525
530
|
scope = useDefaultScope(args.flags),
|
|
526
531
|
refkey,
|
|
527
532
|
flags = OutputSymbolFlags.None,
|
|
533
|
+
metadata = {},
|
|
528
534
|
...rest
|
|
529
535
|
} = args;
|
|
530
536
|
|
|
537
|
+
const allRefkeys = [refkey ?? []].flat();
|
|
538
|
+
|
|
531
539
|
if (!scope) {
|
|
532
540
|
throw new Error(
|
|
533
541
|
"No scope was provided and no scope could be found in context",
|
|
@@ -556,9 +564,10 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
|
|
|
556
564
|
originalName: name,
|
|
557
565
|
name: name,
|
|
558
566
|
scope,
|
|
559
|
-
|
|
567
|
+
refkeys: allRefkeys,
|
|
560
568
|
binder,
|
|
561
569
|
flags,
|
|
570
|
+
metadata,
|
|
562
571
|
...rest,
|
|
563
572
|
}) as T;
|
|
564
573
|
|
|
@@ -583,7 +592,9 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
|
|
|
583
592
|
}
|
|
584
593
|
|
|
585
594
|
scope.symbols.add(symbol);
|
|
586
|
-
|
|
595
|
+
for (const refkey of allRefkeys) {
|
|
596
|
+
scope.symbolsByRefkey.set(refkey, symbol);
|
|
597
|
+
}
|
|
587
598
|
|
|
588
599
|
deconflict(symbol);
|
|
589
600
|
notifyRefkey(symbol);
|
|
@@ -598,9 +609,11 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
|
|
|
598
609
|
return;
|
|
599
610
|
}
|
|
600
611
|
|
|
601
|
-
const
|
|
602
|
-
|
|
603
|
-
|
|
612
|
+
for (const refkey of symbol.refkeys) {
|
|
613
|
+
const resolution = waitingDeclarations.get(refkey);
|
|
614
|
+
if (!resolution) return;
|
|
615
|
+
resolution.value = undefined;
|
|
616
|
+
}
|
|
604
617
|
}
|
|
605
618
|
|
|
606
619
|
function instantiateSymbolInto(source: OutputSymbol, target: OutputSymbol) {
|
|
@@ -619,7 +632,7 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
|
|
|
619
632
|
createSymbol({
|
|
620
633
|
name: sym.name,
|
|
621
634
|
scope: target.instanceMemberScope!,
|
|
622
|
-
refkey: refkey(target.
|
|
635
|
+
refkey: [refkey(target.refkeys[0], sym.refkeys[0])],
|
|
623
636
|
flags: sym.flags | OutputSymbolFlags.InstanceMember,
|
|
624
637
|
});
|
|
625
638
|
}
|
|
@@ -693,12 +706,6 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
|
|
|
693
706
|
targetDeclarationBase: TSymbol,
|
|
694
707
|
): ResolutionResult<TScope, TSymbol> {
|
|
695
708
|
if (targetDeclarationBase.flags & OutputSymbolFlags.InstanceMember) {
|
|
696
|
-
if (targetDeclarationBase.scope !== currentMemberScope) {
|
|
697
|
-
throw new Error(
|
|
698
|
-
"Cannot resolve member symbols from a different member scope",
|
|
699
|
-
);
|
|
700
|
-
}
|
|
701
|
-
|
|
702
709
|
// todo: handle referencing nested objects by refkey
|
|
703
710
|
return {
|
|
704
711
|
pathUp: [],
|
|
@@ -816,22 +823,21 @@ export function createOutputBinder(options: BinderOptions = {}): Binder {
|
|
|
816
823
|
|
|
817
824
|
function notifyRefkey(symbol: OutputSymbol): void {
|
|
818
825
|
effect(() => {
|
|
819
|
-
const refkey
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
signal.value = symbol;
|
|
827
|
-
}
|
|
826
|
+
for (const refkey of symbol.refkeys) {
|
|
827
|
+
// notify those waiting for this refkey
|
|
828
|
+
knownDeclarations.set(refkey, symbol);
|
|
829
|
+
if (waitingDeclarations.has(refkey)) {
|
|
830
|
+
const signal = waitingDeclarations.get(refkey)!;
|
|
831
|
+
signal.value = symbol;
|
|
832
|
+
}
|
|
828
833
|
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
834
|
+
// notify those waiting for this symbol name
|
|
835
|
+
const waitingScope = waitingSymbolNames.get(symbol.scope);
|
|
836
|
+
if (waitingScope) {
|
|
837
|
+
const waitingName = waitingScope.get(symbol.name);
|
|
838
|
+
if (waitingName) {
|
|
839
|
+
waitingName.value = symbol;
|
|
840
|
+
}
|
|
835
841
|
}
|
|
836
842
|
}
|
|
837
843
|
});
|
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 = {
|