@alloy-js/core 0.7.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/babel.config.cjs +1 -4
  3. package/dist/src/binder.d.ts +14 -12
  4. package/dist/src/binder.d.ts.map +1 -1
  5. package/dist/src/binder.js +26 -23
  6. package/dist/src/binder.js.map +1 -1
  7. package/dist/src/code.d.ts +11 -2
  8. package/dist/src/code.d.ts.map +1 -1
  9. package/dist/src/code.js +27 -2
  10. package/dist/src/code.js.map +1 -1
  11. package/dist/src/components/Block.d.ts +2 -2
  12. package/dist/src/components/Block.d.ts.map +1 -1
  13. package/dist/src/components/Block.js +6 -5
  14. package/dist/src/components/Block.js.map +1 -1
  15. package/dist/src/components/Declaration.d.ts +31 -7
  16. package/dist/src/components/Declaration.d.ts.map +1 -1
  17. package/dist/src/components/Declaration.js +15 -7
  18. package/dist/src/components/Declaration.js.map +1 -1
  19. package/dist/src/components/For.d.ts +8 -2
  20. package/dist/src/components/For.d.ts.map +1 -1
  21. package/dist/src/components/For.js +2 -3
  22. package/dist/src/components/For.js.map +1 -1
  23. package/dist/src/components/Indent.d.ts +29 -1
  24. package/dist/src/components/Indent.d.ts.map +1 -1
  25. package/dist/src/components/Indent.js +7 -2
  26. package/dist/src/components/Indent.js.map +1 -1
  27. package/dist/src/components/List.d.ts +7 -3
  28. package/dist/src/components/List.d.ts.map +1 -1
  29. package/dist/src/components/List.js +1 -16
  30. package/dist/src/components/List.js.map +1 -1
  31. package/dist/src/components/MemberDeclaration.d.ts +35 -5
  32. package/dist/src/components/MemberDeclaration.d.ts.map +1 -1
  33. package/dist/src/components/MemberDeclaration.js +18 -7
  34. package/dist/src/components/MemberDeclaration.js.map +1 -1
  35. package/dist/src/components/MemberScope.d.ts +2 -0
  36. package/dist/src/components/MemberScope.d.ts.map +1 -1
  37. package/dist/src/components/MemberScope.js +2 -0
  38. package/dist/src/components/MemberScope.js.map +1 -1
  39. package/dist/src/components/Prose.d.ts +10 -0
  40. package/dist/src/components/Prose.d.ts.map +1 -0
  41. package/dist/src/components/Prose.js +23 -0
  42. package/dist/src/components/Prose.js.map +1 -0
  43. package/dist/src/components/Scope.d.ts +33 -2
  44. package/dist/src/components/Scope.d.ts.map +1 -1
  45. package/dist/src/components/Scope.js +20 -4
  46. package/dist/src/components/Scope.js.map +1 -1
  47. package/dist/src/components/SourceFile.d.ts +5 -0
  48. package/dist/src/components/SourceFile.d.ts.map +1 -1
  49. package/dist/src/components/SourceFile.js +10 -1
  50. package/dist/src/components/SourceFile.js.map +1 -1
  51. package/dist/src/components/index.d.ts +1 -0
  52. package/dist/src/components/index.d.ts.map +1 -1
  53. package/dist/src/components/index.js +1 -0
  54. package/dist/src/components/index.js.map +1 -1
  55. package/dist/src/components/stc/index.d.ts +19 -95
  56. package/dist/src/components/stc/index.d.ts.map +1 -1
  57. package/dist/src/components/stc/index.js +3 -6
  58. package/dist/src/components/stc/index.js.map +1 -1
  59. package/dist/src/components/stc/sti.d.ts +9 -0
  60. package/dist/src/components/stc/sti.d.ts.map +1 -0
  61. package/dist/src/components/stc/sti.js +10 -0
  62. package/dist/src/components/stc/sti.js.map +1 -0
  63. package/dist/src/context/assignment.d.ts +6 -0
  64. package/dist/src/context/assignment.d.ts.map +1 -1
  65. package/dist/src/context/assignment.js +7 -0
  66. package/dist/src/context/assignment.js.map +1 -1
  67. package/dist/src/context.d.ts +2 -0
  68. package/dist/src/context.d.ts.map +1 -1
  69. package/dist/src/context.js +12 -9
  70. package/dist/src/context.js.map +1 -1
  71. package/dist/src/index.d.ts +2 -1
  72. package/dist/src/index.d.ts.map +1 -1
  73. package/dist/src/index.js +2 -1
  74. package/dist/src/index.js.map +1 -1
  75. package/dist/src/jsx-runtime.d.ts +93 -2
  76. package/dist/src/jsx-runtime.d.ts.map +1 -1
  77. package/dist/src/jsx-runtime.js +51 -3
  78. package/dist/src/jsx-runtime.js.map +1 -1
  79. package/dist/src/stc.d.ts +5 -7
  80. package/dist/src/stc.d.ts.map +1 -1
  81. package/dist/src/stc.js +11 -23
  82. package/dist/src/stc.js.map +1 -1
  83. package/dist/src/sti.d.ts +11 -0
  84. package/dist/src/sti.d.ts.map +1 -0
  85. package/dist/src/sti.js +31 -0
  86. package/dist/src/sti.js.map +1 -0
  87. package/dist/src/tap.d.ts +69 -6
  88. package/dist/src/tap.d.ts.map +1 -1
  89. package/dist/src/tap.js +70 -0
  90. package/dist/src/tap.js.map +1 -1
  91. package/dist/src/utils.d.ts +5 -0
  92. package/dist/src/utils.d.ts.map +1 -1
  93. package/dist/src/utils.js +20 -0
  94. package/dist/src/utils.js.map +1 -1
  95. package/dist/test/components/prose.test.d.ts +2 -0
  96. package/dist/test/components/prose.test.d.ts.map +1 -0
  97. package/dist/test/props-with-defaults.test.d.ts +2 -0
  98. package/dist/test/props-with-defaults.test.d.ts.map +1 -0
  99. package/dist/tsconfig.tsbuildinfo +1 -1
  100. package/package.json +3 -3
  101. package/src/binder.ts +44 -29
  102. package/src/code.ts +37 -3
  103. package/src/components/Block.tsx +3 -6
  104. package/src/components/Declaration.tsx +43 -11
  105. package/src/components/For.tsx +16 -4
  106. package/src/components/Indent.tsx +38 -5
  107. package/src/components/List.tsx +14 -40
  108. package/src/components/MemberDeclaration.tsx +51 -12
  109. package/src/components/MemberScope.tsx +2 -0
  110. package/src/components/Prose.tsx +35 -0
  111. package/src/components/Scope.tsx +45 -5
  112. package/src/components/SourceFile.tsx +10 -0
  113. package/src/components/index.tsx +1 -0
  114. package/src/components/stc/index.ts +3 -6
  115. package/src/components/stc/sti.ts +10 -0
  116. package/src/context/assignment.ts +7 -1
  117. package/src/context.ts +15 -11
  118. package/src/index.ts +3 -0
  119. package/src/jsx-runtime.ts +168 -3
  120. package/src/stc.ts +38 -59
  121. package/src/sti.ts +63 -0
  122. package/src/tap.ts +69 -6
  123. package/src/{utils.ts → utils.tsx} +45 -0
  124. package/temp/api.json +1657 -440
  125. package/test/components/declaration.test.tsx +1 -1
  126. package/test/components/prose.test.tsx +36 -0
  127. package/test/components/source-file.test.tsx +17 -0
  128. package/test/control-flow/for.test.tsx +17 -0
  129. package/test/props-with-defaults.test.ts +97 -0
  130. package/test/symbols.test.ts +0 -25
  131. package/vitest.config.ts +2 -10
