foldcn 0.0.18 → 0.0.20
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/bin.js +110 -25
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -17,7 +17,7 @@ var __export = (target, all) => {
|
|
|
17
17
|
// src/bin.ts
|
|
18
18
|
import * as NodeRuntime from "@effect/platform-node/NodeRuntime";
|
|
19
19
|
import * as NodeServices from "@effect/platform-node/NodeServices";
|
|
20
|
-
import { Effect as Effect12 } from "effect";
|
|
20
|
+
import { Console as Console4, Effect as Effect12 } from "effect";
|
|
21
21
|
|
|
22
22
|
// src/cli.ts
|
|
23
23
|
import { Effect as Effect11 } from "effect";
|
|
@@ -62,7 +62,7 @@ var CssVars = Schema.Struct({
|
|
|
62
62
|
var Css = Schema.Record(Schema.String, Schema.Union([Schema.String, Schema.suspend(() => Css)])).annotate({ identifier: "Foldcn.Registry.Css" });
|
|
63
63
|
var Item = Schema.Struct({
|
|
64
64
|
$schema: Schema.optionalKey(Schema.String),
|
|
65
|
-
name: Schema.
|
|
65
|
+
name: Schema.NonEmptyString,
|
|
66
66
|
type: ItemType,
|
|
67
67
|
title: Schema.optionalKey(Schema.String),
|
|
68
68
|
description: Schema.optionalKey(Schema.String),
|
|
@@ -600,6 +600,18 @@ class RegistryNotConfiguredError extends Schema4.TaggedErrorClass()("RegistryNot
|
|
|
600
600
|
}) {
|
|
601
601
|
}
|
|
602
602
|
|
|
603
|
+
class RegistryTemplateError extends Schema4.TaggedErrorClass()("RegistryTemplateError", {
|
|
604
|
+
namespace: Schema4.String,
|
|
605
|
+
template: Schema4.String
|
|
606
|
+
}) {
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
class PackageManagerNotFoundError extends Schema4.TaggedErrorClass()("PackageManagerNotFoundError", {
|
|
610
|
+
packageManager: Schema4.String,
|
|
611
|
+
cause: Schema4.String
|
|
612
|
+
}) {
|
|
613
|
+
}
|
|
614
|
+
|
|
603
615
|
class UnsafeTargetError extends Schema4.TaggedErrorClass()("UnsafeTargetError", {
|
|
604
616
|
target: Schema4.String
|
|
605
617
|
}) {
|
|
@@ -621,6 +633,22 @@ class StylesheetNotFoundError extends Schema4.TaggedErrorClass()("StylesheetNotF
|
|
|
621
633
|
path: Schema4.String
|
|
622
634
|
}) {
|
|
623
635
|
}
|
|
636
|
+
|
|
637
|
+
class FileReadError extends Schema4.TaggedErrorClass()("FileReadError", {
|
|
638
|
+
path: Schema4.String,
|
|
639
|
+
message: Schema4.String
|
|
640
|
+
}) {
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
class DuplicateItemError extends Schema4.TaggedErrorClass()("DuplicateItemError", {
|
|
644
|
+
name: Schema4.String
|
|
645
|
+
}) {
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
class NotAProjectError extends Schema4.TaggedErrorClass()("NotAProjectError", {
|
|
649
|
+
cwd: Schema4.String
|
|
650
|
+
}) {
|
|
651
|
+
}
|
|
624
652
|
// src/installer/installer.ts
|
|
625
653
|
import { Effect as Effect4, FileSystem as FileSystem2, Path } from "effect";
|
|
626
654
|
import { ChildProcess } from "effect/unstable/process";
|
|
@@ -686,7 +714,7 @@ var install = (plan) => Effect4.gen(function* () {
|
|
|
686
714
|
stderr: "inherit"
|
|
687
715
|
});
|
|
688
716
|
return yield* handle.exitCode;
|
|
689
|
-
}));
|
|
717
|
+
})).pipe(Effect4.catchTag("PlatformError", (error2) => Effect4.fail(new PackageManagerNotFoundError({ packageManager: plan.packageManager, cause: String(error2) }))));
|
|
690
718
|
if (exitCode !== 0) {
|
|
691
719
|
return yield* new InstallFailedError({
|
|
692
720
|
packageManager: plan.packageManager,
|
|
@@ -757,6 +785,9 @@ var makeGetItem = (options) => Effect6.gen(function* () {
|
|
|
757
785
|
if (template2 === undefined) {
|
|
758
786
|
return yield* new RegistryNotConfiguredError({ namespace });
|
|
759
787
|
}
|
|
788
|
+
if (!template2.includes(namePlaceholder)) {
|
|
789
|
+
return yield* new RegistryTemplateError({ namespace, template: template2 });
|
|
790
|
+
}
|
|
760
791
|
return { location: template2.replace(namePlaceholder, name), template: template2 };
|
|
761
792
|
}
|
|
762
793
|
const originTemplate = Option2.flatMap(maybeOrigin, (origin) => Option2.fromNullishOr(keyTemplates.get(origin)));
|
|
@@ -850,7 +881,11 @@ var planFiles = (context, files) => Effect8.gen(function* () {
|
|
|
850
881
|
const relativeToKind = stripRegistrySourcePrefix(file.path);
|
|
851
882
|
const baseDir = file.type === "registry:lib" ? context.libDir : context.uiDir;
|
|
852
883
|
const absolutePath = path.resolve(baseDir, relativeToKind);
|
|
853
|
-
|
|
884
|
+
const relativeFromCwd = path.relative(context.cwd, absolutePath);
|
|
885
|
+
if (relativeFromCwd.startsWith("..") || path.isAbsolute(relativeFromCwd)) {
|
|
886
|
+
return yield* new UnsafeTargetError({ target: relativeFromCwd });
|
|
887
|
+
}
|
|
888
|
+
planned.push({ absolutePath, relativePath: relativeFromCwd, content });
|
|
854
889
|
}
|
|
855
890
|
return planned;
|
|
856
891
|
});
|
|
@@ -874,6 +909,22 @@ var runAdd = ({ components, cwd, dryRun, overwrite, registry: registry2 }) => Ef
|
|
|
874
909
|
}
|
|
875
910
|
const writableFiles = tree.files.filter((file) => file.type !== "registry:example");
|
|
876
911
|
const allPlanned = yield* planFiles(context, writableFiles);
|
|
912
|
+
if (dryRun) {
|
|
913
|
+
yield* Console.log(`Would write ${allPlanned.length} ${allPlanned.length === 1 ? "file" : "files"}:`);
|
|
914
|
+
for (const file of allPlanned) {
|
|
915
|
+
const exists = yield* fileSystem.exists(file.absolutePath);
|
|
916
|
+
const existing = exists ? yield* fileSystem.readFileString(file.absolutePath) : undefined;
|
|
917
|
+
const note = exists && existing !== file.content ? " (exists — needs --overwrite)" : exists ? " (unchanged)" : "";
|
|
918
|
+
yield* Console.log(` ${file.relativePath}${note}`);
|
|
919
|
+
}
|
|
920
|
+
if (tree.dependencies.length > 0) {
|
|
921
|
+
yield* Console.log(`Would install: ${tree.dependencies.join(" ")}`);
|
|
922
|
+
}
|
|
923
|
+
if (tree.devDependencies.length > 0) {
|
|
924
|
+
yield* Console.log(`Would install (dev): ${tree.devDependencies.join(" ")}`);
|
|
925
|
+
}
|
|
926
|
+
return;
|
|
927
|
+
}
|
|
877
928
|
const planned = [];
|
|
878
929
|
const conflicts = [];
|
|
879
930
|
for (const file of allPlanned) {
|
|
@@ -895,19 +946,6 @@ var runAdd = ({ components, cwd, dryRun, overwrite, registry: registry2 }) => Ef
|
|
|
895
946
|
if (conflicts.length > 0) {
|
|
896
947
|
return yield* new FileConflictError({ paths: conflicts });
|
|
897
948
|
}
|
|
898
|
-
if (dryRun) {
|
|
899
|
-
yield* Console.log(`Would write ${planned.length} files:`);
|
|
900
|
-
for (const file of planned) {
|
|
901
|
-
yield* Console.log(` ${file.relativePath}`);
|
|
902
|
-
}
|
|
903
|
-
if (tree.dependencies.length > 0) {
|
|
904
|
-
yield* Console.log(`Would install: ${tree.dependencies.join(" ")}`);
|
|
905
|
-
}
|
|
906
|
-
if (tree.devDependencies.length > 0) {
|
|
907
|
-
yield* Console.log(`Would install (dev): ${tree.devDependencies.join(" ")}`);
|
|
908
|
-
}
|
|
909
|
-
return;
|
|
910
|
-
}
|
|
911
949
|
for (const file of planned) {
|
|
912
950
|
yield* fileSystem.makeDirectory(path.dirname(file.absolutePath), { recursive: true });
|
|
913
951
|
yield* fileSystem.writeFileString(file.absolutePath, file.content);
|
|
@@ -950,11 +988,17 @@ var registryArgument = Argument2.string("registry").pipe(Argument2.withDescripti
|
|
|
950
988
|
var outputFlag = Flag2.string("output").pipe(Flag2.withAlias("o"), Flag2.withDescription("Destination directory for built registry JSON"), Flag2.withDefault("./public/r"));
|
|
951
989
|
var cwdFlag2 = Flag2.string("cwd").pipe(Flag2.withAlias("c"), Flag2.withDescription("Working directory"), Flag2.withDefault("."));
|
|
952
990
|
var isLocalName = (spec) => !spec.includes("://") && !spec.startsWith("@") && !spec.startsWith(".") && !spec.startsWith("/");
|
|
953
|
-
var
|
|
954
|
-
const
|
|
991
|
+
var validateManifest = (manifest) => Effect9.gen(function* () {
|
|
992
|
+
const seen = new Set;
|
|
993
|
+
for (const item of manifest.items) {
|
|
994
|
+
if (seen.has(item.name)) {
|
|
995
|
+
return yield* new DuplicateItemError({ name: item.name });
|
|
996
|
+
}
|
|
997
|
+
seen.add(item.name);
|
|
998
|
+
}
|
|
955
999
|
for (const item of manifest.items) {
|
|
956
1000
|
for (const dependency of item.registryDependencies ?? []) {
|
|
957
|
-
if (isLocalName(dependency) && !
|
|
1001
|
+
if (isLocalName(dependency) && !seen.has(dependency)) {
|
|
958
1002
|
return yield* new UnknownRegistryDependencyError({ itemName: item.name, dependency });
|
|
959
1003
|
}
|
|
960
1004
|
}
|
|
@@ -965,14 +1009,21 @@ var buildCommand = Command2.make("build", { registry: registryArgument, output:
|
|
|
965
1009
|
const path = yield* Path5.Path;
|
|
966
1010
|
const cwdAbsolute = path.resolve(cwd);
|
|
967
1011
|
const manifestPath = path.resolve(cwdAbsolute, registry2);
|
|
968
|
-
const manifestJson = yield* readJsonFile(manifestPath);
|
|
1012
|
+
const manifestJson = yield* readJsonFile(manifestPath).pipe(Effect9.catchTag("PlatformError", (error2) => Effect9.fail(new FileReadError({ path: manifestPath, message: `registry manifest not readable: ${error2}` }))));
|
|
969
1013
|
const manifest = yield* Schema7.decodeUnknownEffect(exports_registry.Manifest)(manifestJson);
|
|
970
|
-
yield*
|
|
1014
|
+
yield* validateManifest(manifest);
|
|
971
1015
|
const outputDir = path.resolve(cwdAbsolute, output);
|
|
972
1016
|
yield* fileSystem.makeDirectory(outputDir, { recursive: true });
|
|
1017
|
+
const existingEntries = yield* fileSystem.readDirectory(outputDir).pipe(Effect9.orElseSucceed(() => []));
|
|
1018
|
+
yield* Effect9.forEach(existingEntries.filter((entry) => entry.endsWith(".json")), (entry) => fileSystem.remove(path.join(outputDir, entry)).pipe(Effect9.orElseSucceed(() => {
|
|
1019
|
+
return;
|
|
1020
|
+
})));
|
|
973
1021
|
for (const item of manifest.items) {
|
|
974
1022
|
const files = yield* Effect9.forEach(item.files ?? [], (file) => Effect9.gen(function* () {
|
|
975
|
-
const content = yield* fileSystem.readFileString(path.resolve(cwdAbsolute, file.path))
|
|
1023
|
+
const content = yield* fileSystem.readFileString(path.resolve(cwdAbsolute, file.path)).pipe(Effect9.catchTag("PlatformError", (error2) => Effect9.fail(new FileReadError({
|
|
1024
|
+
path: file.path,
|
|
1025
|
+
message: `source file referenced by item "${item.name}" not readable: ${error2}`
|
|
1026
|
+
}))));
|
|
976
1027
|
return { ...file, content };
|
|
977
1028
|
}));
|
|
978
1029
|
const builtItem = {
|
|
@@ -1076,7 +1127,7 @@ var initCommand = Command3.make("init", {
|
|
|
1076
1127
|
const cwdAbsolute = path.resolve(cwd);
|
|
1077
1128
|
const hasPackageJson = yield* fileSystem.exists(path.join(cwdAbsolute, "package.json"));
|
|
1078
1129
|
if (!hasPackageJson) {
|
|
1079
|
-
return yield* new
|
|
1130
|
+
return yield* new NotAProjectError({ cwd: cwdAbsolute });
|
|
1080
1131
|
}
|
|
1081
1132
|
const packageJson = yield* readJsonFile(path.join(cwdAbsolute, "package.json")).pipe(Effect10.orElseSucceed(() => ({})));
|
|
1082
1133
|
const dependencies = packageJson.dependencies ?? {};
|
|
@@ -1123,4 +1174,38 @@ var run = Effect11.fn("FoldcnCli.run")(function* (argv) {
|
|
|
1123
1174
|
var main = Command4.run(command, { version });
|
|
1124
1175
|
|
|
1125
1176
|
// src/bin.ts
|
|
1126
|
-
|
|
1177
|
+
var fail = (message) => Console4.error(message).pipe(Effect12.andThen(Effect12.sync(() => globalThis.process.exitCode = 1)));
|
|
1178
|
+
var handled = main.pipe(Effect12.catchTags({
|
|
1179
|
+
ConfigNotFoundError: (error2) => fail(`No components.json found in ${error2.cwd}.
|
|
1180
|
+
Run \`foldcn init\` to create one, then try again.`),
|
|
1181
|
+
NotAProjectError: (error2) => fail(`No package.json found in ${error2.cwd}.
|
|
1182
|
+
Run \`foldcn init\` from your project root (a FoldKit app).`),
|
|
1183
|
+
JsonParseError: (error2) => fail(`Could not parse ${error2.path}:
|
|
1184
|
+
${error2.message}`),
|
|
1185
|
+
FileReadError: (error2) => fail(`Could not read ${error2.path}:
|
|
1186
|
+
${error2.message}`),
|
|
1187
|
+
DuplicateItemError: (error2) => fail(`The registry manifest declares two items named "${error2.name}". Item names must be unique.`),
|
|
1188
|
+
RegistryFetchError: (error2) => fail(`Could not fetch registry item "${error2.spec}".
|
|
1189
|
+
${error2.message}
|
|
1190
|
+
Check the component name and your registry configuration.`),
|
|
1191
|
+
RegistryNotConfiguredError: (error2) => fail(`No registry configured for "${error2.namespace}".
|
|
1192
|
+
Add it to the "registries" map in components.json.`),
|
|
1193
|
+
RegistryTemplateError: (error2) => fail(`The registry template for "${error2.namespace}" is missing the {name} placeholder:
|
|
1194
|
+
${error2.template}
|
|
1195
|
+
Add {name} so each component resolves to its own file.`),
|
|
1196
|
+
UnsafeTargetError: (error2) => fail(`Refusing to write outside the project: ${error2.target}
|
|
1197
|
+
Check the "aliases" in components.json and the item's target.`),
|
|
1198
|
+
FileConflictError: (error2) => fail(`These files already exist and differ from the registry:
|
|
1199
|
+
${error2.paths.map((path) => ` ${path}`).join(`
|
|
1200
|
+
`)}
|
|
1201
|
+
Pass --overwrite to replace them.`),
|
|
1202
|
+
InstallFailedError: (error2) => fail(`\`${error2.packageManager} ${error2.invocation}\` failed (exit ${error2.exitCode}).
|
|
1203
|
+
The component files were written; install the dependencies manually.`),
|
|
1204
|
+
PackageManagerNotFoundError: (error2) => fail(`Could not run the package manager "${error2.packageManager}".
|
|
1205
|
+
${error2.cause}
|
|
1206
|
+
Install it (or use a project with a lockfile for another manager), then re-run.`),
|
|
1207
|
+
StylesheetNotFoundError: (error2) => fail(`Stylesheet not found: ${error2.path}
|
|
1208
|
+
Check the "css" path in components.json.`),
|
|
1209
|
+
UnknownRegistryDependencyError: (error2) => fail(`"${error2.itemName}" depends on "${error2.dependency}", which is not in the registry.`)
|
|
1210
|
+
}));
|
|
1211
|
+
NodeRuntime.runMain(handled.pipe(Effect12.provide(NodeServices.layer)));
|
package/package.json
CHANGED