@alloy-js/core 0.19.0-dev.12 → 0.19.0-dev.3
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/dist/src/components/index.d.ts +0 -4
- package/dist/src/components/index.d.ts.map +1 -1
- package/dist/src/components/index.js +0 -4
- package/dist/src/components/stc/index.d.ts +0 -4
- package/dist/src/components/stc/index.d.ts.map +1 -1
- package/dist/src/components/stc/index.js +0 -4
- package/dist/src/context/source-directory.d.ts +3 -3
- package/dist/src/context/source-directory.d.ts.map +1 -1
- package/dist/src/context/source-file.d.ts +0 -4
- package/dist/src/context/source-file.d.ts.map +1 -1
- package/dist/src/debug.d.ts.map +1 -1
- package/dist/src/debug.js +1 -4
- package/dist/src/index.browser.d.ts +1 -1
- package/dist/src/index.browser.d.ts.map +1 -1
- package/dist/src/index.browser.js +2 -2
- package/dist/src/render.d.ts +2 -10
- package/dist/src/render.d.ts.map +1 -1
- package/dist/src/render.js +1 -20
- package/dist/src/scheduler.d.ts +0 -6
- package/dist/src/scheduler.d.ts.map +1 -1
- package/dist/src/scheduler.js +0 -36
- 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.d.ts +1 -1
- package/dist/src/write-output.d.ts.map +1 -1
- package/dist/src/write-output.js +21 -40
- package/dist/test/components/source-file.test.d.ts.map +1 -1
- package/dist/test/rendering/formatting.test.d.ts.map +1 -1
- package/dist/testing/extend-expect.js +54 -60
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/components/index.tsx +0 -4
- package/src/components/stc/index.ts +0 -4
- package/src/context/source-directory.ts +3 -5
- package/src/context/source-file.ts +0 -5
- package/src/debug.ts +1 -4
- package/src/index.browser.ts +1 -1
- package/src/render.ts +5 -44
- package/src/scheduler.ts +0 -39
- package/src/write-output.browser.ts +4 -0
- package/src/write-output.ts +19 -49
- package/temp/api.json +423 -1886
- package/test/components/source-file.test.tsx +2 -5
- package/test/rendering/formatting.test.tsx +3 -9
- package/testing/extend-expect.ts +58 -74
- package/testing/vitest.d.ts +0 -4
- package/dist/src/components/AppendFile.d.ts +0 -90
- package/dist/src/components/AppendFile.d.ts.map +0 -1
- package/dist/src/components/AppendFile.js +0 -226
- package/dist/src/components/CopyFile.d.ts +0 -12
- package/dist/src/components/CopyFile.d.ts.map +0 -1
- package/dist/src/components/CopyFile.js +0 -15
- package/dist/src/components/TemplateFile.d.ts +0 -84
- package/dist/src/components/TemplateFile.d.ts.map +0 -1
- package/dist/src/components/TemplateFile.js +0 -133
- package/dist/src/components/UpdateFile.d.ts +0 -34
- package/dist/src/components/UpdateFile.d.ts.map +0 -1
- package/dist/src/components/UpdateFile.js +0 -66
- package/dist/src/host/alloy-host.browser.d.ts +0 -11
- package/dist/src/host/alloy-host.browser.d.ts.map +0 -1
- package/dist/src/host/alloy-host.browser.js +0 -31
- package/dist/src/host/alloy-host.d.ts +0 -11
- package/dist/src/host/alloy-host.d.ts.map +0 -1
- package/dist/src/host/alloy-host.js +0 -143
- package/dist/src/host/interface.d.ts +0 -144
- package/dist/src/host/interface.d.ts.map +0 -1
- package/dist/src/host/interface.js +0 -1
- package/dist/src/resource.d.ts +0 -80
- package/dist/src/resource.d.ts.map +0 -1
- package/dist/src/resource.js +0 -118
- package/dist/test/components/append-file.test.d.ts +0 -2
- package/dist/test/components/append-file.test.d.ts.map +0 -1
- package/dist/test/components/append-file.test.js +0 -281
- package/dist/test/components/copy-file.test.d.ts +0 -2
- package/dist/test/components/copy-file.test.d.ts.map +0 -1
- package/dist/test/components/copy-file.test.js +0 -94
- package/dist/test/components/template-file.test.d.ts +0 -2
- package/dist/test/components/template-file.test.d.ts.map +0 -1
- package/dist/test/components/template-file.test.js +0 -133
- package/dist/test/components/update-file.test.d.ts +0 -2
- package/dist/test/components/update-file.test.d.ts.map +0 -1
- package/dist/test/components/update-file.test.js +0 -169
- package/src/components/AppendFile.tsx +0 -294
- package/src/components/CopyFile.tsx +0 -29
- package/src/components/TemplateFile.tsx +0 -193
- package/src/components/UpdateFile.tsx +0 -86
- package/src/host/alloy-host.browser.ts +0 -56
- package/src/host/alloy-host.ts +0 -160
- package/src/host/interface.ts +0 -153
- package/src/resource.ts +0 -152
- package/test/components/append-file.test.tsx +0 -275
- package/test/components/copy-file.test.tsx +0 -98
- package/test/components/template-file.test.tsx +0 -127
- package/test/components/update-file.test.tsx +0 -214
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
2
|
computed,
|
|
3
|
-
ContentOutputFile,
|
|
4
3
|
Output,
|
|
5
4
|
render,
|
|
6
5
|
renderTree,
|
|
@@ -51,9 +50,7 @@ it("has reactive context", () => {
|
|
|
51
50
|
</Output>,
|
|
52
51
|
);
|
|
53
52
|
|
|
54
|
-
expect(
|
|
55
|
-
"hi.txt contents.txt",
|
|
56
|
-
);
|
|
53
|
+
expect(tree.contents[1].contents).toEqual("hi.txt contents.txt");
|
|
57
54
|
});
|
|
58
55
|
|
|
59
56
|
it("Includes header", () => {
|
|
@@ -66,7 +63,7 @@ it("Includes header", () => {
|
|
|
66
63
|
</Output>,
|
|
67
64
|
);
|
|
68
65
|
|
|
69
|
-
expect(
|
|
66
|
+
expect(tree.contents[0].contents).toEqual(d`
|
|
70
67
|
# This is a header
|
|
71
68
|
hello!
|
|
72
69
|
`);
|
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
|
-
import {
|
|
3
|
-
ContentOutputFile,
|
|
4
|
-
For,
|
|
5
|
-
Output,
|
|
6
|
-
render,
|
|
7
|
-
SourceFile,
|
|
8
|
-
} from "../../src/index.js";
|
|
2
|
+
import { For, Output, render, SourceFile } from "../../src/index.js";
|
|
9
3
|
import "../../testing/extend-expect.js";
|
|
10
4
|
import { d } from "../../testing/render.js";
|
|
11
5
|
|
|
@@ -460,7 +454,7 @@ it("formats based on the output component props", () => {
|
|
|
460
454
|
);
|
|
461
455
|
|
|
462
456
|
const tree = render(template);
|
|
463
|
-
expect(
|
|
457
|
+
expect(tree.contents[0].contents).toEqual(d`
|
|
464
458
|
1
|
|
465
459
|
2
|
|
466
460
|
3
|
|
@@ -482,7 +476,7 @@ it("formats based on the source file component props", () => {
|
|
|
482
476
|
);
|
|
483
477
|
|
|
484
478
|
const tree = render(template);
|
|
485
|
-
expect(
|
|
479
|
+
expect(tree.contents[0].contents).toEqual(d`
|
|
486
480
|
1
|
|
487
481
|
2
|
|
488
482
|
3
|
package/testing/extend-expect.ts
CHANGED
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
} from "@alloy-js/core";
|
|
8
8
|
import "vitest";
|
|
9
9
|
import { expect } from "vitest";
|
|
10
|
-
import { flushJobs, flushJobsAsync } from "../src/scheduler.js";
|
|
11
10
|
import { dedent } from "./render.js";
|
|
12
11
|
|
|
13
12
|
interface ToRenderToOptions {
|
|
@@ -22,82 +21,67 @@ expect.extend({
|
|
|
22
21
|
expectedRaw: string | Record<string, string>,
|
|
23
22
|
renderOptions?: ToRenderToOptions,
|
|
24
23
|
) {
|
|
25
|
-
const
|
|
26
|
-
flushJobs();
|
|
27
|
-
const actual = getFilesFromTree(tree, renderOptions);
|
|
24
|
+
const message = () => `Render is${isNot ? " not" : ""} incorrect`;
|
|
28
25
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (typeof actual === "
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
26
|
+
const { isNot } = this;
|
|
27
|
+
const actual = renderAsFiles(received, renderOptions);
|
|
28
|
+
if (typeof expectedRaw === "string") {
|
|
29
|
+
const expected = dedent(expectedRaw);
|
|
30
|
+
let actualStr;
|
|
31
|
+
if (typeof actual === "string") {
|
|
32
|
+
actualStr = actual;
|
|
33
|
+
} else if (Object.keys(actual).length === 1) {
|
|
34
|
+
// If we have a single file, we can use its content directly.
|
|
35
|
+
actualStr = Object.values(actual)[0];
|
|
36
|
+
} else {
|
|
37
|
+
return {
|
|
38
|
+
pass: false,
|
|
39
|
+
message,
|
|
40
|
+
actual,
|
|
41
|
+
expected,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
pass: actualStr === expected,
|
|
46
|
+
message,
|
|
47
|
+
actual: actualStr,
|
|
48
|
+
expected,
|
|
49
|
+
};
|
|
50
|
+
} else if (typeof actual === "object" && typeof expectedRaw === "object") {
|
|
51
|
+
const expected = expectedRaw;
|
|
52
|
+
const dedentExpected: Record<string, string> = {};
|
|
53
|
+
for (const [key, value] of Object.entries(expected)) {
|
|
54
|
+
dedentExpected[key] = dedent(value);
|
|
55
|
+
}
|
|
56
|
+
const pass =
|
|
57
|
+
Object.keys(actual).length === Object.keys(expected).length &&
|
|
58
|
+
Object.entries(actual).every(([key, value]) => {
|
|
59
|
+
return dedentExpected[key] === value;
|
|
60
|
+
});
|
|
61
|
+
return {
|
|
62
|
+
pass,
|
|
63
|
+
message,
|
|
64
|
+
actual,
|
|
65
|
+
expected: dedentExpected,
|
|
66
|
+
};
|
|
58
67
|
} else {
|
|
59
68
|
return {
|
|
60
69
|
pass: false,
|
|
61
70
|
message,
|
|
62
71
|
actual,
|
|
63
|
-
expected,
|
|
72
|
+
expected: expectedRaw,
|
|
64
73
|
};
|
|
65
74
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
message,
|
|
69
|
-
actual: actualStr,
|
|
70
|
-
expected,
|
|
71
|
-
};
|
|
72
|
-
} else if (typeof actual === "object" && typeof expectedRaw === "object") {
|
|
73
|
-
const expected = expectedRaw;
|
|
74
|
-
const dedentExpected: Record<string, string> = {};
|
|
75
|
-
for (const [key, value] of Object.entries(expected)) {
|
|
76
|
-
dedentExpected[key] = dedent(value);
|
|
77
|
-
}
|
|
78
|
-
const pass =
|
|
79
|
-
Object.keys(actual).length === Object.keys(expected).length &&
|
|
80
|
-
Object.entries(actual).every(([key, value]) => {
|
|
81
|
-
return dedentExpected[key] === value;
|
|
82
|
-
});
|
|
83
|
-
return {
|
|
84
|
-
pass,
|
|
85
|
-
message,
|
|
86
|
-
actual,
|
|
87
|
-
expected: dedentExpected,
|
|
88
|
-
};
|
|
89
|
-
} else {
|
|
90
|
-
return {
|
|
91
|
-
pass: false,
|
|
92
|
-
message,
|
|
93
|
-
actual,
|
|
94
|
-
expected: expectedRaw,
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
}
|
|
75
|
+
},
|
|
76
|
+
});
|
|
98
77
|
|
|
99
|
-
function
|
|
78
|
+
function renderAsFiles(
|
|
79
|
+
received: Children,
|
|
80
|
+
options?: ToRenderToOptions,
|
|
81
|
+
): Record<string, string> | string {
|
|
100
82
|
const files: Record<string, string> = {};
|
|
83
|
+
const tree = renderTree(received);
|
|
84
|
+
|
|
101
85
|
// when passing Output, the first render tree child is the Output component.
|
|
102
86
|
const rootRenderOptions =
|
|
103
87
|
Array.isArray(tree) ?
|
|
@@ -106,13 +90,6 @@ function getFilesFromTree(tree: RenderedTextTree, options?: ToRenderToOptions) {
|
|
|
106
90
|
: {};
|
|
107
91
|
|
|
108
92
|
collectSourceFiles(tree);
|
|
109
|
-
// If we found no source files, we return the tree as a string.
|
|
110
|
-
if (Object.keys(files).length === 0) {
|
|
111
|
-
return printTree(tree, options);
|
|
112
|
-
} else {
|
|
113
|
-
return files;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
93
|
function collectSourceFiles(root: RenderedTextTree) {
|
|
117
94
|
if (!Array.isArray(root)) {
|
|
118
95
|
return;
|
|
@@ -143,4 +120,11 @@ function getFilesFromTree(tree: RenderedTextTree, options?: ToRenderToOptions) {
|
|
|
143
120
|
}
|
|
144
121
|
}
|
|
145
122
|
}
|
|
123
|
+
|
|
124
|
+
// If we found no source files, we return the tree as a string.
|
|
125
|
+
if (Object.keys(files).length === 0) {
|
|
126
|
+
return printTree(tree, options);
|
|
127
|
+
} else {
|
|
128
|
+
return files;
|
|
129
|
+
}
|
|
146
130
|
}
|
package/testing/vitest.d.ts
CHANGED
|
@@ -11,10 +11,6 @@ interface CustomMatchers<R = unknown> {
|
|
|
11
11
|
str: string | Record<string, string>,
|
|
12
12
|
options?: ToRenderToRenderOptions,
|
|
13
13
|
) => R;
|
|
14
|
-
toRenderToAsync: (
|
|
15
|
-
str: string | Record<string, string>,
|
|
16
|
-
options?: ToRenderToRenderOptions,
|
|
17
|
-
) => Promise<R>;
|
|
18
14
|
}
|
|
19
15
|
|
|
20
16
|
declare module "vitest" {
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { Children } from "../runtime/component.js";
|
|
2
|
-
export interface AppendFileProps {
|
|
3
|
-
/**
|
|
4
|
-
* The path to the file to read and append content to.
|
|
5
|
-
*/
|
|
6
|
-
path: string;
|
|
7
|
-
/**
|
|
8
|
-
* List of region IDs to append to. Defaults to ["append"] if not specified.
|
|
9
|
-
* Each region corresponds to an AppendRegion child component.
|
|
10
|
-
*/
|
|
11
|
-
regions?: string[];
|
|
12
|
-
/**
|
|
13
|
-
* AppendRegion children components that define content to append.
|
|
14
|
-
*/
|
|
15
|
-
children?: Children;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* A component that reads a file and returns content with new content appended
|
|
19
|
-
* at the end or within specific regions marked by alloy-\{region name\}-start/alloy-\{region name\}-end sigils.
|
|
20
|
-
*
|
|
21
|
-
* The component can append content in two ways:
|
|
22
|
-
* 1. **Simple append**: Content is appended to the end of the file
|
|
23
|
-
* 2. **Region-based append**: Content is appended before the end sigil on its own line
|
|
24
|
-
*
|
|
25
|
-
* Region sigils are line-based - any line containing "alloy-\{region name\}-start" or "alloy-\{region name\}-end"
|
|
26
|
-
* is considered a sigil.
|
|
27
|
-
*
|
|
28
|
-
* @example
|
|
29
|
-
* Simple append to end of file:
|
|
30
|
-
* ```tsx
|
|
31
|
-
* <AppendFile path="output.txt">
|
|
32
|
-
* <AppendRegion id="append">New content to add</AppendRegion>
|
|
33
|
-
* </AppendFile>
|
|
34
|
-
*
|
|
35
|
-
* // Returns:
|
|
36
|
-
* // Original file content
|
|
37
|
-
* // New content to add
|
|
38
|
-
* ```
|
|
39
|
-
*
|
|
40
|
-
* @example
|
|
41
|
-
* Append to specific regions:
|
|
42
|
-
* ```tsx
|
|
43
|
-
* // File content before:
|
|
44
|
-
* // Header content
|
|
45
|
-
* // <!-- alloy-main-start -->
|
|
46
|
-
* // <!-- alloy-main-end -->
|
|
47
|
-
* // Footer content
|
|
48
|
-
*
|
|
49
|
-
* <AppendFile path="template.html" regions={["main"]}>
|
|
50
|
-
* <AppendRegion id="main">New main content</AppendRegion>
|
|
51
|
-
* </AppendFile>
|
|
52
|
-
*
|
|
53
|
-
* // Returns:
|
|
54
|
-
* // Header content
|
|
55
|
-
* // <!-- alloy-main-start -->
|
|
56
|
-
* // New main content
|
|
57
|
-
* // <!-- alloy-main-end -->
|
|
58
|
-
* // Footer content
|
|
59
|
-
* ```
|
|
60
|
-
*/
|
|
61
|
-
export declare function AppendFile(props: AppendFileProps): Children;
|
|
62
|
-
export interface AppendRegionPropsWithChildren {
|
|
63
|
-
/**
|
|
64
|
-
* The ID of the region.
|
|
65
|
-
*/
|
|
66
|
-
id: string;
|
|
67
|
-
/**
|
|
68
|
-
* The content to append to the region.
|
|
69
|
-
*/
|
|
70
|
-
children: Children;
|
|
71
|
-
}
|
|
72
|
-
export interface AppendRegionPropsWithContent {
|
|
73
|
-
/**
|
|
74
|
-
* The ID of the region.
|
|
75
|
-
*/
|
|
76
|
-
id: string;
|
|
77
|
-
/**
|
|
78
|
-
* The content to append to the region.
|
|
79
|
-
*/
|
|
80
|
-
content: Children;
|
|
81
|
-
}
|
|
82
|
-
export interface AppendRegionPropsBase {
|
|
83
|
-
/**
|
|
84
|
-
* The ID of the region.
|
|
85
|
-
*/
|
|
86
|
-
id: string;
|
|
87
|
-
}
|
|
88
|
-
export type AppendRegionProps = AppendRegionPropsWithChildren | AppendRegionPropsWithContent | AppendRegionPropsBase;
|
|
89
|
-
export declare function AppendRegion(props: AppendRegionProps): void;
|
|
90
|
-
//# sourceMappingURL=AppendFile.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"AppendFile.d.ts","sourceRoot":"","sources":["../../../src/components/AppendFile.tsx"],"names":[],"mappings":"AAKA,OAAO,EAAE,QAAQ,EAAsB,MAAM,yBAAyB,CAAC;AAavE,MAAM,WAAW,eAAe;IAC9B;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAEnB;;OAEG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,QAAQ,CA0K3D;AAED,MAAM,WAAW,6BAA6B;IAC5C;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;OAEG;IACH,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,MAAM,WAAW,4BAA4B;IAC3C;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;IAEX;;OAEG;IACH,OAAO,EAAE,QAAQ,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC;;OAEG;IACH,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,MAAM,iBAAiB,GACzB,6BAA6B,GAC7B,4BAA4B,GAC5B,qBAAqB,CAAC;AAE1B,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,QAKpD"}
|
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
import { createComponent as _$createComponent } from "@alloy-js/core/jsx-runtime";
|
|
2
|
-
import { computed } from "@vue/reactivity";
|
|
3
|
-
import { join } from "pathe";
|
|
4
|
-
import { useContext } from "../context.js";
|
|
5
|
-
import { SourceDirectoryContext } from "../context/source-directory.js";
|
|
6
|
-
import { createFileResource } from "../resource.js";
|
|
7
|
-
import { isComponentCreator } from "../runtime/component.js";
|
|
8
|
-
import { childrenArray } from "../utils.js";
|
|
9
|
-
import { SourceFile } from "./SourceFile.js";
|
|
10
|
-
|
|
11
|
-
// Regular expression for finding all sigils at once
|
|
12
|
-
const SIGIL_REGEX = /^(\s*)(.*alloy-(.+)-(start|end).*)$/gm;
|
|
13
|
-
/**
|
|
14
|
-
* A component that reads a file and returns content with new content appended
|
|
15
|
-
* at the end or within specific regions marked by alloy-\{region name\}-start/alloy-\{region name\}-end sigils.
|
|
16
|
-
*
|
|
17
|
-
* The component can append content in two ways:
|
|
18
|
-
* 1. **Simple append**: Content is appended to the end of the file
|
|
19
|
-
* 2. **Region-based append**: Content is appended before the end sigil on its own line
|
|
20
|
-
*
|
|
21
|
-
* Region sigils are line-based - any line containing "alloy-\{region name\}-start" or "alloy-\{region name\}-end"
|
|
22
|
-
* is considered a sigil.
|
|
23
|
-
*
|
|
24
|
-
* @example
|
|
25
|
-
* Simple append to end of file:
|
|
26
|
-
* ```tsx
|
|
27
|
-
* <AppendFile path="output.txt">
|
|
28
|
-
* <AppendRegion id="append">New content to add</AppendRegion>
|
|
29
|
-
* </AppendFile>
|
|
30
|
-
*
|
|
31
|
-
* // Returns:
|
|
32
|
-
* // Original file content
|
|
33
|
-
* // New content to add
|
|
34
|
-
* ```
|
|
35
|
-
*
|
|
36
|
-
* @example
|
|
37
|
-
* Append to specific regions:
|
|
38
|
-
* ```tsx
|
|
39
|
-
* // File content before:
|
|
40
|
-
* // Header content
|
|
41
|
-
* // <!-- alloy-main-start -->
|
|
42
|
-
* // <!-- alloy-main-end -->
|
|
43
|
-
* // Footer content
|
|
44
|
-
*
|
|
45
|
-
* <AppendFile path="template.html" regions={["main"]}>
|
|
46
|
-
* <AppendRegion id="main">New main content</AppendRegion>
|
|
47
|
-
* </AppendFile>
|
|
48
|
-
*
|
|
49
|
-
* // Returns:
|
|
50
|
-
* // Header content
|
|
51
|
-
* // <!-- alloy-main-start -->
|
|
52
|
-
* // New main content
|
|
53
|
-
* // <!-- alloy-main-end -->
|
|
54
|
-
* // Footer content
|
|
55
|
-
* ```
|
|
56
|
-
*/
|
|
57
|
-
export function AppendFile(props) {
|
|
58
|
-
const regions = props.regions || ["append"];
|
|
59
|
-
|
|
60
|
-
// Get all children and filter for AppendRegion components
|
|
61
|
-
const children = childrenArray(() => props.children);
|
|
62
|
-
const appendRegions = {};
|
|
63
|
-
|
|
64
|
-
// Check if we have any AppendRegion components
|
|
65
|
-
let hasAppendRegions = false;
|
|
66
|
-
for (const child of children) {
|
|
67
|
-
if (isComponentCreator(child, AppendRegion)) {
|
|
68
|
-
hasAppendRegions = true;
|
|
69
|
-
const regionProps = child.props;
|
|
70
|
-
let content;
|
|
71
|
-
if ("children" in regionProps && regionProps.children !== undefined) {
|
|
72
|
-
content = regionProps.children;
|
|
73
|
-
} else if ("content" in regionProps) {
|
|
74
|
-
content = regionProps.content;
|
|
75
|
-
} else {
|
|
76
|
-
throw new Error(`AppendRegion "${regionProps.id}" must have either children or content`);
|
|
77
|
-
}
|
|
78
|
-
appendRegions[regionProps.id] = content;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// If no AppendRegion components found, treat all children as content for the default "append" region
|
|
83
|
-
if (!hasAppendRegions && children.length > 0) {
|
|
84
|
-
appendRegions["append"] = children;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// Validate that all requested regions have corresponding AppendRegion children
|
|
88
|
-
for (const regionId of regions) {
|
|
89
|
-
if (!(regionId in appendRegions)) {
|
|
90
|
-
throw new Error(`Region "${regionId}" specified but no corresponding AppendRegion child found`);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Read existing file content or start with empty string
|
|
95
|
-
const parentDirectory = useContext(SourceDirectoryContext);
|
|
96
|
-
const fullPath = join(parentDirectory ? parentDirectory.path : "", props.path);
|
|
97
|
-
const currentContents = createFileResource(fullPath);
|
|
98
|
-
const newFileContent = computed(() => {
|
|
99
|
-
if (currentContents.loading) {
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
const fileContent = currentContents.error ? "" : currentContents.data;
|
|
103
|
-
|
|
104
|
-
// Find all sigils in the file
|
|
105
|
-
const sigilInfo = {};
|
|
106
|
-
const endSigils = [];
|
|
107
|
-
|
|
108
|
-
// Reset regex and find all sigils
|
|
109
|
-
SIGIL_REGEX.lastIndex = 0;
|
|
110
|
-
let match;
|
|
111
|
-
while ((match = SIGIL_REGEX.exec(fileContent)) !== null) {
|
|
112
|
-
const indent = match[1];
|
|
113
|
-
const fullLine = match[0];
|
|
114
|
-
const regionId = match[3];
|
|
115
|
-
const sigilType = match[4];
|
|
116
|
-
const index = match.index;
|
|
117
|
-
|
|
118
|
-
// Initialize sigil info for this region if not exists
|
|
119
|
-
if (!sigilInfo[regionId]) {
|
|
120
|
-
sigilInfo[regionId] = {
|
|
121
|
-
id: regionId,
|
|
122
|
-
start: null,
|
|
123
|
-
end: null
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
if (sigilType === "start") {
|
|
127
|
-
sigilInfo[regionId].start = index;
|
|
128
|
-
} else if (sigilType === "end") {
|
|
129
|
-
sigilInfo[regionId].end = index;
|
|
130
|
-
|
|
131
|
-
// If this is a region we care about, track it for processing
|
|
132
|
-
if (regions.includes(regionId)) {
|
|
133
|
-
endSigils.push({
|
|
134
|
-
regionId,
|
|
135
|
-
index,
|
|
136
|
-
indent,
|
|
137
|
-
line: fullLine
|
|
138
|
-
});
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// Validate regions - check for unclosed regions
|
|
144
|
-
for (const regionId of regions) {
|
|
145
|
-
const info = sigilInfo[regionId];
|
|
146
|
-
if (info && info.start !== null && info.end === null) {
|
|
147
|
-
throw new Error(`Region "${regionId}" has start sigil but no corresponding end sigil`);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// Check if we have any sigils to process
|
|
152
|
-
if (endSigils.length === 0) {
|
|
153
|
-
// No sigils found, append all regions to the end
|
|
154
|
-
const result = [fileContent];
|
|
155
|
-
for (const regionId of regions) {
|
|
156
|
-
if (fileContent && !fileContent.endsWith("\n")) {
|
|
157
|
-
result.push("\n");
|
|
158
|
-
}
|
|
159
|
-
result.push(appendRegions[regionId]);
|
|
160
|
-
}
|
|
161
|
-
return _$createComponent(SourceFile, {
|
|
162
|
-
get path() {
|
|
163
|
-
return props.path;
|
|
164
|
-
},
|
|
165
|
-
filetype: "text/plain",
|
|
166
|
-
children: result
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
// Sort end sigils by their position in the file
|
|
171
|
-
endSigils.sort((a, b) => a.index - b.index);
|
|
172
|
-
|
|
173
|
-
// Process content with sigils
|
|
174
|
-
const result = [];
|
|
175
|
-
let lastIndex = 0;
|
|
176
|
-
|
|
177
|
-
// Process each end sigil in order
|
|
178
|
-
for (const {
|
|
179
|
-
regionId,
|
|
180
|
-
index,
|
|
181
|
-
indent,
|
|
182
|
-
line
|
|
183
|
-
} of endSigils) {
|
|
184
|
-
// Add content before this sigil
|
|
185
|
-
if (index > lastIndex) {
|
|
186
|
-
const beforeContent = fileContent.substring(lastIndex, index);
|
|
187
|
-
if (beforeContent) {
|
|
188
|
-
result.push(beforeContent);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
// Add the new content with proper indentation
|
|
193
|
-
result.push(indent);
|
|
194
|
-
result.push(appendRegions[regionId]);
|
|
195
|
-
result.push("\n");
|
|
196
|
-
|
|
197
|
-
// Add the sigil line
|
|
198
|
-
result.push(line);
|
|
199
|
-
|
|
200
|
-
// Update last processed index
|
|
201
|
-
lastIndex = index + line.length;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
// Add any remaining content after the last sigil
|
|
205
|
-
if (lastIndex < fileContent.length) {
|
|
206
|
-
const remainingPart = fileContent.substring(lastIndex);
|
|
207
|
-
if (remainingPart) {
|
|
208
|
-
result.push(remainingPart);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
return result;
|
|
212
|
-
});
|
|
213
|
-
return _$createComponent(SourceFile, {
|
|
214
|
-
get path() {
|
|
215
|
-
return props.path;
|
|
216
|
-
},
|
|
217
|
-
filetype: "text/plain",
|
|
218
|
-
children: newFileContent
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
export function AppendRegion(props) {
|
|
222
|
-
/**
|
|
223
|
-
* This component does nothing except hold props which are retrieved by
|
|
224
|
-
* the `AppendFile` component.
|
|
225
|
-
*/
|
|
226
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
export interface CopyFileProps {
|
|
2
|
-
/**
|
|
3
|
-
* The path to write the copy to, relative to the containing directory.
|
|
4
|
-
*/
|
|
5
|
-
path: string;
|
|
6
|
-
/**
|
|
7
|
-
* The path to the file to copy.
|
|
8
|
-
*/
|
|
9
|
-
src: string;
|
|
10
|
-
}
|
|
11
|
-
export declare function CopyFile(props: CopyFileProps): void;
|
|
12
|
-
//# sourceMappingURL=CopyFile.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"CopyFile.d.ts","sourceRoot":"","sources":["../../../src/components/CopyFile.tsx"],"names":[],"mappings":"AAMA,MAAM,WAAW,aAAa;IAC5B;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;CACb;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,aAAa,QAU5C"}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { join } from "pathe";
|
|
2
|
-
import { useContext } from "../context.js";
|
|
3
|
-
import { SourceDirectoryContext } from "../context/source-directory.js";
|
|
4
|
-
import { getContext } from "../reactivity.js";
|
|
5
|
-
export function CopyFile(props) {
|
|
6
|
-
const parentDirectory = useContext(SourceDirectoryContext);
|
|
7
|
-
const context = {
|
|
8
|
-
path: join(parentDirectory ? parentDirectory.path : "", props.path),
|
|
9
|
-
sourcePath: props.src
|
|
10
|
-
};
|
|
11
|
-
parentDirectory?.addContent(context);
|
|
12
|
-
const nodeContext = getContext();
|
|
13
|
-
nodeContext.meta ??= {};
|
|
14
|
-
nodeContext.meta.copyFile = context;
|
|
15
|
-
}
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
import { Children } from "../runtime/component.js";
|
|
2
|
-
export interface TemplateFileProps {
|
|
3
|
-
/**
|
|
4
|
-
* The path to write the compiled template to.
|
|
5
|
-
*/
|
|
6
|
-
path: string;
|
|
7
|
-
/**
|
|
8
|
-
* The file path of the template.
|
|
9
|
-
*/
|
|
10
|
-
src: string;
|
|
11
|
-
/**
|
|
12
|
-
* Template variable children components.
|
|
13
|
-
*/
|
|
14
|
-
children?: Children;
|
|
15
|
-
}
|
|
16
|
-
/**
|
|
17
|
-
* A component that reads a template file and replaces variable placeholders
|
|
18
|
-
* with actual values.
|
|
19
|
-
*
|
|
20
|
-
* Template files can contain variable placeholders in the format
|
|
21
|
-
* `{{ variable_name }}` which will be replaced with values from `TemplateVariable`
|
|
22
|
-
* children components. Whitespace around variable names is ignored, so
|
|
23
|
-
* `{{ name }}`, `{{name}}`, and `{{ name }}` are all equivalent.
|
|
24
|
-
*
|
|
25
|
-
* @example
|
|
26
|
-
* Basic usage with template variables:
|
|
27
|
-
* ```tsx
|
|
28
|
-
* // Template file content (greeting.txt):
|
|
29
|
-
* // "Hello {{ name }}! You are {{ age }} years old."
|
|
30
|
-
*
|
|
31
|
-
* <TemplateFile src="greeting.txt" path="output.txt">
|
|
32
|
-
* <TemplateVariable name="name" value="John" />
|
|
33
|
-
* <TemplateVariable name="age" value="25" />
|
|
34
|
-
* </TemplateFile>
|
|
35
|
-
* ```
|
|
36
|
-
*
|
|
37
|
-
* @example
|
|
38
|
-
* Using children instead of value prop:
|
|
39
|
-
* ```tsx
|
|
40
|
-
* // Template file content (welcome.txt):
|
|
41
|
-
* // "Welcome {{ greeting }}!"
|
|
42
|
-
*
|
|
43
|
-
* <TemplateFile src="welcome.txt" path="output.txt">
|
|
44
|
-
* <TemplateVariable name="greeting">Hello World</TemplateVariable>
|
|
45
|
-
* </TemplateFile>
|
|
46
|
-
* ```
|
|
47
|
-
*
|
|
48
|
-
* @example
|
|
49
|
-
* Complex template with multiple variables:
|
|
50
|
-
* ```tsx
|
|
51
|
-
* // Template file content (profile.txt):
|
|
52
|
-
* // "Name: {{ name }}\nAge: {{ age }}\nLocation: {{ location }}"
|
|
53
|
-
*
|
|
54
|
-
* <TemplateFile src="profile.txt" path="profile-output.txt">
|
|
55
|
-
* <TemplateVariable name="name" value="Alice" />
|
|
56
|
-
* <TemplateVariable name="age">30</TemplateVariable>
|
|
57
|
-
* <TemplateVariable name="location" value="New York" />
|
|
58
|
-
* </TemplateFile>
|
|
59
|
-
* ```
|
|
60
|
-
*/
|
|
61
|
-
export declare function TemplateFile(props: TemplateFileProps): Children;
|
|
62
|
-
export interface TemplateVariablePropsWithChildren {
|
|
63
|
-
/**
|
|
64
|
-
* The name of the variable.
|
|
65
|
-
*/
|
|
66
|
-
name: string;
|
|
67
|
-
/**
|
|
68
|
-
* The value of the variable.
|
|
69
|
-
*/
|
|
70
|
-
children: Children;
|
|
71
|
-
}
|
|
72
|
-
export interface TemplateVariablePropsWithValue {
|
|
73
|
-
/**
|
|
74
|
-
* The name of the variable.
|
|
75
|
-
*/
|
|
76
|
-
name: string;
|
|
77
|
-
/**
|
|
78
|
-
* The value of the variable.
|
|
79
|
-
*/
|
|
80
|
-
value: string;
|
|
81
|
-
}
|
|
82
|
-
export type TemplateVariableProps = TemplateVariablePropsWithChildren | TemplateVariablePropsWithValue;
|
|
83
|
-
export declare function TemplateVariable(props: TemplateVariableProps): void;
|
|
84
|
-
//# sourceMappingURL=TemplateFile.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"TemplateFile.d.ts","sourceRoot":"","sources":["../../../src/components/TemplateFile.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAsB,MAAM,yBAAyB,CAAC;AAIvE,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;IAEZ;;OAEG;IACH,QAAQ,CAAC,EAAE,QAAQ,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,iBAAiB,GAAG,QAAQ,CAyF/D;AAED,MAAM,WAAW,iCAAiC;IAChD;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,QAAQ,EAAE,QAAQ,CAAC;CACpB;AAED,MAAM,WAAW,8BAA8B;IAC7C;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,qBAAqB,GAC7B,iCAAiC,GACjC,8BAA8B,CAAC;AAEnC,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,QAK5D"}
|