@alloy-js/core 0.21.0-dev.9 → 0.22.0-dev.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/src/render.ts CHANGED
@@ -481,6 +481,7 @@ function appendChild(node: RenderedTextTree, rawChild: Child) {
481
481
  throw new Error("Unknown intrinsic element");
482
482
  }
483
483
  } else if (isComponentCreator(child)) {
484
+ // todo: remove this effect (only needed for context, not needed for anything else)
484
485
  effect(() => {
485
486
  trace(
486
487
  TracePhase.render.appendChild,
@@ -581,6 +582,8 @@ function debugPrintChild(child: Children): string {
581
582
  return `<${child.name}>`;
582
583
  } else if (isRenderableObject(child)) {
583
584
  return `CustomChildElement(${JSON.stringify(child)})`;
585
+ } else if (isRefkeyable(child)) {
586
+ return `refkey`;
584
587
  } else {
585
588
  return JSON.stringify(child);
586
589
  }
package/src/scheduler.ts CHANGED
@@ -1,24 +1,25 @@
1
- import { ReactiveEffectRunner } from "@vue/reactivity";
1
+ import { ReactiveEffect } from "@vue/reactivity";
2
2
 
3
3
  export interface QueueJob {
4
- (): any;
4
+ run(): void;
5
5
  }
6
6
  const immediateQueue = new Set<QueueJob>();
7
7
  const queue = new Set<QueueJob>();
8
8
  const pendingPromises = new Set<Promise<any>>();
9
9
 
10
- export function scheduler(
11
- jobGetter: () => ReactiveEffectRunner,
12
- immediate = false,
13
- ) {
14
- return () => {
15
- queueJob(jobGetter(), immediate);
10
+ export function scheduler(immediate = false) {
11
+ return function (this: ReactiveEffect) {
12
+ queueJob(this, immediate);
16
13
  };
17
14
  }
18
- export function queueJob(job: QueueJob, immediate = false) {
15
+ export function queueJob(job: QueueJob | (() => void), immediate = false) {
19
16
  // if we have an immediate job, we don't need to queue the normal job.
20
17
  // the set is serving an important purpose here in deduping the effects we run
21
18
  // (which in effect coalesces multiple update effects together).
19
+ if (typeof job === "function") {
20
+ job = { run: job };
21
+ }
22
+
22
23
  if (immediate) {
23
24
  immediateQueue.add(job);
24
25
  } else {
@@ -41,7 +42,7 @@ export function flushJobs() {
41
42
  // First, run all synchronous jobs
42
43
  let job;
43
44
  while ((job = takeJob()) !== null) {
44
- job();
45
+ job.run();
45
46
  }
46
47
 
47
48
  // If there are no pending promises, we're done
@@ -58,7 +59,7 @@ export async function flushJobsAsync() {
58
59
  // First, run all synchronous jobs
59
60
  let job;
60
61
  while ((job = takeJob()) !== null) {
61
- job();
62
+ job.run();
62
63
  }
63
64
 
64
65
  // If there are no pending promises, we're done
@@ -256,9 +256,9 @@ export abstract class OutputScope {
256
256
  }
257
257
 
258
258
  toString() {
259
- const ownerSymbol = this.ownerSymbol ? ` for ${this.ownerSymbol}` : "";
260
- return untrack(
261
- () => `${this.constructor.name} ${this.name}[${this.id}]${ownerSymbol}`,
262
- );
259
+ return untrack(() => {
260
+ const ownerSymbol = this.ownerSymbol ? ` for ${this.ownerSymbol}` : "";
261
+ return `${this.constructor.name} ${this.name}[${this.id}]${ownerSymbol}`;
262
+ });
263
263
  }
264
264
  }
package/src/tracer.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { effect, ReactiveEffectRunner } from "@vue/reactivity";
1
+ import { effect } from "@vue/reactivity";
2
2
  import { untrack } from "./reactivity.js";
3
3
  import { inspectRefkey, type Refkey } from "./refkey.js";
4
4
  import { scheduler } from "./scheduler.js";
@@ -210,7 +210,7 @@ export function traceEffect(phase: TracePhase, cb: () => string) {
210
210
  let first = true;
211
211
  const triggerIds = new Set<number>();
212
212
 
213
- const runner: ReactiveEffectRunner<void> = effect(
213
+ effect(
214
214
  () => {
215
215
  if (first) {
216
216
  // just track what we need, don't log.
@@ -222,7 +222,7 @@ export function traceEffect(phase: TracePhase, cb: () => string) {
222
222
  triggerIds.clear();
223
223
  },
224
224
  {
225
- scheduler: scheduler(() => runner, true),
225
+ scheduler: scheduler(true),
226
226
  onTrigger(event) {
227
227
  const id = triggerCount++;
228
228
  if (dids.has(id)) {
package/src/utils.tsx CHANGED
@@ -56,6 +56,22 @@ export function mapJoin<T, U, V>(
56
56
  cb: (key: T, value: U, index: number) => V,
57
57
  options?: JoinOptions,
58
58
  ): () => (V | string | undefined | CustomContext)[];
59
+ /**
60
+ * Map a Map to an array using a mapper and place a joiner between each element.
61
+ * Defaults to joining with a newline.
62
+ *
63
+ * @see {@link join} for joining without mapping.
64
+ * @param src - Source map.
65
+ * @param cb - Mapper function.
66
+ * @param options - Join options.
67
+ * @returns The mapped and joined array.
68
+ *
69
+ */
70
+ export function mapJoin<U, V>(
71
+ src: () => Set<U>,
72
+ cb: (value: U, index: number) => V,
73
+ options?: JoinOptions,
74
+ ): () => (V | string | undefined | CustomContext)[];
59
75
  /**
60
76
  * Map a array or iterator to another array using a mapper and place a joiner
61
77
  * between each element. Defaults to joining with a newline.
@@ -72,7 +88,7 @@ export function mapJoin<T, V>(
72
88
  options?: JoinOptions,
73
89
  ): () => (V | string | undefined | CustomContext)[];
74
90
  export function mapJoin<T, U, V>(
75
- src: () => Map<T, U> | T[] | Iterable<T>,
91
+ src: () => Map<T, U> | Set<T> | T[] | Iterable<T>,
76
92
  cb: (key: T, valueOrIndex: U | number, index: number) => V,
77
93
  rawOptions: JoinOptions = {},
78
94
  ): () => Children {
@@ -94,6 +110,7 @@ export function mapJoin<T, U, V>(
94
110
  const itemsSourceRaw = toRaw(itemsSource);
95
111
  let items =
96
112
  Array.isArray(itemsSourceRaw) ? (itemsSource as T[]) : [...itemsSource];
113
+
97
114
  if (options.skipFalsy) {
98
115
  items = items.filter(
99
116
  (item) =>
@@ -103,8 +120,8 @@ export function mapJoin<T, U, V>(
103
120
  // this is important to access here in reactive context so we are
104
121
  // notified of new items from reactives.
105
122
  const itemsLen = items.length;
106
- const compare: any = getCompareFunction(itemsSource);
107
- const mapper: any = getMapperFunction(itemsSource);
123
+ const compare: any = getCompareFunction(itemsSourceRaw);
124
+ const mapper: any = getMapperFunction(itemsSourceRaw);
108
125
 
109
126
  return untrack(() => {
110
127
  let startIndex = 0;
@@ -160,7 +177,11 @@ export function mapJoin<T, U, V>(
160
177
  }
161
178
 
162
179
  function getMapperFunction(itemsSource: Map<T, U> | T[] | Iterable<T>) {
163
- return Array.isArray(itemsSource) || isIterable(itemsSource) ?
180
+ return (
181
+ Array.isArray(itemsSource) ||
182
+ itemsSource instanceof Set ||
183
+ isIterable(itemsSource)
184
+ ) ?
164
185
  mapArray
165
186
  : mapMap;
166
187
  }
package/temp/api.json CHANGED
@@ -10288,6 +10288,126 @@
10288
10288
  {
10289
10289
  "kind": "Function",
10290
10290
  "canonicalReference": "@alloy-js/core!mapJoin:function(2)",
10291
+ "docComment": "/**\n * Map a Map to an array using a mapper and place a joiner between each element.\n * Defaults to joining with a newline.\n *\n * @param src - Source map.\n *\n * @param cb - Mapper function.\n *\n * @param options - Join options.\n *\n * @returns The mapped and joined array.\n *\n * @see\n *\n * {@link join} for joining without mapping.\n */\n",
10292
+ "excerptTokens": [
10293
+ {
10294
+ "kind": "Content",
10295
+ "text": "export declare function mapJoin<U, V>(src: "
10296
+ },
10297
+ {
10298
+ "kind": "Content",
10299
+ "text": "() => "
10300
+ },
10301
+ {
10302
+ "kind": "Reference",
10303
+ "text": "Set",
10304
+ "canonicalReference": "!Set:interface"
10305
+ },
10306
+ {
10307
+ "kind": "Content",
10308
+ "text": "<U>"
10309
+ },
10310
+ {
10311
+ "kind": "Content",
10312
+ "text": ", cb: "
10313
+ },
10314
+ {
10315
+ "kind": "Content",
10316
+ "text": "(value: U, index: number) => V"
10317
+ },
10318
+ {
10319
+ "kind": "Content",
10320
+ "text": ", options?: "
10321
+ },
10322
+ {
10323
+ "kind": "Reference",
10324
+ "text": "JoinOptions",
10325
+ "canonicalReference": "@alloy-js/core!JoinOptions:interface"
10326
+ },
10327
+ {
10328
+ "kind": "Content",
10329
+ "text": "): "
10330
+ },
10331
+ {
10332
+ "kind": "Content",
10333
+ "text": "() => (V | string | undefined | "
10334
+ },
10335
+ {
10336
+ "kind": "Reference",
10337
+ "text": "CustomContext",
10338
+ "canonicalReference": "@alloy-js/core!CustomContext:interface"
10339
+ },
10340
+ {
10341
+ "kind": "Content",
10342
+ "text": ")[]"
10343
+ },
10344
+ {
10345
+ "kind": "Content",
10346
+ "text": ";"
10347
+ }
10348
+ ],
10349
+ "fileUrlPath": "src/utils.tsx",
10350
+ "returnTypeTokenRange": {
10351
+ "startIndex": 9,
10352
+ "endIndex": 12
10353
+ },
10354
+ "releaseTag": "Public",
10355
+ "overloadIndex": 2,
10356
+ "parameters": [
10357
+ {
10358
+ "parameterName": "src",
10359
+ "parameterTypeTokenRange": {
10360
+ "startIndex": 1,
10361
+ "endIndex": 4
10362
+ },
10363
+ "isOptional": false
10364
+ },
10365
+ {
10366
+ "parameterName": "cb",
10367
+ "parameterTypeTokenRange": {
10368
+ "startIndex": 5,
10369
+ "endIndex": 6
10370
+ },
10371
+ "isOptional": false
10372
+ },
10373
+ {
10374
+ "parameterName": "options",
10375
+ "parameterTypeTokenRange": {
10376
+ "startIndex": 7,
10377
+ "endIndex": 8
10378
+ },
10379
+ "isOptional": true
10380
+ }
10381
+ ],
10382
+ "typeParameters": [
10383
+ {
10384
+ "typeParameterName": "U",
10385
+ "constraintTokenRange": {
10386
+ "startIndex": 0,
10387
+ "endIndex": 0
10388
+ },
10389
+ "defaultTypeTokenRange": {
10390
+ "startIndex": 0,
10391
+ "endIndex": 0
10392
+ }
10393
+ },
10394
+ {
10395
+ "typeParameterName": "V",
10396
+ "constraintTokenRange": {
10397
+ "startIndex": 0,
10398
+ "endIndex": 0
10399
+ },
10400
+ "defaultTypeTokenRange": {
10401
+ "startIndex": 0,
10402
+ "endIndex": 0
10403
+ }
10404
+ }
10405
+ ],
10406
+ "name": "mapJoin"
10407
+ },
10408
+ {
10409
+ "kind": "Function",
10410
+ "canonicalReference": "@alloy-js/core!mapJoin:function(3)",
10291
10411
  "docComment": "/**\n * Map a array or iterator to another array using a mapper and place a joiner\n * between each element. Defaults to joining with a newline.\n *\n * @param src - Source array.\n *\n * @param cb - Mapper function.\n *\n * @param options - Join options.\n *\n * @returns The mapped and joined array.\n *\n * @see\n *\n * {@link join} for joining without mapping.\n */\n",
10292
10412
  "excerptTokens": [
10293
10413
  {
@@ -10352,7 +10472,7 @@
10352
10472
  "endIndex": 12
10353
10473
  },
10354
10474
  "releaseTag": "Public",
10355
- "overloadIndex": 2,
10475
+ "overloadIndex": 3,
10356
10476
  "parameters": [
10357
10477
  {
10358
10478
  "parameterName": "src",
@@ -30,3 +30,23 @@ it("it should work with circular reactives", () => {
30
30
  item 1
31
31
  `);
32
32
  });
33
+
34
+ it("should work with immediately recursive reactives", () => {
35
+ const items: Set<string> = shallowReactive(new Set());
36
+ const template = (
37
+ <>
38
+ <For each={items.values()}>
39
+ {(item) => {
40
+ items.add("item 1");
41
+ return item;
42
+ }}
43
+ </For>
44
+ </>
45
+ );
46
+ const tree = renderTree(template);
47
+ items.add("item start");
48
+ expect(printTree(tree)).toBe(d`
49
+ item start
50
+ item 1
51
+ `);
52
+ });
@@ -32,6 +32,24 @@ describe("mapJoin", () => {
32
32
  `);
33
33
  });
34
34
 
35
+ it("can map a set", () => {
36
+ const set = new Set(["hi", "bye"]);
37
+
38
+ function Foo(props: { value: string }) {
39
+ return <>Value: {props.value}</>;
40
+ }
41
+
42
+ const joined = mapJoin(
43
+ () => set,
44
+ (value) => <Foo value={value} />,
45
+ );
46
+
47
+ expect(joined()).toRenderTo(`
48
+ Value: hi
49
+ Value: bye
50
+ `);
51
+ });
52
+
35
53
  it("can map an array", () => {
36
54
  const arr = [1, 2];
37
55