@alloy-js/core 0.3.0 → 0.4.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 (136) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/src/binder.d.ts +28 -5
  3. package/dist/src/binder.d.ts.map +1 -1
  4. package/dist/src/binder.js +107 -7
  5. package/dist/src/binder.js.map +1 -1
  6. package/dist/src/components/Declaration.d.ts +1 -1
  7. package/dist/src/components/Declaration.d.ts.map +1 -1
  8. package/dist/src/components/Declaration.js.map +1 -1
  9. package/dist/src/components/Indent.d.ts +1 -1
  10. package/dist/src/components/Indent.d.ts.map +1 -1
  11. package/dist/src/components/Indent.js.map +1 -1
  12. package/dist/src/components/MemberDeclaration.d.ts +1 -1
  13. package/dist/src/components/MemberDeclaration.d.ts.map +1 -1
  14. package/dist/src/components/MemberDeclaration.js.map +1 -1
  15. package/dist/src/components/MemberScope.d.ts +1 -1
  16. package/dist/src/components/MemberScope.d.ts.map +1 -1
  17. package/dist/src/components/Output.d.ts +1 -1
  18. package/dist/src/components/Output.d.ts.map +1 -1
  19. package/dist/src/components/Output.js +5 -3
  20. package/dist/src/components/Output.js.map +1 -1
  21. package/dist/src/components/Scope.d.ts +1 -1
  22. package/dist/src/components/Scope.d.ts.map +1 -1
  23. package/dist/src/components/Scope.js.map +1 -1
  24. package/dist/src/components/SourceDirectory.d.ts +1 -1
  25. package/dist/src/components/SourceDirectory.d.ts.map +1 -1
  26. package/dist/src/components/SourceDirectory.js +1 -1
  27. package/dist/src/components/SourceDirectory.js.map +1 -1
  28. package/dist/src/components/SourceFile.d.ts +1 -1
  29. package/dist/src/components/SourceFile.d.ts.map +1 -1
  30. package/dist/src/components/SourceFile.js +1 -1
  31. package/dist/src/components/SourceFile.js.map +1 -1
  32. package/dist/src/context/assignment.d.ts.map +1 -1
  33. package/dist/src/context/assignment.js +2 -2
  34. package/dist/src/context/assignment.js.map +1 -1
  35. package/dist/src/context/binder.d.ts.map +1 -1
  36. package/dist/src/context/binder.js +2 -2
  37. package/dist/src/context/binder.js.map +1 -1
  38. package/dist/src/context/declaration.d.ts.map +1 -1
  39. package/dist/src/context/declaration.js +2 -2
  40. package/dist/src/context/declaration.js.map +1 -1
  41. package/dist/src/context/indent.d.ts.map +1 -1
  42. package/dist/src/context/indent.js +2 -2
  43. package/dist/src/context/indent.js.map +1 -1
  44. package/dist/src/context/member-declaration.d.ts.map +1 -1
  45. package/dist/src/context/member-declaration.js +2 -2
  46. package/dist/src/context/member-declaration.js.map +1 -1
  47. package/dist/src/context/member-scope.d.ts.map +1 -1
  48. package/dist/src/context/member-scope.js +2 -2
  49. package/dist/src/context/member-scope.js.map +1 -1
  50. package/dist/src/context/name-policy.d.ts.map +1 -1
  51. package/dist/src/context/name-policy.js +2 -2
  52. package/dist/src/context/name-policy.js.map +1 -1
  53. package/dist/src/context/scope.d.ts.map +1 -1
  54. package/dist/src/context/scope.js +2 -2
  55. package/dist/src/context/scope.js.map +1 -1
  56. package/dist/src/context/source-directory.d.ts.map +1 -1
  57. package/dist/src/context/source-directory.js +2 -2
  58. package/dist/src/context/source-directory.js.map +1 -1
  59. package/dist/src/context/source-file.d.ts.map +1 -1
  60. package/dist/src/context/source-file.js +2 -2
  61. package/dist/src/context/source-file.js.map +1 -1
  62. package/dist/src/context.d.ts +5 -2
  63. package/dist/src/context.d.ts.map +1 -1
  64. package/dist/src/context.js +11 -4
  65. package/dist/src/context.js.map +1 -1
  66. package/dist/src/debug.d.ts +14 -0
  67. package/dist/src/debug.d.ts.map +1 -0
  68. package/dist/src/debug.js +163 -0
  69. package/dist/src/debug.js.map +1 -0
  70. package/dist/src/index.d.ts +2 -1
  71. package/dist/src/index.d.ts.map +1 -1
  72. package/dist/src/index.js +2 -1
  73. package/dist/src/index.js.map +1 -1
  74. package/dist/src/jsx-runtime.d.ts +6 -2
  75. package/dist/src/jsx-runtime.d.ts.map +1 -1
  76. package/dist/src/jsx-runtime.js +8 -6
  77. package/dist/src/jsx-runtime.js.map +1 -1
  78. package/dist/src/render.d.ts +1 -1
  79. package/dist/src/render.d.ts.map +1 -1
  80. package/dist/src/render.js +3 -3
  81. package/dist/src/render.js.map +1 -1
  82. package/dist/src/slot.d.ts +15 -0
  83. package/dist/src/slot.d.ts.map +1 -0
  84. package/dist/src/slot.js +51 -0
  85. package/dist/src/slot.js.map +1 -0
  86. package/dist/src/utils.d.ts +2 -7
  87. package/dist/src/utils.d.ts.map +1 -1
  88. package/dist/src/utils.js +1 -34
  89. package/dist/src/utils.js.map +1 -1
  90. package/dist/src/write-output.browser.d.ts +2 -0
  91. package/dist/src/write-output.browser.d.ts.map +1 -0
  92. package/dist/src/write-output.browser.js +4 -0
  93. package/dist/src/write-output.browser.js.map +1 -0
  94. package/dist/src/write-output.d.ts +7 -0
  95. package/dist/src/write-output.d.ts.map +1 -0
  96. package/dist/src/write-output.js +34 -0
  97. package/dist/src/write-output.js.map +1 -0
  98. package/dist/test/components/slot.test.d.ts +2 -0
  99. package/dist/test/components/slot.test.d.ts.map +1 -0
  100. package/dist/testing/render.d.ts +1 -1
  101. package/dist/testing/render.d.ts.map +1 -1
  102. package/dist/tsconfig.tsbuildinfo +1 -1
  103. package/package.json +8 -5
  104. package/src/binder.ts +181 -6
  105. package/src/components/Declaration.tsx +1 -1
  106. package/src/components/Indent.tsx +1 -1
  107. package/src/components/MemberDeclaration.tsx +1 -1
  108. package/src/components/MemberScope.tsx +1 -1
  109. package/src/components/Output.tsx +3 -2
  110. package/src/components/Scope.tsx +1 -1
  111. package/src/components/SourceDirectory.tsx +1 -1
  112. package/src/components/SourceFile.tsx +1 -5
  113. package/src/context/assignment.ts +6 -2
  114. package/src/context/binder.ts +7 -2
  115. package/src/context/declaration.ts +2 -2
  116. package/src/context/indent.ts +13 -6
  117. package/src/context/member-declaration.ts +2 -2
  118. package/src/context/member-scope.ts +6 -2
  119. package/src/context/name-policy.ts +6 -2
  120. package/src/context/scope.ts +7 -2
  121. package/src/context/source-directory.ts +2 -2
  122. package/src/context/source-file.ts +2 -2
  123. package/src/context.ts +15 -4
  124. package/src/debug.ts +209 -0
  125. package/src/index.ts +2 -1
  126. package/src/jsx-runtime.ts +19 -8
  127. package/src/render.ts +8 -8
  128. package/src/slot.ts +90 -0
  129. package/src/utils.ts +2 -34
  130. package/src/write-output.browser.ts +3 -0
  131. package/src/write-output.ts +33 -0
  132. package/temp/api.json +575 -69
  133. package/test/components/slot.test.tsx +172 -0
  134. package/test/rendering/basic.test.tsx +1 -1
  135. package/test/symbols.test.ts +102 -0
  136. package/testing/render.ts +1 -1
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,
@@ -19,3 +18,5 @@ export * from "./name-policy.js";
19
18
  export * from "./refkey.js";
