jsrepo 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ import { program as program5 } from "commander";
8
8
  import fs6 from "node:fs";
9
9
  import path5 from "node:path";
10
10
  import { cancel, confirm, isCancel, multiselect, outro, spinner as spinner2 } from "@clack/prompts";
11
- import color4 from "chalk";
11
+ import color5 from "chalk";
12
12
  import { Command, program as program2 } from "commander";
13
13
  import { execa } from "execa";
14
14
  import { resolveCommand } from "package-manager-detector/commands";
@@ -689,7 +689,7 @@ var getConfig = () => {
689
689
  // src/utils/build.ts
690
690
  import fs4 from "node:fs";
691
691
  import path3 from "node:path";
692
- import color2 from "chalk";
692
+ import color3 from "chalk";
693
693
  import { program } from "commander";
694
694
  import * as v2 from "valibot";
695
695
 
@@ -703,6 +703,7 @@ var INFO = color.bgBlueBright.white("INFO");
703
703
  import fs3 from "node:fs";
704
704
  import { builtinModules } from "node:module";
705
705
  import path2 from "node:path";
706
+ import color2 from "chalk";
706
707
  import { walk } from "estree-walker";
707
708
  import * as sv from "svelte/compiler";
708
709
  import { Project } from "ts-morph";
@@ -719,6 +720,19 @@ var findNearestPackageJson = (startDir, until) => {
719
720
  return findNearestPackageJson(segments.slice(0, segments.length - 1).join("/"), until);
720
721
  };
721
722
 
723
+ // src/utils/parse-package-name.ts
724
+ var RE_SCOPED = /^(@[^\/]+\/[^@\/]+)(?:@([^\/]+))?(\/.*)?$/;
725
+ var RE_NON_SCOPED = /^([^@\/]+)(?:@([^\/]+))?(\/.*)?$/;
726
+ var parsePackageName = (input) => {
727
+ const m = RE_SCOPED.exec(input) || RE_NON_SCOPED.exec(input);
728
+ if (!m) return Err(`invalid package name: ${input}`);
729
+ return Ok({
730
+ name: m[1] || "",
731
+ version: m[2] || "latest",
732
+ path: m[3] || ""
733
+ });
734
+ };
735
+
722
736
  // src/utils/language-support.ts
723
737
  var typescript = {
724
738
  matches: (fileName) => fileName.endsWith(".ts") || fileName.endsWith(".js") || fileName.endsWith(".tsx") || fileName.endsWith(".jsx"),
@@ -798,7 +812,7 @@ var resolveLocalImport = (mod, category, isSubDir) => {
798
812
  };
799
813
  var resolveRemoteDeps = (deps, filePath) => {
800
814
  const filteredDeps = deps.filter(
801
- (dep) => !builtinModules.includes(dep) && !dep.startsWith("node:") && validatePackageName(dep).validForNewPackages
815
+ (dep) => !builtinModules.includes(dep) && !dep.startsWith("node:")
802
816
  );
803
817
  const pkgPath = findNearestPackageJson(path2.dirname(filePath), "");
804
818
  const dependencies = /* @__PURE__ */ new Set();
@@ -806,22 +820,36 @@ var resolveRemoteDeps = (deps, filePath) => {
806
820
  if (pkgPath) {
807
821
  const { devDependencies: packageDevDependencies, dependencies: packageDependencies } = JSON.parse(fs3.readFileSync(pkgPath, "utf-8"));
808
822
  for (const dep of filteredDeps) {
823
+ const parsed = parsePackageName(dep);
824
+ if (parsed.isErr()) {
825
+ console.warn(
826
+ `${WARN} Skipped adding import \`${color2.cyan(dep)}\`. Reason: Couldn't parse package name`
827
+ );
828
+ continue;
829
+ }
830
+ const depInfo = parsed.unwrap();
831
+ if (!validatePackageName(depInfo.name).validForNewPackages) {
832
+ console.warn(
833
+ `${WARN} Skipped adding import \`${color2.cyan(dep)}\`. Reason: Not a valid package name`
834
+ );
835
+ continue;
836
+ }
809
837
  let version2 = void 0;
810
838
  if (packageDependencies !== void 0) {
811
- version2 = packageDependencies[dep];
839
+ version2 = packageDependencies[depInfo.name];
812
840
  }
813
841
  if (version2 !== void 0) {
814
- dependencies.add(`${dep}@${version2}`);
842
+ dependencies.add(`${depInfo.name}@${version2}`);
815
843
  continue;
816
844
  }
817
845
  if (packageDevDependencies !== void 0) {
818
- version2 = packageDevDependencies[dep];
846
+ version2 = packageDevDependencies[depInfo.name];
819
847
  }
820
848
  if (version2 !== void 0) {
821
- devDependencies.add(`${dep}@${version2}`);
849
+ devDependencies.add(`${depInfo.name}@${version2}`);
822
850
  continue;
823
851
  }
824
- dependencies.add(dep);
852
+ dependencies.add(depInfo.name);
825
853
  }
826
854
  }
827
855
  return {
@@ -855,7 +883,7 @@ var buildBlocksDirectory = (blocksPath, cwd) => {
855
883
  try {
856
884
  paths = fs4.readdirSync(blocksPath);
857
885
  } catch {
858
- program.error(color2.red(`Couldn't read the ${color2.bold(blocksPath)} directory.`));
886
+ program.error(color3.red(`Couldn't read the ${color3.bold(blocksPath)} directory.`));
859
887
  }
860
888
  const categories = [];
861
889
  for (const categoryPath of paths) {
@@ -874,7 +902,7 @@ var buildBlocksDirectory = (blocksPath, cwd) => {
874
902
  const lang = languages.find((resolver) => resolver.matches(file));
875
903
  if (!lang) {
876
904
  console.warn(
877
- `${WARN} Skipped \`${color2.bold(blockDir)}\` \`${color2.bold(
905
+ `${WARN} Skipped \`${color3.bold(blockDir)}\` \`${color3.bold(
878
906
  path3.parse(file).ext
879
907
  )}\` files are not currently supported!`
880
908
  );
@@ -887,7 +915,7 @@ var buildBlocksDirectory = (blocksPath, cwd) => {
887
915
  const { dependencies, devDependencies, local } = lang.resolveDependencies(blockDir, categoryName, false).match(
888
916
  (val) => val,
889
917
  (err) => {
890
- program.error(color2.red(err));
918
+ program.error(color3.red(err));
891
919
  }
892
920
  );
893
921
  const block = {
@@ -917,7 +945,7 @@ var buildBlocksDirectory = (blocksPath, cwd) => {
917
945
  const lang = languages.find((resolver) => resolver.matches(f));
918
946
  if (!lang) {
919
947
  console.warn(
920
- `${WARN} Skipped \`${color2.bold(path3.join(blockDir, f))}\` \`${color2.bold(
948
+ `${WARN} Skipped \`${color3.bold(path3.join(blockDir, f))}\` \`${color3.bold(
921
949
  path3.parse(file).ext
922
950
  )}\` files are not currently supported!`
923
951
  );
@@ -926,7 +954,7 @@ var buildBlocksDirectory = (blocksPath, cwd) => {
926
954
  const { local, dependencies, devDependencies } = lang.resolveDependencies(path3.join(blockDir, f), categoryName, true).match(
927
955
  (val) => val,
928
956
  (err) => {
929
- program.error(color2.red(err));
957
+ program.error(color3.red(err));
930
958
  }
931
959
  );
932
960
  for (const dep of local) {
@@ -1062,7 +1090,7 @@ var getManifest = async (url) => {
1062
1090
 
1063
1091
  // src/utils/prompts.ts
1064
1092
  import { intro, spinner } from "@clack/prompts";
1065
- import color3 from "chalk";
1093
+ import color4 from "chalk";
1066
1094
 
1067
1095
  // src/blocks/utilities/strip-ansi.ts
1068
1096
  import ansiRegex from "ansi-regex";
@@ -1084,11 +1112,11 @@ var rightPadMin = (str, length, padWith = " ") => {
1084
1112
  };
1085
1113
 
1086
1114
  // src/utils/prompts.ts
1087
- var VERTICAL_BORDER = color3.gray("\u2502");
1088
- var HORIZONTAL_BORDER = color3.gray("\u2500");
1089
- var TOP_RIGHT_CORNER = color3.gray("\u2510");
1090
- var BOTTOM_RIGHT_CORNER = color3.gray("\u2518");
1091
- var JUNCTION_RIGHT = color3.gray("\u251C");
1115
+ var VERTICAL_BORDER = color4.gray("\u2502");
1116
+ var HORIZONTAL_BORDER = color4.gray("\u2500");
1117
+ var TOP_RIGHT_CORNER = color4.gray("\u2510");
1118
+ var BOTTOM_RIGHT_CORNER = color4.gray("\u2518");
1119
+ var JUNCTION_RIGHT = color4.gray("\u251C");
1092
1120
  var runTasks = async (tasks, { verbose = false }) => {
1093
1121
  const loading = spinner();
1094
1122
  for (const task of tasks) {
@@ -1126,7 +1154,7 @@ var nextSteps = (steps) => {
1126
1154
  `;
1127
1155
  return result;
1128
1156
  };
1129
- var _intro = (version2) => intro(`${color3.bgHex("#f7df1e").black(" jsrepo ")}${color3.gray(` v${version2} `)}`);
1157
+ var _intro = (version2) => intro(`${color4.bgHex("#f7df1e").black(" jsrepo ")}${color4.gray(` v${version2} `)}`);
1130
1158
 
1131
1159
  // src/commands/add.ts
1132
1160
  var schema2 = v4.object({
@@ -1150,14 +1178,14 @@ var _add = async (blockNames, options) => {
1150
1178
  const loading = spinner2();
1151
1179
  const config = getConfig().match(
1152
1180
  (val) => val,
1153
- (err) => program2.error(color4.red(err))
1181
+ (err) => program2.error(color5.red(err))
1154
1182
  );
1155
1183
  const blocksMap = /* @__PURE__ */ new Map();
1156
1184
  let repoPaths = config.repos;
1157
1185
  if (options.repo) repoPaths = [options.repo];
1158
1186
  if (!options.allow && options.repo) {
1159
1187
  const result = await confirm({
1160
- message: `Allow ${color4.cyan("jsrepo")} to download and run code from ${color4.cyan(options.repo)}?`,
1188
+ message: `Allow ${color5.cyan("jsrepo")} to download and run code from ${color5.cyan(options.repo)}?`,
1161
1189
  initialValue: true
1162
1190
  });
1163
1191
  if (isCancel(result) || !result) {
@@ -1165,23 +1193,23 @@ var _add = async (blockNames, options) => {
1165
1193
  process.exit(0);
1166
1194
  }
1167
1195
  }
1168
- verbose(`Fetching blocks from ${color4.cyan(repoPaths.join(", "))}`);
1169
- if (!options.verbose) loading.start(`Fetching blocks from ${color4.cyan(repoPaths.join(", "))}`);
1196
+ verbose(`Fetching blocks from ${color5.cyan(repoPaths.join(", "))}`);
1197
+ if (!options.verbose) loading.start(`Fetching blocks from ${color5.cyan(repoPaths.join(", "))}`);
1170
1198
  for (const repo of repoPaths) {
1171
1199
  const providerInfo = (await getProviderInfo(repo)).match(
1172
1200
  (info) => info,
1173
1201
  (err) => {
1174
- loading.stop(`Failed fetching blocks from ${color4.cyan(repo)}`);
1175
- program2.error(color4.red(err));
1202
+ loading.stop(`Failed fetching blocks from ${color5.cyan(repo)}`);
1203
+ program2.error(color5.red(err));
1176
1204
  }
1177
1205
  );
1178
1206
  const manifestUrl = await providerInfo.provider.resolveRaw(providerInfo, OUTPUT_FILE);
1179
- verbose(`Got info for provider ${color4.cyan(providerInfo.name)}`);
1207
+ verbose(`Got info for provider ${color5.cyan(providerInfo.name)}`);
1180
1208
  const categories = (await getManifest(manifestUrl)).match(
1181
1209
  (val) => val,
1182
1210
  (err) => {
1183
- loading.stop(`Failed fetching blocks from ${color4.cyan(repo)}`);
1184
- program2.error(color4.red(err));
1211
+ loading.stop(`Failed fetching blocks from ${color5.cyan(repo)}`);
1212
+ program2.error(color5.red(err));
1185
1213
  }
1186
1214
  );
1187
1215
  for (const category of categories) {
@@ -1196,8 +1224,8 @@ var _add = async (blockNames, options) => {
1196
1224
  }
1197
1225
  }
1198
1226
  }
1199
- verbose(`Retrieved blocks from ${color4.cyan(repoPaths.join(", "))}`);
1200
- if (!options.verbose) loading.stop(`Retrieved blocks from ${color4.cyan(repoPaths.join(", "))}`);
1227
+ verbose(`Retrieved blocks from ${color5.cyan(repoPaths.join(", "))}`);
1228
+ if (!options.verbose) loading.stop(`Retrieved blocks from ${color5.cyan(repoPaths.join(", "))}`);
1201
1229
  const installedBlocks = getInstalledBlocks(blocksMap, config).map((val) => val.specifier);
1202
1230
  let installingBlockNames = blockNames;
1203
1231
  if (installingBlockNames.length === 0) {
@@ -1208,14 +1236,14 @@ var _add = async (blockNames, options) => {
1208
1236
  const blockExists = installedBlocks.findIndex((block) => block === shortName) !== -1;
1209
1237
  let label;
1210
1238
  if (repoPaths.length > 1) {
1211
- label = `${color4.cyan(
1239
+ label = `${color5.cyan(
1212
1240
  `${value.sourceRepo.name}/${value.sourceRepo.owner}/${value.sourceRepo.repoName}/${value.category}`
1213
1241
  )}/${value.name}`;
1214
1242
  } else {
1215
- label = `${color4.cyan(value.category)}/${value.name}`;
1243
+ label = `${color5.cyan(value.category)}/${value.name}`;
1216
1244
  }
1217
1245
  return {
1218
- label: blockExists ? color4.gray(label) : label,
1246
+ label: blockExists ? color5.gray(label) : label,
1219
1247
  value: key,
1220
1248
  // show hint for `Installed` if block is already installed
1221
1249
  hint: blockExists ? "Installed" : void 0
@@ -1229,9 +1257,9 @@ var _add = async (blockNames, options) => {
1229
1257
  }
1230
1258
  installingBlockNames = promptResult;
1231
1259
  }
1232
- verbose(`Installing blocks ${color4.cyan(installingBlockNames.join(", "))}`);
1260
+ verbose(`Installing blocks ${color5.cyan(installingBlockNames.join(", "))}`);
1233
1261
  if (options.verbose) console.log("Blocks map: ", blocksMap);
1234
- const installingBlocks = await getBlocks(installingBlockNames, blocksMap, repoPaths);
1262
+ const installingBlocks = await getBlocks(installingBlockNames, blocksMap, repoPaths, options);
1235
1263
  const pm = (await detect({ cwd: process.cwd() }))?.agent ?? "npm";
1236
1264
  const tasks = [];
1237
1265
  const devDeps = /* @__PURE__ */ new Set();
@@ -1241,11 +1269,11 @@ var _add = async (blockNames, options) => {
1241
1269
  const providerInfo = block.sourceRepo;
1242
1270
  verbose(`Attempting to add ${specifier}`);
1243
1271
  const directory = path5.join(config.path, block.category);
1244
- verbose(`Creating directory ${color4.bold(directory)}`);
1272
+ verbose(`Creating directory ${color5.bold(directory)}`);
1245
1273
  const blockExists = !block.subdirectory && fs6.existsSync(path5.join(directory, block.files[0])) || block.subdirectory && fs6.existsSync(path5.join(directory, block.name));
1246
1274
  if (blockExists && !options.yes) {
1247
1275
  const result = await confirm({
1248
- message: `${color4.bold(block.name)} already exists in your project would you like to overwrite it?`,
1276
+ message: `${color5.bold(block.name)} already exists in your project would you like to overwrite it?`,
1249
1277
  initialValue: false
1250
1278
  });
1251
1279
  if (isCancel(result) || !result) {
@@ -1263,8 +1291,8 @@ var _add = async (blockNames, options) => {
1263
1291
  const rawUrl = await providerInfo.provider.resolveRaw(providerInfo, filePath);
1264
1292
  const response = await fetch(rawUrl);
1265
1293
  if (!response.ok) {
1266
- loading.stop(color4.red(`Error fetching ${color4.bold(rawUrl.href)}`));
1267
- program2.error(color4.red(`There was an error trying to get ${specifier}`));
1294
+ loading.stop(color5.red(`Error fetching ${color5.bold(rawUrl.href)}`));
1295
+ program2.error(color5.red(`There was an error trying to get ${specifier}`));
1268
1296
  }
1269
1297
  return await response.text();
1270
1298
  };
@@ -1316,7 +1344,7 @@ ${content}`;
1316
1344
  }
1317
1345
  await runTasks(tasks, { verbose: options.verbose });
1318
1346
  const installDependencies = async (deps2, dev) => {
1319
- if (!options.verbose) loading.start(`Installing dependencies with ${color4.cyan(pm)}`);
1347
+ if (!options.verbose) loading.start(`Installing dependencies with ${color5.cyan(pm)}`);
1320
1348
  let add2;
1321
1349
  if (dev) {
1322
1350
  add2 = resolveCommand(pm, "install", [...deps2, "-D"]);
@@ -1324,20 +1352,20 @@ ${content}`;
1324
1352
  add2 = resolveCommand(pm, "install", [...deps2]);
1325
1353
  }
1326
1354
  if (add2 == null) {
1327
- program2.error(color4.red(`Could not resolve add command for '${pm}'.`));
1355
+ program2.error(color5.red(`Could not resolve add command for '${pm}'.`));
1328
1356
  }
1329
1357
  try {
1330
1358
  await execa(add2.command, [...add2.args], { cwd: process.cwd() });
1331
1359
  } catch {
1332
1360
  program2.error(
1333
- color4.red(
1334
- `Failed to install ${color4.bold("vitest")}! Failed while running '${color4.bold(
1361
+ color5.red(
1362
+ `Failed to install ${color5.bold("vitest")}! Failed while running '${color5.bold(
1335
1363
  `${add2.command} ${add2.args.join(" ")}`
1336
1364
  )}'`
1337
1365
  )
1338
1366
  );
1339
1367
  }
1340
- if (!options.verbose) loading.stop(`Installed ${color4.cyan(deps2.join(", "))}`);
1368
+ if (!options.verbose) loading.stop(`Installed ${color5.cyan(deps2.join(", "))}`);
1341
1369
  };
1342
1370
  const hasDependencies = deps.size > 0 || devDeps.size > 0;
1343
1371
  if (hasDependencies) {
@@ -1366,13 +1394,13 @@ ${content}`;
1366
1394
  if (deps.size > 0) {
1367
1395
  const cmd = resolveCommand(pm, "install", [...deps]);
1368
1396
  steps.push(
1369
- `Install dependencies \`${color4.cyan(`${cmd?.command} ${cmd?.args.join(" ")}`)}\``
1397
+ `Install dependencies \`${color5.cyan(`${cmd?.command} ${cmd?.args.join(" ")}`)}\``
1370
1398
  );
1371
1399
  }
1372
1400
  if (devDeps.size > 0) {
1373
1401
  const cmd = resolveCommand(pm, "install", [...devDeps, "-D"]);
1374
1402
  steps.push(
1375
- `Install dev dependencies \`${color4.cyan(`${cmd?.command} ${cmd?.args.join(" ")}`)}\``
1403
+ `Install dev dependencies \`${color5.cyan(`${cmd?.command} ${cmd?.args.join(" ")}`)}\``
1376
1404
  );
1377
1405
  }
1378
1406
  }
@@ -1380,21 +1408,21 @@ ${content}`;
1380
1408
  if (!install) {
1381
1409
  steps.push("");
1382
1410
  }
1383
- steps.push(`Import the blocks from \`${color4.cyan(config.path)}\``);
1411
+ steps.push(`Import the blocks from \`${color5.cyan(config.path)}\``);
1384
1412
  const next = nextSteps(steps);
1385
1413
  process.stdout.write(next);
1386
1414
  }
1387
- outro(color4.green("All done!"));
1415
+ outro(color5.green("All done!"));
1388
1416
  };
1389
- var getBlocks = async (blockSpecifiers, blocksMap, repoPaths) => {
1417
+ var getBlocks = async (blockSpecifiers, blocksMap, repoPaths, options) => {
1390
1418
  const blocks = /* @__PURE__ */ new Map();
1391
1419
  for (const blockSpecifier of blockSpecifiers) {
1392
1420
  let block = void 0;
1393
1421
  if (!blockSpecifier.startsWith("github")) {
1394
1422
  if (repoPaths.length === 0) {
1395
1423
  program2.error(
1396
- color4.red(
1397
- `If your config doesn't repos then you must provide the repo in the block specifier ex: \`${color4.bold(
1424
+ color5.red(
1425
+ `If your config doesn't repos then you must provide the repo in the block specifier ex: \`${color5.bold(
1398
1426
  `github/<owner>/<name>/${blockSpecifier}`
1399
1427
  )}\`!`
1400
1428
  )
@@ -1410,43 +1438,48 @@ var getBlocks = async (blockSpecifiers, blocksMap, repoPaths) => {
1410
1438
  break;
1411
1439
  }
1412
1440
  } else {
1413
- if (repoPaths.length === 0) {
1414
- const [providerName, owner, repoName, ...rest] = blockSpecifier.split("/");
1415
- let repo;
1416
- if (rest.length > 2) {
1417
- repo = `${providerName}/${owner}/${repoName}/${rest.join("/")}`;
1418
- } else {
1419
- repo = `${providerName}/${owner}/${repoName}`;
1441
+ const [providerName, owner, repoName, ...rest] = blockSpecifier.split("/");
1442
+ let repo;
1443
+ if (rest.length > 2) {
1444
+ repo = `${providerName}/${owner}/${repoName}/${rest.join("/")}`;
1445
+ } else {
1446
+ repo = `${providerName}/${owner}/${repoName}`;
1447
+ }
1448
+ const providerInfo = (await getProviderInfo(repo)).match(
1449
+ (val) => val,
1450
+ (err) => program2.error(color5.red(err))
1451
+ );
1452
+ const manifestUrl = await providerInfo.provider.resolveRaw(providerInfo, OUTPUT_FILE);
1453
+ if (!options.allow) {
1454
+ const result = await confirm({
1455
+ message: `Allow ${color5.cyan("jsrepo")} to download and run code from ${color5.cyan(repo)}?`,
1456
+ initialValue: true
1457
+ });
1458
+ if (isCancel(result) || !result) {
1459
+ cancel("Canceled!");
1460
+ process.exit(0);
1420
1461
  }
1421
- const providerInfo = (await getProviderInfo(repo)).match(
1422
- (val) => val,
1423
- (err) => program2.error(color4.red(err))
1424
- );
1425
- const manifestUrl = await providerInfo.provider.resolveRaw(
1426
- providerInfo,
1427
- OUTPUT_FILE
1428
- );
1429
- const categories = (await getManifest(manifestUrl)).match(
1430
- (val) => val,
1431
- (err) => program2.error(color4.red(err))
1432
- );
1433
- for (const category of categories) {
1434
- for (const block2 of category.blocks) {
1435
- blocksMap.set(
1436
- `${providerInfo.name}/${providerInfo.owner}/${providerInfo.repoName}/${category.name}/${block2.name}`,
1437
- {
1438
- ...block2,
1439
- sourceRepo: providerInfo
1440
- }
1441
- );
1442
- }
1462
+ }
1463
+ const categories = (await getManifest(manifestUrl)).match(
1464
+ (val) => val,
1465
+ (err) => program2.error(color5.red(err))
1466
+ );
1467
+ for (const category of categories) {
1468
+ for (const block2 of category.blocks) {
1469
+ blocksMap.set(
1470
+ `${providerInfo.name}/${providerInfo.owner}/${providerInfo.repoName}/${category.name}/${block2.name}`,
1471
+ {
1472
+ ...block2,
1473
+ sourceRepo: providerInfo
1474
+ }
1475
+ );
1443
1476
  }
1444
1477
  }
1445
1478
  block = blocksMap.get(blockSpecifier);
1446
1479
  }
1447
1480
  if (!block) {
1448
1481
  program2.error(
1449
- color4.red(`Invalid block! ${color4.bold(blockSpecifier)} does not exist!`)
1482
+ color5.red(`Invalid block! ${color5.bold(blockSpecifier)} does not exist!`)
1450
1483
  );
1451
1484
  }
1452
1485
  blocks.set(blockSpecifier, { name: blockSpecifier, subDependency: false, block });
@@ -1454,7 +1487,8 @@ var getBlocks = async (blockSpecifiers, blocksMap, repoPaths) => {
1454
1487
  const subDeps = await getBlocks(
1455
1488
  block.localDependencies.filter((dep) => blocks.has(dep)),
1456
1489
  blocksMap,
1457
- repoPaths
1490
+ repoPaths,
1491
+ options
1458
1492
  );
1459
1493
  for (const dep of subDeps) {
1460
1494
  blocks.set(dep.name, dep);
@@ -1468,7 +1502,7 @@ var getBlocks = async (blockSpecifiers, blocksMap, repoPaths) => {
1468
1502
  import fs7 from "node:fs";
1469
1503
  import path6 from "node:path";
1470
1504
  import { outro as outro2, spinner as spinner3 } from "@clack/prompts";
1471
- import color5 from "chalk";
1505
+ import color6 from "chalk";
1472
1506
  import { Command as Command2 } from "commander";
1473
1507
  import * as v5 from "valibot";
1474
1508
  var schema3 = v5.object({
@@ -1488,10 +1522,10 @@ var _build = async (options) => {
1488
1522
  const outFile = path6.join(options.cwd, OUTPUT_FILE);
1489
1523
  for (const dir of options.dirs) {
1490
1524
  const dirPath = path6.join(options.cwd, dir);
1491
- loading.start(`Building ${color5.cyan(dirPath)}`);
1525
+ loading.start(`Building ${color6.cyan(dirPath)}`);
1492
1526
  if (options.output && fs7.existsSync(outFile)) fs7.rmSync(outFile);
1493
1527
  categories.push(...buildBlocksDirectory(dirPath, options.cwd));
1494
- loading.stop(`Built ${color5.cyan(dirPath)}`);
1528
+ loading.stop(`Built ${color6.cyan(dirPath)}`);
1495
1529
  }
1496
1530
  const categoriesMap = /* @__PURE__ */ new Map();
1497
1531
  for (const category of categories) {
@@ -1508,20 +1542,20 @@ var _build = async (options) => {
1508
1542
  } else {
1509
1543
  loading.stop("Built successfully!");
1510
1544
  }
1511
- outro2(color5.green("All done!"));
1545
+ outro2(color6.green("All done!"));
1512
1546
  };
1513
1547
 
1514
1548
  // src/commands/diff.ts
1515
1549
  import fs8 from "node:fs";
1516
1550
  import path7 from "node:path";
1517
1551
  import { cancel as cancel2, confirm as confirm2, isCancel as isCancel2, outro as outro3, spinner as spinner4 } from "@clack/prompts";
1518
- import color7 from "chalk";
1552
+ import color8 from "chalk";
1519
1553
  import { Command as Command3, program as program3 } from "commander";
1520
1554
  import { diffLines } from "diff";
1521
1555
  import * as v6 from "valibot";
1522
1556
 
1523
1557
  // src/utils/diff.ts
1524
- import color6 from "chalk";
1558
+ import color7 from "chalk";
1525
1559
  import { diffChars } from "diff";
1526
1560
 
1527
1561
  // src/blocks/utilities/array-sum.ts
@@ -1556,8 +1590,8 @@ var formatDiff = ({
1556
1590
  changes,
1557
1591
  expand = false,
1558
1592
  maxUnchanged = 5,
1559
- colorRemoved = color6.red,
1560
- colorAdded = color6.green,
1593
+ colorRemoved = color7.red,
1594
+ colorAdded = color7.green,
1561
1595
  prefix,
1562
1596
  onUnchanged,
1563
1597
  intro: intro2
@@ -1591,7 +1625,7 @@ var formatDiff = ({
1591
1625
  onUnchanged,
1592
1626
  intro: intro2
1593
1627
  });
1594
- const linePrefix = (line) => color6.gray(`${prefix?.() ?? ""}${leftPadMin(`${line + 1 + lineOffset} `, length)} `);
1628
+ const linePrefix = (line) => color7.gray(`${prefix?.() ?? ""}${leftPadMin(`${line + 1 + lineOffset} `, length)} `);
1595
1629
  for (let i = 0; i < changes.length; i++) {
1596
1630
  const change = changes[i];
1597
1631
  const hasPreviousChange = changes[i - 1]?.added || changes[i - 1]?.removed;
@@ -1621,8 +1655,8 @@ var formatDiff = ({
1621
1655
  const count = ls.length - shownLines;
1622
1656
  result += `${join(
1623
1657
  get(
1624
- color6.gray(
1625
- `+ ${count} more unchanged (${color6.italic("-E to expand")})`
1658
+ color7.gray(
1659
+ `+ ${count} more unchanged (${color7.italic("-E to expand")})`
1626
1660
  )
1627
1661
  ),
1628
1662
  {
@@ -1677,7 +1711,7 @@ var formatDiff = ({
1677
1711
  };
1678
1712
 
1679
1713
  // src/commands/diff.ts
1680
- var L = color7.gray("\u2502");
1714
+ var L = color8.gray("\u2502");
1681
1715
  var schema4 = v6.object({
1682
1716
  allow: v6.boolean(),
1683
1717
  expand: v6.boolean(),
@@ -1699,14 +1733,14 @@ var _diff = async (options) => {
1699
1733
  const loading = spinner4();
1700
1734
  const config = getConfig().match(
1701
1735
  (val) => val,
1702
- (err) => program3.error(color7.red(err))
1736
+ (err) => program3.error(color8.red(err))
1703
1737
  );
1704
1738
  const blocksMap = /* @__PURE__ */ new Map();
1705
1739
  let repoPaths = config.repos;
1706
1740
  if (options.repo) repoPaths = [options.repo];
1707
1741
  if (!options.allow && options.repo) {
1708
1742
  const result = await confirm2({
1709
- message: `Allow ${color7.cyan("jsrepo")} to download and run code from ${color7.cyan(options.repo)}?`,
1743
+ message: `Allow ${color8.cyan("jsrepo")} to download and run code from ${color8.cyan(options.repo)}?`,
1710
1744
  initialValue: true
1711
1745
  });
1712
1746
  if (isCancel2(result) || !result) {
@@ -1714,16 +1748,16 @@ var _diff = async (options) => {
1714
1748
  process.exit(0);
1715
1749
  }
1716
1750
  }
1717
- loading.start(`Fetching blocks from ${color7.cyan(repoPaths.join(", "))}`);
1751
+ loading.start(`Fetching blocks from ${color8.cyan(repoPaths.join(", "))}`);
1718
1752
  for (const repo of repoPaths) {
1719
1753
  const providerInfo = (await getProviderInfo(repo)).match(
1720
1754
  (info) => info,
1721
- (err) => program3.error(color7.red(err))
1755
+ (err) => program3.error(color8.red(err))
1722
1756
  );
1723
1757
  const manifestUrl = await providerInfo.provider.resolveRaw(providerInfo, OUTPUT_FILE);
1724
1758
  const categories = (await getManifest(manifestUrl)).match(
1725
1759
  (val) => val,
1726
- (err) => program3.error(color7.red(err))
1760
+ (err) => program3.error(color8.red(err))
1727
1761
  );
1728
1762
  for (const category of categories) {
1729
1763
  for (const block of category.blocks) {
@@ -1737,7 +1771,7 @@ var _diff = async (options) => {
1737
1771
  }
1738
1772
  }
1739
1773
  }
1740
- loading.stop(`Retrieved blocks from ${color7.cyan(repoPaths.join(", "))}`);
1774
+ loading.stop(`Retrieved blocks from ${color8.cyan(repoPaths.join(", "))}`);
1741
1775
  const installedBlocks = getInstalledBlocks(blocksMap, config);
1742
1776
  for (const blockSpecifier of installedBlocks) {
1743
1777
  let found = false;
@@ -1760,7 +1794,7 @@ var _diff = async (options) => {
1760
1794
  const rawUrl = await providerInfo.provider.resolveRaw(providerInfo, sourcePath);
1761
1795
  const response = await fetch(rawUrl);
1762
1796
  if (!response.ok) {
1763
- program3.error(color7.red(`There was an error trying to get ${fullSpecifier}`));
1797
+ program3.error(color8.red(`There was an error trying to get ${fullSpecifier}`));
1764
1798
  }
1765
1799
  let remoteContent = await response.text();
1766
1800
  let localPath = path7.join(config.path, block.category, file);
@@ -1793,14 +1827,14 @@ ${remoteContent}`;
1793
1827
  changes,
1794
1828
  expand: options.expand,
1795
1829
  maxUnchanged: options.maxUnchanged,
1796
- colorAdded: color7.greenBright,
1797
- colorRemoved: color7.redBright,
1830
+ colorAdded: color8.greenBright,
1831
+ colorRemoved: color8.redBright,
1798
1832
  prefix: () => `${L} `,
1799
- onUnchanged: ({ from: from2, to: to2, prefix }) => `${prefix?.() ?? ""}${color7.cyan(from2)} \u2192 ${color7.gray(to2)} ${color7.gray("(unchanged)")}
1833
+ onUnchanged: ({ from: from2, to: to2, prefix }) => `${prefix?.() ?? ""}${color8.cyan(from2)} \u2192 ${color8.gray(to2)} ${color8.gray("(unchanged)")}
1800
1834
  `,
1801
1835
  intro: ({ from: from2, to: to2, changes: changes2, prefix }) => {
1802
1836
  const totalChanges = changes2.filter((a) => a.added).length;
1803
- return `${prefix?.() ?? ""}${color7.cyan(from2)} \u2192 ${color7.gray(to2)} (${totalChanges} change${totalChanges === 1 ? "" : "s"})
1837
+ return `${prefix?.() ?? ""}${color8.cyan(from2)} \u2192 ${color8.gray(to2)} (${totalChanges} change${totalChanges === 1 ? "" : "s"})
1804
1838
  ${prefix?.() ?? ""}
1805
1839
  `;
1806
1840
  }
@@ -1811,17 +1845,17 @@ ${prefix?.() ?? ""}
1811
1845
  }
1812
1846
  if (!found) {
1813
1847
  program3.error(
1814
- color7.red(`Invalid block! ${color7.bold(blockSpecifier)} does not exist!`)
1848
+ color8.red(`Invalid block! ${color8.bold(blockSpecifier)} does not exist!`)
1815
1849
  );
1816
1850
  }
1817
1851
  }
1818
- outro3(color7.green("All done!"));
1852
+ outro3(color8.green("All done!"));
1819
1853
  };
1820
1854
 
1821
1855
  // src/commands/init.ts
1822
1856
  import fs9 from "node:fs";
1823
1857
  import { cancel as cancel3, confirm as confirm3, isCancel as isCancel3, outro as outro4, spinner as spinner5, text } from "@clack/prompts";
1824
- import color8 from "chalk";
1858
+ import color9 from "chalk";
1825
1859
  import { Command as Command4 } from "commander";
1826
1860
  import * as v7 from "valibot";
1827
1861
  var schema5 = v7.object({
@@ -1874,7 +1908,7 @@ var _init = async (options) => {
1874
1908
  placeholder: "github/ieedan/std",
1875
1909
  validate: (val) => {
1876
1910
  if (!val.startsWith("https://github.com") && !val.startsWith("github/")) {
1877
- return `Must be a ${color8.bold("GitHub")} repository!`;
1911
+ return `Must be a ${color9.bold("GitHub")} repository!`;
1878
1912
  }
1879
1913
  }
1880
1914
  });
@@ -1897,14 +1931,14 @@ var _init = async (options) => {
1897
1931
  `);
1898
1932
  fs9.mkdirSync(config.path, { recursive: true });
1899
1933
  loading.stop(`Wrote config to \`${CONFIG_NAME}\`.`);
1900
- outro4(color8.green("All done!"));
1934
+ outro4(color9.green("All done!"));
1901
1935
  };
1902
1936
 
1903
1937
  // src/commands/test.ts
1904
1938
  import fs10 from "node:fs";
1905
1939
  import path8 from "node:path";
1906
1940
  import { cancel as cancel4, confirm as confirm4, isCancel as isCancel4, outro as outro5, spinner as spinner6 } from "@clack/prompts";
1907
- import color9 from "chalk";
1941
+ import color10 from "chalk";
1908
1942
  import { Argument, Command as Command5, program as program4 } from "commander";
1909
1943
  import { execa as execa2 } from "execa";
1910
1944
  import { resolveCommand as resolveCommand2 } from "package-manager-detector/commands";
@@ -1931,7 +1965,7 @@ var _test = async (blockNames, options) => {
1931
1965
  verbose(`Attempting to test ${JSON.stringify(blockNames)}`);
1932
1966
  const config = getConfig().match(
1933
1967
  (val) => val,
1934
- (err) => program4.error(color9.red(err))
1968
+ (err) => program4.error(color10.red(err))
1935
1969
  );
1936
1970
  const loading = spinner6();
1937
1971
  const blocksMap = /* @__PURE__ */ new Map();
@@ -1939,7 +1973,7 @@ var _test = async (blockNames, options) => {
1939
1973
  if (options.repo) repoPaths = [options.repo];
1940
1974
  if (!options.allow && options.repo) {
1941
1975
  const result = await confirm4({
1942
- message: `Allow ${color9.cyan("jsrepo")} to download and run code from ${color9.cyan(options.repo)}?`,
1976
+ message: `Allow ${color10.cyan("jsrepo")} to download and run code from ${color10.cyan(options.repo)}?`,
1943
1977
  initialValue: true
1944
1978
  });
1945
1979
  if (isCancel4(result) || !result) {
@@ -1947,21 +1981,21 @@ var _test = async (blockNames, options) => {
1947
1981
  process.exit(0);
1948
1982
  }
1949
1983
  }
1950
- verbose(`Fetching blocks from ${color9.cyan(repoPaths.join(", "))}`);
1951
- if (!options.verbose) loading.start(`Fetching blocks from ${color9.cyan(repoPaths.join(", "))}`);
1984
+ verbose(`Fetching blocks from ${color10.cyan(repoPaths.join(", "))}`);
1985
+ if (!options.verbose) loading.start(`Fetching blocks from ${color10.cyan(repoPaths.join(", "))}`);
1952
1986
  for (const repo of repoPaths) {
1953
1987
  const providerInfo = (await getProviderInfo(repo)).match(
1954
1988
  (info) => info,
1955
- (err) => program4.error(color9.red(err))
1989
+ (err) => program4.error(color10.red(err))
1956
1990
  );
1957
1991
  const manifestUrl = await providerInfo.provider.resolveRaw(providerInfo, OUTPUT_FILE);
1958
- verbose(`Got info for provider ${color9.cyan(providerInfo.name)}`);
1992
+ verbose(`Got info for provider ${color10.cyan(providerInfo.name)}`);
1959
1993
  const response = await fetch(manifestUrl);
1960
1994
  if (!response.ok) {
1961
- if (!options.verbose) loading.stop(`Error fetching ${color9.cyan(manifestUrl.href)}`);
1995
+ if (!options.verbose) loading.stop(`Error fetching ${color10.cyan(manifestUrl.href)}`);
1962
1996
  program4.error(
1963
- color9.red(
1964
- `There was an error fetching the \`${OUTPUT_FILE}\` from the repository ${color9.cyan(
1997
+ color10.red(
1998
+ `There was an error fetching the \`${OUTPUT_FILE}\` from the repository ${color10.cyan(
1965
1999
  repo
1966
2000
  )} make sure the target repository has a \`${OUTPUT_FILE}\` in its root?`
1967
2001
  )
@@ -1980,10 +2014,10 @@ var _test = async (blockNames, options) => {
1980
2014
  }
1981
2015
  }
1982
2016
  }
1983
- verbose(`Retrieved blocks from ${color9.cyan(repoPaths.join(", "))}`);
1984
- if (!options.verbose) loading.stop(`Retrieved blocks from ${color9.cyan(repoPaths.join(", "))}`);
2017
+ verbose(`Retrieved blocks from ${color10.cyan(repoPaths.join(", "))}`);
2018
+ if (!options.verbose) loading.stop(`Retrieved blocks from ${color10.cyan(repoPaths.join(", "))}`);
1985
2019
  const tempTestDirectory = `blocks-tests-temp-${Date.now()}`;
1986
- verbose(`Trying to create the temp directory ${color9.bold(tempTestDirectory)}.`);
2020
+ verbose(`Trying to create the temp directory ${color10.bold(tempTestDirectory)}.`);
1987
2021
  fs10.mkdirSync(tempTestDirectory, { recursive: true });
1988
2022
  const cleanUp = () => {
1989
2023
  fs10.rmSync(tempTestDirectory, { recursive: true, force: true });
@@ -1995,7 +2029,7 @@ var _test = async (blockNames, options) => {
1995
2029
  }
1996
2030
  if (testingBlocks.length === 0) {
1997
2031
  cleanUp();
1998
- program4.error(color9.red("There were no blocks found in your project!"));
2032
+ program4.error(color10.red("There were no blocks found in your project!"));
1999
2033
  }
2000
2034
  const testingBlocksMapped = [];
2001
2035
  for (const blockSpecifier of testingBlocks) {
@@ -2021,7 +2055,7 @@ var _test = async (blockNames, options) => {
2021
2055
  }
2022
2056
  const providerInfo = (await getProviderInfo(repo)).match(
2023
2057
  (val) => val,
2024
- (err) => program4.error(color9.red(err))
2058
+ (err) => program4.error(color10.red(err))
2025
2059
  );
2026
2060
  const manifestUrl = await providerInfo.provider.resolveRaw(
2027
2061
  providerInfo,
@@ -2029,7 +2063,7 @@ var _test = async (blockNames, options) => {
2029
2063
  );
2030
2064
  const categories = (await getManifest(manifestUrl)).match(
2031
2065
  (val) => val,
2032
- (err) => program4.error(color9.red(err))
2066
+ (err) => program4.error(color10.red(err))
2033
2067
  );
2034
2068
  for (const category of categories) {
2035
2069
  for (const block2 of category.blocks) {
@@ -2047,7 +2081,7 @@ var _test = async (blockNames, options) => {
2047
2081
  }
2048
2082
  if (!block) {
2049
2083
  program4.error(
2050
- color9.red(`Invalid block! ${color9.bold(blockSpecifier)} does not exist!`)
2084
+ color10.red(`Invalid block! ${color10.bold(blockSpecifier)} does not exist!`)
2051
2085
  );
2052
2086
  }
2053
2087
  testingBlocksMapped.push({ name: blockSpecifier, block });
@@ -2055,18 +2089,18 @@ var _test = async (blockNames, options) => {
2055
2089
  for (const { name: specifier, block } of testingBlocksMapped) {
2056
2090
  const providerInfo = block.sourceRepo;
2057
2091
  if (!options.verbose) {
2058
- loading.start(`Setting up test file for ${color9.cyan(specifier)}`);
2092
+ loading.start(`Setting up test file for ${color10.cyan(specifier)}`);
2059
2093
  }
2060
2094
  if (!block.tests) {
2061
- loading.stop(`No tests found for ${color9.cyan(specifier)}`);
2095
+ loading.stop(`No tests found for ${color10.cyan(specifier)}`);
2062
2096
  continue;
2063
2097
  }
2064
2098
  const getSourceFile = async (filePath) => {
2065
2099
  const rawUrl = await providerInfo.provider.resolveRaw(providerInfo, filePath);
2066
2100
  const response = await fetch(rawUrl);
2067
2101
  if (!response.ok) {
2068
- loading.stop(color9.red(`Error fetching ${color9.bold(rawUrl.href)}`));
2069
- program4.error(color9.red(`There was an error trying to get ${specifier}`));
2102
+ loading.stop(color10.red(`Error fetching ${color10.bold(rawUrl.href)}`));
2103
+ program4.error(color10.red(`There was an error trying to get ${specifier}`));
2070
2104
  }
2071
2105
  return await response.text();
2072
2106
  };
@@ -2081,7 +2115,7 @@ var _test = async (blockNames, options) => {
2081
2115
  const directory = path8.join(config.path, block.category);
2082
2116
  let blockFilePath = path8.join(directory, `${block.name}`);
2083
2117
  blockFilePath = blockFilePath.replaceAll("\\", "/");
2084
- verbose(`${color9.bold(specifier)} file path is ${color9.bold(blockFilePath)}`);
2118
+ verbose(`${color10.bold(specifier)} file path is ${color10.bold(blockFilePath)}`);
2085
2119
  const project = new Project2();
2086
2120
  for (const file of testFiles) {
2087
2121
  verbose(`Opening test file ${file}`);
@@ -2113,19 +2147,19 @@ var _test = async (blockNames, options) => {
2113
2147
  }
2114
2148
  }
2115
2149
  project.saveSync();
2116
- verbose(`Completed ${color9.cyan.bold(specifier)} test file`);
2150
+ verbose(`Completed ${color10.cyan.bold(specifier)} test file`);
2117
2151
  if (!options.verbose) {
2118
- loading.stop(`Completed setup for ${color9.bold(specifier)}`);
2152
+ loading.stop(`Completed setup for ${color10.bold(specifier)}`);
2119
2153
  }
2120
2154
  }
2121
2155
  verbose("Beginning testing");
2122
2156
  const pm = await detect2({ cwd: process.cwd() });
2123
2157
  if (pm == null) {
2124
- program4.error(color9.red("Could not detect package manager"));
2158
+ program4.error(color10.red("Could not detect package manager"));
2125
2159
  }
2126
2160
  const resolved = resolveCommand2(pm.agent, "execute", ["vitest", "run", tempTestDirectory]);
2127
2161
  if (resolved == null) {
2128
- program4.error(color9.red(`Could not resolve add command for '${pm.agent}'.`));
2162
+ program4.error(color10.red(`Could not resolve add command for '${pm.agent}'.`));
2129
2163
  }
2130
2164
  const { command, args } = resolved;
2131
2165
  const testCommand = `${command} ${args.join(" ")}`;
@@ -2139,11 +2173,11 @@ var _test = async (blockNames, options) => {
2139
2173
  try {
2140
2174
  await testingProcess;
2141
2175
  cleanUp();
2142
- outro5(color9.green("All done!"));
2176
+ outro5(color10.green("All done!"));
2143
2177
  } catch (err) {
2144
2178
  if (options.debug) {
2145
2179
  console.info(
2146
- `${color9.bold("--debug")} flag provided. Skipping cleanup. Run '${color9.bold(
2180
+ `${color10.bold("--debug")} flag provided. Skipping cleanup. Run '${color10.bold(
2147
2181
  testCommand
2148
2182
  )}' to retry tests.
2149
2183
  `
@@ -2151,7 +2185,7 @@ var _test = async (blockNames, options) => {
2151
2185
  } else {
2152
2186
  cleanUp();
2153
2187
  }
2154
- program4.error(color9.red(`Tests failed! Error ${err}`));
2188
+ program4.error(color10.red(`Tests failed! Error ${err}`));
2155
2189
  }
2156
2190
  };
2157
2191
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "jsrepo",
3
3
  "description": "A CLI to add shared code from remote repositories.",
4
- "version": "1.0.1",
4
+ "version": "1.0.3",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/ieedan/jsrepo"
@@ -168,7 +168,7 @@ const _add = async (blockNames: string[], options: Options) => {
168
168
 
169
169
  if (options.verbose) console.log('Blocks map: ', blocksMap);
170
170
 
171
- const installingBlocks = await getBlocks(installingBlockNames, blocksMap, repoPaths);
171
+ const installingBlocks = await getBlocks(installingBlockNames, blocksMap, repoPaths, options);
172
172
 
173
173
  const pm = (await detect({ cwd: process.cwd() }))?.agent ?? 'npm';
174
174
 
@@ -392,7 +392,8 @@ type InstallingBlock = {
392
392
  const getBlocks = async (
393
393
  blockSpecifiers: string[],
394
394
  blocksMap: Map<string, RemoteBlock>,
395
- repoPaths: string[]
395
+ repoPaths: string[],
396
+ options: Options
396
397
  ): Promise<InstallingBlock[]> => {
397
398
  const blocks = new Map<string, InstallingBlock>();
398
399
 
@@ -426,42 +427,49 @@ const getBlocks = async (
426
427
  break;
427
428
  }
428
429
  } else {
429
- if (repoPaths.length === 0) {
430
- const [providerName, owner, repoName, ...rest] = blockSpecifier.split('/');
430
+ const [providerName, owner, repoName, ...rest] = blockSpecifier.split('/');
431
+
432
+ let repo: string;
433
+ // if rest is greater than 2 it isn't the block specifier so it is part of the path
434
+ if (rest.length > 2) {
435
+ repo = `${providerName}/${owner}/${repoName}/${rest.join('/')}`;
436
+ } else {
437
+ repo = `${providerName}/${owner}/${repoName}`;
438
+ }
431
439
 
432
- let repo: string;
433
- // if rest is greater than 2 it isn't the block specifier so it is part of the path
434
- if (rest.length > 2) {
435
- repo = `${providerName}/${owner}/${repoName}/${rest.join('/')}`;
436
- } else {
437
- repo = `${providerName}/${owner}/${repoName}`;
438
- }
440
+ const providerInfo = (await gitProviders.getProviderInfo(repo)).match(
441
+ (val) => val,
442
+ (err) => program.error(color.red(err))
443
+ );
439
444
 
440
- const providerInfo = (await gitProviders.getProviderInfo(repo)).match(
441
- (val) => val,
442
- (err) => program.error(color.red(err))
443
- );
445
+ const manifestUrl = await providerInfo.provider.resolveRaw(providerInfo, OUTPUT_FILE);
444
446
 
445
- const manifestUrl = await providerInfo.provider.resolveRaw(
446
- providerInfo,
447
- OUTPUT_FILE
448
- );
447
+ if (!options.allow) {
448
+ const result = await confirm({
449
+ message: `Allow ${color.cyan('jsrepo')} to download and run code from ${color.cyan(repo)}?`,
450
+ initialValue: true,
451
+ });
449
452
 
450
- const categories = (await gitProviders.getManifest(manifestUrl)).match(
451
- (val) => val,
452
- (err) => program.error(color.red(err))
453
- );
453
+ if (isCancel(result) || !result) {
454
+ cancel('Canceled!');
455
+ process.exit(0);
456
+ }
457
+ }
454
458
 
455
- for (const category of categories) {
456
- for (const block of category.blocks) {
457
- blocksMap.set(
458
- `${providerInfo.name}/${providerInfo.owner}/${providerInfo.repoName}/${category.name}/${block.name}`,
459
- {
460
- ...block,
461
- sourceRepo: providerInfo,
462
- }
463
- );
464
- }
459
+ const categories = (await gitProviders.getManifest(manifestUrl)).match(
460
+ (val) => val,
461
+ (err) => program.error(color.red(err))
462
+ );
463
+
464
+ for (const category of categories) {
465
+ for (const block of category.blocks) {
466
+ blocksMap.set(
467
+ `${providerInfo.name}/${providerInfo.owner}/${providerInfo.repoName}/${category.name}/${block.name}`,
468
+ {
469
+ ...block,
470
+ sourceRepo: providerInfo,
471
+ }
472
+ );
465
473
  }
466
474
  }
467
475
 
@@ -480,7 +488,8 @@ const getBlocks = async (
480
488
  const subDeps = await getBlocks(
481
489
  block.localDependencies.filter((dep) => blocks.has(dep)),
482
490
  blocksMap,
483
- repoPaths
491
+ repoPaths,
492
+ options
484
493
  );
485
494
 
486
495
  for (const dep of subDeps) {
@@ -1,12 +1,15 @@
1
1
  import fs from 'node:fs';
2
2
  import { builtinModules } from 'node:module';
3
3
  import path from 'node:path';
4
+ import color from 'chalk';
4
5
  import { walk } from 'estree-walker';
5
6
  import * as sv from 'svelte/compiler';
6
7
  import { Project } from 'ts-morph';
7
8
  import validatePackageName from 'validate-npm-package-name';
8
- import { Err, Ok, type Result } from '../blocks/types/result';
9
+ import { WARN } from '.';
10
+ import { Ok, type Result } from '../blocks/types/result';
9
11
  import { findNearestPackageJson } from './package';
12
+ import { parsePackageName } from './parse-package-name';
10
13
 
11
14
  export type ResolvedDependencies = {
12
15
  local: string[];
@@ -147,10 +150,7 @@ const resolveLocalImport = (
147
150
  */
148
151
  const resolveRemoteDeps = (deps: string[], filePath: string) => {
149
152
  const filteredDeps = deps.filter(
150
- (dep) =>
151
- !builtinModules.includes(dep) &&
152
- !dep.startsWith('node:') &&
153
- validatePackageName(dep).validForNewPackages
153
+ (dep) => !builtinModules.includes(dep) && !dep.startsWith('node:')
154
154
  );
155
155
 
156
156
  const pkgPath = findNearestPackageJson(path.dirname(filePath), '');
@@ -163,27 +163,45 @@ const resolveRemoteDeps = (deps: string[], filePath: string) => {
163
163
  JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
164
164
 
165
165
  for (const dep of filteredDeps) {
166
+ const parsed = parsePackageName(dep);
167
+
168
+ if (parsed.isErr()) {
169
+ console.warn(
170
+ `${WARN} Skipped adding import \`${color.cyan(dep)}\`. Reason: Couldn't parse package name`
171
+ );
172
+ continue;
173
+ }
174
+
175
+ const depInfo = parsed.unwrap();
176
+
177
+ if (!validatePackageName(depInfo.name).validForNewPackages) {
178
+ console.warn(
179
+ `${WARN} Skipped adding import \`${color.cyan(dep)}\`. Reason: Not a valid package name`
180
+ );
181
+ continue;
182
+ }
183
+
166
184
  let version: string | undefined = undefined;
167
185
  if (packageDependencies !== undefined) {
168
- version = packageDependencies[dep];
186
+ version = packageDependencies[depInfo.name];
169
187
  }
170
188
 
171
189
  if (version !== undefined) {
172
- dependencies.add(`${dep}@${version}`);
190
+ dependencies.add(`${depInfo.name}@${version}`);
173
191
  continue;
174
192
  }
175
193
 
176
194
  if (packageDevDependencies !== undefined) {
177
- version = packageDevDependencies[dep];
195
+ version = packageDevDependencies[depInfo.name];
178
196
  }
179
197
 
180
198
  if (version !== undefined) {
181
- devDependencies.add(`${dep}@${version}`);
199
+ devDependencies.add(`${depInfo.name}@${version}`);
182
200
  continue;
183
201
  }
184
202
 
185
203
  // if no version found just add it without a version
186
- dependencies.add(dep);
204
+ dependencies.add(depInfo.name);
187
205
  }
188
206
  }
189
207
 
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Adapted from https://github.com/egoist/parse-package-name/blob/main/src/index.ts
3
+ * @module
4
+ */
5
+
6
+ import { Err, Ok } from '../blocks/types/result';
7
+
8
+ // Parsed a scoped package name into name, version, and path.
9
+ const RE_SCOPED = /^(@[^\/]+\/[^@\/]+)(?:@([^\/]+))?(\/.*)?$/;
10
+ // Parsed a non-scoped package name into name, version, path
11
+ const RE_NON_SCOPED = /^([^@\/]+)(?:@([^\/]+))?(\/.*)?$/;
12
+
13
+ const parsePackageName = (input: string) => {
14
+ const m = RE_SCOPED.exec(input) || RE_NON_SCOPED.exec(input);
15
+
16
+ if (!m) return Err(`invalid package name: ${input}`);
17
+
18
+ return Ok({
19
+ name: m[1] || '',
20
+ version: m[2] || 'latest',
21
+ path: m[3] || '',
22
+ });
23
+ };
24
+
25
+ export { parsePackageName };