@sealcode/sealgen 0.17.9 → 0.17.11
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/@types/src/builders/backend-ts-builder.d.ts +7 -0
- package/@types/src/builders/builder.d.ts +11 -0
- package/@types/src/builders/colors-builder.d.ts +10 -0
- package/@types/src/builders/css-builder.d.ts +19 -0
- package/@types/src/builders/fonts-builder.d.ts +7 -0
- package/@types/src/builders/frontend-ts-builder.d.ts +11 -0
- package/lib/build.js +7 -6
- package/lib/builders/backend-ts-builder.js +62 -0
- package/lib/builders/builder.js +23 -0
- package/lib/builders/colors-builder.js +204 -0
- package/lib/{CSSBuilder.js → builders/css-builder.js} +2 -2
- package/lib/builders/fonts-builder.js +20 -0
- package/lib/builders/frontend-ts-builder.js +43 -0
- package/lib/get-fonts.js +2 -1
- package/package.json +4 -1
- package/src/build.ts +7 -6
- package/src/builders/backend-ts-builder.ts +73 -0
- package/src/builders/builder.ts +25 -0
- package/src/builders/colors-builder.ts +216 -0
- package/src/{CSSBuilder.ts → builders/css-builder.ts} +1 -1
- package/src/builders/fonts-builder.ts +19 -0
- package/src/builders/frontend-ts-builder.ts +47 -0
- package/src/get-fonts.ts +2 -1
- package/lib/builder.js +0 -133
- package/src/builder.ts +0 -158
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare abstract class Builder {
|
|
2
|
+
project_dir: string;
|
|
3
|
+
style_dirs: string[];
|
|
4
|
+
abstract ownsFile(file_path: string): boolean;
|
|
5
|
+
abstract getName(): string;
|
|
6
|
+
abstract _build(): Promise<void>;
|
|
7
|
+
abstract dispose(): Promise<void>;
|
|
8
|
+
constructor(project_dir: string, style_dirs: string[]);
|
|
9
|
+
ongoing_build: Promise<void> | null;
|
|
10
|
+
build(notifier?: (message: string) => void): Promise<void>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Builder } from "./builder.js";
|
|
2
|
+
export declare const COLORS_TS_PATH = "src/back/colors.ts";
|
|
3
|
+
export declare const COLORS_CSS_PATH = "src/colors.css";
|
|
4
|
+
export declare const COLORS_HTML_PATH = "src/colors.html";
|
|
5
|
+
export declare class ColorsBuilder extends Builder {
|
|
6
|
+
getName(): string;
|
|
7
|
+
ownsFile(file_path: string): boolean;
|
|
8
|
+
dispose(): Promise<void>;
|
|
9
|
+
_build(): Promise<void>;
|
|
10
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Builder } from "./builder.js";
|
|
2
|
+
export declare class CSSClump {
|
|
3
|
+
project_dir: string;
|
|
4
|
+
name: string;
|
|
5
|
+
files: string[];
|
|
6
|
+
constructor(project_dir: string, name: string);
|
|
7
|
+
addFile(full_path: string): void;
|
|
8
|
+
build(): Promise<void>;
|
|
9
|
+
getEntrypointPath(): string;
|
|
10
|
+
makeEntrypoint(): Promise<void>;
|
|
11
|
+
static assignFileToClumps(file_path: string): string[];
|
|
12
|
+
static findCSSClumps(project_dir: string, style_dirs: string[]): Promise<CSSClump[]>;
|
|
13
|
+
}
|
|
14
|
+
export declare class CSSBuilder extends Builder {
|
|
15
|
+
getName(): string;
|
|
16
|
+
ownsFile(file_path: string): boolean;
|
|
17
|
+
dispose(): Promise<void>;
|
|
18
|
+
_build(): Promise<void>;
|
|
19
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Builder } from "./builder.js";
|
|
2
|
+
export declare class FrontendTSBuilder extends Builder {
|
|
3
|
+
project_dir: string;
|
|
4
|
+
style_dirs: string[];
|
|
5
|
+
controller_dirs: string[];
|
|
6
|
+
constructor(project_dir: string, style_dirs: string[], controller_dirs: string[]);
|
|
7
|
+
getName(): string;
|
|
8
|
+
ownsFile(file_path: string): boolean;
|
|
9
|
+
dispose(): Promise<void>;
|
|
10
|
+
_build(): Promise<void>;
|
|
11
|
+
}
|
package/lib/build.js
CHANGED
|
@@ -4,13 +4,12 @@ import { make_notifier } from "./notifier.js";
|
|
|
4
4
|
import getPort from "get-port";
|
|
5
5
|
import { resolve } from "node:path";
|
|
6
6
|
import _locreq from "locreq";
|
|
7
|
-
import {
|
|
8
|
-
BackendTSBuilder,
|
|
9
|
-
FontsBuilder,
|
|
10
|
-
FrontendTSBuilder
|
|
11
|
-
} from "./builder.js";
|
|
12
|
-
import { CSSBuilder } from "./CSSBuilder.js";
|
|
13
7
|
import { hasShape, predicates } from "@sealcode/ts-predicates";
|
|
8
|
+
import { FontsBuilder } from "./builders/fonts-builder.js";
|
|
9
|
+
import { BackendTSBuilder } from "./builders/backend-ts-builder.js";
|
|
10
|
+
import { FrontendTSBuilder } from "./builders/frontend-ts-builder.js";
|
|
11
|
+
import { CSSBuilder } from "./builders/css-builder.js";
|
|
12
|
+
import { ColorsBuilder } from "./builders/colors-builder.js";
|
|
14
13
|
const target_locreq = _locreq(process.cwd());
|
|
15
14
|
async function get_notifier_port() {
|
|
16
15
|
return getPort({ port: 4e3 });
|
|
@@ -77,9 +76,11 @@ async function build(watch) {
|
|
|
77
76
|
controller_dirs
|
|
78
77
|
);
|
|
79
78
|
const css_builder = new CSSBuilder(project_dir, style_dirs);
|
|
79
|
+
const colors_builder = new ColorsBuilder(project_dir, style_dirs);
|
|
80
80
|
const builders = [
|
|
81
81
|
fonts_builder,
|
|
82
82
|
backend_ts_builder,
|
|
83
|
+
colors_builder,
|
|
83
84
|
css_builder,
|
|
84
85
|
frontend_ts_builder
|
|
85
86
|
];
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import glob from "tiny-glob";
|
|
2
|
+
import { build } from "esbuild";
|
|
3
|
+
import { promises as fs } from "fs";
|
|
4
|
+
import { relative } from "node:path";
|
|
5
|
+
import { embeddable_file_extensions } from "../embeddable-file-extensions.js";
|
|
6
|
+
import { generateCollections } from "../generate-collections.js";
|
|
7
|
+
import { generateComponents } from "../generate-components.js";
|
|
8
|
+
import { generateRoutes } from "../generate-routes.js";
|
|
9
|
+
import { Builder } from "./builder.js";
|
|
10
|
+
import { rewrite_asset_imports_plugin } from "../esbuild-plugins/rewrite-asset-imports.js";
|
|
11
|
+
import { load_assets_plugin } from "../esbuild-plugins/load-assets.js";
|
|
12
|
+
class BackendTSBuilder extends Builder {
|
|
13
|
+
getName() {
|
|
14
|
+
return "backend-ts";
|
|
15
|
+
}
|
|
16
|
+
ownsFile(file_path) {
|
|
17
|
+
return (file_path.endsWith(".ts") || file_path.endsWith(".tsx")) && !file_path.endsWith("src/back/collections/collections.ts") && !file_path.endsWith("src/back/routes/routes.ts") && !file_path.endsWith("src/back/routes/urls.ts") && !file_path.endsWith("stimulus.ts") && !file_path.startsWith("src/front");
|
|
18
|
+
}
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
20
|
+
async dispose() {
|
|
21
|
+
}
|
|
22
|
+
async _build() {
|
|
23
|
+
await Promise.all([
|
|
24
|
+
generateCollections(),
|
|
25
|
+
generateRoutes(),
|
|
26
|
+
generateComponents()
|
|
27
|
+
]);
|
|
28
|
+
const entryPoints = (await glob(
|
|
29
|
+
`./src/back/**/*.{ts,tsx,${embeddable_file_extensions.join(
|
|
30
|
+
","
|
|
31
|
+
)}}`
|
|
32
|
+
)).filter((path) => !path.includes(".#"));
|
|
33
|
+
const { metafile } = await build({
|
|
34
|
+
entryPoints,
|
|
35
|
+
sourcemap: true,
|
|
36
|
+
bundle: false,
|
|
37
|
+
jsxFactory: "TempstreamJSX.createElement",
|
|
38
|
+
jsxFragment: "TempstreamJSX.Fragment",
|
|
39
|
+
outdir: "./dist/back",
|
|
40
|
+
logLevel: "info",
|
|
41
|
+
platform: "node",
|
|
42
|
+
target: "es2022",
|
|
43
|
+
format: "esm",
|
|
44
|
+
loader: Object.fromEntries(
|
|
45
|
+
embeddable_file_extensions.map((ext) => ["." + ext, "js"])
|
|
46
|
+
),
|
|
47
|
+
plugins: [
|
|
48
|
+
rewrite_asset_imports_plugin(this.project_dir),
|
|
49
|
+
load_assets_plugin
|
|
50
|
+
],
|
|
51
|
+
metafile: true
|
|
52
|
+
});
|
|
53
|
+
await fs.writeFile(
|
|
54
|
+
relative(this.project_dir, "dist") + "/back.meta.json",
|
|
55
|
+
JSON.stringify(metafile)
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
export {
|
|
60
|
+
BackendTSBuilder
|
|
61
|
+
};
|
|
62
|
+
//# sourceMappingURL=backend-ts-builder.js.map
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
class Builder {
|
|
2
|
+
constructor(project_dir, style_dirs) {
|
|
3
|
+
this.project_dir = project_dir;
|
|
4
|
+
this.style_dirs = style_dirs;
|
|
5
|
+
this.ongoing_build = null;
|
|
6
|
+
}
|
|
7
|
+
build(notifier) {
|
|
8
|
+
if (!this.ongoing_build) {
|
|
9
|
+
const build = this._build().catch((err) => {
|
|
10
|
+
console.error(err);
|
|
11
|
+
}).then(() => {
|
|
12
|
+
notifier?.(this.getName());
|
|
13
|
+
this.ongoing_build = null;
|
|
14
|
+
});
|
|
15
|
+
this.ongoing_build = build;
|
|
16
|
+
}
|
|
17
|
+
return this.ongoing_build;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export {
|
|
21
|
+
Builder
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=builder.js.map
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { build } from "esbuild";
|
|
2
|
+
import tempfile from "tempfile";
|
|
3
|
+
import { promises as fs } from "fs";
|
|
4
|
+
import { resolve } from "path";
|
|
5
|
+
import { colord } from "colord";
|
|
6
|
+
import { formatWithPrettier } from "../utils/prettier.js";
|
|
7
|
+
import { Builder } from "./builder.js";
|
|
8
|
+
import { exec } from "../utils/exec.js";
|
|
9
|
+
const COLORS_TS_PATH = "src/back/colors.ts";
|
|
10
|
+
const COLORS_CSS_PATH = "src/colors.css";
|
|
11
|
+
const COLORS_HTML_PATH = "src/colors.html";
|
|
12
|
+
class ColorsBuilder extends Builder {
|
|
13
|
+
getName() {
|
|
14
|
+
return "colors";
|
|
15
|
+
}
|
|
16
|
+
ownsFile(file_path) {
|
|
17
|
+
return file_path == COLORS_TS_PATH;
|
|
18
|
+
}
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
20
|
+
async dispose() {
|
|
21
|
+
}
|
|
22
|
+
async _build() {
|
|
23
|
+
const outfile = tempfile({ extension: "mjs" });
|
|
24
|
+
await build({
|
|
25
|
+
entryPoints: [COLORS_TS_PATH],
|
|
26
|
+
bundle: true,
|
|
27
|
+
format: "esm",
|
|
28
|
+
outfile
|
|
29
|
+
});
|
|
30
|
+
await fs.appendFile(outfile, "console.log(JSON.stringify(colors))");
|
|
31
|
+
const output = await exec("node", [outfile]);
|
|
32
|
+
const colors = JSON.parse(output.stdout);
|
|
33
|
+
let css_colors = "";
|
|
34
|
+
let html_colors = "";
|
|
35
|
+
for (const group_name of Object.keys(colors).sort(
|
|
36
|
+
(key) => key == "basic" ? 1 : -1
|
|
37
|
+
)) {
|
|
38
|
+
const sorted_colors = Object.entries(colors[group_name]).sort(
|
|
39
|
+
([key1], [key2]) => key1 > key2 ? 1 : -1
|
|
40
|
+
);
|
|
41
|
+
html_colors += `<h2>${group_name}</h2><div class="group"><div class="base">`;
|
|
42
|
+
let last_color_name_base = "";
|
|
43
|
+
for (const [color_name, color] of sorted_colors) {
|
|
44
|
+
const color_name_elements = color_name.split("-");
|
|
45
|
+
const color_name_base = color_name_elements.filter((s) => !/^(light|dark)[0-9]$/.test(s)).join("-");
|
|
46
|
+
let index = 0;
|
|
47
|
+
const modifier = color_name_elements.at(-1);
|
|
48
|
+
let multiplier = 1;
|
|
49
|
+
let steps = 0;
|
|
50
|
+
if (modifier) {
|
|
51
|
+
if (modifier.startsWith("dark")) {
|
|
52
|
+
multiplier = -1;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (modifier && modifier.match(/[0-9]$/) && modifier.match(/^(dark|light)[0-9]/)) {
|
|
56
|
+
steps = parseInt(modifier.at(-1));
|
|
57
|
+
}
|
|
58
|
+
index = multiplier * steps;
|
|
59
|
+
const is_new_base = color_name_base != last_color_name_base;
|
|
60
|
+
css_colors += `--color-${group_name}-${color_name}: ${color};`;
|
|
61
|
+
if (is_new_base) {
|
|
62
|
+
html_colors += `</div><h3>${color_name_base}</h3><div class="base" base="${color_name_base}">`;
|
|
63
|
+
}
|
|
64
|
+
if (color != "#000000" && color != "#ffffff") {
|
|
65
|
+
html_colors += /* HTML */
|
|
66
|
+
`<div
|
|
67
|
+
class="color-box ${colord(color).isDark() ? "is-dark" : ""} ${index == 0 ? "is-main" : ""}"
|
|
68
|
+
style="background-color: ${color}; order: ${index}"
|
|
69
|
+
data-color-name="${color_name}"
|
|
70
|
+
data-color-group="${group_name}"
|
|
71
|
+
></div>`;
|
|
72
|
+
}
|
|
73
|
+
last_color_name_base = color_name_base;
|
|
74
|
+
}
|
|
75
|
+
html_colors += "</div></div>";
|
|
76
|
+
}
|
|
77
|
+
const css = await formatWithPrettier(
|
|
78
|
+
`/* DO NOT EDIT! This file is automatically generated by sealgen */
|
|
79
|
+
:root {
|
|
80
|
+
${css_colors}
|
|
81
|
+
}`,
|
|
82
|
+
"css"
|
|
83
|
+
);
|
|
84
|
+
const html = await formatWithPrettier(
|
|
85
|
+
/* HTML */
|
|
86
|
+
`<!DOCTYPE html>
|
|
87
|
+
<html>
|
|
88
|
+
<head>
|
|
89
|
+
<style>
|
|
90
|
+
* {
|
|
91
|
+
font-family: sans-serif;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.base {
|
|
95
|
+
display: flex;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.color-box {
|
|
99
|
+
width: 100px;
|
|
100
|
+
height: 100px;
|
|
101
|
+
transition: all 50ms;
|
|
102
|
+
transition-timing-function: ease-in-out;
|
|
103
|
+
cursor: pointer;
|
|
104
|
+
|
|
105
|
+
&:hover {
|
|
106
|
+
transform: scale(1.1);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
&.is-main {
|
|
110
|
+
height: 116px;
|
|
111
|
+
width: 116px;
|
|
112
|
+
margin-top: -8px;
|
|
113
|
+
box-shadow: 0px 0px 6px 2px white;
|
|
114
|
+
z-index: 1;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.color-box:after {
|
|
119
|
+
content: attr(data-color-name);
|
|
120
|
+
display: block;
|
|
121
|
+
color: black;
|
|
122
|
+
font-size: 14px;
|
|
123
|
+
width: 100%;
|
|
124
|
+
height: 100%;
|
|
125
|
+
padding: 10px;
|
|
126
|
+
opacity: 0.3;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.color-box.is-dark:after {
|
|
130
|
+
color: white;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
@keyframes float-up {
|
|
134
|
+
from {
|
|
135
|
+
transform: translateY(0);
|
|
136
|
+
opacity: 1;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
to {
|
|
140
|
+
transform: translateY(-20px);
|
|
141
|
+
opacity: 0;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
.toast {
|
|
146
|
+
background-color: black;
|
|
147
|
+
position: absolute;
|
|
148
|
+
color: white;
|
|
149
|
+
border-radius: 8px;
|
|
150
|
+
padding: 8px;
|
|
151
|
+
animation: float-up 800ms;
|
|
152
|
+
animation-timing-function: ease-out;
|
|
153
|
+
z-index: 2;
|
|
154
|
+
}
|
|
155
|
+
</style>
|
|
156
|
+
</head>
|
|
157
|
+
<body>
|
|
158
|
+
${html_colors}
|
|
159
|
+
</body>
|
|
160
|
+
<script>
|
|
161
|
+
document.addEventListener("click", (event) => {
|
|
162
|
+
navigator.clipboard.writeText(
|
|
163
|
+
\`var(--color-\${event.target.getAttribute(
|
|
164
|
+
"data-color-group"
|
|
165
|
+
)}-\${event.target.getAttribute(
|
|
166
|
+
"data-color-name"
|
|
167
|
+
)})\`
|
|
168
|
+
);
|
|
169
|
+
const toast = document.createElement("div");
|
|
170
|
+
document.body.appendChild(toast);
|
|
171
|
+
toast.classList.add("toast");
|
|
172
|
+
toast.textContent = "Copied!";
|
|
173
|
+
toast.style.setProperty(
|
|
174
|
+
"top",
|
|
175
|
+
event.clientY +
|
|
176
|
+
document.scrollingElement.scrollTop -
|
|
177
|
+
40 +
|
|
178
|
+
"px"
|
|
179
|
+
);
|
|
180
|
+
toast.style.setProperty(
|
|
181
|
+
"left",
|
|
182
|
+
event.clientX + "px"
|
|
183
|
+
);
|
|
184
|
+
toast.addEventListener("animationend", () => {
|
|
185
|
+
toast.remove();
|
|
186
|
+
});
|
|
187
|
+
});
|
|
188
|
+
</script>
|
|
189
|
+
</html>`,
|
|
190
|
+
"html"
|
|
191
|
+
);
|
|
192
|
+
await Promise.all([
|
|
193
|
+
fs.writeFile(resolve(this.project_dir, COLORS_CSS_PATH), css),
|
|
194
|
+
fs.writeFile(resolve(this.project_dir, COLORS_HTML_PATH), html)
|
|
195
|
+
]);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
export {
|
|
199
|
+
COLORS_CSS_PATH,
|
|
200
|
+
COLORS_HTML_PATH,
|
|
201
|
+
COLORS_TS_PATH,
|
|
202
|
+
ColorsBuilder
|
|
203
|
+
};
|
|
204
|
+
//# sourceMappingURL=colors-builder.js.map
|
|
@@ -2,7 +2,7 @@ import { build } from "esbuild";
|
|
|
2
2
|
import { resolve, relative, basename, dirname } from "node:path";
|
|
3
3
|
import glob from "tiny-glob";
|
|
4
4
|
import { promises as fs } from "fs";
|
|
5
|
-
import { walkDir } from "
|
|
5
|
+
import { walkDir } from "../utils/walk.js";
|
|
6
6
|
import { Builder } from "./builder.js";
|
|
7
7
|
class CSSClump {
|
|
8
8
|
constructor(project_dir, name) {
|
|
@@ -140,4 +140,4 @@ export {
|
|
|
140
140
|
CSSBuilder,
|
|
141
141
|
CSSClump
|
|
142
142
|
};
|
|
143
|
-
//# sourceMappingURL=
|
|
143
|
+
//# sourceMappingURL=css-builder.js.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Builder } from "./builder.js";
|
|
2
|
+
import { FONTS_CONFIG_PATH, getFonts } from "../get-fonts.js";
|
|
3
|
+
class FontsBuilder extends Builder {
|
|
4
|
+
getName() {
|
|
5
|
+
return "fonts";
|
|
6
|
+
}
|
|
7
|
+
ownsFile(file_path) {
|
|
8
|
+
return file_path == FONTS_CONFIG_PATH;
|
|
9
|
+
}
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
11
|
+
async dispose() {
|
|
12
|
+
}
|
|
13
|
+
async _build() {
|
|
14
|
+
return getFonts();
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export {
|
|
18
|
+
FontsBuilder
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=fonts-builder.js.map
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { generateStimulusControllers } from "../generate-stimulus.js";
|
|
2
|
+
import { promises as fs } from "fs";
|
|
3
|
+
import { build } from "esbuild";
|
|
4
|
+
import { Builder } from "./builder.js";
|
|
5
|
+
import { relative } from "node:path";
|
|
6
|
+
class FrontendTSBuilder extends Builder {
|
|
7
|
+
constructor(project_dir, style_dirs, controller_dirs) {
|
|
8
|
+
super(project_dir, style_dirs);
|
|
9
|
+
this.project_dir = project_dir;
|
|
10
|
+
this.style_dirs = style_dirs;
|
|
11
|
+
this.controller_dirs = controller_dirs;
|
|
12
|
+
}
|
|
13
|
+
getName() {
|
|
14
|
+
return "frontend-ts";
|
|
15
|
+
}
|
|
16
|
+
ownsFile(file_path) {
|
|
17
|
+
return file_path.startsWith("src/front") || file_path.endsWith(".stimulus.ts");
|
|
18
|
+
}
|
|
19
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
20
|
+
async dispose() {
|
|
21
|
+
}
|
|
22
|
+
async _build() {
|
|
23
|
+
await generateStimulusControllers(this.controller_dirs);
|
|
24
|
+
const { metafile } = await build({
|
|
25
|
+
entryPoints: ["./src/front/index.ts"],
|
|
26
|
+
sourcemap: true,
|
|
27
|
+
outfile: "./public/dist/bundle.js",
|
|
28
|
+
logLevel: "info",
|
|
29
|
+
bundle: true,
|
|
30
|
+
minify: true,
|
|
31
|
+
metafile: true,
|
|
32
|
+
treeShaking: true
|
|
33
|
+
});
|
|
34
|
+
await fs.writeFile(
|
|
35
|
+
relative(this.project_dir, "dist") + "/front.meta.json",
|
|
36
|
+
JSON.stringify(metafile)
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export {
|
|
41
|
+
FrontendTSBuilder
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=frontend-ts-builder.js.map
|
package/lib/get-fonts.js
CHANGED
|
@@ -2,10 +2,11 @@ import { readFile, writeFile } from "fs/promises";
|
|
|
2
2
|
import { constructURL, download } from "google-fonts-helper";
|
|
3
3
|
import { resolve } from "node:path";
|
|
4
4
|
import { target_locreq } from "./target-locreq.js";
|
|
5
|
+
import JSON5 from "json5";
|
|
5
6
|
const FONTS_CONFIG_PATH = "src/fonts.json";
|
|
6
7
|
async function getFonts(_ = {}) {
|
|
7
8
|
const fonts_config_path = target_locreq.resolve(FONTS_CONFIG_PATH);
|
|
8
|
-
const fonts_config =
|
|
9
|
+
const fonts_config = JSON5.parse(await readFile(fonts_config_path, "utf8"));
|
|
9
10
|
const fonts_url = constructURL(fonts_config.googleFonts);
|
|
10
11
|
if (!fonts_url) {
|
|
11
12
|
throw new Error("Invalid font config");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sealcode/sealgen",
|
|
3
|
-
"version": "0.17.
|
|
3
|
+
"version": "0.17.11",
|
|
4
4
|
"description": "Module to automate adding routes and collections to a sealious application",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -63,18 +63,21 @@
|
|
|
63
63
|
"@sealcode/file-manager": "^1.0.2",
|
|
64
64
|
"@sealcode/ts-predicates": "^0.4.3",
|
|
65
65
|
"chokidar": "^3.6.0",
|
|
66
|
+
"colord": "^2.9.3",
|
|
66
67
|
"deepmerge": "^4.3.1",
|
|
67
68
|
"esbuild": "^0.20.0",
|
|
68
69
|
"escape-goat": "^4.0.0",
|
|
69
70
|
"google-fonts-helper": "^3.4.1",
|
|
70
71
|
"is-what": "^4.1.16",
|
|
71
72
|
"js-convert-case": "^4.2.0",
|
|
73
|
+
"json5": "^2.2.3",
|
|
72
74
|
"locreq": "^3.0.0",
|
|
73
75
|
"md5": "^2.3.0",
|
|
74
76
|
"merge": "^2.1.1",
|
|
75
77
|
"prettier": "^2.7.1",
|
|
76
78
|
"prompts": "^2.4.2",
|
|
77
79
|
"recursive-readdir": "^2.2.3",
|
|
80
|
+
"tempfile": "^5.0.0",
|
|
78
81
|
"tempstream": "^0.4.4",
|
|
79
82
|
"tiny-glob": "^0.2.9",
|
|
80
83
|
"ws": "^8.16.0",
|
package/src/build.ts
CHANGED
|
@@ -6,13 +6,12 @@ import { resolve } from "node:path";
|
|
|
6
6
|
|
|
7
7
|
import _locreq from "locreq";
|
|
8
8
|
|
|
9
|
-
import {
|
|
10
|
-
BackendTSBuilder,
|
|
11
|
-
FontsBuilder,
|
|
12
|
-
FrontendTSBuilder,
|
|
13
|
-
} from "./builder.js";
|
|
14
|
-
import { CSSBuilder } from "./CSSBuilder.js";
|
|
15
9
|
import { hasShape, predicates } from "@sealcode/ts-predicates";
|
|
10
|
+
import { FontsBuilder } from "./builders/fonts-builder.js";
|
|
11
|
+
import { BackendTSBuilder } from "./builders/backend-ts-builder.js";
|
|
12
|
+
import { FrontendTSBuilder } from "./builders/frontend-ts-builder.js";
|
|
13
|
+
import { CSSBuilder } from "./builders/css-builder.js";
|
|
14
|
+
import { ColorsBuilder } from "./builders/colors-builder.js";
|
|
16
15
|
const target_locreq = _locreq(process.cwd());
|
|
17
16
|
|
|
18
17
|
async function get_notifier_port() {
|
|
@@ -85,9 +84,11 @@ async function build(watch: boolean): Promise<void> {
|
|
|
85
84
|
controller_dirs
|
|
86
85
|
);
|
|
87
86
|
const css_builder = new CSSBuilder(project_dir, style_dirs);
|
|
87
|
+
const colors_builder = new ColorsBuilder(project_dir, style_dirs);
|
|
88
88
|
const builders = [
|
|
89
89
|
fonts_builder,
|
|
90
90
|
backend_ts_builder,
|
|
91
|
+
colors_builder,
|
|
91
92
|
css_builder,
|
|
92
93
|
frontend_ts_builder,
|
|
93
94
|
];
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import glob from "tiny-glob";
|
|
2
|
+
import { build } from "esbuild";
|
|
3
|
+
import { promises as fs } from "fs";
|
|
4
|
+
import { relative } from "node:path";
|
|
5
|
+
|
|
6
|
+
import { embeddable_file_extensions } from "../embeddable-file-extensions.js";
|
|
7
|
+
import { generateCollections } from "../generate-collections.js";
|
|
8
|
+
import { generateComponents } from "../generate-components.js";
|
|
9
|
+
import { generateRoutes } from "../generate-routes.js";
|
|
10
|
+
import { Builder } from "./builder.js";
|
|
11
|
+
import { rewrite_asset_imports_plugin } from "../esbuild-plugins/rewrite-asset-imports.js";
|
|
12
|
+
import { load_assets_plugin } from "../esbuild-plugins/load-assets.js";
|
|
13
|
+
|
|
14
|
+
export class BackendTSBuilder extends Builder {
|
|
15
|
+
getName(): string {
|
|
16
|
+
return "backend-ts";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
ownsFile(file_path: string) {
|
|
20
|
+
return (
|
|
21
|
+
(file_path.endsWith(".ts") || file_path.endsWith(".tsx")) &&
|
|
22
|
+
!file_path.endsWith("src/back/collections/collections.ts") &&
|
|
23
|
+
!file_path.endsWith("src/back/routes/routes.ts") &&
|
|
24
|
+
!file_path.endsWith("src/back/routes/urls.ts") &&
|
|
25
|
+
!file_path.endsWith("stimulus.ts") &&
|
|
26
|
+
!file_path.startsWith("src/front")
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
31
|
+
async dispose(): Promise<void> {}
|
|
32
|
+
|
|
33
|
+
async _build(): Promise<void> {
|
|
34
|
+
await Promise.all([
|
|
35
|
+
generateCollections(),
|
|
36
|
+
generateRoutes(),
|
|
37
|
+
generateComponents(),
|
|
38
|
+
]);
|
|
39
|
+
const entryPoints = (
|
|
40
|
+
await glob(
|
|
41
|
+
`./src/back/**/*.{ts,tsx,${embeddable_file_extensions.join(
|
|
42
|
+
","
|
|
43
|
+
)}}`
|
|
44
|
+
)
|
|
45
|
+
).filter((path) => !path.includes(".#"));
|
|
46
|
+
|
|
47
|
+
const { metafile } = await build({
|
|
48
|
+
entryPoints,
|
|
49
|
+
sourcemap: true,
|
|
50
|
+
bundle: false,
|
|
51
|
+
jsxFactory: "TempstreamJSX.createElement",
|
|
52
|
+
jsxFragment: "TempstreamJSX.Fragment",
|
|
53
|
+
outdir: "./dist/back",
|
|
54
|
+
logLevel: "info",
|
|
55
|
+
platform: "node",
|
|
56
|
+
target: "es2022",
|
|
57
|
+
format: "esm",
|
|
58
|
+
loader: Object.fromEntries(
|
|
59
|
+
embeddable_file_extensions.map((ext) => ["." + ext, "js"])
|
|
60
|
+
),
|
|
61
|
+
plugins: [
|
|
62
|
+
rewrite_asset_imports_plugin(this.project_dir),
|
|
63
|
+
load_assets_plugin,
|
|
64
|
+
],
|
|
65
|
+
metafile: true,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
await fs.writeFile(
|
|
69
|
+
relative(this.project_dir, "dist") + "/" + "back" + ".meta.json",
|
|
70
|
+
JSON.stringify(metafile)
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export abstract class Builder {
|
|
2
|
+
abstract ownsFile(file_path: string): boolean;
|
|
3
|
+
abstract getName(): string;
|
|
4
|
+
abstract _build(): Promise<void>;
|
|
5
|
+
abstract dispose(): Promise<void>;
|
|
6
|
+
|
|
7
|
+
constructor(public project_dir: string, public style_dirs: string[]) {}
|
|
8
|
+
|
|
9
|
+
public ongoing_build: Promise<void> | null = null;
|
|
10
|
+
|
|
11
|
+
public build(notifier?: (message: string) => void) {
|
|
12
|
+
if (!this.ongoing_build) {
|
|
13
|
+
const build = this._build()
|
|
14
|
+
.catch((err) => {
|
|
15
|
+
console.error(err);
|
|
16
|
+
})
|
|
17
|
+
.then(() => {
|
|
18
|
+
notifier?.(this.getName());
|
|
19
|
+
this.ongoing_build = null;
|
|
20
|
+
});
|
|
21
|
+
this.ongoing_build = build;
|
|
22
|
+
}
|
|
23
|
+
return this.ongoing_build;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-non-null-assertion */
|
|
2
|
+
import { build } from "esbuild";
|
|
3
|
+
import tempfile from "tempfile";
|
|
4
|
+
import { promises as fs } from "fs";
|
|
5
|
+
import { resolve } from "path";
|
|
6
|
+
import { colord } from "colord";
|
|
7
|
+
|
|
8
|
+
import { formatWithPrettier } from "../utils/prettier.js";
|
|
9
|
+
|
|
10
|
+
import { Builder } from "./builder.js";
|
|
11
|
+
import { exec } from "../utils/exec.js";
|
|
12
|
+
|
|
13
|
+
export const COLORS_TS_PATH = "src/back/colors.ts"; // keeping it in src/back instead of just src to make typescript hints work there
|
|
14
|
+
export const COLORS_CSS_PATH = "src/colors.css";
|
|
15
|
+
export const COLORS_HTML_PATH = "src/colors.html";
|
|
16
|
+
|
|
17
|
+
export class ColorsBuilder extends Builder {
|
|
18
|
+
getName(): string {
|
|
19
|
+
return "colors";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
ownsFile(file_path: string) {
|
|
23
|
+
return file_path == COLORS_TS_PATH;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
27
|
+
async dispose(): Promise<void> {}
|
|
28
|
+
|
|
29
|
+
async _build() {
|
|
30
|
+
const outfile = tempfile({ extension: "mjs" });
|
|
31
|
+
await build({
|
|
32
|
+
entryPoints: [COLORS_TS_PATH],
|
|
33
|
+
bundle: true,
|
|
34
|
+
format: "esm",
|
|
35
|
+
outfile,
|
|
36
|
+
});
|
|
37
|
+
await fs.appendFile(outfile, "console.log(JSON.stringify(colors))");
|
|
38
|
+
const output = await exec("node", [outfile]);
|
|
39
|
+
const colors = JSON.parse(output.stdout) as Record<
|
|
40
|
+
string,
|
|
41
|
+
Record<string, string>
|
|
42
|
+
>;
|
|
43
|
+
|
|
44
|
+
let css_colors = "";
|
|
45
|
+
let html_colors = "";
|
|
46
|
+
for (const group_name of Object.keys(colors).sort((key) =>
|
|
47
|
+
key == "basic" ? 1 : -1
|
|
48
|
+
)) {
|
|
49
|
+
const sorted_colors = Object.entries(colors[group_name]).sort(
|
|
50
|
+
([key1], [key2]) => (key1 > key2 ? 1 : -1)
|
|
51
|
+
);
|
|
52
|
+
html_colors += `<h2>${group_name}</h2><div class="group"><div class="base">`;
|
|
53
|
+
let last_color_name_base = "";
|
|
54
|
+
for (const [color_name, color] of sorted_colors) {
|
|
55
|
+
const color_name_elements = color_name.split("-");
|
|
56
|
+
const color_name_base = color_name_elements
|
|
57
|
+
.filter((s) => !/^(light|dark)[0-9]$/.test(s))
|
|
58
|
+
.join("-");
|
|
59
|
+
let index = 0;
|
|
60
|
+
const modifier = color_name_elements.at(-1);
|
|
61
|
+
let multiplier = 1;
|
|
62
|
+
let steps = 0;
|
|
63
|
+
if (modifier) {
|
|
64
|
+
if (modifier.startsWith("dark")) {
|
|
65
|
+
multiplier = -1;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (
|
|
69
|
+
modifier &&
|
|
70
|
+
modifier.match(/[0-9]$/) &&
|
|
71
|
+
modifier.match(/^(dark|light)[0-9]/)
|
|
72
|
+
) {
|
|
73
|
+
steps = parseInt(modifier.at(-1)!);
|
|
74
|
+
}
|
|
75
|
+
index = multiplier * steps;
|
|
76
|
+
const is_new_base = color_name_base != last_color_name_base;
|
|
77
|
+
css_colors += `--color-${group_name}-${color_name}: ${color};`;
|
|
78
|
+
if (is_new_base) {
|
|
79
|
+
html_colors += `</div><h3>${color_name_base}</h3><div class="base" base="${color_name_base}">`;
|
|
80
|
+
}
|
|
81
|
+
if (color != "#000000" && color != "#ffffff") {
|
|
82
|
+
html_colors += /* HTML */ `<div
|
|
83
|
+
class="color-box ${colord(color).isDark()
|
|
84
|
+
? "is-dark"
|
|
85
|
+
: ""} ${index == 0 ? "is-main" : ""}"
|
|
86
|
+
style="background-color: ${color}; order: ${index}"
|
|
87
|
+
data-color-name="${color_name}"
|
|
88
|
+
data-color-group="${group_name}"
|
|
89
|
+
></div>`;
|
|
90
|
+
}
|
|
91
|
+
last_color_name_base = color_name_base;
|
|
92
|
+
}
|
|
93
|
+
html_colors += "</div></div>"; // close group and base
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const css = await formatWithPrettier(
|
|
97
|
+
`/* DO NOT EDIT! This file is automatically generated by sealgen */
|
|
98
|
+
:root {
|
|
99
|
+
${css_colors}
|
|
100
|
+
}`,
|
|
101
|
+
"css"
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
const html = await formatWithPrettier(
|
|
105
|
+
/* HTML */ `<!DOCTYPE html>
|
|
106
|
+
<html>
|
|
107
|
+
<head>
|
|
108
|
+
<style>
|
|
109
|
+
* {
|
|
110
|
+
font-family: sans-serif;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.base {
|
|
114
|
+
display: flex;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.color-box {
|
|
118
|
+
width: 100px;
|
|
119
|
+
height: 100px;
|
|
120
|
+
transition: all 50ms;
|
|
121
|
+
transition-timing-function: ease-in-out;
|
|
122
|
+
cursor: pointer;
|
|
123
|
+
|
|
124
|
+
&:hover {
|
|
125
|
+
transform: scale(1.1);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
&.is-main {
|
|
129
|
+
height: 116px;
|
|
130
|
+
width: 116px;
|
|
131
|
+
margin-top: -8px;
|
|
132
|
+
box-shadow: 0px 0px 6px 2px white;
|
|
133
|
+
z-index: 1;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.color-box:after {
|
|
138
|
+
content: attr(data-color-name);
|
|
139
|
+
display: block;
|
|
140
|
+
color: black;
|
|
141
|
+
font-size: 14px;
|
|
142
|
+
width: 100%;
|
|
143
|
+
height: 100%;
|
|
144
|
+
padding: 10px;
|
|
145
|
+
opacity: 0.3;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.color-box.is-dark:after {
|
|
149
|
+
color: white;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
@keyframes float-up {
|
|
153
|
+
from {
|
|
154
|
+
transform: translateY(0);
|
|
155
|
+
opacity: 1;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
to {
|
|
159
|
+
transform: translateY(-20px);
|
|
160
|
+
opacity: 0;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.toast {
|
|
165
|
+
background-color: black;
|
|
166
|
+
position: absolute;
|
|
167
|
+
color: white;
|
|
168
|
+
border-radius: 8px;
|
|
169
|
+
padding: 8px;
|
|
170
|
+
animation: float-up 800ms;
|
|
171
|
+
animation-timing-function: ease-out;
|
|
172
|
+
z-index: 2;
|
|
173
|
+
}
|
|
174
|
+
</style>
|
|
175
|
+
</head>
|
|
176
|
+
<body>
|
|
177
|
+
${html_colors}
|
|
178
|
+
</body>
|
|
179
|
+
<script>
|
|
180
|
+
document.addEventListener("click", (event) => {
|
|
181
|
+
navigator.clipboard.writeText(
|
|
182
|
+
\`var(--color-\${event.target.getAttribute(
|
|
183
|
+
"data-color-group"
|
|
184
|
+
)}-\${event.target.getAttribute(
|
|
185
|
+
"data-color-name"
|
|
186
|
+
)})\`
|
|
187
|
+
);
|
|
188
|
+
const toast = document.createElement("div");
|
|
189
|
+
document.body.appendChild(toast);
|
|
190
|
+
toast.classList.add("toast");
|
|
191
|
+
toast.textContent = "Copied!";
|
|
192
|
+
toast.style.setProperty(
|
|
193
|
+
"top",
|
|
194
|
+
event.clientY +
|
|
195
|
+
document.scrollingElement.scrollTop -
|
|
196
|
+
40 +
|
|
197
|
+
"px"
|
|
198
|
+
);
|
|
199
|
+
toast.style.setProperty(
|
|
200
|
+
"left",
|
|
201
|
+
event.clientX + "px"
|
|
202
|
+
);
|
|
203
|
+
toast.addEventListener("animationend", () => {
|
|
204
|
+
toast.remove();
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
</script>
|
|
208
|
+
</html>`,
|
|
209
|
+
"html"
|
|
210
|
+
);
|
|
211
|
+
await Promise.all([
|
|
212
|
+
fs.writeFile(resolve(this.project_dir, COLORS_CSS_PATH), css),
|
|
213
|
+
fs.writeFile(resolve(this.project_dir, COLORS_HTML_PATH), html),
|
|
214
|
+
]);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
@@ -2,7 +2,7 @@ import { build } from "esbuild";
|
|
|
2
2
|
import { resolve, relative, basename, dirname } from "node:path";
|
|
3
3
|
import glob from "tiny-glob";
|
|
4
4
|
import { promises as fs } from "fs";
|
|
5
|
-
import { walkDir } from "
|
|
5
|
+
import { walkDir } from "../utils/walk.js";
|
|
6
6
|
import { Builder } from "./builder.js";
|
|
7
7
|
|
|
8
8
|
export class CSSClump {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Builder } from "./builder.js";
|
|
2
|
+
import { FONTS_CONFIG_PATH, getFonts } from "../get-fonts.js";
|
|
3
|
+
|
|
4
|
+
export class FontsBuilder extends Builder {
|
|
5
|
+
getName(): string {
|
|
6
|
+
return "fonts";
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
ownsFile(file_path: string) {
|
|
10
|
+
return file_path == FONTS_CONFIG_PATH;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
14
|
+
async dispose(): Promise<void> {}
|
|
15
|
+
|
|
16
|
+
async _build() {
|
|
17
|
+
return getFonts();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { generateStimulusControllers } from "../generate-stimulus.js";
|
|
2
|
+
import { promises as fs } from "fs";
|
|
3
|
+
import { build } from "esbuild";
|
|
4
|
+
import { Builder } from "./builder.js";
|
|
5
|
+
import { relative } from "node:path";
|
|
6
|
+
|
|
7
|
+
export class FrontendTSBuilder extends Builder {
|
|
8
|
+
constructor(
|
|
9
|
+
public project_dir: string,
|
|
10
|
+
public style_dirs: string[],
|
|
11
|
+
public controller_dirs: string[]
|
|
12
|
+
) {
|
|
13
|
+
super(project_dir, style_dirs);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
getName(): string {
|
|
17
|
+
return "frontend-ts";
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
ownsFile(file_path: string) {
|
|
21
|
+
return (
|
|
22
|
+
file_path.startsWith("src/front") ||
|
|
23
|
+
file_path.endsWith(".stimulus.ts")
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
28
|
+
async dispose(): Promise<void> {}
|
|
29
|
+
|
|
30
|
+
async _build(): Promise<void> {
|
|
31
|
+
await generateStimulusControllers(this.controller_dirs);
|
|
32
|
+
const { metafile } = await build({
|
|
33
|
+
entryPoints: ["./src/front/index.ts"],
|
|
34
|
+
sourcemap: true,
|
|
35
|
+
outfile: "./public/dist/bundle.js",
|
|
36
|
+
logLevel: "info",
|
|
37
|
+
bundle: true,
|
|
38
|
+
minify: true,
|
|
39
|
+
metafile: true,
|
|
40
|
+
treeShaking: true,
|
|
41
|
+
});
|
|
42
|
+
await fs.writeFile(
|
|
43
|
+
relative(this.project_dir, "dist") + "/" + "front" + ".meta.json",
|
|
44
|
+
JSON.stringify(metafile)
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
}
|
package/src/get-fonts.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { readFile, writeFile } from "fs/promises";
|
|
|
2
2
|
import { constructURL, download } from "google-fonts-helper";
|
|
3
3
|
import { resolve } from "node:path";
|
|
4
4
|
import { target_locreq } from "./target-locreq.js";
|
|
5
|
+
import JSON5 from "json5";
|
|
5
6
|
|
|
6
7
|
export const FONTS_CONFIG_PATH = "src/fonts.json";
|
|
7
8
|
|
|
@@ -9,7 +10,7 @@ export async function getFonts(_: Record<string, string | boolean> = {}) {
|
|
|
9
10
|
const fonts_config_path = target_locreq.resolve(FONTS_CONFIG_PATH);
|
|
10
11
|
|
|
11
12
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
12
|
-
const fonts_config =
|
|
13
|
+
const fonts_config = JSON5.parse(await readFile(fonts_config_path, "utf8"));
|
|
13
14
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-member-access
|
|
14
15
|
const fonts_url = constructURL(fonts_config.googleFonts);
|
|
15
16
|
if (!fonts_url) {
|
package/lib/builder.js
DELETED
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
import { build } from "esbuild";
|
|
2
|
-
import glob from "tiny-glob";
|
|
3
|
-
import { promises as fs } from "fs";
|
|
4
|
-
import { embeddable_file_extensions } from "./embeddable-file-extensions.js";
|
|
5
|
-
import { load_assets_plugin } from "./esbuild-plugins/load-assets.js";
|
|
6
|
-
import { rewrite_asset_imports_plugin } from "./esbuild-plugins/rewrite-asset-imports.js";
|
|
7
|
-
import { generateCollections } from "./generate-collections.js";
|
|
8
|
-
import { generateComponents } from "./generate-components.js";
|
|
9
|
-
import { generateRoutes } from "./generate-routes.js";
|
|
10
|
-
import { generateStimulusControllers } from "./generate-stimulus.js";
|
|
11
|
-
import { FONTS_CONFIG_PATH, getFonts } from "./get-fonts.js";
|
|
12
|
-
import { relative } from "node:path";
|
|
13
|
-
class Builder {
|
|
14
|
-
constructor(project_dir, style_dirs) {
|
|
15
|
-
this.project_dir = project_dir;
|
|
16
|
-
this.style_dirs = style_dirs;
|
|
17
|
-
this.ongoing_build = null;
|
|
18
|
-
}
|
|
19
|
-
build(notifier) {
|
|
20
|
-
if (!this.ongoing_build) {
|
|
21
|
-
const build2 = this._build().catch((err) => {
|
|
22
|
-
console.error(err);
|
|
23
|
-
}).then(() => {
|
|
24
|
-
notifier?.(this.getName());
|
|
25
|
-
this.ongoing_build = null;
|
|
26
|
-
});
|
|
27
|
-
this.ongoing_build = build2;
|
|
28
|
-
}
|
|
29
|
-
return this.ongoing_build;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
class FontsBuilder extends Builder {
|
|
33
|
-
getName() {
|
|
34
|
-
return "fonts";
|
|
35
|
-
}
|
|
36
|
-
ownsFile(file_path) {
|
|
37
|
-
return file_path == FONTS_CONFIG_PATH;
|
|
38
|
-
}
|
|
39
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
40
|
-
async dispose() {
|
|
41
|
-
}
|
|
42
|
-
async _build() {
|
|
43
|
-
return getFonts();
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
class BackendTSBuilder extends Builder {
|
|
47
|
-
getName() {
|
|
48
|
-
return "backend-ts";
|
|
49
|
-
}
|
|
50
|
-
ownsFile(file_path) {
|
|
51
|
-
return (file_path.endsWith(".ts") || file_path.endsWith(".tsx")) && !file_path.endsWith("src/back/collections/collections.ts") && !file_path.endsWith("src/back/routes/routes.ts") && !file_path.endsWith("src/back/routes/urls.ts") && !file_path.endsWith("stimulus.ts") && !file_path.startsWith("src/front");
|
|
52
|
-
}
|
|
53
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
54
|
-
async dispose() {
|
|
55
|
-
}
|
|
56
|
-
async _build() {
|
|
57
|
-
await Promise.all([
|
|
58
|
-
generateCollections(),
|
|
59
|
-
generateRoutes(),
|
|
60
|
-
generateComponents()
|
|
61
|
-
]);
|
|
62
|
-
const entryPoints = (await glob(
|
|
63
|
-
`./src/back/**/*.{ts,tsx,${embeddable_file_extensions.join(
|
|
64
|
-
","
|
|
65
|
-
)}}`
|
|
66
|
-
)).filter((path) => !path.includes(".#"));
|
|
67
|
-
const { metafile } = await build({
|
|
68
|
-
entryPoints,
|
|
69
|
-
sourcemap: true,
|
|
70
|
-
bundle: false,
|
|
71
|
-
jsxFactory: "TempstreamJSX.createElement",
|
|
72
|
-
jsxFragment: "TempstreamJSX.Fragment",
|
|
73
|
-
outdir: "./dist/back",
|
|
74
|
-
logLevel: "info",
|
|
75
|
-
platform: "node",
|
|
76
|
-
target: "es2022",
|
|
77
|
-
format: "esm",
|
|
78
|
-
loader: Object.fromEntries(
|
|
79
|
-
embeddable_file_extensions.map((ext) => ["." + ext, "js"])
|
|
80
|
-
),
|
|
81
|
-
plugins: [
|
|
82
|
-
rewrite_asset_imports_plugin(this.project_dir),
|
|
83
|
-
load_assets_plugin
|
|
84
|
-
],
|
|
85
|
-
metafile: true
|
|
86
|
-
});
|
|
87
|
-
await fs.writeFile(
|
|
88
|
-
relative(this.project_dir, "dist") + "/back.meta.json",
|
|
89
|
-
JSON.stringify(metafile)
|
|
90
|
-
);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
class FrontendTSBuilder extends Builder {
|
|
94
|
-
constructor(project_dir, style_dirs, controller_dirs) {
|
|
95
|
-
super(project_dir, style_dirs);
|
|
96
|
-
this.project_dir = project_dir;
|
|
97
|
-
this.style_dirs = style_dirs;
|
|
98
|
-
this.controller_dirs = controller_dirs;
|
|
99
|
-
}
|
|
100
|
-
getName() {
|
|
101
|
-
return "frontend-ts";
|
|
102
|
-
}
|
|
103
|
-
ownsFile(file_path) {
|
|
104
|
-
return file_path.startsWith("src/front") || file_path.endsWith(".stimulus.ts");
|
|
105
|
-
}
|
|
106
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
107
|
-
async dispose() {
|
|
108
|
-
}
|
|
109
|
-
async _build() {
|
|
110
|
-
await generateStimulusControllers(this.controller_dirs);
|
|
111
|
-
const { metafile } = await build({
|
|
112
|
-
entryPoints: ["./src/front/index.ts"],
|
|
113
|
-
sourcemap: true,
|
|
114
|
-
outfile: "./public/dist/bundle.js",
|
|
115
|
-
logLevel: "info",
|
|
116
|
-
bundle: true,
|
|
117
|
-
minify: true,
|
|
118
|
-
metafile: true,
|
|
119
|
-
treeShaking: true
|
|
120
|
-
});
|
|
121
|
-
await fs.writeFile(
|
|
122
|
-
relative(this.project_dir, "dist") + "/front.meta.json",
|
|
123
|
-
JSON.stringify(metafile)
|
|
124
|
-
);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
export {
|
|
128
|
-
BackendTSBuilder,
|
|
129
|
-
Builder,
|
|
130
|
-
FontsBuilder,
|
|
131
|
-
FrontendTSBuilder
|
|
132
|
-
};
|
|
133
|
-
//# sourceMappingURL=builder.js.map
|
package/src/builder.ts
DELETED
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
import { build } from "esbuild";
|
|
2
|
-
import glob from "tiny-glob";
|
|
3
|
-
import { promises as fs } from "fs";
|
|
4
|
-
import { embeddable_file_extensions } from "./embeddable-file-extensions.js";
|
|
5
|
-
import { load_assets_plugin } from "./esbuild-plugins/load-assets.js";
|
|
6
|
-
import { rewrite_asset_imports_plugin } from "./esbuild-plugins/rewrite-asset-imports.js";
|
|
7
|
-
import { generateCollections } from "./generate-collections.js";
|
|
8
|
-
import { generateComponents } from "./generate-components.js";
|
|
9
|
-
import { generateRoutes } from "./generate-routes.js";
|
|
10
|
-
import { generateStimulusControllers } from "./generate-stimulus.js";
|
|
11
|
-
import { FONTS_CONFIG_PATH, getFonts } from "./get-fonts.js";
|
|
12
|
-
import { relative, resolve } from "node:path";
|
|
13
|
-
|
|
14
|
-
export abstract class Builder {
|
|
15
|
-
abstract ownsFile(file_path: string): boolean;
|
|
16
|
-
abstract getName(): string;
|
|
17
|
-
abstract _build(): Promise<void>;
|
|
18
|
-
abstract dispose(): Promise<void>;
|
|
19
|
-
|
|
20
|
-
constructor(public project_dir: string, public style_dirs: string[]) {}
|
|
21
|
-
|
|
22
|
-
public ongoing_build: Promise<void> | null = null;
|
|
23
|
-
|
|
24
|
-
public build(notifier?: (message: string) => void) {
|
|
25
|
-
if (!this.ongoing_build) {
|
|
26
|
-
const build = this._build()
|
|
27
|
-
.catch((err) => {
|
|
28
|
-
console.error(err);
|
|
29
|
-
})
|
|
30
|
-
.then(() => {
|
|
31
|
-
notifier?.(this.getName());
|
|
32
|
-
this.ongoing_build = null;
|
|
33
|
-
});
|
|
34
|
-
this.ongoing_build = build;
|
|
35
|
-
}
|
|
36
|
-
return this.ongoing_build;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export class FontsBuilder extends Builder {
|
|
41
|
-
getName(): string {
|
|
42
|
-
return "fonts";
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
ownsFile(file_path: string) {
|
|
46
|
-
return file_path == FONTS_CONFIG_PATH;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
50
|
-
async dispose(): Promise<void> {}
|
|
51
|
-
|
|
52
|
-
async _build() {
|
|
53
|
-
return getFonts();
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export class BackendTSBuilder extends Builder {
|
|
58
|
-
getName(): string {
|
|
59
|
-
return "backend-ts";
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
ownsFile(file_path: string) {
|
|
63
|
-
return (
|
|
64
|
-
(file_path.endsWith(".ts") || file_path.endsWith(".tsx")) &&
|
|
65
|
-
!file_path.endsWith("src/back/collections/collections.ts") &&
|
|
66
|
-
!file_path.endsWith("src/back/routes/routes.ts") &&
|
|
67
|
-
!file_path.endsWith("src/back/routes/urls.ts") &&
|
|
68
|
-
!file_path.endsWith("stimulus.ts") &&
|
|
69
|
-
!file_path.startsWith("src/front")
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
74
|
-
async dispose(): Promise<void> {}
|
|
75
|
-
|
|
76
|
-
async _build(): Promise<void> {
|
|
77
|
-
await Promise.all([
|
|
78
|
-
generateCollections(),
|
|
79
|
-
generateRoutes(),
|
|
80
|
-
generateComponents(),
|
|
81
|
-
]);
|
|
82
|
-
const entryPoints = (
|
|
83
|
-
await glob(
|
|
84
|
-
`./src/back/**/*.{ts,tsx,${embeddable_file_extensions.join(
|
|
85
|
-
","
|
|
86
|
-
)}}`
|
|
87
|
-
)
|
|
88
|
-
).filter((path) => !path.includes(".#"));
|
|
89
|
-
|
|
90
|
-
const { metafile } = await build({
|
|
91
|
-
entryPoints,
|
|
92
|
-
sourcemap: true,
|
|
93
|
-
bundle: false,
|
|
94
|
-
jsxFactory: "TempstreamJSX.createElement",
|
|
95
|
-
jsxFragment: "TempstreamJSX.Fragment",
|
|
96
|
-
outdir: "./dist/back",
|
|
97
|
-
logLevel: "info",
|
|
98
|
-
platform: "node",
|
|
99
|
-
target: "es2022",
|
|
100
|
-
format: "esm",
|
|
101
|
-
loader: Object.fromEntries(
|
|
102
|
-
embeddable_file_extensions.map((ext) => ["." + ext, "js"])
|
|
103
|
-
),
|
|
104
|
-
plugins: [
|
|
105
|
-
rewrite_asset_imports_plugin(this.project_dir),
|
|
106
|
-
load_assets_plugin,
|
|
107
|
-
],
|
|
108
|
-
metafile: true,
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
await fs.writeFile(
|
|
112
|
-
relative(this.project_dir, "dist") + "/" + "back" + ".meta.json",
|
|
113
|
-
JSON.stringify(metafile)
|
|
114
|
-
);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
export class FrontendTSBuilder extends Builder {
|
|
119
|
-
constructor(
|
|
120
|
-
public project_dir: string,
|
|
121
|
-
public style_dirs: string[],
|
|
122
|
-
public controller_dirs: string[]
|
|
123
|
-
) {
|
|
124
|
-
super(project_dir, style_dirs);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
getName(): string {
|
|
128
|
-
return "frontend-ts";
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
ownsFile(file_path: string) {
|
|
132
|
-
return (
|
|
133
|
-
file_path.startsWith("src/front") ||
|
|
134
|
-
file_path.endsWith(".stimulus.ts")
|
|
135
|
-
);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
139
|
-
async dispose(): Promise<void> {}
|
|
140
|
-
|
|
141
|
-
async _build(): Promise<void> {
|
|
142
|
-
await generateStimulusControllers(this.controller_dirs);
|
|
143
|
-
const { metafile } = await build({
|
|
144
|
-
entryPoints: ["./src/front/index.ts"],
|
|
145
|
-
sourcemap: true,
|
|
146
|
-
outfile: "./public/dist/bundle.js",
|
|
147
|
-
logLevel: "info",
|
|
148
|
-
bundle: true,
|
|
149
|
-
minify: true,
|
|
150
|
-
metafile: true,
|
|
151
|
-
treeShaking: true,
|
|
152
|
-
});
|
|
153
|
-
await fs.writeFile(
|
|
154
|
-
relative(this.project_dir, "dist") + "/" + "front" + ".meta.json",
|
|
155
|
-
JSON.stringify(metafile)
|
|
156
|
-
);
|
|
157
|
-
}
|
|
158
|
-
}
|