20
19
  export * from "./render.js";
21
20
  export * from "./utils.js";
21
+ export * from "./write-output.js";
22
+ import "./debug.js";
@@ -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>(fn: (d: Disposable) => T, src?: string): T {
46
+ export function root<T>(
47
+ fn: (d: Disposable) => T,
48
+ componentOwner?: ComponentCreator<any>,
49
+ ): T {
41
50
  globalContext = {
42
- src,
51
+ componentOwner,
43
52
  disposables: [],
44
53
  owner: globalContext,
45
54
  context: {},
46
- } as any;
55
+ };
47
56
  let ret;
48
57
  try {
49
58
  ret = untrack(() =>
@@ -148,20 +157,18 @@ const renderStack: {
148
157
  props: Props;
149
158
  }[] = [];
150
159
 
151
- export const shouldDebug = !!process.env.ALLOY_DEBUG;
152
-
153
160
  export function pushStack(component: Component<any>, props: Props) {
154
- if (!shouldDebug) return;
161
+ if (!shouldDebug()) return;
155
162
  renderStack.push({ component, props });
156
163
  }
157
164
 
158
165
  export function popStack() {
159
- if (!shouldDebug) return;
166
+ if (!shouldDebug()) return;
160
167
  renderStack.pop();
161
168
  }
162
169
 
163
170
  export function printRenderStack() {
164
- if (!shouldDebug) return;
171
+ if (!shouldDebug()) return;
165
172
 
166
173
  // eslint-disable-next-line no-console
167
174
  console.error("Error rendering:");
@@ -264,3 +271,7 @@ export function mergeProps(...sources: any): any {
264
271
  }
265
272
  return target;
266
273
  }
274
+
275
+ function shouldDebug() {
276
+ return typeof process !== "undefined" && !!process.env?.ALLOY_DEBUG;
277
+ }
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 "@alloy-js/core/jsx-runtime";
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
  /**
@@ -250,7 +250,7 @@ export function renderTree(children: Children) {
250
250
  try {
251
251
  root(() => {
252
252
  renderWorker(rootElem, children, state);
253
- }, "render worker");
253
+ });
254
254
  } catch (e) {
255
255
  printRenderStack();
256
256
  throw e;
@@ -314,7 +314,7 @@ function appendChild(
314
314
  popStack();
315
315
  node.push(componentRoot);
316
316
  traceRender("appendChild:component-done", printChild(child));
317
- }, child.component.name);
317
+ }, child);
318
318
  } else if (typeof child === "function") {
319
319
  traceRender("appendChild:memo", child.toString());
320
320
  const index = node.length;
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/utils.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { code } from "./code.js";
1
2
  import {
2
3
  Child,
3
4
  Children,
@@ -5,10 +6,7 @@ import {
5
6
  ComponentDefinition,
6
7
  isComponentCreator,
7
8
  memo,
8
- } from "@alloy-js/core/jsx-runtime";
9
- import { mkdirSync, statSync, writeFileSync } from "node:fs";
10
- import { relative, resolve } from "pathe";
11
- import { code } from "./code.js";
9
+ } from "./jsx-runtime.js";
12
10
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
13
11
  import { OutputDirectory, OutputFile, render } from "./render.js";
14
12
 
@@ -256,33 +254,3 @@ export function traverseOutput(
256
254
  }
257
255
  }
258
256
  }
259
-
260
- /**
261
- * Write the output from {@link render} to the file system.
262
- *
263
- */
264
- export function writeOutput(output: OutputDirectory, basePath: string = "") {
265
- traverseOutput(output, {
266
- visitDirectory(directory) {
267
- const path = resolve(basePath, directory.path);
268
- if (statSync(path)) {
269
- return;
270
- }
271
- // eslint-disable-next-line no-console
272
- console.log("create", relative(process.cwd(), path));
273
- mkdirSync(path, { recursive: true });
274
- },
275
- visitFile(file) {
276
- const path = resolve(basePath, file.path);
277
- if (statSync(path)) {
278
- // eslint-disable-next-line no-console
279
- console.log("overwrite", relative(process.cwd(), path));
280
- } else {
281
- // eslint-disable-next-line no-console
282
- console.log("create", relative(process.cwd(), path));
283
- }
284
-
285
- writeFileSync(path, file.contents);
286
- },
287
- });
288
- }
@@ -0,0 +1,3 @@
1
+ export function writeOutput(output: any, basePath: string = "") {
2
+ console.warn("writeOutput is not supported in a browser environment.");
3
+ }
@@ -0,0 +1,33 @@
1
+ import { mkdirSync, statSync, writeFileSync } from "node:fs";
2
+ import { relative, resolve } from "pathe";
3
+ import { OutputDirectory } from "./render.js";
4
+ import { traverseOutput } from "./utils.js";
5
+ /**
6
+ * Write the output from {@link render} to the file system.
7
+ *
8
+ */
9
+ export function writeOutput(output: OutputDirectory, basePath: string = "") {
10
+ traverseOutput(output, {
11
+ visitDirectory(directory) {
12
+ const path = resolve(basePath, directory.path);
13
+ if (statSync(path)) {
14
+ return;
15
+ }
16
+ // eslint-disable-next-line no-console
17
+ console.log("create", relative(process.cwd(), path));
18
+ mkdirSync(path, { recursive: true });
19
+ },
20
+ visitFile(file) {
21
+ const path = resolve(basePath, file.path);
22
+ if (statSync(path)) {
23
+ // eslint-disable-next-line no-console
24
+ console.log("overwrite", relative(process.cwd(), path));
25
+ } else {
26
+ // eslint-disable-next-line no-console
27
+ console.log("create", relative(process.cwd(), path));
28
+ }
29
+
30
+ writeFileSync(path, file.contents);
31
+ },
32
+ });
33
+ }