@@ -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
- export interface ScopeProps {
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
- value?: OutputScope;
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.value) {
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({ kind, name: props.name! });
57
+ scope = binder.createScope({
58
+ kind: props.kind,
59
+ metadata: props.metadata,
60
+ name: props.name ?? "",
61
+ });
22
62
  }
23
63
 
24
64
  return (
@@ -5,6 +5,7 @@ import { SourceFileContext } from "../context/source-file.js";
5
5
  import { Children, ComponentDefinition, getContext } from "../jsx-runtime.js";
6
6
  import { Refkey } from "../refkey.js";
7
7
  import { PrintTreeOptions } from "../render.js";
8
+ import { Show } from "./Show.jsx";
8
9
 
9
10
  export interface SourceFileProps extends PrintTreeOptions {
10
11
  /**
@@ -24,6 +25,11 @@ export interface SourceFileProps extends PrintTreeOptions {
24
25
  * contents.
25
26
  */
26
27
  reference?: ComponentDefinition<{ refkey: Refkey }>;
28
+ /**
29
+ * The header of the file. This is rendered before the contents of the file.
30
+ * This is useful for adding license headers or other metadata to the file.
31
+ */
32
+ header?: Children;
27
33
  }
28
34
 
29
35
  export function SourceFile(props: SourceFileProps) {
@@ -45,6 +51,10 @@ export function SourceFile(props: SourceFileProps) {
45
51
 
46
52
  return (
47
53
  <SourceFileContext.Provider value={context}>
54
+ <Show when={props.header !== undefined}>
55
+ {props.header}
56
+ <hbr />
57
+ </Show>
48
58
  {props.children}
49
59
  </SourceFileContext.Provider>
50
60
  );
@@ -8,6 +8,7 @@ export * from "./MemberName.jsx";
8
8
  export * from "./MemberScope.jsx";
9
9
  export * from "./Name.jsx";
10
10
  export * from "./Output.js";
11
+ export * from "./Prose.jsx";
11
12
  export * from "./Scope.js";
12
13
  export * from "./Show.jsx";
13
14
  export * from "./SourceDirectory.js";
@@ -1,4 +1,4 @@
1
- import { stc, sti } from "../../stc.js";
1
+ import { stc } from "../../stc.js";
2
2
  import * as base from "../index.js";
3
3
 
4
4
  export const Block = stc(base.Block);
@@ -11,6 +11,7 @@ export const MemberName = stc(base.MemberName);
11
11
  export const MemberScope = stc(base.MemberScope);
12
12
  export const Name = stc(base.Name);
13
13
  export const Output = stc(base.Output);
14
+ export const Prose = stc(base.Prose);
14
15
  export const Scope = stc(base.Scope);
15
16
  export const Show = stc(base.Show);
16
17
  export const StatementList = stc(base.StatementList);
@@ -19,8 +20,4 @@ export const SourceFile = stc(base.SourceFile);
19
20
  export const Switch = stc(base.Switch);
20
21
  export const Wrap = stc(base.Wrap);
21
22
 
22
- export const indent = sti("indent");
23
- export const hbr = sti("hbr");
24
- export const sbr = sti("sbr");
25
- export const lbr = sti("lbr");
26
- export const br = sti("br");
23
+ export * from "./sti.js";
@@ -0,0 +1,10 @@
1
+ import { sti } from "../../sti.js";
2
+
3
+ export const indent = sti("indent");
4
+ export const group = sti("group");
5
+ export const ifBreak = sti("ifBreak");
6
+ export const hbr = sti("hbr");
7
+ export const sbr = sti("sbr");
8
+ export const lbr = sti("lbr");
9
+ export const br = sti("br");
10
+ export const dedentToRoot = sti("dedentToRoot");
@@ -52,7 +52,13 @@ export function createAssignmentContext(
52
52
  };
53
53
  }
54
54
 
55
- export function getAssignmentSymbol() {
55
+ /**
56
+ * Get the symbol being defined.
57
+ *
58
+ * @returns The symbol currently being defined, or `undefined` if no symbol is
59
+ * being defined.
60
+ */
61
+ export function getAssignmentSymbol(): OutputSymbol | undefined {
56
62
  const assignmentContext = useContext(AssignmentContext);
57
63
  if (assignmentContext) {
58
64
  return assignmentContext.target;
package/src/context.ts CHANGED
@@ -5,11 +5,13 @@ import {
5
5
  effect,
6
6
  getContext,
7
7
  } from "./jsx-runtime.js";
8
+ import { stc, StcSignature } from "./stc.js";
8
9
 
9
10
  export interface ComponentContext<T> {
10
11
  id: symbol;
11
12
  default: T | undefined;
12
13
  Provider: ComponentDefinition<ContextProviderProps<T>>;
14
+ ProviderStc: StcSignature<ContextProviderProps<T>>;
13
15
  name?: string;
14
16
  }
15
17
 
@@ -38,21 +40,23 @@ export function createContext<T = unknown>(
38
40
  name?: string,
39
41
  ): ComponentContext<T> {
40
42
  const id = Symbol(name ?? "context");
43
+ function Provider(props: ContextProviderProps<T>) {
44
+ const context = getContext();
45
+
46
+ const rendered = shallowRef();
47
+ effect(() => {
48
+ context!.context![id] = props.value;
49
+ rendered.value = () => props.children;
50
+ }, undefined);
51
+
52
+ return rendered.value;
53
+ }
41
54
  const ctx = {
42
55
  id,
43
56
  default: defaultValue,
44
57
  name,
45
- Provider(props: ContextProviderProps<T>) {
46
- const context = getContext();
47
-
48
- const rendered = shallowRef();
49
- effect(() => {
50
- context!.context![id] = props.value;
51
- rendered.value = () => props.children;
52
- }, undefined);
53
-
54
- return rendered.value;
55
- },
58
+ Provider,
59
+ ProviderStc: stc(Provider),
56
60
  };
57
61
  contextsByKey.set(id, ctx);
58
62
  return ctx;
package/src/index.ts CHANGED
@@ -6,6 +6,8 @@ export {
6
6
  shallowReactive,
7
7
  shallowRef,
8
8
  toRaw,
9
+ toRef,
10
+ toRefs,
9
11
  type Ref,
10
12
  } from "@vue/reactivity";
11
13
  export * from "./binder.js";
@@ -18,6 +20,7 @@ export * from "./name-policy.js";
18
20
  export * from "./refkey.js";
19
21
  export * from "./render.js";
20
22
  export * from "./stc.js";
23
+ export * from "./sti.js";
21
24
  export * from "./tap.js";
22
25
  export * from "./utils.js";
23
26
  export * from "./write-output.js";
@@ -1,6 +1,7 @@
1
1
  // Much of the implementations in this file are inspired by vuerx-js
2
2
  // See: https://github.com/ryansolid/vuerx-jsx.
3
3
  import {
4
+ computed,
4
5
  isReactive,
5
6
  pauseTracking,
6
7
  proxyRefs,
@@ -219,10 +220,11 @@ export interface Component<TProps = Props> {
219
220
  (props: TProps): Children;
220
221
  tag?: symbol;
221
222
  }
223
+
222
224
  export interface ComponentCreator<TProps = Props> {
223
225
  component: Component<TProps>;
224
226
  (): Children;
225
- props: Props;
227
+ props: TProps;
226
228
  tag?: symbol;
227
229
  }
228
230
 
@@ -283,8 +285,14 @@ function inspectProps(props: Props) {
283
285
 
284
286
  // These can be removed with a smarter transform that encodes the information we
285
287
  // need in the compiled JSX output.
286
- export function isComponentCreator(item: unknown): item is ComponentCreator {
287
- return typeof item === "function" && (item as any).component;
288
+ export function isComponentCreator<TProps = any>(
289
+ item: unknown,
290
+ component?: Component<TProps>,
291
+ ): item is ComponentCreator<TProps> {
292
+ if (!component) {
293
+ return typeof item === "function" && (item as any).component;
294
+ }
295
+ return typeof item === "function" && (item as any).component === component;
288
296
  }
289
297
 
290
298
  /**
@@ -294,27 +302,131 @@ export function isComponentCreator(item: unknown): item is ComponentCreator {
294
302
  // eslint-disable-next-line @typescript-eslint/no-namespace
295
303
  export namespace JSX {
296
304
  export interface IntrinsicElements {
305
+ /**
306
+ * Attempt to render the children on a single line if possible. If a group
307
+ * contains `<breakParent />` or a hard line, or if the group exceeds the
308
+ * print width, all linebreaks in the group will be broken.
309
+ */
297
310
  group: { shouldBreak?: boolean; id?: symbol; children: Children };
311
+
312
+ /**
313
+ * A regular line break. This will break if the line exceeds the print
314
+ * width, otherwise it will be a space.
315
+ */
298
316
  line: {};
317
+
318
+ /**
319
+ * A regular line break. This will break if the line exceeds the print
320
+ * width, otherwise it will be a space.
321
+ */
299
322
  br: {};
323
+
324
+ /**
325
+ * A hard line break. This is a line that will always break, even if the
326
+ * group does not exceed print width.
327
+ */
300
328
  hardline: {};
329
+
330
+ /**
331
+ * A hard line break. This is a line that will always break, even if the
332
+ * group does not exceed print width.
333
+ */
301
334
  hbr: {};
335
+
336
+ /**
337
+ * A soft line break. This will break if the line exceeds the print width,
338
+ * otherwise it will be be nothing.
339
+ */
302
340
  softline: {};
341
+
342
+ /**
343
+ * A soft line break. This will break if the line exceeds the print width,
344
+ * otherwise it will be be nothing.
345
+ */
303
346
  sbr: {};
347
+
348
+ /**
349
+ * A literal line break. This will always break, even if the group does not
350
+ * exceed print width. The new line will ignore indentation.
351
+ */
304
352
  literalline: {};
353
+
354
+ /**
355
+ * A literal line break. This will always break, even if the group does not
356
+ * exceed print width. The new line will ignore indentation.
357
+ */
305
358
  lbr: {};
359
+
360
+ /**
361
+ * Increase the indentation level of the children of this component.
362
+ * Indentation is determined by the print options provided to the Output
363
+ * component or source file.
364
+ */
306
365
  indent: { children: Children };
366
+
367
+ /**
368
+ * Indent the children of this component if the group specified by `groupId`
369
+ * is broken (or not broken if `negate` is passed). The specified group must
370
+ * already be printed.
371
+ */
307
372
  indentIfBreak: { children: Children; groupId: symbol; negate?: boolean };
373
+
374
+ /**
375
+ * Similar to `group`, but will only place a line break before the last
376
+ * segment to exceed the print width. This is useful for formatting
377
+ * paragraphs of text where breaks are inserted prior to words which would
378
+ * otherwise exceed the print width.
379
+ */
308
380
  fill: { children: Children };
381
+
382
+ /**
383
+ * Force the parent group to break.
384
+ */
309
385
  breakParent: {};
386
+
387
+ /**
388
+ * Print children if the current group or already printed group specified by
389
+ * `groupId` is broken. Otherwise, `flatContents` is printed instead.
390
+ */
310
391
  ifBreak: { children: Children; flatContents?: Children; groupId?: symbol };
392
+
393
+ /**
394
+ * Print this content at the end of the line. Useful for things like line
395
+ * comments.
396
+ */
311
397
  lineSuffix: { children: Children };
398
+
399
+ /**
400
+ * Force any line suffixes to print at this point.
401
+ */
312
402
  lineSuffixBoundary: {};
403
+
404
+ /**
405
+ * Decrease the indentation level of the children of this component.
406
+ * Indentation is determined by the print options provided to the Output
407
+ * component or source file.
408
+ */
313
409
  dedent: { children: Children };
410
+
411
+ /**
412
+ * Indent the children of this component by either the number of characters
413
+ * indicated by the `width` prop, or by the provided string indicated by the
414
+ * `string` prop.
415
+ */
314
416
  align:
315
417
  | { children: Children; width: number }
316
418
  | { children: Children; string: string };
419
+
420
+ /**
421
+ * Mark the current indentation level as "root" for the purposes of literal
422
+ * line breaks and `dedentToRoot`.
423
+ */
317
424
  markAsRoot: { children: Children };
425
+
426
+ /**
427
+ * Decrease the indentation level to the root level specified by
428
+ * `<markAsRoot />`, or else to no indentation.
429
+ */
318
430
  dedentToRoot: { children: Children };
319
431
  }
320
432
  export type ElementType = string | ComponentDefinition<any>;
@@ -518,6 +630,59 @@ export function splitProps<
518
630
  return [...result, remaining] as any;
519
631
  }
520
632
 
633
+ /**
634
+ * Applies default values to a props object. Reactive props are handled properly
635
+ * by ensuring that their value is not accessed by `defaultProps`, avoiding any
636
+ * unintended side effects.
637
+ */
638
+ export function defaultProps<T extends {}>(props: T, defaults: Partial<T>): T {
639
+ if (isReactive(props)) {
640
+ const refs = untrack(() => toRefs(props));
641
+ for (const key in defaults) {
642
+ const originalRef = refs[key];
643
+ refs[key] = computed(() =>
644
+ originalRef.value === undefined ? defaults[key] : originalRef.value,
645
+ ) as any;
646
+ }
647
+
648
+ return proxyRefs(refs);
649
+ }
650
+ const withDefaults = {} as T;
651
+ const copied = new Set<string>();
652
+ for (const key in defaults) {
653
+ copied.add(key);
654
+ const desc = Object.getOwnPropertyDescriptor(props, key);
655
+ if (!desc) {
656
+ withDefaults[key] = defaults[key]!;
657
+ continue;
658
+ }
659
+
660
+ if (desc.get) {
661
+ const originalGet = desc.get;
662
+ desc.get = function () {
663
+ const value = originalGet.call(this);
664
+ return value === undefined ? defaults[key as keyof T] : value;
665
+ };
666
+ Object.defineProperty(withDefaults, key, desc);
667
+ } else {
668
+ desc.value =
669
+ desc.value === undefined ? defaults[key as keyof T] : desc.value;
670
+ Object.defineProperty(withDefaults, key, desc);
671
+ }
672
+ }
673
+
674
+ const descriptors = Object.getOwnPropertyDescriptors(props);
675
+ for (const key in descriptors) {
676
+ if (copied.has(key)) {
677
+ continue;
678
+ }
679
+
680
+ Object.defineProperty(withDefaults, key, descriptors[key]);
681
+ }
682
+
683
+ return withDefaults;
684
+ }
685
+
521
686
  function shouldDebug() {
522
687
  return typeof process !== "undefined" && !!process.env?.ALLOY_DEBUG;
523
688
  }
package/src/stc.ts CHANGED
@@ -2,71 +2,40 @@ import {
2
2
  Children,
3
3
  ComponentCreator,
4
4
  ComponentDefinition,
5
- createIntrinsic,
6
- IntrinsicElementBase,
7
- JSX,
8
5
  } from "@alloy-js/core/jsx-runtime";
9
- import { code } from "./code.js";
10
-
11
- export function sti<T extends keyof JSX.IntrinsicElements>(name: T) {
12
- return (
13
- ...args: unknown extends T ? []
14
- : {} extends Omit<JSX.IntrinsicElements[T], "children"> ?
15
- [props?: JSX.IntrinsicElements[T]]
16
- : [props: JSX.IntrinsicElements[T]]
17
- ) => {
18
- const props: JSX.IntrinsicElements[T] | undefined = args[0];
19
- const fn = () => createIntrinsic(name, props!);
20
- fn.children = (
21
- ...children: Children[]
22
- ): (() => IntrinsicElementBase<T>) => {
23
- const propsWithChildren = {
24
- ...(props ?? {}),
25
- children,
26
- };
27
-
28
- return () => createIntrinsic(name, propsWithChildren as any);
29
- };
30
-
31
- fn.code = (
32
- template: TemplateStringsArray,
33
- ...substitutions: Children[]
34
- ): (() => IntrinsicElementBase<T>) => {
35
- const propsWithChildren = {
36
- ...(args[0] ?? {}),
37
- children: code(template, ...substitutions),
38
- };
39
-
40
- return () => createIntrinsic(name, propsWithChildren as any);
41
- };
42
- return fn;
43
- };
44
- }
6
+ import { code, text } from "./code.js";
45
7
 
46
8
  export type MakeChildrenOptional<T extends object> =
47
9
  T extends { children?: any } ?
48
10
  Omit<T, "children"> & Partial<Pick<T, "children">>
49
11
  : T;
50
12
 
51
- export function stc<T extends {}>(Component: ComponentDefinition<T>) {
52
- return (
53
- ...args: unknown extends T ? []
54
- : {} extends Omit<T, "children"> ? [props?: MakeChildrenOptional<T>]
55
- : [props: MakeChildrenOptional<T>]
56
- ) => {
57
- const fn: ComponentCreator<T> & {
58
- code(
59
- template: TemplateStringsArray,
60
- ...substitutions: Children[]
61
- ): ComponentCreator<T>;
62
- children(...children: Children[]): ComponentCreator<T>;
63
- } = () => Component(args[0] as any);
13
+ export type StcSignature<T extends {}> = (
14
+ ...args: unknown extends T ? []
15
+ : {} extends Omit<T, "children"> ? [props?: MakeChildrenOptional<T>]
16
+ : [props: MakeChildrenOptional<T>]
17
+ ) => StcComponentCreator<T>;
18
+
19
+ export type StcComponentCreator<T> = ComponentCreator<T> & {
20
+ code(
21
+ template: TemplateStringsArray,
22
+ ...substitutions: Children[]
23
+ ): ComponentCreator<T>;
24
+ text(
25
+ template: TemplateStringsArray,
26
+ ...substitutions: Children[]
27
+ ): ComponentCreator<T>;
28
+ children(...children: Children[]): ComponentCreator<T>;
29
+ };
30
+
31
+ export function stc<T extends {}>(
32
+ Component: ComponentDefinition<T>,
33
+ ): StcSignature<T> {
34
+ return (...args) => {
35
+ const fn: StcComponentCreator<T> = (() => Component(args[0] as T)) as any;
64
36
  fn.component = Component;
65
- fn.props = args[0]!;
66
- fn.code = (
67
- template: TemplateStringsArray,
68
- ...substitutions: Children[]
69
- ): ComponentCreator<T> => {
37
+ fn.props = args[0]! as T;
38
+ fn.code = (template, ...substitutions): ComponentCreator<T> => {
70
39
  const propsWithChildren = {
71
40
  ...(args[0] ?? {}),
72
41
  children: code(template, ...substitutions),
@@ -74,10 +43,20 @@ export function stc<T extends {}>(Component: ComponentDefinition<T>) {
74
43
 
75
44
  const fn = () => Component(propsWithChildren as any);
76
45
  fn.component = Component;
77
- fn.props = args[0]!;
46
+ fn.props = args[0]! as T;
78
47
  return fn;
79
48
  };
49
+ fn.text = (template, ...substitutions) => {
50
+ const propsWithChildren = {
51
+ ...(args[0] ?? {}),
52
+ children: text(template, ...substitutions),
53
+ };
80
54
 
55
+ const fn = () => Component(propsWithChildren as any);
56
+ fn.component = Component;
57
+ fn.props = args[0]! as T;
58
+ return fn;
59
+ };
81
60
  fn.children = (...children: Children[]): ComponentCreator<T> => {
82
61
  const propsWithChildren = {
83
62
  ...(args[0] ?? {}),
@@ -86,7 +65,7 @@ export function stc<T extends {}>(Component: ComponentDefinition<T>) {
86
65
 
87
66
  const fn = () => Component(propsWithChildren as any);
88
67
  fn.component = Component;
89
- fn.props = args[0]!;
68
+ fn.props = args[0]! as T;
90
69
  return fn;
91
70
  };
92
71
 
package/src/sti.ts ADDED
@@ -0,0 +1,63 @@
1
+ import {
2
+ Children,
3
+ createIntrinsic,
4
+ IntrinsicElementBase,
5
+ JSX,
6
+ } from "@alloy-js/core/jsx-runtime";
7
+ import { code, text } from "./code.js";
8
+
9
+ export type StiSignature<T extends keyof JSX.IntrinsicElements> = (
10
+ ...args: unknown extends T ? []
11
+ : {} extends Omit<JSX.IntrinsicElements[T], "children"> ?
12
+ [props?: JSX.IntrinsicElements[T]]
13
+ : [props: JSX.IntrinsicElements[T]]
14
+ ) => StiComponentCreator<T>;
15
+
16
+ export type StiComponentCreator<T extends keyof JSX.IntrinsicElements> =
17
+ (() => IntrinsicElementBase<T>) & {
18
+ code(
19
+ template: TemplateStringsArray,
20
+ ...substitutions: Children[]
21
+ ): () => IntrinsicElementBase<T>;
22
+ text(
23
+ template: TemplateStringsArray,
24
+ ...substitutions: Children[]
25
+ ): () => IntrinsicElementBase<T>;
26
+ children(...children: Children[]): () => IntrinsicElementBase<T>;
27
+ };
28
+
29
+ export function sti<T extends keyof JSX.IntrinsicElements>(
30
+ name: T,
31
+ ): StiSignature<T> {
32
+ return (...args) => {
33
+ const props: JSX.IntrinsicElements[T] | undefined = args[0];
34
+ const fn: StiComponentCreator<T> = () => createIntrinsic(name, props!);
35
+ fn.children = (...children: Children[]) => {
36
+ const propsWithChildren = {
37
+ ...(props ?? {}),
38
+ children,
39
+ };
40
+
41
+ return () => createIntrinsic(name, propsWithChildren as any);
42
+ };
43
+
44
+ fn.code = (template, ...substitutions) => {
45
+ const propsWithChildren = {
46
+ ...(args[0] ?? {}),
47
+ children: code(template, ...substitutions),
48
+ };
49
+
50
+ return () => createIntrinsic(name, propsWithChildren as any);
51
+ };
52
+
53
+ fn.text = (template, ...substitutions) => {
54
+ const propsWithChildren = {
55
+ ...(args[0] ?? {}),
56
+ children: text(template, ...substitutions),
57
+ };
58
+
59
+ return () => createIntrinsic(name, propsWithChildren as any);
60
+ };
61
+ return fn;
62
+ };
63
+ }