jsrepo 1.2.4 → 1.3.1

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/index.js CHANGED
@@ -1,35 +1,37 @@
1
1
  // src/index.ts
2
- import fs11 from "node:fs";
3
- import path11 from "node:path";
2
+ import fs12 from "node:fs";
3
+ import path12 from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
- import { program as program5 } from "commander";
5
+ import { program as program6 } from "commander";
6
6
 
7
7
  // src/commands/add.ts
8
8
  import fs6 from "node:fs";
9
9
  import path6 from "node:path";
10
10
  import { cancel, confirm, isCancel, multiselect, outro, spinner as spinner2 } from "@clack/prompts";
11
- import color5 from "chalk";
11
+ import color7 from "chalk";
12
12
  import { Command, program as program2 } from "commander";
13
- import { execa } from "execa";
14
- import { resolveCommand } from "package-manager-detector/commands";
13
+ import { resolveCommand as resolveCommand2 } from "package-manager-detector/commands";
15
14
  import { detect } from "package-manager-detector/detect";
16
15
  import * as v4 from "valibot";
17
16
 
18
- // src/blocks/utils/map-to-array.ts
19
- var mapToArray = (map, fn) => {
20
- const items = [];
21
- for (const [key, value] of map) {
22
- items.push(fn(key, value));
23
- }
24
- return items;
25
- };
17
+ // src/utils/ascii.ts
18
+ import color from "chalk";
19
+ var VERTICAL_LINE = color.gray("\u2502");
20
+ var HORIZONTAL_LINE = color.gray("\u2500");
21
+ var TOP_RIGHT_CORNER = color.gray("\u2510");
22
+ var BOTTOM_RIGHT_CORNER = color.gray("\u2518");
23
+ var JUNCTION_RIGHT = color.gray("\u251C");
24
+ var TOP_LEFT_CORNER = color.gray("\u250C");
25
+ var BOTTOM_LEFT_CORNER = color.gray("\u2514");
26
+ var WARN = color.bgRgb(245, 149, 66).white("WARN");
27
+ var INFO = color.bgBlueBright.white("INFO");
26
28
 
27
- // src/config/index.ts
28
- import fs from "node:fs";
29
- import path from "node:path";
30
- import * as v from "valibot";
29
+ // src/utils/blocks.ts
30
+ import fs4 from "node:fs";
31
+ import path4 from "node:path";
32
+ import color4 from "chalk";
31
33
 
