@typeonce/effect-machine-devtools 0.26.2 → 0.27.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -0
- package/dist/bin.js +11 -1
- package/dist/bin.js.map +1 -1
- package/dist/client/assets/index-BFxKU97K.js +37 -0
- package/dist/client/index.html +2 -2
- package/dist/internal/staticSite.d.ts +25 -0
- package/dist/internal/staticSite.d.ts.map +1 -0
- package/dist/internal/staticSite.js +147 -0
- package/dist/internal/staticSite.js.map +1 -0
- package/package.json +2 -2
- package/src/bin.ts +31 -1
- package/src/internal/browser/main.ts +24 -1
- package/src/internal/staticSite.ts +209 -0
- package/dist/client/assets/index-H0UhNc0S.js +0 -37
package/dist/client/index.html
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<meta name="description" content="Interactive statechart visualization for Effect Machine" />
|
|
7
7
|
<title>Effect Machine · Statechart</title>
|
|
8
|
-
<script type="module" crossorigin src="
|
|
9
|
-
<link rel="stylesheet" crossorigin href="
|
|
8
|
+
<script type="module" crossorigin src="./assets/index-BFxKU97K.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="./assets/index-BsorPSDS.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="app"></div>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as FileSystem from "effect/FileSystem";
|
|
3
|
+
import * as Path from "effect/Path";
|
|
4
|
+
import * as Schema from "effect/Schema";
|
|
5
|
+
import * as ProjectInspector from "../ProjectInspector.js";
|
|
6
|
+
export interface Options {
|
|
7
|
+
readonly root: string;
|
|
8
|
+
readonly include?: string | undefined;
|
|
9
|
+
readonly outputDirectory: string;
|
|
10
|
+
}
|
|
11
|
+
export interface BuildResult {
|
|
12
|
+
readonly outputDirectory: string;
|
|
13
|
+
readonly machineIds: ReadonlyArray<string>;
|
|
14
|
+
}
|
|
15
|
+
declare const StaticSiteError_base: Schema.Class<StaticSiteError, Schema.Struct<{
|
|
16
|
+
readonly _tag: Schema.tag<"StaticSiteError">;
|
|
17
|
+
readonly message: Schema.String;
|
|
18
|
+
readonly cause: Schema.optional<Schema.Defect>;
|
|
19
|
+
}>, import("effect/Cause").YieldableError>;
|
|
20
|
+
export declare class StaticSiteError extends StaticSiteError_base {
|
|
21
|
+
}
|
|
22
|
+
export declare const staticIndex: (index: string) => Effect.Effect<string, StaticSiteError>;
|
|
23
|
+
export declare const build: (options: Options) => Effect.Effect<BuildResult, StaticSiteError, FileSystem.FileSystem | Path.Path | ProjectInspector.ProjectInspector>;
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=staticSite.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"staticSite.d.ts","sourceRoot":"","sources":["../../src/internal/staticSite.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AACvC,OAAO,KAAK,UAAU,MAAM,mBAAmB,CAAA;AAC/C,OAAO,KAAK,IAAI,MAAM,aAAa,CAAA;AACnC,OAAO,KAAK,MAAM,MAAM,eAAe,CAAA;AAMvC,OAAO,KAAK,gBAAgB,MAAM,wBAAwB,CAAA;AAE1D,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACrC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;CACjC;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;IAChC,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;CAC3C;;;;;;AAED,qBAAa,eAAgB,SAAQ,oBAMnC;CAAG;AAQL,eAAO,MAAM,WAAW,GAAI,OAAO,MAAM,KAAG,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,eAAe,CAShF,CAAA;AAyED,eAAO,MAAM,KAAK,GAAI,SAAS,OAAO,KAAG,MAAM,CAAC,MAAM,CACpD,WAAW,EACX,eAAe,EACf,UAAU,CAAC,UAAU,GAAG,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC,gBAAgB,CAuFpE,CAAA"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as FileSystem from "effect/FileSystem";
|
|
3
|
+
import * as Path from "effect/Path";
|
|
4
|
+
import * as Schema from "effect/Schema";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
6
|
+
import { build as buildVite } from "vite";
|
|
7
|
+
import PackageJson from "../../package.json" with { type: "json" };
|
|
8
|
+
import * as DevToolsProtocol from "../DevToolsProtocol.js";
|
|
9
|
+
import * as MachineDocument from "../MachineDocument.js";
|
|
10
|
+
import * as ProjectInspector from "../ProjectInspector.js";
|
|
11
|
+
export class StaticSiteError extends Schema.Error("@typeonce/effect-machine-devtools/internal/StaticSiteError")({
|
|
12
|
+
_tag: Schema.tag("StaticSiteError"),
|
|
13
|
+
message: Schema.String,
|
|
14
|
+
cause: Schema.optional(Schema.Defect())
|
|
15
|
+
}) {
|
|
16
|
+
}
|
|
17
|
+
const packageRoot = fileURLToPath(new URL("../..", import.meta.url));
|
|
18
|
+
const generatedMarker = ".effect-machine-site";
|
|
19
|
+
const staticDataMeta = "<meta name=\"effect-machine-static-data\" content=\"./machines.json\" />";
|
|
20
|
+
const prettyJson = (value) => `${JSON.stringify(value, null, 2)}\n`;
|
|
21
|
+
export const staticIndex = (index) => {
|
|
22
|
+
if (!index.includes("</head>")) {
|
|
23
|
+
return Effect.fail(new StaticSiteError({
|
|
24
|
+
message: "The visualizer index does not contain a closing head element"
|
|
25
|
+
}));
|
|
26
|
+
}
|
|
27
|
+
return Effect.succeed(index.replace("</head>", ` ${staticDataMeta}\n </head>`));
|
|
28
|
+
};
|
|
29
|
+
const formatFailures = (failures) => failures.map((failure) => {
|
|
30
|
+
const messages = failure.diagnostics.map((diagnostic) => diagnostic.message).join("; ");
|
|
31
|
+
return `- ${failure.key}: ${messages}`;
|
|
32
|
+
}).join("\n");
|
|
33
|
+
const ensureReplaceable = Effect.fnUntraced(function* (fs, path, outputDirectory) {
|
|
34
|
+
if (!(yield* fs.exists(outputDirectory)))
|
|
35
|
+
return;
|
|
36
|
+
if (yield* fs.exists(path.join(outputDirectory, generatedMarker)))
|
|
37
|
+
return;
|
|
38
|
+
const entries = yield* fs.readDirectory(outputDirectory);
|
|
39
|
+
if (entries.length === 0)
|
|
40
|
+
return;
|
|
41
|
+
return yield* new StaticSiteError({
|
|
42
|
+
message: `Refusing to replace non-generated directory: ${outputDirectory}`
|
|
43
|
+
});
|
|
44
|
+
}, (effect, _fs, _path, outputDirectory) => effect.pipe(Effect.mapError((cause) => cause instanceof StaticSiteError
|
|
45
|
+
? cause
|
|
46
|
+
: new StaticSiteError({
|
|
47
|
+
message: `Could not inspect output directory: ${outputDirectory}`,
|
|
48
|
+
cause
|
|
49
|
+
}))));
|
|
50
|
+
const inspect = Effect.fnUntraced(function* (options) {
|
|
51
|
+
const inspector = yield* ProjectInspector.ProjectInspector;
|
|
52
|
+
const results = yield* inspector.inspect({
|
|
53
|
+
root: options.root,
|
|
54
|
+
include: options.include,
|
|
55
|
+
revision: 1
|
|
56
|
+
});
|
|
57
|
+
const failures = results.filter((result) => result._tag === "Failed");
|
|
58
|
+
if (failures.length > 0) {
|
|
59
|
+
return yield* new StaticSiteError({
|
|
60
|
+
message: `Static site generation failed for ${failures.length} machine candidate${failures.length === 1 ? "" : "s"}:\n${formatFailures(failures)}`
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
const ready = results
|
|
64
|
+
.filter((result) => result._tag === "Ready")
|
|
65
|
+
.sort((left, right) => left.key.localeCompare(right.key));
|
|
66
|
+
if (ready.length === 0) {
|
|
67
|
+
return yield* new StaticSiteError({
|
|
68
|
+
message: `No Effect Machine definitions were found under ${options.root}`
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
const snapshot = yield* Schema.decodeUnknownEffect(DevToolsProtocol.RegistrySnapshot)({
|
|
72
|
+
protocolVersion: DevToolsProtocol.protocolVersion,
|
|
73
|
+
revision: 1,
|
|
74
|
+
results: ready
|
|
75
|
+
}).pipe(Effect.mapError((cause) => new StaticSiteError({
|
|
76
|
+
message: "The generated machine registry is invalid",
|
|
77
|
+
cause
|
|
78
|
+
})));
|
|
79
|
+
return { ready, snapshot };
|
|
80
|
+
});
|
|
81
|
+
export const build = (options) => Effect.gen(function* () {
|
|
82
|
+
const fs = yield* FileSystem.FileSystem;
|
|
83
|
+
const path = yield* Path.Path;
|
|
84
|
+
const root = path.resolve(options.root);
|
|
85
|
+
const outputDirectory = path.resolve(options.outputDirectory);
|
|
86
|
+
if (outputDirectory === root || path.dirname(outputDirectory) === outputDirectory) {
|
|
87
|
+
return yield* new StaticSiteError({
|
|
88
|
+
message: `Refusing to replace project or filesystem root: ${outputDirectory}`
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
yield* ensureReplaceable(fs, path, outputDirectory);
|
|
92
|
+
const { ready, snapshot } = yield* inspect({ ...options, root });
|
|
93
|
+
const parent = path.dirname(outputDirectory);
|
|
94
|
+
yield* fs.makeDirectory(parent, { recursive: true });
|
|
95
|
+
return yield* Effect.acquireUseRelease(fs.makeTempDirectory({ directory: parent, prefix: ".effect-machine-site-" }), (stagingDirectory) => Effect.gen(function* () {
|
|
96
|
+
yield* Effect.tryPromise({
|
|
97
|
+
try: () => buildVite({
|
|
98
|
+
root: packageRoot,
|
|
99
|
+
base: "./",
|
|
100
|
+
configFile: false,
|
|
101
|
+
logLevel: "error",
|
|
102
|
+
build: {
|
|
103
|
+
outDir: stagingDirectory,
|
|
104
|
+
emptyOutDir: true
|
|
105
|
+
}
|
|
106
|
+
}),
|
|
107
|
+
catch: (cause) => new StaticSiteError({
|
|
108
|
+
message: "Could not bundle the static visualizer",
|
|
109
|
+
cause
|
|
110
|
+
})
|
|
111
|
+
});
|
|
112
|
+
const indexPath = path.join(stagingDirectory, "index.html");
|
|
113
|
+
const index = yield* fs.readFileString(indexPath);
|
|
114
|
+
yield* fs.writeFileString(indexPath, yield* staticIndex(index));
|
|
115
|
+
yield* fs.writeFileString(path.join(stagingDirectory, "machines.json"), prettyJson(snapshot));
|
|
116
|
+
yield* fs.writeFileString(path.join(stagingDirectory, "manifest.json"), prettyJson({
|
|
117
|
+
formatVersion: 1,
|
|
118
|
+
generator: {
|
|
119
|
+
name: PackageJson.name,
|
|
120
|
+
version: PackageJson.version
|
|
121
|
+
},
|
|
122
|
+
protocolVersion: DevToolsProtocol.protocolVersion,
|
|
123
|
+
machineDocumentSchemaVersion: MachineDocument.schemaVersion,
|
|
124
|
+
machines: ready.map((result) => ({
|
|
125
|
+
key: result.key,
|
|
126
|
+
machineId: result.document.machineId,
|
|
127
|
+
source: result.document.source
|
|
128
|
+
}))
|
|
129
|
+
}));
|
|
130
|
+
yield* fs.writeFileString(path.join(stagingDirectory, generatedMarker), `${PackageJson.name}@${PackageJson.version}\n`);
|
|
131
|
+
yield* ensureReplaceable(fs, path, outputDirectory);
|
|
132
|
+
if (yield* fs.exists(outputDirectory)) {
|
|
133
|
+
yield* fs.remove(outputDirectory, { recursive: true });
|
|
134
|
+
}
|
|
135
|
+
yield* fs.rename(stagingDirectory, outputDirectory);
|
|
136
|
+
return {
|
|
137
|
+
outputDirectory,
|
|
138
|
+
machineIds: ready.map((result) => result.document.machineId)
|
|
139
|
+
};
|
|
140
|
+
}), (stagingDirectory) => fs.remove(stagingDirectory, { recursive: true }).pipe(Effect.ignore));
|
|
141
|
+
}).pipe(Effect.mapError((cause) => cause instanceof StaticSiteError
|
|
142
|
+
? cause
|
|
143
|
+
: new StaticSiteError({
|
|
144
|
+
message: "Could not build the Effect Machine static site",
|
|
145
|
+
cause
|
|
146
|
+
})));
|
|
147
|
+
//# sourceMappingURL=staticSite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"staticSite.js","sourceRoot":"","sources":["../../src/internal/staticSite.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@typeonce/effect-machine-devtools",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"description": "Local development tools for Effect Machine",
|
|
5
5
|
"author": "Sandro Maglione",
|
|
6
6
|
"repository": {
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
"elkjs": "0.12.0",
|
|
34
34
|
"typescript": "6.0.3",
|
|
35
35
|
"vite": "8.1.5",
|
|
36
|
-
"@typeonce/effect-machine": "^0.
|
|
36
|
+
"@typeonce/effect-machine": "^0.27.0"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"effect": "4.0.0-rc.112"
|
package/src/bin.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import * as NodeRuntime from "@effect/platform-node/NodeRuntime"
|
|
3
3
|
import * as NodeServices from "@effect/platform-node/NodeServices"
|
|
4
|
+
import * as Console from "effect/Console"
|
|
4
5
|
import * as Effect from "effect/Effect"
|
|
5
6
|
import * as Layer from "effect/Layer"
|
|
6
7
|
import * as Command from "effect/unstable/cli/Command"
|
|
7
8
|
import * as Flag from "effect/unstable/cli/Flag"
|
|
8
9
|
import PackageJson from "../package.json" with { type: "json" }
|
|
9
10
|
import * as DevServer from "./DevServer.js"
|
|
11
|
+
import * as StaticSite from "./internal/staticSite.js"
|
|
10
12
|
import * as MachineRegistry from "./MachineRegistry.js"
|
|
11
13
|
import * as ProjectInspector from "./ProjectInspector.js"
|
|
12
14
|
|
|
@@ -40,7 +42,18 @@ const watchPolling = Flag.boolean("watch-polling").pipe(
|
|
|
40
42
|
Flag.withDefault(false)
|
|
41
43
|
)
|
|
42
44
|
|
|
43
|
-
const
|
|
45
|
+
const outputDirectory = Flag.directory("out-dir").pipe(
|
|
46
|
+
Flag.withAlias("o"),
|
|
47
|
+
Flag.withDescription("Directory to write the static website"),
|
|
48
|
+
Flag.withDefault(".effect-machine/site")
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
const base = Command.make("effect-machine", { host, port, open, watchPolling }).pipe(
|
|
52
|
+
Command.withSharedFlags({ root, include }),
|
|
53
|
+
Command.withDescription("Inspect and publish Effect Machine visualizations")
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
const dev = base.pipe(
|
|
44
57
|
Command.withDescription("Inspect Effect Machine definitions in a live local visualizer"),
|
|
45
58
|
Command.withHandler(({ host, include, open, port, root, watchPolling }) => {
|
|
46
59
|
const RegistryLayer = MachineRegistry.layer({ root, include }).pipe(
|
|
@@ -50,6 +63,23 @@ const cli = Command.make("effect-machine", { root, include, host, port, open, wa
|
|
|
50
63
|
})
|
|
51
64
|
)
|
|
52
65
|
|
|
66
|
+
const build = Command.make("build", { outputDirectory }).pipe(
|
|
67
|
+
Command.withDescription("Generate a static website from the project's machines"),
|
|
68
|
+
Command.withHandler(Effect.fnUntraced(function*({ outputDirectory }) {
|
|
69
|
+
const { include, root } = yield* base
|
|
70
|
+
const result = yield* StaticSite.build({ root, include, outputDirectory }).pipe(
|
|
71
|
+
Effect.provide(ProjectInspector.layer)
|
|
72
|
+
)
|
|
73
|
+
yield* Console.log(
|
|
74
|
+
`Effect Machine static site: ${result.outputDirectory}\n${result.machineIds.length} machine${
|
|
75
|
+
result.machineIds.length === 1 ? "" : "s"
|
|
76
|
+
}: ${result.machineIds.join(", ")}`
|
|
77
|
+
)
|
|
78
|
+
}))
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
const cli = dev.pipe(Command.withSubcommands([build]))
|
|
82
|
+
|
|
53
83
|
Command.run(cli, { version: PackageJson.version }).pipe(
|
|
54
84
|
Effect.provide(NodeServices.layer),
|
|
55
85
|
NodeRuntime.runMain
|
|
@@ -8,6 +8,8 @@ import { mountMachineIndex } from "./machine-index.js"
|
|
|
8
8
|
const root = document.querySelector<HTMLDivElement>("#app")
|
|
9
9
|
if (root === null) throw new Error("Visualizer root element was not found")
|
|
10
10
|
|
|
11
|
+
const staticData = document.querySelector<HTMLMetaElement>("meta[name=\"effect-machine-static-data\"]")?.content
|
|
12
|
+
|
|
11
13
|
const showConnectionFailure = (message: string): void => {
|
|
12
14
|
const failure = document.createElement("div")
|
|
13
15
|
failure.className = "connection-failure"
|
|
@@ -39,4 +41,25 @@ const connect = Effect.acquireRelease(
|
|
|
39
41
|
)
|
|
40
42
|
)
|
|
41
43
|
|
|
42
|
-
|
|
44
|
+
const loadStatic = (location: string) =>
|
|
45
|
+
Effect.tryPromise({
|
|
46
|
+
try: async () => {
|
|
47
|
+
const response = await fetch(location)
|
|
48
|
+
if (!response.ok) throw new Error(`Could not load ${location}: ${response.status} ${response.statusText}`)
|
|
49
|
+
return response.json() as Promise<unknown>
|
|
50
|
+
},
|
|
51
|
+
catch: (cause) => cause instanceof Error ? cause : new Error(String(cause))
|
|
52
|
+
}).pipe(
|
|
53
|
+
Effect.flatMap(Schema.decodeUnknownEffect(DevToolsProtocol.RegistrySnapshot)),
|
|
54
|
+
Effect.tap((snapshot) => Effect.sync(() => mountMachineIndex(root, snapshot))),
|
|
55
|
+
Effect.asVoid
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
const run = staticData === undefined ? Effect.scoped(connect) : loadStatic(staticData)
|
|
59
|
+
|
|
60
|
+
run.pipe(
|
|
61
|
+
Effect.catch((cause) =>
|
|
62
|
+
Effect.sync(() => showConnectionFailure(cause instanceof Error ? cause.message : String(cause)))
|
|
63
|
+
),
|
|
64
|
+
BrowserRuntime.runMain
|
|
65
|
+
)
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect"
|
|
2
|
+
import * as FileSystem from "effect/FileSystem"
|
|
3
|
+
import * as Path from "effect/Path"
|
|
4
|
+
import * as Schema from "effect/Schema"
|
|
5
|
+
import { fileURLToPath } from "node:url"
|
|
6
|
+
import { build as buildVite } from "vite"
|
|
7
|
+
import PackageJson from "../../package.json" with { type: "json" }
|
|
8
|
+
import * as DevToolsProtocol from "../DevToolsProtocol.js"
|
|
9
|
+
import * as MachineDocument from "../MachineDocument.js"
|
|
10
|
+
import * as ProjectInspector from "../ProjectInspector.js"
|
|
11
|
+
|
|
12
|
+
export interface Options {
|
|
13
|
+
readonly root: string
|
|
14
|
+
readonly include?: string | undefined
|
|
15
|
+
readonly outputDirectory: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface BuildResult {
|
|
19
|
+
readonly outputDirectory: string
|
|
20
|
+
readonly machineIds: ReadonlyArray<string>
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export class StaticSiteError extends Schema.Error<StaticSiteError>(
|
|
24
|
+
"@typeonce/effect-machine-devtools/internal/StaticSiteError"
|
|
25
|
+
)({
|
|
26
|
+
_tag: Schema.tag("StaticSiteError"),
|
|
27
|
+
message: Schema.String,
|
|
28
|
+
cause: Schema.optional(Schema.Defect())
|
|
29
|
+
}) {}
|
|
30
|
+
|
|
31
|
+
const packageRoot = fileURLToPath(new URL("../..", import.meta.url))
|
|
32
|
+
const generatedMarker = ".effect-machine-site"
|
|
33
|
+
const staticDataMeta = "<meta name=\"effect-machine-static-data\" content=\"./machines.json\" />"
|
|
34
|
+
|
|
35
|
+
const prettyJson = (value: unknown): string => `${JSON.stringify(value, null, 2)}\n`
|
|
36
|
+
|
|
37
|
+
export const staticIndex = (index: string): Effect.Effect<string, StaticSiteError> => {
|
|
38
|
+
if (!index.includes("</head>")) {
|
|
39
|
+
return Effect.fail(
|
|
40
|
+
new StaticSiteError({
|
|
41
|
+
message: "The visualizer index does not contain a closing head element"
|
|
42
|
+
})
|
|
43
|
+
)
|
|
44
|
+
}
|
|
45
|
+
return Effect.succeed(index.replace("</head>", ` ${staticDataMeta}\n </head>`))
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const formatFailures = (failures: ReadonlyArray<DevToolsProtocol.Failed>): string =>
|
|
49
|
+
failures.map((failure) => {
|
|
50
|
+
const messages = failure.diagnostics.map((diagnostic) => diagnostic.message).join("; ")
|
|
51
|
+
return `- ${failure.key}: ${messages}`
|
|
52
|
+
}).join("\n")
|
|
53
|
+
|
|
54
|
+
const ensureReplaceable = Effect.fnUntraced(
|
|
55
|
+
function*(
|
|
56
|
+
fs: FileSystem.FileSystem,
|
|
57
|
+
path: Path.Path,
|
|
58
|
+
outputDirectory: string
|
|
59
|
+
) {
|
|
60
|
+
if (!(yield* fs.exists(outputDirectory))) return
|
|
61
|
+
if (yield* fs.exists(path.join(outputDirectory, generatedMarker))) return
|
|
62
|
+
const entries = yield* fs.readDirectory(outputDirectory)
|
|
63
|
+
if (entries.length === 0) return
|
|
64
|
+
return yield* new StaticSiteError({
|
|
65
|
+
message: `Refusing to replace non-generated directory: ${outputDirectory}`
|
|
66
|
+
})
|
|
67
|
+
},
|
|
68
|
+
(effect, _fs, _path, outputDirectory) =>
|
|
69
|
+
effect.pipe(
|
|
70
|
+
Effect.mapError((cause) =>
|
|
71
|
+
cause instanceof StaticSiteError
|
|
72
|
+
? cause
|
|
73
|
+
: new StaticSiteError({
|
|
74
|
+
message: `Could not inspect output directory: ${outputDirectory}`,
|
|
75
|
+
cause
|
|
76
|
+
})
|
|
77
|
+
)
|
|
78
|
+
)
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
const inspect = Effect.fnUntraced(function*(options: Options) {
|
|
82
|
+
const inspector = yield* ProjectInspector.ProjectInspector
|
|
83
|
+
const results = yield* inspector.inspect({
|
|
84
|
+
root: options.root,
|
|
85
|
+
include: options.include,
|
|
86
|
+
revision: 1
|
|
87
|
+
})
|
|
88
|
+
const failures = results.filter((result): result is DevToolsProtocol.Failed => result._tag === "Failed")
|
|
89
|
+
if (failures.length > 0) {
|
|
90
|
+
return yield* new StaticSiteError({
|
|
91
|
+
message: `Static site generation failed for ${failures.length} machine candidate${
|
|
92
|
+
failures.length === 1 ? "" : "s"
|
|
93
|
+
}:\n${formatFailures(failures)}`
|
|
94
|
+
})
|
|
95
|
+
}
|
|
96
|
+
const ready = results
|
|
97
|
+
.filter((result): result is DevToolsProtocol.Ready => result._tag === "Ready")
|
|
98
|
+
.sort((left, right) => left.key.localeCompare(right.key))
|
|
99
|
+
if (ready.length === 0) {
|
|
100
|
+
return yield* new StaticSiteError({
|
|
101
|
+
message: `No Effect Machine definitions were found under ${options.root}`
|
|
102
|
+
})
|
|
103
|
+
}
|
|
104
|
+
const snapshot = yield* Schema.decodeUnknownEffect(DevToolsProtocol.RegistrySnapshot)({
|
|
105
|
+
protocolVersion: DevToolsProtocol.protocolVersion,
|
|
106
|
+
revision: 1,
|
|
107
|
+
results: ready
|
|
108
|
+
}).pipe(
|
|
109
|
+
Effect.mapError((cause) =>
|
|
110
|
+
new StaticSiteError({
|
|
111
|
+
message: "The generated machine registry is invalid",
|
|
112
|
+
cause
|
|
113
|
+
})
|
|
114
|
+
)
|
|
115
|
+
)
|
|
116
|
+
return { ready, snapshot }
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
export const build = (options: Options): Effect.Effect<
|
|
120
|
+
BuildResult,
|
|
121
|
+
StaticSiteError,
|
|
122
|
+
FileSystem.FileSystem | Path.Path | ProjectInspector.ProjectInspector
|
|
123
|
+
> =>
|
|
124
|
+
Effect.gen(function*() {
|
|
125
|
+
const fs = yield* FileSystem.FileSystem
|
|
126
|
+
const path = yield* Path.Path
|
|
127
|
+
const root = path.resolve(options.root)
|
|
128
|
+
const outputDirectory = path.resolve(options.outputDirectory)
|
|
129
|
+
if (outputDirectory === root || path.dirname(outputDirectory) === outputDirectory) {
|
|
130
|
+
return yield* new StaticSiteError({
|
|
131
|
+
message: `Refusing to replace project or filesystem root: ${outputDirectory}`
|
|
132
|
+
})
|
|
133
|
+
}
|
|
134
|
+
yield* ensureReplaceable(fs, path, outputDirectory)
|
|
135
|
+
const { ready, snapshot } = yield* inspect({ ...options, root })
|
|
136
|
+
const parent = path.dirname(outputDirectory)
|
|
137
|
+
yield* fs.makeDirectory(parent, { recursive: true })
|
|
138
|
+
|
|
139
|
+
return yield* Effect.acquireUseRelease(
|
|
140
|
+
fs.makeTempDirectory({ directory: parent, prefix: ".effect-machine-site-" }),
|
|
141
|
+
(stagingDirectory) =>
|
|
142
|
+
Effect.gen(function*() {
|
|
143
|
+
yield* Effect.tryPromise({
|
|
144
|
+
try: () =>
|
|
145
|
+
buildVite({
|
|
146
|
+
root: packageRoot,
|
|
147
|
+
base: "./",
|
|
148
|
+
configFile: false,
|
|
149
|
+
logLevel: "error",
|
|
150
|
+
build: {
|
|
151
|
+
outDir: stagingDirectory,
|
|
152
|
+
emptyOutDir: true
|
|
153
|
+
}
|
|
154
|
+
}),
|
|
155
|
+
catch: (cause) =>
|
|
156
|
+
new StaticSiteError({
|
|
157
|
+
message: "Could not bundle the static visualizer",
|
|
158
|
+
cause
|
|
159
|
+
})
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
const indexPath = path.join(stagingDirectory, "index.html")
|
|
163
|
+
const index = yield* fs.readFileString(indexPath)
|
|
164
|
+
yield* fs.writeFileString(indexPath, yield* staticIndex(index))
|
|
165
|
+
yield* fs.writeFileString(path.join(stagingDirectory, "machines.json"), prettyJson(snapshot))
|
|
166
|
+
yield* fs.writeFileString(
|
|
167
|
+
path.join(stagingDirectory, "manifest.json"),
|
|
168
|
+
prettyJson({
|
|
169
|
+
formatVersion: 1,
|
|
170
|
+
generator: {
|
|
171
|
+
name: PackageJson.name,
|
|
172
|
+
version: PackageJson.version
|
|
173
|
+
},
|
|
174
|
+
protocolVersion: DevToolsProtocol.protocolVersion,
|
|
175
|
+
machineDocumentSchemaVersion: MachineDocument.schemaVersion,
|
|
176
|
+
machines: ready.map((result) => ({
|
|
177
|
+
key: result.key,
|
|
178
|
+
machineId: result.document.machineId,
|
|
179
|
+
source: result.document.source
|
|
180
|
+
}))
|
|
181
|
+
})
|
|
182
|
+
)
|
|
183
|
+
yield* fs.writeFileString(
|
|
184
|
+
path.join(stagingDirectory, generatedMarker),
|
|
185
|
+
`${PackageJson.name}@${PackageJson.version}\n`
|
|
186
|
+
)
|
|
187
|
+
|
|
188
|
+
yield* ensureReplaceable(fs, path, outputDirectory)
|
|
189
|
+
if (yield* fs.exists(outputDirectory)) {
|
|
190
|
+
yield* fs.remove(outputDirectory, { recursive: true })
|
|
191
|
+
}
|
|
192
|
+
yield* fs.rename(stagingDirectory, outputDirectory)
|
|
193
|
+
return {
|
|
194
|
+
outputDirectory,
|
|
195
|
+
machineIds: ready.map((result) => result.document.machineId)
|
|
196
|
+
}
|
|
197
|
+
}),
|
|
198
|
+
(stagingDirectory) => fs.remove(stagingDirectory, { recursive: true }).pipe(Effect.ignore)
|
|
199
|
+
)
|
|
200
|
+
}).pipe(
|
|
201
|
+
Effect.mapError((cause) =>
|
|
202
|
+
cause instanceof StaticSiteError
|
|
203
|
+
? cause
|
|
204
|
+
: new StaticSiteError({
|
|
205
|
+
message: "Could not build the Effect Machine static site",
|
|
206
|
+
cause
|
|
207
|
+
})
|
|
208
|
+
)
|
|
209
|
+
)
|