@alloy-js/core 0.3.0 → 0.5.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 +20 -0
- package/dist/src/binder.d.ts +43 -18
- package/dist/src/binder.d.ts.map +1 -1
- package/dist/src/binder.js +120 -16
- package/dist/src/binder.js.map +1 -1
- package/dist/src/components/Declaration.d.ts +2 -2
- package/dist/src/components/Declaration.d.ts.map +1 -1
- package/dist/src/components/Declaration.js.map +1 -1
- package/dist/src/components/Indent.d.ts +2 -2
- package/dist/src/components/Indent.d.ts.map +1 -1
- package/dist/src/components/Indent.js.map +1 -1
- package/dist/src/components/MemberDeclaration.d.ts +2 -2
- package/dist/src/components/MemberDeclaration.d.ts.map +1 -1
- package/dist/src/components/MemberDeclaration.js.map +1 -1
- package/dist/src/components/MemberName.d.ts +1 -1
- package/dist/src/components/MemberName.d.ts.map +1 -1
- package/dist/src/components/MemberScope.d.ts +2 -2
- package/dist/src/components/MemberScope.d.ts.map +1 -1
- package/dist/src/components/Name.d.ts +1 -1
- package/dist/src/components/Name.d.ts.map +1 -1
- package/dist/src/components/Output.d.ts +2 -2
- package/dist/src/components/Output.d.ts.map +1 -1
- package/dist/src/components/Output.js +6 -2
- package/dist/src/components/Output.js.map +1 -1
- package/dist/src/components/Scope.d.ts +2 -2
- package/dist/src/components/Scope.d.ts.map +1 -1
- package/dist/src/components/Scope.js.map +1 -1
- package/dist/src/components/SourceDirectory.d.ts +3 -3
- package/dist/src/components/SourceDirectory.d.ts.map +1 -1
- package/dist/src/components/SourceDirectory.js +1 -1
- package/dist/src/components/SourceDirectory.js.map +1 -1
- package/dist/src/components/SourceFile.d.ts +3 -3
- package/dist/src/components/SourceFile.d.ts.map +1 -1
- package/dist/src/components/SourceFile.js +1 -1
- package/dist/src/components/SourceFile.js.map +1 -1
- package/dist/src/components/stc/index.d.ts +18 -18
- package/dist/src/context/assignment.d.ts.map +1 -1
- package/dist/src/context/assignment.js +2 -2
- package/dist/src/context/assignment.js.map +1 -1
- package/dist/src/context/binder.d.ts.map +1 -1
- package/dist/src/context/binder.js +2 -2
- package/dist/src/context/binder.js.map +1 -1
- package/dist/src/context/declaration.d.ts.map +1 -1
- package/dist/src/context/declaration.js +2 -2
- package/dist/src/context/declaration.js.map +1 -1
- package/dist/src/context/indent.d.ts.map +1 -1
- package/dist/src/context/indent.js +2 -2
- package/dist/src/context/indent.js.map +1 -1
- package/dist/src/context/member-declaration.d.ts +1 -0
- package/dist/src/context/member-declaration.d.ts.map +1 -1
- package/dist/src/context/member-declaration.js +5 -2
- package/dist/src/context/member-declaration.js.map +1 -1
- package/dist/src/context/member-scope.d.ts.map +1 -1
- package/dist/src/context/member-scope.js +2 -2
- package/dist/src/context/member-scope.js.map +1 -1
- package/dist/src/context/name-policy.d.ts.map +1 -1
- package/dist/src/context/name-policy.js +2 -2
- package/dist/src/context/name-policy.js.map +1 -1
- package/dist/src/context/scope.d.ts.map +1 -1
- package/dist/src/context/scope.js +2 -2
- package/dist/src/context/scope.js.map +1 -1
- package/dist/src/context/source-directory.d.ts.map +1 -1
- package/dist/src/context/source-directory.js +2 -2
- package/dist/src/context/source-directory.js.map +1 -1
- package/dist/src/context/source-file.d.ts.map +1 -1
- package/dist/src/context/source-file.js +2 -2
- package/dist/src/context/source-file.js.map +1 -1
- package/dist/src/context.d.ts +5 -2
- package/dist/src/context.d.ts.map +1 -1
- package/dist/src/context.js +11 -4
- package/dist/src/context.js.map +1 -1
- package/dist/src/debug.d.ts +14 -0
- package/dist/src/debug.d.ts.map +1 -0
- package/dist/src/debug.js +163 -0
- package/dist/src/debug.js.map +1 -0
- package/dist/src/index.d.ts +3 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/jsx-runtime.d.ts +27 -4
- package/dist/src/jsx-runtime.d.ts.map +1 -1
- package/dist/src/jsx-runtime.js +20 -7
- package/dist/src/jsx-runtime.js.map +1 -1
- package/dist/src/render.d.ts +1 -1
- package/dist/src/render.d.ts.map +1 -1
- package/dist/src/render.js +15 -13
- package/dist/src/render.js.map +1 -1
- package/dist/src/slot.d.ts +15 -0
- package/dist/src/slot.d.ts.map +1 -0
- package/dist/src/slot.js +51 -0
- package/dist/src/slot.js.map +1 -0
- package/dist/src/tap.d.ts +19 -0
- package/dist/src/tap.d.ts.map +1 -0
- package/dist/src/tap.js +39 -0
- package/dist/src/tap.js.map +1 -0
- package/dist/src/utils.d.ts +1 -6
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/src/utils.js +1 -34
- package/dist/src/utils.js.map +1 -1
- package/dist/src/write-output.browser.d.ts +2 -0
- package/dist/src/write-output.browser.d.ts.map +1 -0
- package/dist/src/write-output.browser.js +4 -0
- package/dist/src/write-output.browser.js.map +1 -0
- package/dist/src/write-output.d.ts +7 -0
- package/dist/src/write-output.d.ts.map +1 -0
- package/dist/src/write-output.js +34 -0
- package/dist/src/write-output.js.map +1 -0
- package/dist/test/components/slot.test.d.ts +2 -0
- package/dist/test/components/slot.test.d.ts.map +1 -0
- package/dist/testing/render.d.ts +1 -1
- package/dist/testing/render.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -6
- package/src/binder.ts +214 -50
- package/src/components/Declaration.tsx +1 -1
- package/src/components/Indent.tsx +1 -1
- package/src/components/MemberDeclaration.tsx +1 -1
- package/src/components/MemberScope.tsx +1 -1
- package/src/components/Output.tsx +4 -2
- package/src/components/Scope.tsx +1 -1
- package/src/components/SourceDirectory.tsx +2 -2
- package/src/components/SourceFile.tsx +2 -6
- package/src/context/assignment.ts +6 -2
- package/src/context/binder.ts +7 -2
- package/src/context/declaration.ts +2 -2
- package/src/context/indent.ts +13 -6
- package/src/context/member-declaration.ts +10 -2
- package/src/context/member-scope.ts +6 -2
- package/src/context/name-policy.ts +6 -2
- package/src/context/scope.ts +7 -2
- package/src/context/source-directory.ts +2 -2
- package/src/context/source-file.ts +2 -2
- package/src/context.ts +15 -4
- package/src/debug.ts +209 -0
- package/src/index.ts +3 -1
- package/src/jsx-runtime.ts +46 -11
- package/src/render.ts +21 -19
- package/src/slot.ts +90 -0
- package/src/tap.ts +69 -0
- package/src/utils.ts +2 -34
- package/src/write-output.browser.ts +3 -0
- package/src/write-output.ts +33 -0
- package/temp/api.json +1848 -203
- package/test/components/slot.test.tsx +172 -0
- package/test/rendering/basic.test.tsx +1 -1
- package/test/symbols.test.ts +161 -3
- package/testing/render.ts +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ComponentContext,
|
|
1
|
+
import { ComponentContext, createNamedContext } from "../context.js";
|
|
2
2
|
import { SourceFileContext } from "./source-file.js";
|
|
3
3
|
|
|
4
4
|
export interface SourceDirectoryContext {
|
|
@@ -8,4 +8,4 @@ export interface SourceDirectoryContext {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
export const SourceDirectoryContext: ComponentContext<SourceDirectoryContext> =
|
|
11
|
-
|
|
11
|
+
createNamedContext("SourceDirectory");
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ComponentContext,
|
|
1
|
+
import { ComponentContext, createNamedContext } from "../context.js";
|
|
2
2
|
import { ComponentDefinition } from "../jsx-runtime.js";
|
|
3
3
|
import { Refkey } from "../refkey.js";
|
|
4
4
|
|
|
@@ -9,4 +9,4 @@ export interface SourceFileContext {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
export const SourceFileContext: ComponentContext<SourceFileContext> =
|
|
12
|
-
|
|
12
|
+
createNamedContext("SourceFile");
|
package/src/context.ts
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
+
import { shallowRef } from "@vue/reactivity";
|
|
1
2
|
import {
|
|
2
3
|
Children,
|
|
3
4
|
ComponentDefinition,
|
|
4
5
|
effect,
|
|
5
6
|
getContext,
|
|
6
7
|
untrack,
|
|
7
|
-
} from "
|
|
8
|
-
import { shallowRef } from "@vue/reactivity";
|
|
8
|
+
} from "./jsx-runtime.js";
|
|
9
9
|
|
|
10
10
|
export interface ComponentContext<T> {
|
|
11
11
|
id: symbol;
|
|
12
12
|
default: T | undefined;
|
|
13
13
|
Provider: ComponentDefinition<ContextProviderProps<T>>;
|
|
14
|
+
name?: string;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
export interface ContextProviderProps<T = unknown> {
|
|
@@ -31,13 +32,17 @@ export function useContext<T>(context: ComponentContext<T>): T | undefined {
|
|
|
31
32
|
return context.default;
|
|
32
33
|
}
|
|
33
34
|
|
|
35
|
+
export const contextsByKey = new Map<symbol, ComponentContext<any>>();
|
|
36
|
+
|
|
34
37
|
export function createContext<T = unknown>(
|
|
35
38
|
defaultValue?: T,
|
|
39
|
+
name?: string,
|
|
36
40
|
): ComponentContext<T> {
|
|
37
|
-
const id = Symbol("context");
|
|
38
|
-
|
|
41
|
+
const id = Symbol(name ?? "context");
|
|
42
|
+
const ctx = {
|
|
39
43
|
id,
|
|
40
44
|
default: defaultValue,
|
|
45
|
+
name,
|
|
41
46
|
Provider(props: ContextProviderProps<T>) {
|
|
42
47
|
const context = getContext();
|
|
43
48
|
|
|
@@ -50,4 +55,10 @@ export function createContext<T = unknown>(
|
|
|
50
55
|
return rendered.value;
|
|
51
56
|
},
|
|
52
57
|
};
|
|
58
|
+
contextsByKey.set(id, ctx);
|
|
59
|
+
return ctx;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function createNamedContext<T>(name: string, defaultValue?: T) {
|
|
63
|
+
return createContext<T>(defaultValue, name);
|
|
53
64
|
}
|
package/src/debug.ts
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { isReactive } from "@vue/reactivity";
|
|
2
|
+
import { Chalk } from "chalk";
|
|
3
|
+
import Table from "cli-table3";
|
|
4
|
+
import { contextsByKey } from "./context.js";
|
|
5
|
+
import { Context, getContext } from "./jsx-runtime.js";
|
|
6
|
+
|
|
7
|
+
interface DebugInterface {
|
|
8
|
+
component: {
|
|
9
|
+
stack(): void;
|
|
10
|
+
tree(): void;
|
|
11
|
+
watch(): void;
|
|
12
|
+
render(): void;
|
|
13
|
+
context(): void;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const debug: DebugInterface = {
|
|
18
|
+
component: {
|
|
19
|
+
stack: debugStack,
|
|
20
|
+
tree() {
|
|
21
|
+
console.log("tree");
|
|
22
|
+
},
|
|
23
|
+
watch() {
|
|
24
|
+
console.log("watch");
|
|
25
|
+
},
|
|
26
|
+
render() {
|
|
27
|
+
console.log("render");
|
|
28
|
+
},
|
|
29
|
+
context: debugContext,
|
|
30
|
+
},
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
function debugStack() {
|
|
34
|
+
let currentContext = getContext();
|
|
35
|
+
let foundContexts: Context[] = [];
|
|
36
|
+
while (currentContext !== null) {
|
|
37
|
+
if (
|
|
38
|
+
currentContext.context &&
|
|
39
|
+
Object.getOwnPropertySymbols(currentContext.context)[0]
|
|
40
|
+
) {
|
|
41
|
+
foundContexts.push(currentContext);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (
|
|
45
|
+
currentContext.componentOwner &&
|
|
46
|
+
currentContext.componentOwner.component.name !== "Provider"
|
|
47
|
+
) {
|
|
48
|
+
process.stdout.write(
|
|
49
|
+
style.component.name(currentContext.componentOwner.component.name) +
|
|
50
|
+
"\n",
|
|
51
|
+
);
|
|
52
|
+
const table = kvTable();
|
|
53
|
+
const props = currentContext.componentOwner.props;
|
|
54
|
+
|
|
55
|
+
table.push([
|
|
56
|
+
{ hAlign: "right", content: "props" },
|
|
57
|
+
props && Object.keys(props).length > 0 ?
|
|
58
|
+
dumpValue(props)
|
|
59
|
+
: chalk.gray("(none)"),
|
|
60
|
+
]);
|
|
61
|
+
|
|
62
|
+
table.push([
|
|
63
|
+
{ hAlign: "right", content: "contexts" },
|
|
64
|
+
foundContexts.length > 0 ?
|
|
65
|
+
foundContexts.map((c) => printContext(c, true)).join("\n")
|
|
66
|
+
: chalk.gray("(none)"),
|
|
67
|
+
]);
|
|
68
|
+
|
|
69
|
+
process.stdout.write(table.toString() + "\n\n");
|
|
70
|
+
foundContexts = [];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
currentContext = currentContext.owner;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function debugContext() {
|
|
78
|
+
let currentContext = getContext();
|
|
79
|
+
while (currentContext !== null) {
|
|
80
|
+
console.log(printContext(currentContext));
|
|
81
|
+
currentContext = currentContext.owner;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function printContext(context: Context, omitOwner: boolean = false) {
|
|
85
|
+
if (!context.context) return "";
|
|
86
|
+
const key = Object.getOwnPropertySymbols(context.context)[0];
|
|
87
|
+
if (!key) return "";
|
|
88
|
+
const contextDefinition = contextsByKey.get(key);
|
|
89
|
+
const contextName = contextDefinition?.name ?? "unknown context";
|
|
90
|
+
const value = context.context[key];
|
|
91
|
+
|
|
92
|
+
let output = style.context.name(contextName);
|
|
93
|
+
if (!omitOwner) {
|
|
94
|
+
const owner = findContextOwner(context);
|
|
95
|
+
output += " provided by " + style.component.name(owner);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
output += "\n" + dumpValue(value) + "\n";
|
|
99
|
+
|
|
100
|
+
return output;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function findContextOwner(context: Context) {
|
|
104
|
+
let currentContext: Context | null = context;
|
|
105
|
+
while (
|
|
106
|
+
currentContext &&
|
|
107
|
+
(currentContext.componentOwner === undefined ||
|
|
108
|
+
currentContext.componentOwner.component.name === "Provider")
|
|
109
|
+
) {
|
|
110
|
+
currentContext = currentContext.owner;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return currentContext?.componentOwner?.component.name ?? "unknown";
|
|
114
|
+
}
|
|
115
|
+
declare global {
|
|
116
|
+
// eslint-disable-next-line no-var
|
|
117
|
+
var debug: DebugInterface;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
globalThis.debug = debug;
|
|
121
|
+
|
|
122
|
+
const chalk = new Chalk();
|
|
123
|
+
const style = {
|
|
124
|
+
value: {
|
|
125
|
+
primitive(value: string | number | boolean | null | undefined) {
|
|
126
|
+
switch (typeof value) {
|
|
127
|
+
case "string":
|
|
128
|
+
return chalk.blue(`"${value}"`);
|
|
129
|
+
case "object":
|
|
130
|
+
case "undefined":
|
|
131
|
+
return chalk.gray(String(value));
|
|
132
|
+
default:
|
|
133
|
+
return chalk.blue(String(value));
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
symbol(value: symbol) {
|
|
137
|
+
return chalk.gray(String(value));
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
context: {
|
|
141
|
+
name(name: string) {
|
|
142
|
+
return chalk.bgGray(` ${chalk.white(name)} `);
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
component: {
|
|
146
|
+
name(name: string) {
|
|
147
|
+
return chalk.bgBlue(` <${chalk.white(name)}> `);
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
function reactiveTag(value: unknown) {
|
|
153
|
+
if (isReactive(value)) {
|
|
154
|
+
return " " + chalk.greenBright(`reactive`) + " ";
|
|
155
|
+
}
|
|
156
|
+
return "";
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function dumpValue(value: unknown, level = 0) {
|
|
160
|
+
switch (typeof value) {
|
|
161
|
+
case "boolean":
|
|
162
|
+
case "string":
|
|
163
|
+
case "number":
|
|
164
|
+
return style.value.primitive(value) + reactiveTag(value);
|
|
165
|
+
case "symbol":
|
|
166
|
+
return style.value.symbol(value) + reactiveTag(value);
|
|
167
|
+
case "object":
|
|
168
|
+
if (value === null) {
|
|
169
|
+
return style.value.primitive(null) + reactiveTag(value);
|
|
170
|
+
} else {
|
|
171
|
+
if (level > 0) return chalk.gray(`{ ... }` + reactiveTag(value));
|
|
172
|
+
|
|
173
|
+
const table = kvTable(" ");
|
|
174
|
+
|
|
175
|
+
for (const [key, propValue] of Object.entries(value)) {
|
|
176
|
+
table.push([{ content: key }, dumpValue(propValue, level + 1)]);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
return table.toString();
|
|
180
|
+
}
|
|
181
|
+
case "function":
|
|
182
|
+
return chalk.gray("ƒ ()");
|
|
183
|
+
case "undefined":
|
|
184
|
+
return style.value.primitive(undefined);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function kvTable(sep = " ") {
|
|
189
|
+
return new Table({
|
|
190
|
+
chars: {
|
|
191
|
+
top: "",
|
|
192
|
+
"top-mid": "",
|
|
193
|
+
"top-left": "",
|
|
194
|
+
"top-right": "",
|
|
195
|
+
bottom: "",
|
|
196
|
+
"bottom-mid": "",
|
|
197
|
+
"bottom-left": "",
|
|
198
|
+
"bottom-right": "",
|
|
199
|
+
left: "",
|
|
200
|
+
"left-mid": "",
|
|
201
|
+
mid: "",
|
|
202
|
+
"mid-mid": "",
|
|
203
|
+
right: "",
|
|
204
|
+
"right-mid": "",
|
|
205
|
+
middle: sep,
|
|
206
|
+
},
|
|
207
|
+
style: { "padding-left": 0, "padding-right": 0 },
|
|
208
|
+
});
|
|
209
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export * from "@alloy-js/core/jsx-runtime";
|
|
2
1
|
export {
|
|
3
2
|
computed,
|
|
4
3
|
isProxy,
|
|
@@ -18,4 +17,7 @@ export * from "./jsx-runtime.js";
|
|
|
18
17
|
export * from "./name-policy.js";
|
|
19
18
|
export * from "./refkey.js";
|
|
20
19
|
export * from "./render.js";
|
|
20
|
+
export * from "./tap.js";
|
|
21
21
|
export * from "./utils.js";
|
|
22
|
+
export * from "./write-output.js";
|
|
23
|
+
import "./debug.js";
|
package/src/jsx-runtime.ts
CHANGED
|
@@ -30,6 +30,12 @@ export interface Context {
|
|
|
30
30
|
|
|
31
31
|
// store random info about the node
|
|
32
32
|
meta?: Record<string, any>;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* When this context was created by a component, this will
|
|
36
|
+
* be the component that created it.
|
|
37
|
+
*/
|
|
38
|
+
componentOwner?: ComponentCreator<unknown>;
|
|
33
39
|
}
|
|
34
40
|
|
|
35
41
|
let globalContext: Context | null = null;
|
|
@@ -37,13 +43,16 @@ export function getContext() {
|
|
|
37
43
|
return globalContext;
|
|
38
44
|
}
|
|
39
45
|
|
|
40
|
-
export function root<T>(
|
|
46
|
+
export function root<T>(
|
|
47
|
+
fn: (d: Disposable) => T,
|
|
48
|
+
componentOwner?: ComponentCreator<any>,
|
|
49
|
+
): T {
|
|
41
50
|
globalContext = {
|
|
42
|
-
|
|
51
|
+
componentOwner,
|
|
43
52
|
disposables: [],
|
|
44
53
|
owner: globalContext,
|
|
45
54
|
context: {},
|
|
46
|
-
}
|
|
55
|
+
};
|
|
47
56
|
let ret;
|
|
48
57
|
try {
|
|
49
58
|
ret = untrack(() =>
|
|
@@ -108,7 +117,7 @@ export function effect<T>(fn: (prev?: T) => T, current?: T) {
|
|
|
108
117
|
cleanup(() => cleanupFn(true));
|
|
109
118
|
}
|
|
110
119
|
|
|
111
|
-
function cleanup(fn: Disposable) {
|
|
120
|
+
export function cleanup(fn: Disposable) {
|
|
112
121
|
if (globalContext != null) {
|
|
113
122
|
globalContext.disposables.push(fn);
|
|
114
123
|
}
|
|
@@ -120,13 +129,14 @@ export type Child =
|
|
|
120
129
|
| number
|
|
121
130
|
| undefined
|
|
122
131
|
| null
|
|
123
|
-
|
|
|
132
|
+
| void
|
|
133
|
+
| (() => Children)
|
|
124
134
|
| Child[]
|
|
125
135
|
| Ref
|
|
126
136
|
| Refkey;
|
|
127
137
|
|
|
128
138
|
export type Children = Child | Child[];
|
|
129
|
-
export type Props = Record<string,
|
|
139
|
+
export type Props = Record<string, any>;
|
|
130
140
|
|
|
131
141
|
export interface ComponentDefinition<TProps = Props> {
|
|
132
142
|
(props: TProps): Child | Children;
|
|
@@ -148,20 +158,18 @@ const renderStack: {
|
|
|
148
158
|
props: Props;
|
|
149
159
|
}[] = [];
|
|
150
160
|
|
|
151
|
-
export const shouldDebug = !!process.env.ALLOY_DEBUG;
|
|
152
|
-
|
|
153
161
|
export function pushStack(component: Component<any>, props: Props) {
|
|
154
|
-
if (!shouldDebug) return;
|
|
162
|
+
if (!shouldDebug()) return;
|
|
155
163
|
renderStack.push({ component, props });
|
|
156
164
|
}
|
|
157
165
|
|
|
158
166
|
export function popStack() {
|
|
159
|
-
if (!shouldDebug) return;
|
|
167
|
+
if (!shouldDebug()) return;
|
|
160
168
|
renderStack.pop();
|
|
161
169
|
}
|
|
162
170
|
|
|
163
171
|
export function printRenderStack() {
|
|
164
|
-
if (!shouldDebug) return;
|
|
172
|
+
if (!shouldDebug()) return;
|
|
165
173
|
|
|
166
174
|
// eslint-disable-next-line no-console
|
|
167
175
|
console.error("Error rendering:");
|
|
@@ -205,6 +213,29 @@ export function isComponentCreator(item: unknown): item is ComponentCreator {
|
|
|
205
213
|
return typeof item === "function" && (item as any).component;
|
|
206
214
|
}
|
|
207
215
|
|
|
216
|
+
/**
|
|
217
|
+
* This namespace is predominantly for interop with React tooling in VSCode
|
|
218
|
+
* and controls the type of JSX elements, components, and the like.
|
|
219
|
+
*/
|
|
220
|
+
// eslint-disable-next-line @typescript-eslint/no-namespace
|
|
221
|
+
export namespace JSX {
|
|
222
|
+
export interface IntrinsicElements {}
|
|
223
|
+
export type ElementType = ComponentDefinition<any>;
|
|
224
|
+
export type Element = Children;
|
|
225
|
+
export interface ElementChildrenAttribute {
|
|
226
|
+
children: {};
|
|
227
|
+
}
|
|
228
|
+
export interface ElementAttributesProperty {
|
|
229
|
+
props: {};
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export function jsx(type: Component<any>, props: Record<string, unknown>) {
|
|
234
|
+
return createComponent(type, props);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export const jsxs = jsx;
|
|
238
|
+
|
|
208
239
|
export function createComponent<TProps extends Props = Props>(
|
|
209
240
|
C: Component<TProps>,
|
|
210
241
|
props: TProps,
|
|
@@ -264,3 +295,7 @@ export function mergeProps(...sources: any): any {
|
|
|
264
295
|
}
|
|
265
296
|
return target;
|
|
266
297
|
}
|
|
298
|
+
|
|
299
|
+
function shouldDebug() {
|
|
300
|
+
return typeof process !== "undefined" && !!process.env?.ALLOY_DEBUG;
|
|
301
|
+
}
|
package/src/render.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import { isRef } from "@vue/reactivity";
|
|
2
|
+
import { Indent, IndentState } from "./components/Indent.js";
|
|
3
|
+
import { useContext } from "./context.js";
|
|
4
|
+
import { IndentContext } from "./context/indent.js";
|
|
5
|
+
import { SourceFileContext } from "./context/source-file.js";
|
|
1
6
|
import {
|
|
2
7
|
Child,
|
|
3
8
|
Children,
|
|
@@ -10,12 +15,7 @@ import {
|
|
|
10
15
|
pushStack,
|
|
11
16
|
root,
|
|
12
17
|
untrack,
|
|
13
|
-
} from "
|
|
14
|
-
import { isRef } from "@vue/reactivity";
|
|
15
|
-
import { Indent, IndentState } from "./components/Indent.js";
|
|
16
|
-
import { useContext } from "./context.js";
|
|
17
|
-
import { IndentContext } from "./context/indent.js";
|
|
18
|
-
import { SourceFileContext } from "./context/source-file.js";
|
|
18
|
+
} from "./jsx-runtime.js";
|
|
19
19
|
import { isRefkey } from "./refkey.js";
|
|
20
20
|
|
|
21
21
|
/**
|
|
@@ -171,7 +171,7 @@ export type RenderStructure = {};
|
|
|
171
171
|
|
|
172
172
|
export type RenderTextTree = (string | RenderTextTree)[];
|
|
173
173
|
|
|
174
|
-
function traceRender(phase: string, message: string) {
|
|
174
|
+
function traceRender(phase: string, message: () => string) {
|
|
175
175
|
return false;
|
|
176
176
|
// console.log(`[\x1b[34m${phase}\x1b[0m]: ${message}`);
|
|
177
177
|
}
|
|
@@ -250,7 +250,7 @@ export function renderTree(children: Children) {
|
|
|
250
250
|
try {
|
|
251
251
|
root(() => {
|
|
252
252
|
renderWorker(rootElem, children, state);
|
|
253
|
-
}
|
|
253
|
+
});
|
|
254
254
|
} catch (e) {
|
|
255
255
|
printRenderStack();
|
|
256
256
|
throw e;
|
|
@@ -268,7 +268,7 @@ function renderWorker(
|
|
|
268
268
|
children: Children,
|
|
269
269
|
state: RenderState,
|
|
270
270
|
) {
|
|
271
|
-
traceRender("render", dumpChildren(children));
|
|
271
|
+
traceRender("render", () => dumpChildren(children));
|
|
272
272
|
|
|
273
273
|
if (Array.isArray(node)) {
|
|
274
274
|
nodesToContext.set(node, getContext()!);
|
|
@@ -290,7 +290,7 @@ function appendChild(
|
|
|
290
290
|
indentState: IndentState,
|
|
291
291
|
state: RenderState,
|
|
292
292
|
) {
|
|
293
|
-
traceRender("appendChild", printChild(rawChild));
|
|
293
|
+
traceRender("appendChild", () => printChild(rawChild));
|
|
294
294
|
const child = normalizeChild(rawChild);
|
|
295
295
|
|
|
296
296
|
if (typeof child === "string") {
|
|
@@ -300,11 +300,11 @@ function appendChild(
|
|
|
300
300
|
state.newline = false;
|
|
301
301
|
}
|
|
302
302
|
const reindented = reindent(child, indentState.indentString);
|
|
303
|
-
traceRender("appendChild:string", JSON.stringify(reindented));
|
|
303
|
+
traceRender("appendChild:string", () => JSON.stringify(reindented));
|
|
304
304
|
node.push(reindented);
|
|
305
305
|
} else if (isComponentCreator(child)) {
|
|
306
306
|
root(() => {
|
|
307
|
-
traceRender("appendChild:component", printChild(child));
|
|
307
|
+
traceRender("appendChild:component", () => printChild(child));
|
|
308
308
|
if (child.component === Indent && state.newline) {
|
|
309
309
|
node.push(indentState.indent);
|
|
310
310
|
}
|
|
@@ -313,13 +313,13 @@ function appendChild(
|
|
|
313
313
|
renderWorker(componentRoot, untrack(child), state);
|
|
314
314
|
popStack();
|
|
315
315
|
node.push(componentRoot);
|
|
316
|
-
traceRender("appendChild:component-done", printChild(child));
|
|
317
|
-
}, child
|
|
316
|
+
traceRender("appendChild:component-done", () => printChild(child));
|
|
317
|
+
}, child);
|
|
318
318
|
} else if (typeof child === "function") {
|
|
319
|
-
traceRender("appendChild:memo", child.toString());
|
|
319
|
+
traceRender("appendChild:memo", () => child.toString());
|
|
320
320
|
const index = node.length;
|
|
321
321
|
effect((prev: any) => {
|
|
322
|
-
traceRender("memoEffect:run", "");
|
|
322
|
+
traceRender("memoEffect:run", () => "");
|
|
323
323
|
let res = child();
|
|
324
324
|
while (typeof res === "function" && !isComponentCreator(res)) {
|
|
325
325
|
res = res();
|
|
@@ -330,11 +330,11 @@ function appendChild(
|
|
|
330
330
|
node[index] = newNodes;
|
|
331
331
|
return newNodes;
|
|
332
332
|
});
|
|
333
|
-
traceRender("appendChild:memo-done", "");
|
|
333
|
+
traceRender("appendChild:memo-done", () => "");
|
|
334
334
|
} else {
|
|
335
|
-
traceRender("appendChild:array", dumpChildren(child));
|
|
335
|
+
traceRender("appendChild:array", () => dumpChildren(child));
|
|
336
336
|
renderWorker(node, child, state);
|
|
337
|
-
traceRender("appendChild:array-done", dumpChildren(child));
|
|
337
|
+
traceRender("appendChild:array-done", () => dumpChildren(child));
|
|
338
338
|
}
|
|
339
339
|
}
|
|
340
340
|
|
|
@@ -383,6 +383,8 @@ function printChild(child: Child): string {
|
|
|
383
383
|
return "<" + child.component.name + ">";
|
|
384
384
|
} else if (typeof child === "function") {
|
|
385
385
|
return "$memo";
|
|
386
|
+
} else if (isRef(child)) {
|
|
387
|
+
return "$ref";
|
|
386
388
|
} else {
|
|
387
389
|
return JSON.stringify(child);
|
|
388
390
|
}
|
package/src/slot.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { ref, Ref } from "@vue/reactivity";
|
|
2
|
+
import { OutputSymbol } from "./binder.js";
|
|
3
|
+
import {
|
|
4
|
+
Children,
|
|
5
|
+
Component,
|
|
6
|
+
ComponentDefinition,
|
|
7
|
+
effect,
|
|
8
|
+
memo,
|
|
9
|
+
} from "./jsx-runtime.js";
|
|
10
|
+
|
|
11
|
+
export interface SlotInstance extends ComponentDefinition {}
|
|
12
|
+
|
|
13
|
+
export interface SlotDefinition<TSlotProps> {
|
|
14
|
+
find: (...args: any[]) => () => Ref<unknown>;
|
|
15
|
+
create(
|
|
16
|
+
key: unknown,
|
|
17
|
+
props: TSlotProps,
|
|
18
|
+
defaultContent?: Children,
|
|
19
|
+
): ComponentDefinition;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export type SlotKey = Ref<unknown>;
|
|
23
|
+
|
|
24
|
+
const slotMappers = new Map<unknown, ComponentDefinition<any>>();
|
|
25
|
+
|
|
26
|
+
export function defineSlot<
|
|
27
|
+
TSlotProps,
|
|
28
|
+
TFinder extends (...args: any[]) => Ref<unknown> | unknown = (
|
|
29
|
+
...args: any[]
|
|
30
|
+
) => Ref<unknown> | unknown,
|
|
31
|
+
>(finder: TFinder): SlotDefinition<TSlotProps> {
|
|
32
|
+
return {
|
|
33
|
+
find: ((...args: any[]) =>
|
|
34
|
+
() =>
|
|
35
|
+
ref(finder(...args))) as any,
|
|
36
|
+
create(key, props, defaultContent) {
|
|
37
|
+
return function () {
|
|
38
|
+
return memo(() => {
|
|
39
|
+
if (key === undefined) {
|
|
40
|
+
return defaultContent;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const component = slotMappers.get(key);
|
|
44
|
+
if (!component) {
|
|
45
|
+
return defaultContent;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return component({ ...props, original: defaultContent });
|
|
49
|
+
});
|
|
50
|
+
};
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export const extensionEffects: (() => void)[] = [];
|
|
56
|
+
|
|
57
|
+
export function replace<T>(
|
|
58
|
+
slotKeyFn: () => SlotKey,
|
|
59
|
+
replacement: Component<T>,
|
|
60
|
+
) {
|
|
61
|
+
extensionEffects.push(() => {
|
|
62
|
+
effect((prev: SlotKey | undefined) => {
|
|
63
|
+
if (prev) {
|
|
64
|
+
slotMappers.delete(prev.value);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const slotKey = slotKeyFn();
|
|
68
|
+
if (slotKey.value === undefined) {
|
|
69
|
+
return slotKey;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
slotMappers.set(slotKey.value, replacement);
|
|
73
|
+
|
|
74
|
+
return slotKey;
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export function rename(
|
|
80
|
+
slotKeyFn: () => Ref<OutputSymbol | undefined>,
|
|
81
|
+
newName: string,
|
|
82
|
+
) {
|
|
83
|
+
extensionEffects.push(() => {
|
|
84
|
+
effect(() => {
|
|
85
|
+
const sym = slotKeyFn().value;
|
|
86
|
+
if (!sym) return;
|
|
87
|
+
sym.name = newName;
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
}
|
package/src/tap.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { ShallowRef, shallowRef } from "@vue/reactivity";
|
|
2
|
+
import { OutputScope, OutputSymbol } from "./binder.js";
|
|
3
|
+
import { useContext } from "./context.js";
|
|
4
|
+
import { DeclarationContext } from "./context/declaration.js";
|
|
5
|
+
import { MemberDeclarationContext } from "./context/member-declaration.js";
|
|
6
|
+
import { useScope } from "./context/scope.js";
|
|
7
|
+
import { SourceFileContext } from "./context/source-file.js";
|
|
8
|
+
import { ComponentDefinition } from "./jsx-runtime.js";
|
|
9
|
+
|
|
10
|
+
export interface Tap<T> extends ComponentDefinition {
|
|
11
|
+
ref: ShallowRef<T | undefined>;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface Tapper<T> {
|
|
15
|
+
(): T | undefined;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface Handler<T> {
|
|
19
|
+
(value: T): void;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function createTap<T = unknown>(
|
|
23
|
+
tapper: Tapper<T>,
|
|
24
|
+
handler?: Handler<T>,
|
|
25
|
+
): Tap<T> {
|
|
26
|
+
const signal = shallowRef<T | undefined>(undefined);
|
|
27
|
+
const fn = () => {
|
|
28
|
+
signal.value = tapper();
|
|
29
|
+
if (handler && signal.value !== undefined) {
|
|
30
|
+
handler(signal.value);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return "";
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
fn.ref = signal;
|
|
37
|
+
|
|
38
|
+
return fn;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function createDeclarationTap<
|
|
42
|
+
TSymbol extends OutputSymbol = OutputSymbol,
|
|
43
|
+
>(handler?: Handler<TSymbol>) {
|
|
44
|
+
return createTap<TSymbol>(() => {
|
|
45
|
+
return useContext(DeclarationContext) as any;
|
|
46
|
+
}, handler);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function createMemberTap<TSymbol extends OutputSymbol = OutputSymbol>(
|
|
50
|
+
handler?: Handler<TSymbol>,
|
|
51
|
+
) {
|
|
52
|
+
return createTap<TSymbol>(() => {
|
|
53
|
+
return useContext(MemberDeclarationContext) as any;
|
|
54
|
+
}, handler);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function createScopeTap<TScope extends OutputScope = OutputScope>(
|
|
58
|
+
handler?: Handler<TScope>,
|
|
59
|
+
) {
|
|
60
|
+
return createTap<TScope>(() => {
|
|
61
|
+
return useScope() as any;
|
|
62
|
+
}, handler);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function createSourceFileTap(handler?: Handler<SourceFileContext>) {
|
|
66
|
+
return createTap(() => {
|
|
67
|
+
return useContext(SourceFileContext);
|
|
68
|
+
}, handler);
|
|
69
|
+
}
|