32
- // src/blocks/types/result.ts
34
+ // src/utils/blocks/types/result.ts
33
35
  var Result = class {
34
36
  _result;
35
37
  constructor(result) {
@@ -667,46 +669,30 @@ var Err = (err) => {
667
669
  return new Result({ ok: false, err });
668
670
  };
669
671
 
670
- // src/config/index.ts
671
- var CONFIG_NAME = "jsrepo.json";
672
- var schema = v.object({
673
- $schema: v.string(),
674
- repos: v.optional(v.array(v.string()), []),
675
- includeTests: v.boolean(),
676
- path: v.pipe(v.string(), v.minLength(1)),
677
- watermark: v.optional(v.boolean(), true)
678
- });
679
- var getConfig = (cwd) => {
680
- if (!fs.existsSync(path.join(cwd, CONFIG_NAME))) {
681
- return Err("Could not find your configuration file! Please run `init`.");
682
- }
683
- const config = v.safeParse(
684
- schema,
685
- JSON.parse(fs.readFileSync(path.join(cwd, CONFIG_NAME)).toString())
686
- );
687
- if (!config.success) {
688
- return Err(`There was an error reading your \`${CONFIG_NAME}\` file!`);
672
+ // src/utils/blocks/utils/map-to-array.ts
673
+ var mapToArray = (map, fn) => {
674
+ const items = [];
675
+ for (const [key, value] of map) {
676
+ items.push(fn(key, value));
689
677
  }
690
- return Ok(config.output);
678
+ return items;
691
679
  };
692
680
 
681
+ // src/utils/git-providers.ts
682
+ import { Octokit } from "octokit";
683
+ import * as v2 from "valibot";
684
+
693
685
  // src/utils/build.ts
694
- import fs4 from "node:fs";
695
- import path4 from "node:path";
686
+ import fs3 from "node:fs";
687
+ import path3 from "node:path";
696
688
  import color3 from "chalk";
697
689
  import { program } from "commander";
698
- import * as v2 from "valibot";
699
-
700
- // src/utils/index.ts
701
- import color from "chalk";
702
- var OUTPUT_FILE = "jsrepo-manifest.json";
703
- var WARN = color.bgRgb(245, 149, 66).white("WARN");
704
- var INFO = color.bgBlueBright.white("INFO");
690
+ import * as v from "valibot";
705
691
 
706
692
  // src/utils/language-support.ts
707
- import fs3 from "node:fs";
693
+ import fs2 from "node:fs";
708
694
  import { builtinModules } from "node:module";
709
- import path3 from "node:path";
695
+ import path2 from "node:path";
710
696
  import color2 from "chalk";
711
697
  import { walk } from "estree-walker";
712
698
  import * as sv from "svelte/compiler";
@@ -714,11 +700,11 @@ import { Project } from "ts-morph";
714
700
  import validatePackageName from "validate-npm-package-name";
715
701
 
716
702
  // src/utils/package.ts
717
- import fs2 from "node:fs";
718
- import path2 from "node:path";
703
+ import fs from "node:fs";
704
+ import path from "node:path";
719
705
  var findNearestPackageJson = (startDir, until) => {
720
- const packagePath = path2.join(startDir, "package.json");
721
- if (fs2.existsSync(packagePath)) return packagePath;
706
+ const packagePath = path.join(startDir, "package.json");
707
+ if (fs.existsSync(packagePath)) return packagePath;
722
708
  if (startDir === until) return void 0;
723
709
  const segments = startDir.split(/[\/\\]/);
724
710
  return findNearestPackageJson(segments.slice(0, segments.length - 1).join("/"), until);
@@ -768,7 +754,7 @@ ${content}
768
754
  var svelte = {
769
755
  matches: (fileName) => fileName.endsWith(".svelte"),
770
756
  resolveDependencies: (filePath, category, isSubDir) => {
771
- const sourceCode = fs3.readFileSync(filePath).toString();
757
+ const sourceCode = fs2.readFileSync(filePath).toString();
772
758
  const root = sv.parse(sourceCode, { modern: true });
773
759
  if (!root.instance) return Ok({ dependencies: [], devDependencies: [], local: [] });
774
760
  const localDeps = /* @__PURE__ */ new Set();
@@ -805,10 +791,10 @@ ${content}
805
791
  var resolveLocalImport = (mod, category, isSubDir) => {
806
792
  if (isSubDir && mod.startsWith("./")) return void 0;
807
793
  if (mod.startsWith("./")) {
808
- return `${category}/${path3.parse(path3.basename(mod)).name}`;
794
+ return `${category}/${path2.parse(path2.basename(mod)).name}`;
809
795
  }
810
796
  if (isSubDir && mod.startsWith("../") && !mod.startsWith("../.")) {
811
- return `${category}/${path3.parse(path3.basename(mod)).name}`;
797
+ return `${category}/${path2.parse(path2.basename(mod)).name}`;
812
798
  }
813
799
  const segments = mod.replaceAll("../", "").split("/");
814
800
  if (segments.length !== 2) return void 0;
@@ -818,11 +804,11 @@ var resolveRemoteDeps = (deps, filePath) => {
818
804
  const filteredDeps = deps.filter(
819
805
  (dep) => !builtinModules.includes(dep) && !dep.startsWith("node:")
820
806
  );
821
- const pkgPath = findNearestPackageJson(path3.dirname(filePath), "");
807
+ const pkgPath = findNearestPackageJson(path2.dirname(filePath), "");
822
808
  const dependencies = /* @__PURE__ */ new Set();
823
809
  const devDependencies = /* @__PURE__ */ new Set();
824
810
  if (pkgPath) {
825
- const { devDependencies: packageDevDependencies, dependencies: packageDependencies } = JSON.parse(fs3.readFileSync(pkgPath, "utf-8"));
811
+ const { devDependencies: packageDevDependencies, dependencies: packageDependencies } = JSON.parse(fs2.readFileSync(pkgPath, "utf-8"));
826
812
  for (const dep of filteredDeps) {
827
813
  const parsed = parsePackageName(dep);
828
814
  if (parsed.isErr()) {
@@ -864,55 +850,55 @@ var resolveRemoteDeps = (deps, filePath) => {
864
850
  var languages = [typescript, svelte];
865
851
 
866
852
  // src/utils/build.ts
867
- var blockSchema = v2.object({
868
- name: v2.string(),
869
- category: v2.string(),
870
- localDependencies: v2.array(v2.string()),
871
- dependencies: v2.array(v2.string()),
872
- devDependencies: v2.array(v2.string()),
873
- tests: v2.boolean(),
853
+ var blockSchema = v.object({
854
+ name: v.string(),
855
+ category: v.string(),
856
+ localDependencies: v.array(v.string()),
857
+ dependencies: v.array(v.string()),
858
+ devDependencies: v.array(v.string()),
859
+ tests: v.boolean(),
874
860
  /** Where to find the block relative to root */
875
- directory: v2.string(),
876
- subdirectory: v2.boolean(),
877
- files: v2.array(v2.string())
861
+ directory: v.string(),
862
+ subdirectory: v.boolean(),
863
+ files: v.array(v.string())
878
864
  });
879
- var categorySchema = v2.object({
880
- name: v2.string(),
881
- blocks: v2.array(blockSchema)
865
+ var categorySchema = v.object({
866
+ name: v.string(),
867
+ blocks: v.array(blockSchema)
882
868
  });
883
869
  var TEST_SUFFIXES = [".test.ts", "_test.ts", ".test.js", "_test.js"];
884
870
  var isTestFile = (file) => TEST_SUFFIXES.find((suffix) => file.endsWith(suffix)) !== void 0;
885
871
  var buildBlocksDirectory = (blocksPath, cwd) => {
886
872
  let paths;
887
873
  try {
888
- paths = fs4.readdirSync(blocksPath);
874
+ paths = fs3.readdirSync(blocksPath);
889
875
  } catch {
890
876
  program.error(color3.red(`Couldn't read the ${color3.bold(blocksPath)} directory.`));
891
877
  }
892
878
  const categories = [];
893
879
  for (const categoryPath of paths) {
894
- const categoryDir = path4.join(blocksPath, categoryPath);
895
- if (fs4.statSync(categoryDir).isFile()) continue;
896
- const categoryName = path4.basename(categoryPath);
880
+ const categoryDir = path3.join(blocksPath, categoryPath);
881
+ if (fs3.statSync(categoryDir).isFile()) continue;
882
+ const categoryName = path3.basename(categoryPath);
897
883
  const category = {
898
884
  name: categoryName,
899
885
  blocks: []
900
886
  };
901
- const files = fs4.readdirSync(categoryDir);
887
+ const files = fs3.readdirSync(categoryDir);
902
888
  for (const file of files) {
903
- const blockDir = path4.join(categoryDir, file);
904
- if (fs4.statSync(blockDir).isFile()) {
889
+ const blockDir = path3.join(categoryDir, file);
890
+ if (fs3.statSync(blockDir).isFile()) {
905
891
  if (isTestFile(file)) continue;
906
892
  const lang = languages.find((resolver) => resolver.matches(file));
907
893
  if (!lang) {
908
894
  console.warn(
909
895
  `${WARN} Skipped \`${color3.bold(blockDir)}\` \`${color3.bold(
910
- path4.parse(file).ext
896
+ path3.parse(file).ext
911
897
  )}\` files are not currently supported!`
912
898
  );
913
899
  continue;
914
900
  }
915
- const name2 = path4.parse(path4.basename(file)).name;
901
+ const name2 = path3.parse(path3.basename(file)).name;
916
902
  const testsPath = files.find(
917
903
  (f) => TEST_SUFFIXES.find((suffix) => f === `${name2}${suffix}`)
918
904
  );
@@ -924,7 +910,7 @@ var buildBlocksDirectory = (blocksPath, cwd) => {
924
910
  );
925
911
  const block = {
926
912
  name: name2,
927
- directory: path4.relative(cwd, categoryDir),
913
+ directory: path3.relative(cwd, categoryDir),
928
914
  category: categoryName,
929
915
  tests: testsPath !== void 0,
930
916
  subdirectory: false,
@@ -939,7 +925,7 @@ var buildBlocksDirectory = (blocksPath, cwd) => {
939
925
  category.blocks.push(block);
940
926
  } else {
941
927
  const blockName = file;
942
- const blockFiles = fs4.readdirSync(blockDir);
928
+ const blockFiles = fs3.readdirSync(blockDir);
943
929
  const hasTests = blockFiles.findIndex((f) => isTestFile(f)) !== -1;
944
930
  const localDepsSet = /* @__PURE__ */ new Set();
945
931
  const depsSet = /* @__PURE__ */ new Set();
@@ -949,13 +935,13 @@ var buildBlocksDirectory = (blocksPath, cwd) => {
949
935
  const lang = languages.find((resolver) => resolver.matches(f));
950
936
  if (!lang) {
951
937
  console.warn(
952
- `${WARN} Skipped \`${color3.bold(path4.join(blockDir, f))}\` \`${color3.bold(
953
- path4.parse(file).ext
938
+ `${WARN} Skipped \`${color3.bold(path3.join(blockDir, f))}\` \`${color3.bold(
939
+ path3.parse(file).ext
954
940
  )}\` files are not currently supported!`
955
941
  );
956
942
  continue;
957
943
  }
958
- const { local, dependencies, devDependencies } = lang.resolveDependencies(path4.join(blockDir, f), categoryName, true).match(
944
+ const { local, dependencies, devDependencies } = lang.resolveDependencies(path3.join(blockDir, f), categoryName, true).match(
959
945
  (val) => val,
960
946
  (err) => {
961
947
  program.error(color3.red(err));
@@ -973,7 +959,7 @@ var buildBlocksDirectory = (blocksPath, cwd) => {
973
959
  }
974
960
  const block = {
975
961
  name: blockName,
976
- directory: path4.relative(cwd, blockDir),
962
+ directory: path3.relative(cwd, blockDir),
977
963
  category: categoryName,
978
964
  tests: hasTests,
979
965
  subdirectory: true,
@@ -990,36 +976,10 @@ var buildBlocksDirectory = (blocksPath, cwd) => {
990
976
  return categories;
991
977
  };
992
978
 
993
- // src/utils/get-installed-blocks.ts
994
- import fs5 from "node:fs";
995
- import path5 from "node:path";
996
- var getInstalledBlocks = (blocks, config, cwd) => {
997
- const installedBlocks = [];
998
- for (const [_, block] of blocks) {
999
- const baseDir = path5.join(cwd, config.path, block.category);
1000
- let blockPath = path5.join(baseDir, block.files[0]);
1001
- if (block.subdirectory) {
1002
- blockPath = path5.join(baseDir, block.name);
1003
- }
1004
- if (fs5.existsSync(blockPath))
1005
- installedBlocks.push({
1006
- specifier: `${block.category}/${block.name}`,
1007
- path: blockPath
1008
- });
1009
- }
1010
- return installedBlocks;
1011
- };
1012
-
1013
- // src/utils/get-watermark.ts
1014
- var getWatermark = (version2, repoUrl) => {
1015
- return ` jsrepo ${version2}
1016
- Installed from ${repoUrl}
1017
- ${(/* @__PURE__ */ new Date()).toLocaleDateString().replaceAll("/", "-")}`;
1018
- };
979
+ // src/utils/context.ts
980
+ var OUTPUT_FILE = "jsrepo-manifest.json";
1019
981
 
1020
982
  // src/utils/git-providers.ts
1021
- import { Octokit } from "octokit";
1022
- import * as v3 from "valibot";
1023
983
  var octokit = new Octokit({});
1024
984
  var github = {
1025
985
  name: () => "github",
@@ -1069,38 +1029,194 @@ var github = {
1069
1029
  },
1070
1030
  matches: (repoPath) => repoPath.toLowerCase().startsWith("https://github.com") || repoPath.toLowerCase().startsWith("github")
1071
1031
  };
1032
+ var providers = [github];
1072
1033
  var getProviderInfo = async (repo) => {
1073
- if (github.matches(repo)) {
1074
- return Ok(await github.info(repo));
1034
+ const provider = providers.find((provider2) => provider2.matches(repo));
1035
+ if (provider) {
1036
+ return Ok(await provider.info(repo));
1075
1037
  }
1076
1038
  return Err("Only GitHub repositories are supported at this time!");
1077
1039
  };
1078
1040
  var getManifest = async (url) => {
1041
+ const errorMessage = (err) => {
1042
+ return Err(
1043
+ `There was an error fetching the \`${OUTPUT_FILE}\` from the repository \`${url.href}\` make sure the target repository has a \`${OUTPUT_FILE}\` in its root.
1044
+ Error: ${err}`
1045
+ );
1046
+ };
1079
1047
  try {
1080
1048
  const response = await fetch(url);
1081
1049
  if (!response.ok) {
1082
- return Err(
1083
- `There was an error fetching the \`${OUTPUT_FILE}\` from the repository \`${url.href}\` make sure the target repository has a \`${OUTPUT_FILE}\` in its root?`
1084
- );
1050
+ return errorMessage(`${response.status} ${response.text}`);
1085
1051
  }
1086
- const categories = v3.parse(v3.array(categorySchema), await response.json());
1052
+ const categories = v2.parse(v2.array(categorySchema), await response.json());
1087
1053
  return Ok(categories);
1054
+ } catch (err) {
1055
+ return errorMessage(`${err}`);
1056
+ }
1057
+ };
1058
+ var fetchBlocks = async (...repos) => {
1059
+ const blocksMap = /* @__PURE__ */ new Map();
1060
+ for (const repo of repos) {
1061
+ const getProviderResult = await getProviderInfo(repo);
1062
+ if (getProviderResult.isErr()) return Err({ message: getProviderResult.unwrapErr(), repo });
1063
+ const providerInfo = getProviderResult.unwrap();
1064
+ const manifestUrl = await providerInfo.provider.resolveRaw(providerInfo, OUTPUT_FILE);
1065
+ const getManifestResult = await getManifest(manifestUrl);
1066
+ if (getManifestResult.isErr()) return Err({ message: getManifestResult.unwrapErr(), repo });
1067
+ const categories = getManifestResult.unwrap();
1068
+ for (const category of categories) {
1069
+ for (const block of category.blocks) {
1070
+ blocksMap.set(
1071
+ `${providerInfo.name}/${providerInfo.owner}/${providerInfo.repoName}/${category.name}/${block.name}`,
1072
+ {
1073
+ ...block,
1074
+ sourceRepo: providerInfo
1075
+ }
1076
+ );
1077
+ }
1078
+ }
1079
+ }
1080
+ return Ok(blocksMap);
1081
+ };
1082
+
1083
+ // src/utils/blocks.ts
1084
+ var resolveTree = async (blockSpecifiers, blocksMap, repoPaths) => {
1085
+ const blocks = /* @__PURE__ */ new Map();
1086
+ for (const blockSpecifier of blockSpecifiers) {
1087
+ let block = void 0;
1088
+ if (!blockSpecifier.startsWith("github")) {
1089
+ if (repoPaths.length === 0) {
1090
+ return Err(
1091
+ color4.red(
1092
+ `If your config doesn't repos then you must provide the repo in the block specifier ex: \`${color4.bold(
1093
+ `github/<owner>/<name>/${blockSpecifier}`
1094
+ )}\`!`
1095
+ )
1096
+ );
1097
+ }
1098
+ for (const repo of repoPaths) {
1099
+ const providerInfo = (await getProviderInfo(repo)).unwrap();
1100
+ const tempBlock = blocksMap.get(
1101
+ `${providerInfo.name}/${providerInfo.owner}/${providerInfo.repoName}/${blockSpecifier}`
1102
+ );
1103
+ if (tempBlock === void 0) continue;
1104
+ block = tempBlock;
1105
+ break;
1106
+ }
1107
+ } else {
1108
+ block = blocksMap.get(blockSpecifier);
1109
+ }
1110
+ if (!block) {
1111
+ return Err(`Invalid block! ${color4.bold(blockSpecifier)} does not exist!`);
1112
+ }
1113
+ const fullSpecifier = `${block.sourceRepo.url}/${block.category}/${block.name}`;
1114
+ blocks.set(fullSpecifier, { name: fullSpecifier, subDependency: false, block });
1115
+ if (block.localDependencies && block.localDependencies.length > 0) {
1116
+ const subDeps = await resolveTree(
1117
+ block.localDependencies.filter((dep) => !blocks.has(dep)),
1118
+ blocksMap,
1119
+ repoPaths
1120
+ );
1121
+ if (subDeps.isErr()) return Err(subDeps.unwrapErr());
1122
+ for (const dep of subDeps.unwrap()) {
1123
+ blocks.set(dep.name, dep);
1124
+ }
1125
+ }
1126
+ }
1127
+ return Ok(mapToArray(blocks, (_, val) => val));
1128
+ };
1129
+ var getInstalled = (blocks, config, cwd) => {
1130
+ const installedBlocks = [];
1131
+ for (const [_, block] of blocks) {
1132
+ const baseDir = path4.join(cwd, config.path, block.category);
1133
+ let blockPath = path4.join(baseDir, block.files[0]);
1134
+ if (block.subdirectory) {
1135
+ blockPath = path4.join(baseDir, block.name);
1136
+ }
1137
+ if (fs4.existsSync(blockPath))
1138
+ installedBlocks.push({
1139
+ specifier: `${block.category}/${block.name}`,
1140
+ path: blockPath,
1141
+ block
1142
+ });
1143
+ }
1144
+ return installedBlocks;
1145
+ };
1146
+
1147
+ // src/utils/config.ts
1148
+ import fs5 from "node:fs";
1149
+ import path5 from "node:path";
1150
+ import * as v3 from "valibot";
1151
+ var CONFIG_NAME = "jsrepo.json";
1152
+ var schema = v3.object({
1153
+ $schema: v3.string(),
1154
+ repos: v3.optional(v3.array(v3.string()), []),
1155
+ includeTests: v3.boolean(),
1156
+ path: v3.pipe(v3.string(), v3.minLength(1)),
1157
+ watermark: v3.optional(v3.boolean(), true)
1158
+ });
1159
+ var getConfig = (cwd) => {
1160
+ if (!fs5.existsSync(path5.join(cwd, CONFIG_NAME))) {
1161
+ return Err("Could not find your configuration file! Please run `init`.");
1162
+ }
1163
+ const config = v3.safeParse(
1164
+ schema,
1165
+ JSON.parse(fs5.readFileSync(path5.join(cwd, CONFIG_NAME)).toString())
1166
+ );
1167
+ if (!config.success) {
1168
+ return Err(`There was an error reading your \`${CONFIG_NAME}\` file!`);
1169
+ }
1170
+ return Ok(config.output);
1171
+ };
1172
+
1173
+ // src/utils/dependencies.ts
1174
+ import color5 from "chalk";
1175
+ import { execa } from "execa";
1176
+ import { resolveCommand } from "package-manager-detector";
1177
+ var installDependencies = async ({
1178
+ pm,
1179
+ deps,
1180
+ dev,
1181
+ cwd
1182
+ }) => {
1183
+ let add2;
1184
+ if (dev) {
1185
+ add2 = resolveCommand(pm, "install", [...deps, "-D"]);
1186
+ } else {
1187
+ add2 = resolveCommand(pm, "install", [...deps]);
1188
+ }
1189
+ if (add2 == null) return Err(color5.red(`Could not resolve add command for '${pm}'.`));
1190
+ try {
1191
+ await execa(add2.command, [...add2.args], { cwd });
1192
+ return Ok(deps);
1088
1193
  } catch {
1089
1194
  return Err(
1090
- `There was an error fetching the \`${OUTPUT_FILE}\` from the repository \`${url.href}\` make sure the target repository has a \`${OUTPUT_FILE}\` in its root?`
1195
+ color5.red(
1196
+ `Failed to install ${color5.bold(deps.join(", "))}! Failed while running '${color5.bold(
1197
+ `${add2.command} ${add2.args.join(" ")}`
1198
+ )}'`
1199
+ )
1091
1200
  );
1092
1201
  }
1093
1202
  };
1094
1203
 
1204
+ // src/utils/get-watermark.ts
1205
+ var getWatermark = (version2, repoUrl) => {
1206
+ return ` jsrepo ${version2}
1207
+ Installed from ${repoUrl}
1208
+ ${(/* @__PURE__ */ new Date()).toLocaleDateString().replaceAll("/", "-")}`;
1209
+ };
1210
+
1095
1211
  // src/utils/prompts.ts
1096
1212
  import { intro, spinner } from "@clack/prompts";
1097
- import color4 from "chalk";
1213
+ import color6 from "chalk";
1098
1214
 
1099
- // src/blocks/utils/strip-ansi.ts
1215
+ // src/utils/blocks/utils/strip-ansi.ts
1100
1216
  import ansiRegex from "ansi-regex";
1101
1217
  var stripAsni = (str) => str.replace(ansiRegex(), "");
1102
1218
 
1103
- // src/blocks/utils/pad.ts
1219
+ // src/utils/blocks/utils/pad.ts
1104
1220
  var leftPadMin = (str, length, padWith = " ") => {
1105
1221
  if (stripAsni(str).length > length)
1106
1222
  throw new Error("String length is greater than the length provided.");
@@ -1116,21 +1232,25 @@ var rightPadMin = (str, length, padWith = " ") => {
1116
1232
  };
1117
1233
 
1118
1234
  // src/utils/prompts.ts
1119
- var VERTICAL_BORDER = color4.gray("\u2502");
1120
- var HORIZONTAL_BORDER = color4.gray("\u2500");
1121
- var TOP_RIGHT_CORNER = color4.gray("\u2510");
1122
- var BOTTOM_RIGHT_CORNER = color4.gray("\u2518");
1123
- var JUNCTION_RIGHT = color4.gray("\u251C");
1124
- var runTasks = async (tasks, { verbose = false }) => {
1235
+ var runTasks = async (tasks, { verbose = void 0 }) => {
1125
1236
  const loading = spinner();
1126
1237
  for (const task of tasks) {
1127
- if (!verbose) loading.start(task.loadingMessage);
1238
+ if (verbose) {
1239
+ verbose(task.loadingMessage);
1240
+ } else {
1241
+ loading.start(task.loadingMessage);
1242
+ }
1128
1243
  try {
1129
1244
  await task.run();
1130
1245
  } catch (err) {
1246
+ loading.stop(`Error while ${task.loadingMessage}`);
1131
1247
  console.error(err);
1132
1248
  }
1133
- if (!verbose) loading.stop(task.completedMessage);
1249
+ if (verbose) {
1250
+ verbose(task.completedMessage);
1251
+ } else {
1252
+ loading.stop(task.completedMessage);
1253
+ }
1134
1254
  }
1135
1255
  };
1136
1256
  var nextSteps = (steps) => {
@@ -1140,40 +1260,44 @@ var nextSteps = (steps) => {
1140
1260
  if (reset.length > max) max = reset.length;
1141
1261
  });
1142
1262
  const NEXT_STEPS = "Next Steps";
1143
- let result = `${VERTICAL_BORDER}
1263
+ let result = `${VERTICAL_LINE}
1144
1264
  `;
1145
- result += `${JUNCTION_RIGHT} ${NEXT_STEPS} ${HORIZONTAL_BORDER.repeat(
1265
+ result += `${JUNCTION_RIGHT} ${NEXT_STEPS} ${HORIZONTAL_LINE.repeat(
1146
1266
  max - NEXT_STEPS.length - 1
1147
1267
  )}${TOP_RIGHT_CORNER}
1148
1268
  `;
1149
- result += `${VERTICAL_BORDER} ${" ".repeat(max)} ${VERTICAL_BORDER}
1269
+ result += `${VERTICAL_LINE} ${" ".repeat(max)} ${VERTICAL_LINE}
1150
1270
  `;
1151
1271
  steps.map((step) => {
1152
- result += `${VERTICAL_BORDER} ${rightPadMin(step, max - 1)} ${VERTICAL_BORDER}
1272
+ result += `${VERTICAL_LINE} ${rightPadMin(step, max - 1)} ${VERTICAL_LINE}
1153
1273
  `;
1154
1274
  });
1155
- result += `${VERTICAL_BORDER} ${" ".repeat(max)} ${VERTICAL_BORDER}
1275
+ result += `${VERTICAL_LINE} ${" ".repeat(max)} ${VERTICAL_LINE}
1156
1276
  `;
1157
- result += `${JUNCTION_RIGHT}${HORIZONTAL_BORDER.repeat(max + 2)}${BOTTOM_RIGHT_CORNER}
1277
+ result += `${JUNCTION_RIGHT}${HORIZONTAL_LINE.repeat(max + 2)}${BOTTOM_RIGHT_CORNER}
1158
1278
  `;
1159
1279
  return result;
1160
1280
  };
1161
- var _intro = (version2) => intro(`${color4.bgHex("#f7df1e").black(" jsrepo ")}${color4.gray(` v${version2} `)}`);
1281
+ var _intro = (version2) => intro(`${color6.bgHex("#f7df1e").black(" jsrepo ")}${color6.gray(` v${version2} `)}`);
1162
1282
 
1163
1283
  // src/commands/add.ts
1164
1284
  var schema2 = v4.object({
1165
- yes: v4.boolean(),
1166
- verbose: v4.boolean(),
1167
1285
  repo: v4.optional(v4.string()),
1168
1286
  allow: v4.boolean(),
1287
+ yes: v4.boolean(),
1288
+ verbose: v4.boolean(),
1169
1289
  cwd: v4.string()
1170
1290
  });
1171
- var add = new Command("add").argument("[blocks...]", "Names of the blocks you want to add to your project.").option("-y, --yes", "Add and install any required dependencies.", false).option("-A, --allow", "Allow jsrepo to download code from the provided repo.", false).option("--repo <repo>", "Repository to download the blocks from.").option("--verbose", "Include debug logs.", false).option("--cwd <path>", "The current working directory.", process.cwd()).action(async (blockNames, opts) => {
1291
+ var add = new Command("add").argument(
1292
+ "[blocks...]",
1293
+ "Names of the blocks you want to add to your project. ex: (utils/math, github/ieedan/std/utils/math)"
1294
+ ).option("--repo <repo>", "Repository to download the blocks from.").option("-A, --allow", "Allow jsrepo to download code from the provided repo.", false).option("-y, --yes", "Skip confirmation prompt.", false).option("--verbose", "Include debug logs.", false).option("--cwd <path>", "The current working directory.", process.cwd()).action(async (blockNames, opts) => {
1172
1295
  const options = v4.parse(schema2, opts);
1296
+ _intro(context.package.version);
1173
1297
  await _add(blockNames, options);
1298
+ outro(color7.green("All done!"));
1174
1299
  });
1175
1300
  var _add = async (blockNames, options) => {
1176
- _intro(context.package.version);
1177
1301
  const verbose = (msg) => {
1178
1302
  if (options.verbose) {
1179
1303
  console.info(`${INFO} ${msg}`);
@@ -1183,9 +1307,8 @@ var _add = async (blockNames, options) => {
1183
1307
  const loading = spinner2();
1184
1308
  const config = getConfig(options.cwd).match(
1185
1309
  (val) => val,
1186
- (err) => program2.error(color5.red(err))
1310
+ (err) => program2.error(color7.red(err))
1187
1311
  );
1188
- const blocksMap = /* @__PURE__ */ new Map();
1189
1312
  let repoPaths = config.repos;
1190
1313
  if (options.repo) repoPaths = [options.repo];
1191
1314
  for (const blockSpecifier of blockNames) {
@@ -1200,7 +1323,7 @@ var _add = async (blockNames, options) => {
1200
1323
  if (!repoPaths.find((repoPath) => repoPath === repo)) {
1201
1324
  if (!options.allow) {
1202
1325
  const result = await confirm({
1203
- message: `Allow ${color5.cyan("jsrepo")} to download and run code from ${color5.cyan(repo)}?`,
1326
+ message: `Allow ${color7.cyan("jsrepo")} to download and run code from ${color7.cyan(repo)}?`,
1204
1327
  initialValue: true
1205
1328
  });
1206
1329
  if (isCancel(result) || !result) {
@@ -1213,7 +1336,7 @@ var _add = async (blockNames, options) => {
1213
1336
  }
1214
1337
  if (!options.allow && options.repo) {
1215
1338
  const result = await confirm({
1216
- message: `Allow ${color5.cyan("jsrepo")} to download and run code from ${color5.cyan(options.repo)}?`,
1339
+ message: `Allow ${color7.cyan("jsrepo")} to download and run code from ${color7.cyan(options.repo)}?`,
1217
1340
  initialValue: true
1218
1341
  });
1219
1342
  if (isCancel(result) || !result) {
@@ -1221,40 +1344,25 @@ var _add = async (blockNames, options) => {
1221
1344
  process.exit(0);
1222
1345
  }
1223
1346
  }
1224
- verbose(`Fetching blocks from ${color5.cyan(repoPaths.join(", "))}`);
1225
- if (!options.verbose) loading.start(`Fetching blocks from ${color5.cyan(repoPaths.join(", "))}`);
1226
- for (const repo of repoPaths) {
1227
- const providerInfo = (await getProviderInfo(repo)).match(
1228
- (info) => info,
1229
- (err) => {
1230
- loading.stop(`Failed fetching blocks from ${color5.cyan(repo)}`);
1231
- program2.error(color5.red(err));
1232
- }
1347
+ if (repoPaths.length === 0) {
1348
+ program2.error(
1349
+ color7.red(
1350
+ `There were no repos present in your config and you didn't provide the \`${color7.bold("--repo")}\` flag with a repo.`
1351
+ )
1233
1352
  );
1234
- const manifestUrl = await providerInfo.provider.resolveRaw(providerInfo, OUTPUT_FILE);
1235
- verbose(`Got info for provider ${color5.cyan(providerInfo.name)}`);
1236
- const categories = (await getManifest(manifestUrl)).match(
1237
- (val) => val,
1238
- (err) => {
1239
- loading.stop(`Failed fetching blocks from ${color5.cyan(repo)}`);
1240
- program2.error(color5.red(err));
1241
- }
1242
- );
1243
- for (const category of categories) {
1244
- for (const block of category.blocks) {
1245
- blocksMap.set(
1246
- `${providerInfo.name}/${providerInfo.owner}/${providerInfo.repoName}/${category.name}/${block.name}`,
1247
- {
1248
- ...block,
1249
- sourceRepo: providerInfo
1250
- }
1251
- );
1252
- }
1253
- }
1254
1353
  }
1255
- verbose(`Retrieved blocks from ${color5.cyan(repoPaths.join(", "))}`);
1256
- if (!options.verbose) loading.stop(`Retrieved blocks from ${color5.cyan(repoPaths.join(", "))}`);
1257
- const installedBlocks = getInstalledBlocks(blocksMap, config, options.cwd).map(
1354
+ verbose(`Fetching blocks from ${color7.cyan(repoPaths.join(", "))}`);
1355
+ if (!options.verbose) loading.start(`Fetching blocks from ${color7.cyan(repoPaths.join(", "))}`);
1356
+ const blocksMap = (await fetchBlocks(...repoPaths)).match(
1357
+ (val) => val,
1358
+ ({ repo, message }) => {
1359
+ loading.stop(`Failed fetching blocks from ${color7.cyan(repo)}`);
1360
+ program2.error(color7.red(message));
1361
+ }
1362
+ );
1363
+ if (!options.verbose) loading.stop(`Retrieved blocks from ${color7.cyan(repoPaths.join(", "))}`);
1364
+ verbose(`Retrieved blocks from ${color7.cyan(repoPaths.join(", "))}`);
1365
+ const installedBlocks = getInstalled(blocksMap, config, options.cwd).map(
1258
1366
  (val) => val.specifier
1259
1367
  );
1260
1368
  let installingBlockNames = blockNames;
@@ -1266,14 +1374,14 @@ var _add = async (blockNames, options) => {
1266
1374
  const blockExists = installedBlocks.findIndex((block) => block === shortName) !== -1;
1267
1375
  let label;
1268
1376
  if (repoPaths.length > 1) {
1269
- label = `${color5.cyan(
1377
+ label = `${color7.cyan(
1270
1378
  `${value.sourceRepo.name}/${value.sourceRepo.owner}/${value.sourceRepo.repoName}/${value.category}`
1271
1379
  )}/${value.name}`;
1272
1380
  } else {
1273
- label = `${color5.cyan(value.category)}/${value.name}`;
1381
+ label = `${color7.cyan(value.category)}/${value.name}`;
1274
1382
  }
1275
1383
  return {
1276
- label: blockExists ? color5.gray(label) : label,
1384
+ label: blockExists ? color7.gray(label) : label,
1277
1385
  value: key,
1278
1386
  // show hint for `Installed` if block is already installed
1279
1387
  hint: blockExists ? "Installed" : void 0
@@ -1287,9 +1395,12 @@ var _add = async (blockNames, options) => {
1287
1395
  }
1288
1396
  installingBlockNames = promptResult;
1289
1397
  }
1290
- verbose(`Installing blocks ${color5.cyan(installingBlockNames.join(", "))}`);
1398
+ verbose(`Installing blocks ${color7.cyan(installingBlockNames.join(", "))}`);
1291
1399
  if (options.verbose) console.log("Blocks map: ", blocksMap);
1292
- const installingBlocks = await getBlocks(installingBlockNames, blocksMap, repoPaths, options);
1400
+ const installingBlocks = (await resolveTree(installingBlockNames, blocksMap, repoPaths)).match(
1401
+ (val) => val,
1402
+ program2.error
1403
+ );
1293
1404
  const pm = (await detect({ cwd: process.cwd() }))?.agent ?? "npm";
1294
1405
  const tasks = [];
1295
1406
  const devDeps = /* @__PURE__ */ new Set();
@@ -1298,13 +1409,12 @@ var _add = async (blockNames, options) => {
1298
1409
  const fullSpecifier = `${block.sourceRepo.url}/${block.category}/${block.name}`;
1299
1410
  const watermark = getWatermark(context.package.version, block.sourceRepo.url);
1300
1411
  const providerInfo = block.sourceRepo;
1301
- verbose(`Attempting to add ${fullSpecifier}`);
1412
+ verbose(`Setting up ${fullSpecifier}`);
1302
1413
  const directory = path6.join(options.cwd, config.path, block.category);
1303
- verbose(`Creating directory ${color5.bold(directory)}`);
1304
1414
  const blockExists = !block.subdirectory && fs6.existsSync(path6.join(directory, block.files[0])) || block.subdirectory && fs6.existsSync(path6.join(directory, block.name));
1305
1415
  if (blockExists && !options.yes) {
1306
1416
  const result = await confirm({
1307
- message: `${color5.bold(block.name)} already exists in your project would you like to overwrite it?`,
1417
+ message: `${color7.bold(block.name)} already exists in your project would you like to overwrite it?`,
1308
1418
  initialValue: false
1309
1419
  });
1310
1420
  if (isCancel(result) || !result) {
@@ -1316,15 +1426,16 @@ var _add = async (blockNames, options) => {
1316
1426
  loadingMessage: `Adding ${fullSpecifier}`,
1317
1427
  completedMessage: `Added ${fullSpecifier}`,
1318
1428
  run: async () => {
1429
+ verbose(`Creating directory ${color7.bold(directory)}`);
1319
1430
  fs6.mkdirSync(directory, { recursive: true });
1320
1431
  const files = [];
1321
1432
  const getSourceFile = async (filePath) => {
1322
1433
  const rawUrl = await providerInfo.provider.resolveRaw(providerInfo, filePath);
1323
1434
  const response = await fetch(rawUrl);
1324
1435
  if (!response.ok) {
1325
- loading.stop(color5.red(`Error fetching ${color5.bold(rawUrl.href)}`));
1436
+ loading.stop(color7.red(`Error fetching ${color7.bold(rawUrl.href)}`));
1326
1437
  program2.error(
1327
- color5.red(`There was an error trying to get ${fullSpecifier}`)
1438
+ color7.red(`There was an error trying to get ${fullSpecifier}`)
1328
1439
  );
1329
1440
  }
1330
1441
  return await response.text();
@@ -1375,31 +1486,7 @@ ${content}`;
1375
1486
  }
1376
1487
  });
1377
1488
  }
1378
- await runTasks(tasks, { verbose: options.verbose });
1379
- const installDependencies = async (deps2, dev) => {
1380
- if (!options.verbose) loading.start(`Installing dependencies with ${color5.cyan(pm)}`);
1381
- let add2;
1382
- if (dev) {
1383
- add2 = resolveCommand(pm, "install", [...deps2, "-D"]);
1384
- } else {
1385
- add2 = resolveCommand(pm, "install", [...deps2]);
1386
- }
1387
- if (add2 == null) {
1388
- program2.error(color5.red(`Could not resolve add command for '${pm}'.`));
1389
- }
1390
- try {
1391
- await execa(add2.command, [...add2.args], { cwd: options.cwd });
1392
- } catch {
1393
- program2.error(
1394
- color5.red(
1395
- `Failed to install ${color5.bold("vitest")}! Failed while running '${color5.bold(
1396
- `${add2.command} ${add2.args.join(" ")}`
1397
- )}'`
1398
- )
1399
- );
1400
- }
1401
- if (!options.verbose) loading.stop(`Installed ${color5.cyan(deps2.join(", "))}`);
1402
- };
1489
+ await runTasks(tasks, { verbose: options.verbose ? verbose : void 0 });
1403
1490
  const hasDependencies = deps.size > 0 || devDeps.size > 0;
1404
1491
  if (hasDependencies) {
1405
1492
  let install = options.yes;
@@ -1416,24 +1503,56 @@ ${content}`;
1416
1503
  }
1417
1504
  if (install) {
1418
1505
  if (deps.size > 0) {
1419
- await installDependencies(Array.from(deps), false);
1506
+ if (!options.verbose)
1507
+ loading.start(`Installing dependencies with ${color7.cyan(pm)}`);
1508
+ (await installDependencies({
1509
+ pm,
1510
+ deps: Array.from(deps),
1511
+ dev: false,
1512
+ cwd: options.cwd
1513
+ })).match(
1514
+ (installed) => {
1515
+ if (!options.verbose)
1516
+ loading.stop(`Installed ${color7.cyan(installed.join(", "))}`);
1517
+ },
1518
+ (err) => {
1519
+ if (!options.verbose) loading.stop("Failed to install dependencies");
1520
+ program2.error(err);
1521
+ }
1522
+ );
1420
1523
  }
1421
1524
  if (devDeps.size > 0) {
1422
- await installDependencies(Array.from(devDeps), true);
1525
+ if (!options.verbose)
1526
+ loading.start(`Installing dependencies with ${color7.cyan(pm)}`);
1527
+ (await installDependencies({
1528
+ pm,
1529
+ deps: Array.from(devDeps),
1530
+ dev: true,
1531
+ cwd: options.cwd
1532
+ })).match(
1533
+ (installed) => {
1534
+ if (!options.verbose)
1535
+ loading.stop(`Installed ${color7.cyan(installed.join(", "))}`);
1536
+ },
1537
+ (err) => {
1538
+ if (!options.verbose) loading.stop("Failed to install dev dependencies");
1539
+ program2.error(err);
1540
+ }
1541
+ );
1423
1542
  }
1424
1543
  }
1425
1544
  let steps = [];
1426
1545
  if (!install) {
1427
1546
  if (deps.size > 0) {
1428
- const cmd = resolveCommand(pm, "install", [...deps]);
1547
+ const cmd = resolveCommand2(pm, "install", [...deps]);
1429
1548
  steps.push(
1430
- `Install dependencies \`${color5.cyan(`${cmd?.command} ${cmd?.args.join(" ")}`)}\``
1549
+ `Install dependencies \`${color7.cyan(`${cmd?.command} ${cmd?.args.join(" ")}`)}\``
1431
1550
  );
1432
1551
  }
1433
1552
  if (devDeps.size > 0) {
1434
- const cmd = resolveCommand(pm, "install", [...devDeps, "-D"]);
1553
+ const cmd = resolveCommand2(pm, "install", [...devDeps, "-D"]);
1435
1554
  steps.push(
1436
- `Install dev dependencies \`${color5.cyan(`${cmd?.command} ${cmd?.args.join(" ")}`)}\``
1555
+ `Install dev dependencies \`${color7.cyan(`${cmd?.command} ${cmd?.args.join(" ")}`)}\``
1437
1556
  );
1438
1557
  }
1439
1558
  }
@@ -1441,88 +1560,41 @@ ${content}`;
1441
1560
  if (!install) {
1442
1561
  steps.push("");
1443
1562
  }
1444
- steps.push(`Import the blocks from \`${color5.cyan(config.path)}\``);
1563
+ steps.push(`Import the blocks from \`${color7.cyan(config.path)}\``);
1445
1564
  const next = nextSteps(steps);
1446
1565
  process.stdout.write(next);
1447
1566
  }
1448
- outro(color5.green("All done!"));
1449
- };
1450
- var getBlocks = async (blockSpecifiers, blocksMap, repoPaths, options) => {
1451
- const blocks = /* @__PURE__ */ new Map();
1452
- for (const blockSpecifier of blockSpecifiers) {
1453
- let block = void 0;
1454
- if (!blockSpecifier.startsWith("github")) {
1455
- if (repoPaths.length === 0) {
1456
- program2.error(
1457
- color5.red(
1458
- `If your config doesn't repos then you must provide the repo in the block specifier ex: \`${color5.bold(
1459
- `github/<owner>/<name>/${blockSpecifier}`
1460
- )}\`!`
1461
- )
1462
- );
1463
- }
1464
- for (const repo of repoPaths) {
1465
- const providerInfo = (await getProviderInfo(repo)).unwrap();
1466
- const tempBlock = blocksMap.get(
1467
- `${providerInfo.name}/${providerInfo.owner}/${providerInfo.repoName}/${blockSpecifier}`
1468
- );
1469
- if (tempBlock === void 0) continue;
1470
- block = tempBlock;
1471
- break;
1472
- }
1473
- } else {
1474
- block = blocksMap.get(blockSpecifier);
1475
- }
1476
- if (!block) {
1477
- program2.error(
1478
- color5.red(`Invalid block! ${color5.bold(blockSpecifier)} does not exist!`)
1479
- );
1480
- }
1481
- const fullSpecifier = `${block.sourceRepo.url}/${block.category}/${block.name}`;
1482
- blocks.set(fullSpecifier, { name: fullSpecifier, subDependency: false, block });
1483
- if (block.localDependencies && block.localDependencies.length > 0) {
1484
- const subDeps = await getBlocks(
1485
- block.localDependencies.filter((dep) => !blocks.has(dep)),
1486
- blocksMap,
1487
- repoPaths,
1488
- options
1489
- );
1490
- for (const dep of subDeps) {
1491
- blocks.set(dep.name, dep);
1492
- }
1493
- }
1494
- }
1495
- return mapToArray(blocks, (_, val) => val);
1496
1567
  };
1497
1568
 
1498
1569
  // src/commands/build.ts
1499
1570
  import fs7 from "node:fs";
1500
1571
  import path7 from "node:path";
1501
1572
  import { outro as outro2, spinner as spinner3 } from "@clack/prompts";
1502
- import color6 from "chalk";
1573
+ import color8 from "chalk";
1503
1574
  import { Command as Command2 } from "commander";
1504
1575
  import * as v5 from "valibot";
1505
1576
  var schema3 = v5.object({
1506
- verbose: v5.boolean(),
1507
- output: v5.boolean(),
1508
1577
  dirs: v5.array(v5.string()),
1578
+ output: v5.boolean(),
1579
+ verbose: v5.boolean(),
1509
1580
  cwd: v5.string()
1510
1581
  });
1511
1582
  var build = new Command2("build").description(`Builds the provided --dirs in the project root into a \`${OUTPUT_FILE}\` file.`).option("--dirs [dirs...]", "The directories containing the blocks.", ["./blocks"]).option("--no-output", `Do not output a \`${OUTPUT_FILE}\` file.`).option("--verbose", "Include debug logs.", false).option("--cwd <path>", "The current working directory.", process.cwd()).action(async (opts) => {
1512
1583
  const options = v5.parse(schema3, opts);
1584
+ _intro(context.package.version);
1513
1585
  await _build(options);
1586
+ outro2(color8.green("All done!"));
1514
1587
  });
1515
1588
  var _build = async (options) => {
1516
- _intro(context.package.version);
1517
1589
  const loading = spinner3();
1518
1590
  const categories = [];
1519
1591
  const outFile = path7.join(options.cwd, OUTPUT_FILE);
1520
1592
  for (const dir of options.dirs) {
1521
1593
  const dirPath = path7.join(options.cwd, dir);
1522
- loading.start(`Building ${color6.cyan(dirPath)}`);
1594
+ loading.start(`Building ${color8.cyan(dirPath)}`);
1523
1595
  if (options.output && fs7.existsSync(outFile)) fs7.rmSync(outFile);
1524
1596
  categories.push(...buildBlocksDirectory(dirPath, options.cwd));
1525
- loading.stop(`Built ${color6.cyan(dirPath)}`);
1597
+ loading.stop(`Built ${color8.cyan(dirPath)}`);
1526
1598
  }
1527
1599
  const categoriesMap = /* @__PURE__ */ new Map();
1528
1600
  for (const category of categories) {
@@ -1539,23 +1611,22 @@ var _build = async (options) => {
1539
1611
  } else {
1540
1612
  loading.stop("Built successfully!");
1541
1613
  }
1542
- outro2(color6.green("All done!"));
1543
1614
  };
1544
1615
 
1545
1616
  // src/commands/diff.ts
1546
1617
  import fs8 from "node:fs";
1547
1618
  import path8 from "node:path";
1548
1619
  import { cancel as cancel2, confirm as confirm2, isCancel as isCancel2, outro as outro3, spinner as spinner4 } from "@clack/prompts";
1549
- import color8 from "chalk";
1620
+ import color10 from "chalk";
1550
1621
  import { Command as Command3, program as program3 } from "commander";
1551
1622
  import { diffLines } from "diff";
1552
1623
  import * as v6 from "valibot";
1553
1624
 
1554
1625
  // src/utils/diff.ts
1555
- import color7 from "chalk";
1626
+ import color9 from "chalk";
1556
1627
  import { diffChars } from "diff";
1557
1628
 
1558
- // src/blocks/utils/array-sum.ts
1629
+ // src/utils/blocks/utils/array-sum.ts
1559
1630
  var arraySum = (arr, fn) => {
1560
1631
  let total = 0;
1561
1632
  for (const item of arr) {
@@ -1564,7 +1635,7 @@ var arraySum = (arr, fn) => {
1564
1635
  return total;
1565
1636
  };
1566
1637
 
1567
- // src/blocks/utils/lines.ts
1638
+ // src/utils/blocks/utils/lines.ts
1568
1639
  import os from "node:os";
1569
1640
  var NEW_LINE_REGEX = /\n|\r\n/g;
1570
1641
  var get = (str) => str.split(NEW_LINE_REGEX);
@@ -1601,10 +1672,10 @@ var formatDiff = ({
1601
1672
  changes,
1602
1673
  expand = false,
1603
1674
  maxUnchanged = 5,
1604
- colorRemoved = color7.red,
1605
- colorAdded = color7.green,
1606
- colorCharsRemoved = color7.bgRed,
1607
- colorCharsAdded = color7.bgGreen,
1675
+ colorRemoved = color9.red,
1676
+ colorAdded = color9.green,
1677
+ colorCharsRemoved = color9.bgRed,
1678
+ colorCharsAdded = color9.bgGreen,
1608
1679
  prefix,
1609
1680
  onUnchanged,
1610
1681
  intro: intro2
@@ -1638,7 +1709,7 @@ var formatDiff = ({
1638
1709
  onUnchanged,
1639
1710
  intro: intro2
1640
1711
  });
1641
- const linePrefix = (line) => color7.gray(`${prefix?.() ?? ""}${leftPadMin(`${line + 1 + lineOffset} `, length)} `);
1712
+ const linePrefix = (line) => color9.gray(`${prefix?.() ?? ""}${leftPadMin(`${line + 1 + lineOffset} `, length)} `);
1642
1713
  for (let i = 0; i < changes.length; i++) {
1643
1714
  const change = changes[i];
1644
1715
  const hasPreviousChange = changes[i - 1]?.added || changes[i - 1]?.removed;
@@ -1668,8 +1739,8 @@ var formatDiff = ({
1668
1739
  const count = ls.length - shownLines;
1669
1740
  result += `${join(
1670
1741
  get(
1671
- color7.gray(
1672
- `+ ${count} more unchanged (${color7.italic("-E to expand")})`
1742
+ color9.gray(
1743
+ `+ ${count} more unchanged (${color9.italic("-E to expand")})`
1673
1744
  )
1674
1745
  ),
1675
1746
  {
@@ -1743,37 +1814,36 @@ var formatDiff = ({
1743
1814
  };
1744
1815
 
1745
1816
  // src/commands/diff.ts
1746
- var L = color8.gray("\u2502");
1747
1817
  var schema4 = v6.object({
1748
- allow: v6.boolean(),
1749
1818
  expand: v6.boolean(),
1750
1819
  maxUnchanged: v6.number(),
1751
1820
  repo: v6.optional(v6.string()),
1821
+ allow: v6.boolean(),
1752
1822
  cwd: v6.string()
1753
1823
  });
1754
- var diff = new Command3("diff").description("Compares local blocks to the blocks in the provided repository.").option("-A, --allow", "Allow jsrepo to download code from the provided repo.", false).option("-E, --expand", "Expands the diff so you see everything.", false).option("--repo <repo>", "Repository to download the blocks from.").option(
1824
+ var diff = new Command3("diff").description("Compares local blocks to the blocks in the provided repository.").option("-E, --expand", "Expands the diff so you see everything.", false).option(
1755
1825
  "--max-unchanged <number>",
1756
1826
  "Maximum unchanged lines that will show without being collapsed.",
1757
1827
  (val) => Number.parseInt(val),
1758
1828
  // this is such a dumb api thing
1759
1829
  3
1760
- ).option("--cwd <path>", "The current working directory.", process.cwd()).action(async (opts) => {
1830
+ ).option("--repo <repo>", "Repository to download the blocks from.").option("-A, --allow", "Allow jsrepo to download code from the provided repo.", false).option("--cwd <path>", "The current working directory.", process.cwd()).action(async (opts) => {
1761
1831
  const options = v6.parse(schema4, opts);
1832
+ _intro(context.package.version);
1762
1833
  await _diff(options);
1834
+ outro3(color10.green("All done!"));
1763
1835
  });
1764
1836
  var _diff = async (options) => {
1765
- _intro(context.package.version);
1766
1837
  const loading = spinner4();
1767
1838
  const config = getConfig(options.cwd).match(
1768
1839
  (val) => val,
1769
- (err) => program3.error(color8.red(err))
1840
+ (err) => program3.error(color10.red(err))
1770
1841
  );
1771
- const blocksMap = /* @__PURE__ */ new Map();
1772
1842
  let repoPaths = config.repos;
1773
1843
  if (options.repo) repoPaths = [options.repo];
1774
1844
  if (!options.allow && options.repo) {
1775
1845
  const result = await confirm2({
1776
- message: `Allow ${color8.cyan("jsrepo")} to download and run code from ${color8.cyan(options.repo)}?`,
1846
+ message: `Allow ${color10.cyan("jsrepo")} to download and run code from ${color10.cyan(options.repo)}?`,
1777
1847
  initialValue: true
1778
1848
  });
1779
1849
  if (isCancel2(result) || !result) {
@@ -1781,31 +1851,16 @@ var _diff = async (options) => {
1781
1851
  process.exit(0);
1782
1852
  }
1783
1853
  }
1784
- loading.start(`Fetching blocks from ${color8.cyan(repoPaths.join(", "))}`);
1785
- for (const repo of repoPaths) {
1786
- const providerInfo = (await getProviderInfo(repo)).match(
1787
- (info) => info,
1788
- (err) => program3.error(color8.red(err))
1789
- );
1790
- const manifestUrl = await providerInfo.provider.resolveRaw(providerInfo, OUTPUT_FILE);
1791
- const categories = (await getManifest(manifestUrl)).match(
1792
- (val) => val,
1793
- (err) => program3.error(color8.red(err))
1794
- );
1795
- for (const category of categories) {
1796
- for (const block of category.blocks) {
1797
- blocksMap.set(
1798
- `${providerInfo.name}/${providerInfo.owner}/${providerInfo.repoName}/${category.name}/${block.name}`,
1799
- {
1800
- ...block,
1801
- sourceRepo: providerInfo
1802
- }
1803
- );
1804
- }
1854
+ loading.start(`Fetching blocks from ${color10.cyan(repoPaths.join(", "))}`);
1855
+ const blocksMap = (await fetchBlocks(...repoPaths)).match(
1856
+ (val) => val,
1857
+ ({ repo, message }) => {
1858
+ loading.stop(`Failed fetching blocks from ${color10.cyan(repo)}`);
1859
+ program3.error(color10.red(message));
1805
1860
  }
1806
- }
1807
- loading.stop(`Retrieved blocks from ${color8.cyan(repoPaths.join(", "))}`);
1808
- const installedBlocks = getInstalledBlocks(blocksMap, config, options.cwd);
1861
+ );
1862
+ loading.stop(`Retrieved blocks from ${color10.cyan(repoPaths.join(", "))}`);
1863
+ const installedBlocks = getInstalled(blocksMap, config, options.cwd);
1809
1864
  for (const blockSpecifier of installedBlocks) {
1810
1865
  let found = false;
1811
1866
  for (const repo of repoPaths) {
@@ -1813,21 +1868,21 @@ var _diff = async (options) => {
1813
1868
  const fullSpecifier = `${providerInfo.name}/${providerInfo.owner}/${providerInfo.repoName}/${blockSpecifier.specifier}`;
1814
1869
  const block = blocksMap.get(fullSpecifier);
1815
1870
  if (block === void 0) continue;
1871
+ const watermark = getWatermark(context.package.version, repo);
1816
1872
  found = true;
1817
- process.stdout.write(`${L}
1873
+ process.stdout.write(`${VERTICAL_LINE}
1818
1874
  `);
1819
- process.stdout.write(`${L} ${fullSpecifier}
1875
+ process.stdout.write(`${VERTICAL_LINE} ${fullSpecifier}
1820
1876
  `);
1821
- fullSpecifier;
1822
1877
  for (const file of block.files) {
1823
1878
  if (!config.includeTests && isTestFile(file)) continue;
1824
- process.stdout.write(`${L}
1879
+ process.stdout.write(`${VERTICAL_LINE}
1825
1880
  `);
1826
1881
  const sourcePath = path8.join(block.directory, file);
1827
1882
  const rawUrl = await providerInfo.provider.resolveRaw(providerInfo, sourcePath);
1828
1883
  const response = await fetch(rawUrl);
1829
1884
  if (!response.ok) {
1830
- program3.error(color8.red(`There was an error trying to get ${fullSpecifier}`));
1885
+ program3.error(color10.red(`There was an error trying to get ${fullSpecifier}`));
1831
1886
  }
1832
1887
  let remoteContent = await response.text();
1833
1888
  const directory = path8.join(options.cwd, config.path, block.category);
@@ -1844,7 +1899,6 @@ var _diff = async (options) => {
1844
1899
  if (config.watermark) {
1845
1900
  const lang = languages.find((lang2) => lang2.matches(sourcePath));
1846
1901
  if (lang) {
1847
- const watermark = getWatermark(context.package.version, repo);
1848
1902
  const comment = lang.comment(watermark);
1849
1903
  remoteContent = `${comment}
1850
1904
 
@@ -1863,16 +1917,16 @@ ${remoteContent}`;
1863
1917
  changes,
1864
1918
  expand: options.expand,
1865
1919
  maxUnchanged: options.maxUnchanged,
1866
- colorAdded: color8.greenBright,
1867
- colorRemoved: color8.redBright,
1868
- colorCharsAdded: color8.bgGreenBright,
1869
- colorCharsRemoved: color8.bgRedBright,
1870
- prefix: () => `${L} `,
1871
- onUnchanged: ({ from: from2, to: to2, prefix }) => `${prefix?.() ?? ""}${color8.cyan(from2)} \u2192 ${color8.gray(to2)} ${color8.gray("(unchanged)")}
1920
+ colorAdded: color10.greenBright,
1921
+ colorRemoved: color10.redBright,
1922
+ colorCharsAdded: color10.bgGreenBright,
1923
+ colorCharsRemoved: color10.bgRedBright,
1924
+ prefix: () => `${VERTICAL_LINE} `,
1925
+ onUnchanged: ({ from: from2, to: to2, prefix }) => `${prefix?.() ?? ""}${color10.cyan(from2)} \u2192 ${color10.gray(to2)} ${color10.gray("(unchanged)")}
1872
1926
  `,
1873
1927
  intro: ({ from: from2, to: to2, changes: changes2, prefix }) => {
1874
1928
  const totalChanges = changes2.filter((a) => a.added).length;
1875
- return `${prefix?.() ?? ""}${color8.cyan(from2)} \u2192 ${color8.gray(to2)} (${totalChanges} change${totalChanges === 1 ? "" : "s"})
1929
+ return `${prefix?.() ?? ""}${color10.cyan(from2)} \u2192 ${color10.gray(to2)} (${totalChanges} change${totalChanges === 1 ? "" : "s"})
1876
1930
  ${prefix?.() ?? ""}
1877
1931
  `;
1878
1932
  }
@@ -1883,25 +1937,24 @@ ${prefix?.() ?? ""}
1883
1937
  }
1884
1938
  if (!found) {
1885
1939
  program3.error(
1886
- color8.red(`Invalid block! ${color8.bold(blockSpecifier)} does not exist!`)
1940
+ color10.red(`Invalid block! ${color10.bold(blockSpecifier)} does not exist!`)
1887
1941
  );
1888
1942
  }
1889
1943
  }
1890
- outro3(color8.green("All done!"));
1891
1944
  };
1892
1945
 
1893
1946
  // src/commands/init.ts
1894
1947
  import fs9 from "node:fs";
1895
1948
  import path9 from "node:path";
1896
1949
  import { cancel as cancel3, confirm as confirm3, isCancel as isCancel3, outro as outro4, spinner as spinner5, text } from "@clack/prompts";
1897
- import color9 from "chalk";
1950
+ import color11 from "chalk";
1898
1951
  import { Command as Command4 } from "commander";
1899
1952
  import * as v7 from "valibot";
1900
1953
  var schema5 = v7.object({
1901
1954
  path: v7.optional(v7.string()),
1902
- tests: v7.optional(v7.boolean()),
1903
1955
  repos: v7.optional(v7.array(v7.string())),
1904
1956
  watermark: v7.boolean(),
1957
+ tests: v7.optional(v7.boolean()),
1905
1958
  cwd: v7.string()
1906
1959
  });
1907
1960
  var init = new Command4("init").description("Initializes your project with a configuration file.").option("--path <path>", "Path to install the blocks.").option("--repos [repos...]", "Repository to install the blocks from.").option(
@@ -1909,10 +1962,11 @@ var init = new Command4("init").description("Initializes your project with a con
1909
1962
  "Will not add a watermark to each file upon adding it to your project."
1910
1963
  ).option("--tests", "Will include tests with the blocks.").option("--cwd <path>", "The current working directory.", process.cwd()).action(async (opts) => {
1911
1964
  const options = v7.parse(schema5, opts);
1965
+ _intro(context.package.version);
1912
1966
  await _init(options);
1967
+ outro4(color11.green("All done!"));
1913
1968
  });
1914
1969
  var _init = async (options) => {
1915
- _intro(context.package.version);
1916
1970
  const initialConfig = getConfig(options.cwd);
1917
1971
  const loading = spinner5();
1918
1972
  if (!options.path) {
@@ -1934,7 +1988,8 @@ var _init = async (options) => {
1934
1988
  while (true) {
1935
1989
  const confirmResult = await confirm3({
1936
1990
  message: `Add ${options.repos.length > 0 ? "another" : "a"} repo?`,
1937
- initialValue: false
1991
+ initialValue: options.repos.length === 0
1992
+ // default to yes for first repo
1938
1993
  });
1939
1994
  if (isCancel3(confirmResult)) {
1940
1995
  cancel3("Canceled!");
@@ -1946,7 +2001,7 @@ var _init = async (options) => {
1946
2001
  placeholder: "github/ieedan/std",
1947
2002
  validate: (val) => {
1948
2003
  if (!val.startsWith("https://github.com") && !val.startsWith("github/")) {
1949
- return `Must be a ${color9.bold("GitHub")} repository!`;
2004
+ return `Must be a ${color11.bold("GitHub")} repository!`;
1950
2005
  }
1951
2006
  }
1952
2007
  });
@@ -1972,33 +2027,33 @@ var _init = async (options) => {
1972
2027
  );
1973
2028
  fs9.mkdirSync(path9.join(options.cwd, config.path), { recursive: true });
1974
2029
  loading.stop(`Wrote config to \`${CONFIG_NAME}\`.`);
1975
- outro4(color9.green("All done!"));
1976
2030
  };
1977
2031
 
1978
2032
  // src/commands/test.ts
1979
2033
  import fs10 from "node:fs";
1980
2034
  import path10 from "node:path";
1981
2035
  import { cancel as cancel4, confirm as confirm4, isCancel as isCancel4, outro as outro5, spinner as spinner6 } from "@clack/prompts";
1982
- import color10 from "chalk";
2036
+ import color12 from "chalk";
1983
2037
  import { Argument, Command as Command5, program as program4 } from "commander";
1984
2038
  import { execa as execa2 } from "execa";
1985
- import { resolveCommand as resolveCommand2 } from "package-manager-detector/commands";
2039
+ import { resolveCommand as resolveCommand3 } from "package-manager-detector/commands";
1986
2040
  import { detect as detect2 } from "package-manager-detector/detect";
1987
2041
  import { Project as Project2 } from "ts-morph";
1988
2042
  import * as v8 from "valibot";
1989
2043
  var schema6 = v8.object({
1990
- debug: v8.boolean(),
1991
- verbose: v8.boolean(),
1992
2044
  repo: v8.optional(v8.string()),
1993
2045
  allow: v8.boolean(),
2046
+ debug: v8.boolean(),
2047
+ verbose: v8.boolean(),
1994
2048
  cwd: v8.string()
1995
2049
  });
1996
- var test = new Command5("test").description("Tests local blocks against most recent remote tests.").addArgument(new Argument("[blocks...]", "The blocks you want to test.").default([])).option("--verbose", "Include debug logs.", false).option("-A, --allow", "Allow jsrepo to download code from the provided repo.", false).option("--repo <repo>", "Repository to download the blocks from.").option("--debug", "Leaves the temp test file around for debugging upon failure.", false).option("--cwd <path>", "The current working directory.", process.cwd()).action(async (blockNames, opts) => {
2050
+ var test = new Command5("test").description("Tests local blocks against most recent remote tests.").addArgument(new Argument("[blocks...]", "The blocks you want to test.").default([])).option("--repo <repo>", "Repository to download the blocks from.").option("-A, --allow", "Allow jsrepo to download code from the provided repo.", false).option("--debug", "Leaves the temp test file around for debugging upon failure.", false).option("--verbose", "Include debug logs.", false).option("--cwd <path>", "The current working directory.", process.cwd()).action(async (blockNames, opts) => {
1997
2051
  const options = v8.parse(schema6, opts);
2052
+ _intro(context.package.version);
1998
2053
  await _test(blockNames, options);
2054
+ outro5(color12.green("All done!"));
1999
2055
  });
2000
2056
  var _test = async (blockNames, options) => {
2001
- _intro(context.package.version);
2002
2057
  const verbose = (msg) => {
2003
2058
  if (options.verbose) {
2004
2059
  console.info(`${INFO} ${msg}`);
@@ -2007,7 +2062,7 @@ var _test = async (blockNames, options) => {
2007
2062
  verbose(`Attempting to test ${JSON.stringify(blockNames)}`);
2008
2063
  const config = getConfig(options.cwd).match(
2009
2064
  (val) => val,
2010
- (err) => program4.error(color10.red(err))
2065
+ (err) => program4.error(color12.red(err))
2011
2066
  );
2012
2067
  const loading = spinner6();
2013
2068
  const blocksMap = /* @__PURE__ */ new Map();
@@ -2015,7 +2070,7 @@ var _test = async (blockNames, options) => {
2015
2070
  if (options.repo) repoPaths = [options.repo];
2016
2071
  if (!options.allow && options.repo) {
2017
2072
  const result = await confirm4({
2018
- message: `Allow ${color10.cyan("jsrepo")} to download and run code from ${color10.cyan(options.repo)}?`,
2073
+ message: `Allow ${color12.cyan("jsrepo")} to download and run code from ${color12.cyan(options.repo)}?`,
2019
2074
  initialValue: true
2020
2075
  });
2021
2076
  if (isCancel4(result) || !result) {
@@ -2023,21 +2078,21 @@ var _test = async (blockNames, options) => {
2023
2078
  process.exit(0);
2024
2079
  }
2025
2080
  }
2026
- verbose(`Fetching blocks from ${color10.cyan(repoPaths.join(", "))}`);
2027
- if (!options.verbose) loading.start(`Fetching blocks from ${color10.cyan(repoPaths.join(", "))}`);
2081
+ verbose(`Fetching blocks from ${color12.cyan(repoPaths.join(", "))}`);
2082
+ if (!options.verbose) loading.start(`Fetching blocks from ${color12.cyan(repoPaths.join(", "))}`);
2028
2083
  for (const repo of repoPaths) {
2029
2084
  const providerInfo = (await getProviderInfo(repo)).match(
2030
2085
  (info) => info,
2031
- (err) => program4.error(color10.red(err))
2086
+ (err) => program4.error(color12.red(err))
2032
2087
  );
2033
2088
  const manifestUrl = await providerInfo.provider.resolveRaw(providerInfo, OUTPUT_FILE);
2034
- verbose(`Got info for provider ${color10.cyan(providerInfo.name)}`);
2089
+ verbose(`Got info for provider ${color12.cyan(providerInfo.name)}`);
2035
2090
  const response = await fetch(manifestUrl);
2036
2091
  if (!response.ok) {
2037
- if (!options.verbose) loading.stop(`Error fetching ${color10.cyan(manifestUrl.href)}`);
2092
+ if (!options.verbose) loading.stop(`Error fetching ${color12.cyan(manifestUrl.href)}`);
2038
2093
  program4.error(
2039
- color10.red(
2040
- `There was an error fetching the \`${OUTPUT_FILE}\` from the repository ${color10.cyan(
2094
+ color12.red(
2095
+ `There was an error fetching the \`${OUTPUT_FILE}\` from the repository ${color12.cyan(
2041
2096
  repo
2042
2097
  )} make sure the target repository has a \`${OUTPUT_FILE}\` in its root?`
2043
2098
  )
@@ -2056,17 +2111,17 @@ var _test = async (blockNames, options) => {
2056
2111
  }
2057
2112
  }
2058
2113
  }
2059
- verbose(`Retrieved blocks from ${color10.cyan(repoPaths.join(", "))}`);
2060
- if (!options.verbose) loading.stop(`Retrieved blocks from ${color10.cyan(repoPaths.join(", "))}`);
2114
+ verbose(`Retrieved blocks from ${color12.cyan(repoPaths.join(", "))}`);
2115
+ if (!options.verbose) loading.stop(`Retrieved blocks from ${color12.cyan(repoPaths.join(", "))}`);
2061
2116
  const tempTestDirectory = path10.resolve(
2062
2117
  path10.join(options.cwd, `blocks-tests-temp-${Date.now()}`)
2063
2118
  );
2064
- verbose(`Trying to create the temp directory ${color10.bold(tempTestDirectory)}.`);
2119
+ verbose(`Trying to create the temp directory ${color12.bold(tempTestDirectory)}.`);
2065
2120
  fs10.mkdirSync(tempTestDirectory, { recursive: true });
2066
2121
  const cleanUp = () => {
2067
2122
  fs10.rmSync(tempTestDirectory, { recursive: true, force: true });
2068
2123
  };
2069
- const installedBlocks = getInstalledBlocks(blocksMap, config, options.cwd).map(
2124
+ const installedBlocks = getInstalled(blocksMap, config, options.cwd).map(
2070
2125
  (val) => val.specifier
2071
2126
  );
2072
2127
  let testingBlocks = blockNames;
@@ -2075,7 +2130,7 @@ var _test = async (blockNames, options) => {
2075
2130
  }
2076
2131
  if (testingBlocks.length === 0) {
2077
2132
  cleanUp();
2078
- program4.error(color10.red("There were no blocks found in your project!"));
2133
+ program4.error(color12.red("There were no blocks found in your project!"));
2079
2134
  }
2080
2135
  const testingBlocksMapped = [];
2081
2136
  for (const blockSpecifier of testingBlocks) {
@@ -2101,7 +2156,7 @@ var _test = async (blockNames, options) => {
2101
2156
  }
2102
2157
  const providerInfo = (await getProviderInfo(repo)).match(
2103
2158
  (val) => val,
2104
- (err) => program4.error(color10.red(err))
2159
+ (err) => program4.error(color12.red(err))
2105
2160
  );
2106
2161
  const manifestUrl = await providerInfo.provider.resolveRaw(
2107
2162
  providerInfo,
@@ -2109,7 +2164,7 @@ var _test = async (blockNames, options) => {
2109
2164
  );
2110
2165
  const categories = (await getManifest(manifestUrl)).match(
2111
2166
  (val) => val,
2112
- (err) => program4.error(color10.red(err))
2167
+ (err) => program4.error(color12.red(err))
2113
2168
  );
2114
2169
  for (const category of categories) {
2115
2170
  for (const block2 of category.blocks) {
@@ -2127,7 +2182,7 @@ var _test = async (blockNames, options) => {
2127
2182
  }
2128
2183
  if (!block) {
2129
2184
  program4.error(
2130
- color10.red(`Invalid block! ${color10.bold(blockSpecifier)} does not exist!`)
2185
+ color12.red(`Invalid block! ${color12.bold(blockSpecifier)} does not exist!`)
2131
2186
  );
2132
2187
  }
2133
2188
  testingBlocksMapped.push({ name: blockSpecifier, block });
@@ -2135,18 +2190,18 @@ var _test = async (blockNames, options) => {
2135
2190
  for (const { name: specifier, block } of testingBlocksMapped) {
2136
2191
  const providerInfo = block.sourceRepo;
2137
2192
  if (!options.verbose) {
2138
- loading.start(`Setting up test file for ${color10.cyan(specifier)}`);
2193
+ loading.start(`Setting up test file for ${color12.cyan(specifier)}`);
2139
2194
  }
2140
2195
  if (!block.tests) {
2141
- loading.stop(`No tests found for ${color10.cyan(specifier)}`);
2196
+ loading.stop(`No tests found for ${color12.cyan(specifier)}`);
2142
2197
  continue;
2143
2198
  }
2144
2199
  const getSourceFile = async (filePath) => {
2145
2200
  const rawUrl = await providerInfo.provider.resolveRaw(providerInfo, filePath);
2146
2201
  const response = await fetch(rawUrl);
2147
2202
  if (!response.ok) {
2148
- loading.stop(color10.red(`Error fetching ${color10.bold(rawUrl.href)}`));
2149
- program4.error(color10.red(`There was an error trying to get ${specifier}`));
2203
+ loading.stop(color12.red(`Error fetching ${color12.bold(rawUrl.href)}`));
2204
+ program4.error(color12.red(`There was an error trying to get ${specifier}`));
2150
2205
  }
2151
2206
  return await response.text();
2152
2207
  };
@@ -2189,19 +2244,19 @@ var _test = async (blockNames, options) => {
2189
2244
  }
2190
2245
  }
2191
2246
  project.saveSync();
2192
- verbose(`Completed ${color10.cyan.bold(specifier)} test file`);
2247
+ verbose(`Completed ${color12.cyan.bold(specifier)} test file`);
2193
2248
  if (!options.verbose) {
2194
- loading.stop(`Completed setup for ${color10.bold(specifier)}`);
2249
+ loading.stop(`Completed setup for ${color12.bold(specifier)}`);
2195
2250
  }
2196
2251
  }
2197
2252
  verbose("Beginning testing");
2198
2253
  const pm = await detect2({ cwd: options.cwd });
2199
2254
  if (pm == null) {
2200
- program4.error(color10.red("Could not detect package manager"));
2255
+ program4.error(color12.red("Could not detect package manager"));
2201
2256
  }
2202
- const resolved = resolveCommand2(pm.agent, "execute", ["vitest", "run", tempTestDirectory]);
2257
+ const resolved = resolveCommand3(pm.agent, "execute", ["vitest", "run", tempTestDirectory]);
2203
2258
  if (resolved == null) {
2204
- program4.error(color10.red(`Could not resolve add command for '${pm.agent}'.`));
2259
+ program4.error(color12.red(`Could not resolve add command for '${pm.agent}'.`));
2205
2260
  }
2206
2261
  const { command, args } = resolved;
2207
2262
  const testCommand = `${command} ${args.join(" ")}`;
@@ -2215,11 +2270,10 @@ var _test = async (blockNames, options) => {
2215
2270
  try {
2216
2271
  await testingProcess;
2217
2272
  cleanUp();
2218
- outro5(color10.green("All done!"));
2219
2273
  } catch (err) {
2220
2274
  if (options.debug) {
2221
2275
  console.info(
2222
- `${color10.bold("--debug")} flag provided. Skipping cleanup. Run '${color10.bold(
2276
+ `${color12.bold("--debug")} flag provided. Skipping cleanup. Run '${color12.bold(
2223
2277
  testCommand
2224
2278
  )}' to retry tests.
2225
2279
  `
@@ -2227,17 +2281,328 @@ var _test = async (blockNames, options) => {
2227
2281
  } else {
2228
2282
  cleanUp();
2229
2283
  }
2230
- program4.error(color10.red(`Tests failed! Error ${err}`));
2284
+ program4.error(color12.red(`Tests failed! Error ${err}`));
2285
+ }
2286
+ };
2287
+
2288
+ // src/commands/update.ts
2289
+ import fs11 from "node:fs";
2290
+ import path11 from "node:path";
2291
+ import { cancel as cancel5, confirm as confirm5, isCancel as isCancel5, multiselect as multiselect2, outro as outro6, spinner as spinner7 } from "@clack/prompts";
2292
+ import color13 from "chalk";
2293
+ import { Command as Command6, program as program5 } from "commander";
2294
+ import { diffLines as diffLines2 } from "diff";
2295
+ import { resolveCommand as resolveCommand4 } from "package-manager-detector/commands";
2296
+ import { detect as detect3 } from "package-manager-detector/detect";
2297
+ import * as v9 from "valibot";
2298
+ var schema7 = v9.object({
2299
+ all: v9.boolean(),
2300
+ expand: v9.boolean(),
2301
+ maxUnchanged: v9.number(),
2302
+ repo: v9.optional(v9.string()),
2303
+ allow: v9.boolean(),
2304
+ yes: v9.boolean(),
2305
+ verbose: v9.boolean(),
2306
+ cwd: v9.string()
2307
+ });
2308
+ var update = new Command6("update").argument("[blocks...]", "Names of the blocks you want to update. ex: (utils/math)").option("--all", "Update all installed components.", false).option("-E, --expand", "Expands the diff so you see everything.", false).option(
2309
+ "--max-unchanged <number>",
2310
+ "Maximum unchanged lines that will show without being collapsed.",
2311
+ (val) => Number.parseInt(val),
2312
+ // this is such a dumb api thing
2313
+ 3
2314
+ ).option("--repo <repo>", "Repository to download the blocks from.").option("-A, --allow", "Allow jsrepo to download code from the provided repo.", false).option("-y, --yes", "Skip confirmation prompt.", false).option("--verbose", "Include debug logs.", false).option("--cwd <path>", "The current working directory.", process.cwd()).action(async (blockNames, opts) => {
2315
+ const options = v9.parse(schema7, opts);
2316
+ _intro(context.package.version);
2317
+ await _update(blockNames, options);
2318
+ outro6(color13.green("All done!"));
2319
+ });
2320
+ var _update = async (blockNames, options) => {
2321
+ const verbose = (msg) => {
2322
+ if (options.verbose) {
2323
+ console.info(`${INFO} ${msg}`);
2324
+ }
2325
+ };
2326
+ verbose(`Attempting to update ${JSON.stringify(blockNames)}`);
2327
+ const loading = spinner7();
2328
+ const config = getConfig(options.cwd).match(
2329
+ (val) => val,
2330
+ (err) => program5.error(color13.red(err))
2331
+ );
2332
+ let repoPaths = config.repos;
2333
+ if (options.repo) repoPaths = [options.repo];
2334
+ for (const blockSpecifier of blockNames) {
2335
+ if (blockSpecifier.startsWith("github")) {
2336
+ program5.error(
2337
+ color13.red(
2338
+ `Invalid value provided for block names \`${color13.bold(blockSpecifier)}\`. Block names are expected to be provided in the format of \`${color13.bold("<category>/<name>")}\``
2339
+ )
2340
+ );
2341
+ }
2342
+ }
2343
+ if (!options.allow && options.repo) {
2344
+ const result = await confirm5({
2345
+ message: `Allow ${color13.cyan("jsrepo")} to download and run code from ${color13.cyan(options.repo)}?`,
2346
+ initialValue: true
2347
+ });
2348
+ if (isCancel5(result) || !result) {
2349
+ cancel5("Canceled!");
2350
+ process.exit(0);
2351
+ }
2352
+ }
2353
+ verbose(`Fetching blocks from ${color13.cyan(repoPaths.join(", "))}`);
2354
+ if (!options.verbose) loading.start(`Fetching blocks from ${color13.cyan(repoPaths.join(", "))}`);
2355
+ const blocksMap = (await fetchBlocks(...repoPaths)).match(
2356
+ (val) => val,
2357
+ ({ repo, message }) => {
2358
+ loading.stop(`Failed fetching blocks from ${color13.cyan(repo)}`);
2359
+ program5.error(color13.red(message));
2360
+ }
2361
+ );
2362
+ if (!options.verbose) loading.stop(`Retrieved blocks from ${color13.cyan(repoPaths.join(", "))}`);
2363
+ verbose(`Retrieved blocks from ${color13.cyan(repoPaths.join(", "))}`);
2364
+ const installedBlocks = getInstalled(blocksMap, config, options.cwd);
2365
+ let updatingBlockNames = blockNames;
2366
+ if (options.all) {
2367
+ updatingBlockNames = installedBlocks.map((block) => block.specifier);
2368
+ }
2369
+ if (updatingBlockNames.length === 0) {
2370
+ const promptResult = await multiselect2({
2371
+ message: "Which blocks would you like to update?",
2372
+ options: installedBlocks.map((block) => {
2373
+ return {
2374
+ label: `${color13.cyan(block.block.category)}/${block.block.name}`,
2375
+ value: block.specifier
2376
+ };
2377
+ }),
2378
+ required: true
2379
+ });
2380
+ if (isCancel5(promptResult)) {
2381
+ cancel5("Canceled!");
2382
+ process.exit(0);
2383
+ }
2384
+ updatingBlockNames = promptResult;
2385
+ }
2386
+ verbose(`Preparing to update ${color13.cyan(updatingBlockNames.join(", "))}`);
2387
+ const updatingBlocks = (await resolveTree(updatingBlockNames, blocksMap, repoPaths)).match(
2388
+ (val) => val,
2389
+ program5.error
2390
+ );
2391
+ const pm = (await detect3({ cwd: process.cwd() }))?.agent ?? "npm";
2392
+ const tasks = [];
2393
+ const devDeps = /* @__PURE__ */ new Set();
2394
+ const deps = /* @__PURE__ */ new Set();
2395
+ for (const { block } of updatingBlocks) {
2396
+ const fullSpecifier = `${block.sourceRepo.url}/${block.category}/${block.name}`;
2397
+ const watermark = getWatermark(context.package.version, block.sourceRepo.url);
2398
+ const providerInfo = block.sourceRepo;
2399
+ verbose(`Attempting to add ${fullSpecifier}`);
2400
+ const directory = path11.join(options.cwd, config.path, block.category);
2401
+ const files = [];
2402
+ const getSourceFile = async (filePath) => {
2403
+ const rawUrl = await providerInfo.provider.resolveRaw(providerInfo, filePath);
2404
+ const response = await fetch(rawUrl);
2405
+ if (!response.ok) {
2406
+ loading.stop(color13.red(`Error fetching ${color13.bold(rawUrl.href)}`));
2407
+ program5.error(color13.red(`There was an error trying to get ${fullSpecifier}`));
2408
+ }
2409
+ return await response.text();
2410
+ };
2411
+ for (const sourceFile of block.files) {
2412
+ if (!config.includeTests && isTestFile(sourceFile)) continue;
2413
+ const sourcePath = path11.join(block.directory, sourceFile);
2414
+ let destPath;
2415
+ if (block.subdirectory) {
2416
+ destPath = path11.join(directory, block.name, sourceFile);
2417
+ } else {
2418
+ destPath = path11.join(directory, sourceFile);
2419
+ }
2420
+ const content = await getSourceFile(sourcePath);
2421
+ fs11.mkdirSync(destPath.slice(0, destPath.length - sourceFile.length), {
2422
+ recursive: true
2423
+ });
2424
+ files.push({ content, destPath, fileName: sourceFile });
2425
+ }
2426
+ process.stdout.write(`${VERTICAL_LINE}
2427
+ `);
2428
+ process.stdout.write(`${VERTICAL_LINE} ${fullSpecifier}
2429
+ `);
2430
+ for (const file of files) {
2431
+ let remoteContent = file.content;
2432
+ if (config.watermark) {
2433
+ const lang = languages.find((lang2) => lang2.matches(file.destPath));
2434
+ if (lang) {
2435
+ const comment = lang.comment(watermark);
2436
+ remoteContent = `${comment}
2437
+
2438
+ ${remoteContent}`;
2439
+ }
2440
+ }
2441
+ let acceptedChanges = options.yes;
2442
+ if (!options.yes) {
2443
+ process.stdout.write(`${VERTICAL_LINE}
2444
+ `);
2445
+ let localContent = "";
2446
+ if (fs11.existsSync(file.destPath)) {
2447
+ localContent = fs11.readFileSync(file.destPath).toString();
2448
+ }
2449
+ const changes = diffLines2(localContent, remoteContent);
2450
+ const from = path11.join(
2451
+ `${providerInfo.name}/${providerInfo.owner}/${providerInfo.repoName}`,
2452
+ file.fileName
2453
+ ).replaceAll("\\", "/");
2454
+ const to = path11.relative(options.cwd, file.destPath).replaceAll("\\", "/");
2455
+ const formattedDiff = formatDiff({
2456
+ from,
2457
+ to,
2458
+ changes,
2459
+ expand: options.expand,
2460
+ maxUnchanged: options.maxUnchanged,
2461
+ colorAdded: color13.greenBright,
2462
+ colorRemoved: color13.redBright,
2463
+ colorCharsAdded: color13.bgGreenBright,
2464
+ colorCharsRemoved: color13.bgRedBright,
2465
+ prefix: () => `${VERTICAL_LINE} `,
2466
+ onUnchanged: ({ from: from2, to: to2, prefix }) => `${prefix?.() ?? ""}${color13.cyan(from2)} \u2192 ${color13.gray(to2)} ${color13.gray("(unchanged)")}
2467
+ `,
2468
+ intro: ({ from: from2, to: to2, changes: changes2, prefix }) => {
2469
+ const totalChanges = changes2.filter((a) => a.added).length;
2470
+ return `${prefix?.() ?? ""}${color13.cyan(from2)} \u2192 ${color13.gray(to2)} (${totalChanges} change${totalChanges === 1 ? "" : "s"})
2471
+ ${prefix?.() ?? ""}
2472
+ `;
2473
+ }
2474
+ });
2475
+ process.stdout.write(formattedDiff);
2476
+ if (changes.length > 1) {
2477
+ const confirmResult = await confirm5({
2478
+ message: "Accept changes?",
2479
+ initialValue: true
2480
+ });
2481
+ if (isCancel5(confirmResult)) {
2482
+ cancel5("Canceled!");
2483
+ process.exit(0);
2484
+ }
2485
+ acceptedChanges = confirmResult;
2486
+ }
2487
+ }
2488
+ if (acceptedChanges) {
2489
+ await runTasks(
2490
+ [
2491
+ {
2492
+ loadingMessage: `Writing changes to ${color13.cyan(file.destPath)}`,
2493
+ completedMessage: `Wrote changes to ${color13.cyan(file.destPath)}.`,
2494
+ run: async () => fs11.writeFileSync(file.destPath, remoteContent)
2495
+ }
2496
+ ],
2497
+ {
2498
+ verbose: options.verbose ? verbose : void 0
2499
+ }
2500
+ );
2501
+ }
2502
+ }
2503
+ if (config.includeTests) {
2504
+ verbose("Trying to include tests");
2505
+ const { devDependencies } = JSON.parse(
2506
+ fs11.readFileSync(path11.join(options.cwd, "package.json")).toString()
2507
+ );
2508
+ if (devDependencies.vitest === void 0) {
2509
+ devDeps.add("vitest");
2510
+ }
2511
+ }
2512
+ for (const dep of block.devDependencies) {
2513
+ devDeps.add(dep);
2514
+ }
2515
+ for (const dep of block.dependencies) {
2516
+ deps.add(dep);
2517
+ }
2518
+ }
2519
+ await runTasks(tasks, { verbose: options.verbose ? verbose : void 0 });
2520
+ const hasDependencies = deps.size > 0 || devDeps.size > 0;
2521
+ if (hasDependencies) {
2522
+ let install = options.yes;
2523
+ if (!options.yes) {
2524
+ const result = await confirm5({
2525
+ message: "Would you like to install dependencies?",
2526
+ initialValue: true
2527
+ });
2528
+ if (isCancel5(result)) {
2529
+ cancel5("Canceled!");
2530
+ process.exit(0);
2531
+ }
2532
+ install = result;
2533
+ }
2534
+ if (install) {
2535
+ if (deps.size > 0) {
2536
+ if (!options.verbose)
2537
+ loading.start(`Installing dependencies with ${color13.cyan(pm)}`);
2538
+ (await installDependencies({
2539
+ pm,
2540
+ deps: Array.from(deps),
2541
+ dev: false,
2542
+ cwd: options.cwd
2543
+ })).match(
2544
+ (installed) => {
2545
+ if (!options.verbose)
2546
+ loading.stop(`Installed ${color13.cyan(installed.join(", "))}`);
2547
+ },
2548
+ (err) => {
2549
+ if (!options.verbose) loading.stop("Failed to install dependencies");
2550
+ program5.error(err);
2551
+ }
2552
+ );
2553
+ }
2554
+ if (devDeps.size > 0) {
2555
+ if (!options.verbose)
2556
+ loading.start(`Installing dependencies with ${color13.cyan(pm)}`);
2557
+ (await installDependencies({
2558
+ pm,
2559
+ deps: Array.from(devDeps),
2560
+ dev: true,
2561
+ cwd: options.cwd
2562
+ })).match(
2563
+ (installed) => {
2564
+ if (!options.verbose)
2565
+ loading.stop(`Installed ${color13.cyan(installed.join(", "))}`);
2566
+ },
2567
+ (err) => {
2568
+ if (!options.verbose) loading.stop("Failed to install dev dependencies");
2569
+ program5.error(err);
2570
+ }
2571
+ );
2572
+ }
2573
+ }
2574
+ let steps = [];
2575
+ if (!install) {
2576
+ if (deps.size > 0) {
2577
+ const cmd = resolveCommand4(pm, "install", [...deps]);
2578
+ steps.push(
2579
+ `Install dependencies \`${color13.cyan(`${cmd?.command} ${cmd?.args.join(" ")}`)}\``
2580
+ );
2581
+ }
2582
+ if (devDeps.size > 0) {
2583
+ const cmd = resolveCommand4(pm, "install", [...devDeps, "-D"]);
2584
+ steps.push(
2585
+ `Install dev dependencies \`${color13.cyan(`${cmd?.command} ${cmd?.args.join(" ")}`)}\``
2586
+ );
2587
+ }
2588
+ }
2589
+ steps = steps.map((step, i) => `${i + 1}. ${step}`);
2590
+ if (!install) {
2591
+ steps.push("");
2592
+ }
2593
+ steps.push(`Import the blocks from \`${color13.cyan(config.path)}\``);
2594
+ const next = nextSteps(steps);
2595
+ process.stdout.write(next);
2231
2596
  }
2232
2597
  };
2233
2598
 
2234
2599
  // src/index.ts
2235
2600
  var resolveRelativeToRoot = (p) => {
2236
2601
  const dirname = fileURLToPath(import.meta.url);
2237
- return path11.join(dirname, "../..", p);
2602
+ return path12.join(dirname, "../..", p);
2238
2603
  };
2239
2604
  var { version, name, description, repository } = JSON.parse(
2240
- fs11.readFileSync(resolveRelativeToRoot("package.json"), "utf-8")
2605
+ fs12.readFileSync(resolveRelativeToRoot("package.json"), "utf-8")
2241
2606
  );
2242
2607
  var context = {
2243
2608
  package: {
@@ -2248,8 +2613,8 @@ var context = {
2248
2613
  },
2249
2614
  resolveRelativeToRoot
2250
2615
  };
2251
- program5.name(name).description(description).version(version).addCommand(add).addCommand(init).addCommand(test).addCommand(build).addCommand(diff);
2252
- program5.parse();
2616
+ program6.name(name).description(description).version(version).addCommand(add).addCommand(init).addCommand(test).addCommand(build).addCommand(update).addCommand(diff);
2617
+ program6.parse();
2253
2618
  export {
2254
2619
  context
2255
2620
  };