jsrepo 1.4.1 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // src/index.ts
2
2
  import fs12 from "node:fs";
3
3
  import { fileURLToPath } from "node:url";
4
- import { program as program6 } from "commander";
4
+ import { program as program7 } from "commander";
5
5
  import path12 from "pathe";
6
6
 
7
7
  // src/commands/add.ts
@@ -25,6 +25,7 @@ var TOP_LEFT_CORNER = color.gray("\u250C");
25
25
  var BOTTOM_LEFT_CORNER = color.gray("\u2514");
26
26
  var WARN = color.bgRgb(245, 149, 66).white("WARN");
27
27
  var INFO = color.bgBlueBright.white("INFO");
28
+ var JSREPO = color.hex("#f7df1e")("jsrepo");
28
29
 
29
30
  // src/utils/blocks.ts
30
31
  import fs4 from "node:fs";
@@ -981,11 +982,17 @@ var buildBlocksDirectory = (blocksPath, { cwd, excludeDeps }) => {
981
982
  const devDepsSet = /* @__PURE__ */ new Set();
982
983
  for (const f of blockFiles) {
983
984
  if (isTestFile(f)) continue;
985
+ if (fs3.statSync(path3.join(blockDir, f)).isDirectory()) {
986
+ console.warn(
987
+ `${VERTICAL_LINE} ${WARN} Skipped \`${color3.bold(path3.join(blockDir, f))}\` subdirectories are not currently supported!`
988
+ );
989
+ continue;
990
+ }
984
991
  const lang = languages.find((resolver) => resolver.matches(f));
985
992
  if (!lang) {
986
993
  console.warn(
987
- `${WARN} Skipped \`${color3.bold(path3.join(blockDir, f))}\` \`${color3.bold(
988
- path3.parse(file).ext
994
+ `${VERTICAL_LINE} ${WARN} Skipped \`${color3.bold(path3.join(blockDir, f))}\` \`*${color3.bold(
995
+ path3.parse(f).ext
989
996
  )}\` files are not currently supported!`
990
997
  );
991
998
  continue;
@@ -1455,7 +1462,7 @@ var _add = async (blockNames, options) => {
1455
1462
  (val) => val,
1456
1463
  program2.error
1457
1464
  );
1458
- const pm = (await detect({ cwd: process.cwd() }))?.agent ?? "npm";
1465
+ const pm = (await detect({ cwd: options.cwd }))?.agent ?? "npm";
1459
1466
  const tasks = [];
1460
1467
  const devDeps = /* @__PURE__ */ new Set();
1461
1468
  const deps = /* @__PURE__ */ new Set();
@@ -2001,9 +2008,10 @@ ${prefix?.() ?? ""}
2001
2008
 
2002
2009
  // src/commands/init.ts
2003
2010
  import fs9 from "node:fs";
2004
- import { cancel as cancel3, confirm as confirm3, isCancel as isCancel3, outro as outro4, spinner as spinner5, text } from "@clack/prompts";
2011
+ import { cancel as cancel3, confirm as confirm3, isCancel as isCancel3, outro as outro4, select, spinner as spinner5, text } from "@clack/prompts";
2005
2012
  import color11 from "chalk";
2006
- import { Command as Command4 } from "commander";
2013
+ import { Command as Command4, program as program4 } from "commander";
2014
+ import { detect as detect2, resolveCommand as resolveCommand3 } from "package-manager-detector";
2007
2015
  import path9 from "pathe";
2008
2016
  import * as v8 from "valibot";
2009
2017
  var schema5 = v8.object({
@@ -2011,18 +2019,48 @@ var schema5 = v8.object({
2011
2019
  repos: v8.optional(v8.array(v8.string())),
2012
2020
  watermark: v8.boolean(),
2013
2021
  tests: v8.optional(v8.boolean()),
2022
+ project: v8.optional(v8.boolean()),
2023
+ registry: v8.optional(v8.boolean()),
2024
+ script: v8.string(),
2025
+ yes: v8.boolean(),
2014
2026
  cwd: v8.string()
2015
2027
  });
2016
- 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(
2028
+ var init = new Command4("init").description("Initializes your project with a configuration file.").option("--path <path>", "Path to install the blocks / Path to build the blocks from.").option("--repos [repos...]", "Repository to install the blocks from.").option(
2017
2029
  "--no-watermark",
2018
2030
  "Will not add a watermark to each file upon adding it to your project."
2019
- ).option("--tests", "Will include tests with the blocks.").option("--cwd <path>", "The current working directory.", process.cwd()).action(async (opts) => {
2031
+ ).option("--tests", "Will include tests with the blocks.").option("-P, --project", "Takes you through the steps to initialize a project.").option("-R, --registry", "Takes you through the steps to initialize a registry.").option("--script <name>", "The name of the build script. (For Registry setup)", "build").option("-y, --yes", "Skip confirmation prompt.", false).option("--cwd <path>", "The current working directory.", process.cwd()).action(async (opts) => {
2020
2032
  const options = v8.parse(schema5, opts);
2021
2033
  _intro(context.package.version);
2022
- await _init(options);
2034
+ if (options.registry !== void 0 && options.project !== void 0) {
2035
+ program4.error(
2036
+ color11.red(
2037
+ `You cannot provide both ${color11.bold("--project")} and ${color11.bold("--registry")} at the same time.`
2038
+ )
2039
+ );
2040
+ }
2041
+ if (options.registry === void 0 && options.project === void 0) {
2042
+ const response = await select({
2043
+ message: "Initialize a project or registry?",
2044
+ options: [
2045
+ { value: "project", label: "project" },
2046
+ { value: "registry", label: "registry" }
2047
+ ],
2048
+ initialValue: "project"
2049
+ });
2050
+ if (isCancel3(response)) {
2051
+ cancel3("Canceled!");
2052
+ process.exit(0);
2053
+ }
2054
+ options.registry = response === "registry";
2055
+ }
2056
+ if (options.registry) {
2057
+ await _initRegistry(options);
2058
+ } else {
2059
+ await _initProject(options);
2060
+ }
2023
2061
  outro4(color11.green("All done!"));
2024
2062
  });
2025
- var _init = async (options) => {
2063
+ var _initProject = async (options) => {
2026
2064
  const initialConfig = getConfig(options.cwd);
2027
2065
  const loading = spinner5();
2028
2066
  if (!options.path) {
@@ -2084,15 +2122,146 @@ var _init = async (options) => {
2084
2122
  fs9.mkdirSync(path9.join(options.cwd, config.path), { recursive: true });
2085
2123
  loading.stop(`Wrote config to \`${CONFIG_NAME}\`.`);
2086
2124
  };
2125
+ var _initRegistry = async (options) => {
2126
+ const loading = spinner5();
2127
+ if (!options.path) {
2128
+ const response = await text({
2129
+ message: "Where are your blocks located?",
2130
+ defaultValue: "./blocks",
2131
+ initialValue: "./blocks",
2132
+ placeholder: "./blocks"
2133
+ });
2134
+ if (isCancel3(response)) {
2135
+ cancel3("Canceled!");
2136
+ process.exit(0);
2137
+ }
2138
+ options.path = response;
2139
+ }
2140
+ const packagePath = path9.join(options.cwd, "package.json");
2141
+ if (!fs9.existsSync(packagePath)) {
2142
+ program4.error(color11.red(`Couldn't find your ${color11.bold("package.json")}!`));
2143
+ }
2144
+ const pkg = JSON.parse(fs9.readFileSync(packagePath).toString());
2145
+ const scriptAlreadyExists = pkg.scripts !== void 0 && pkg.scripts[options.script] !== void 0;
2146
+ if (!options.yes && scriptAlreadyExists) {
2147
+ const response = await confirm3({
2148
+ message: `The \`${color11.cyan(options.script)}\` already exists overwrite?`,
2149
+ initialValue: false
2150
+ });
2151
+ if (isCancel3(response)) {
2152
+ cancel3("Canceled!");
2153
+ process.exit(0);
2154
+ }
2155
+ if (!response) {
2156
+ const response2 = await text({
2157
+ message: "What would you like to call the script?",
2158
+ defaultValue: "build:registry",
2159
+ placeholder: "build:registry",
2160
+ initialValue: "build:registry",
2161
+ validate: (val) => {
2162
+ if (val.trim().length === 0) return "Please provide a value!";
2163
+ }
2164
+ });
2165
+ if (isCancel3(response2)) {
2166
+ cancel3("Canceled!");
2167
+ process.exit(0);
2168
+ }
2169
+ options.script = response2;
2170
+ }
2171
+ }
2172
+ const alreadyInstalled = pkg.devDependencies && pkg.devDependencies.jsrepo !== void 0;
2173
+ let installAsDevDependency = options.yes || alreadyInstalled;
2174
+ if (!options.yes && !alreadyInstalled) {
2175
+ const response = await confirm3({
2176
+ message: `Add ${JSREPO} as a dev dependency?`,
2177
+ initialValue: true
2178
+ });
2179
+ if (isCancel3(response)) {
2180
+ cancel3("Canceled!");
2181
+ process.exit(0);
2182
+ }
2183
+ installAsDevDependency = response;
2184
+ }
2185
+ const pm = (await detect2({ cwd: "cwd" }))?.agent ?? "npm";
2186
+ let buildScript = "";
2187
+ if (installAsDevDependency) {
2188
+ buildScript += "jsrepo build ";
2189
+ } else {
2190
+ const command = resolveCommand3(pm, "execute", ["jsrepo", "build"]);
2191
+ if (!command) program4.error(color11.red(`Error resolving execute command for ${pm}`));
2192
+ buildScript += `${command.command} ${command.args.join(" ")} `;
2193
+ }
2194
+ if (options.path !== "./build") {
2195
+ buildScript += `--dirs ${options.path}`;
2196
+ }
2197
+ if (pkg.scripts === void 0) {
2198
+ pkg.scripts = {};
2199
+ }
2200
+ pkg.scripts[options.script] = buildScript;
2201
+ loading.start(`Adding \`${color11.cyan(options.script)}\` to scripts in package.json`);
2202
+ try {
2203
+ fs9.writeFileSync(packagePath, JSON.stringify(pkg, null, " "));
2204
+ } catch (err) {
2205
+ program4.error(color11.red(`Error writing to \`${color11.bold(packagePath)}\`. Error: ${err}`));
2206
+ }
2207
+ loading.stop(`Added \`${color11.cyan(options.script)}\` to scripts in package.json`);
2208
+ let installed = alreadyInstalled;
2209
+ if (installAsDevDependency && !alreadyInstalled) {
2210
+ let shouldInstall = options.yes;
2211
+ if (!options.yes) {
2212
+ const response = await confirm3({
2213
+ message: "Install dependencies?",
2214
+ initialValue: true
2215
+ });
2216
+ if (isCancel3(response)) {
2217
+ cancel3("Canceled!");
2218
+ process.exit(0);
2219
+ }
2220
+ shouldInstall = response;
2221
+ }
2222
+ if (shouldInstall) {
2223
+ loading.start(`Installing ${JSREPO}`);
2224
+ const installedResult = await installDependencies({
2225
+ pm,
2226
+ deps: ["jsrepo"],
2227
+ dev: true,
2228
+ cwd: options.cwd
2229
+ });
2230
+ installedResult.match(
2231
+ () => loading.stop(`Installed ${JSREPO}.`),
2232
+ (err) => {
2233
+ loading.stop(`Failed to install ${JSREPO}.`);
2234
+ program4.error(err);
2235
+ }
2236
+ );
2237
+ installed = true;
2238
+ }
2239
+ }
2240
+ let steps = [];
2241
+ if (!installed && installAsDevDependency) {
2242
+ const cmd = resolveCommand3(pm, "install", ["jsrepo", "-D"]);
2243
+ steps.push(
2244
+ `Install ${JSREPO} as a dev dependency \`${color11.cyan(`${cmd?.command} ${cmd?.args.join(" ")}`)}\``
2245
+ );
2246
+ }
2247
+ steps.push(`Add blocks to \`${color11.cyan(options.path)}\`.`);
2248
+ const runScript = resolveCommand3(pm, "run", [options.script]);
2249
+ steps.push(
2250
+ `Run \`${color11.cyan(`${runScript?.command} ${runScript?.args.join(" ")}`)}\` to build the registry.`
2251
+ );
2252
+ steps = steps.map((step, i) => `${i + 1}. ${step}`);
2253
+ const next = nextSteps(steps);
2254
+ process.stdout.write(next);
2255
+ };
2087
2256
 
2088
2257
  // src/commands/test.ts
2089
2258
  import fs10 from "node:fs";
2090
2259
  import { cancel as cancel4, confirm as confirm4, isCancel as isCancel4, outro as outro5, spinner as spinner6 } from "@clack/prompts";
2091
2260
  import color12 from "chalk";
2092
- import { Argument, Command as Command5, program as program4 } from "commander";
2261
+ import { Argument, Command as Command5, program as program5 } from "commander";
2093
2262
  import { execa as execa2 } from "execa";
2094
- import { resolveCommand as resolveCommand3 } from "package-manager-detector/commands";
2095
- import { detect as detect2 } from "package-manager-detector/detect";
2263
+ import { resolveCommand as resolveCommand4 } from "package-manager-detector/commands";
2264
+ import { detect as detect3 } from "package-manager-detector/detect";
2096
2265
  import path10 from "pathe";
2097
2266
  import { Project as Project2 } from "ts-morph";
2098
2267
  import * as v9 from "valibot";
@@ -2118,7 +2287,7 @@ var _test = async (blockNames, options) => {
2118
2287
  verbose(`Attempting to test ${JSON.stringify(blockNames)}`);
2119
2288
  const config = getConfig(options.cwd).match(
2120
2289
  (val) => val,
2121
- (err) => program4.error(color12.red(err))
2290
+ (err) => program5.error(color12.red(err))
2122
2291
  );
2123
2292
  const loading = spinner6();
2124
2293
  const blocksMap = /* @__PURE__ */ new Map();
@@ -2139,14 +2308,14 @@ var _test = async (blockNames, options) => {
2139
2308
  for (const repo of repoPaths) {
2140
2309
  const providerInfo = (await getProviderInfo(repo)).match(
2141
2310
  (info) => info,
2142
- (err) => program4.error(color12.red(err))
2311
+ (err) => program5.error(color12.red(err))
2143
2312
  );
2144
2313
  const manifestUrl = await providerInfo.provider.resolveRaw(providerInfo, OUTPUT_FILE);
2145
2314
  verbose(`Got info for provider ${color12.cyan(providerInfo.name)}`);
2146
2315
  const response = await fetch(manifestUrl);
2147
2316
  if (!response.ok) {
2148
2317
  if (!options.verbose) loading.stop(`Error fetching ${color12.cyan(manifestUrl.href)}`);
2149
- program4.error(
2318
+ program5.error(
2150
2319
  color12.red(
2151
2320
  `There was an error fetching the \`${OUTPUT_FILE}\` from the repository ${color12.cyan(
2152
2321
  repo
@@ -2186,7 +2355,7 @@ var _test = async (blockNames, options) => {
2186
2355
  }
2187
2356
  if (testingBlocks.length === 0) {
2188
2357
  cleanUp();
2189
- program4.error(color12.red("There were no blocks found in your project!"));
2358
+ program5.error(color12.red("There were no blocks found in your project!"));
2190
2359
  }
2191
2360
  const testingBlocksMapped = [];
2192
2361
  for (const blockSpecifier of testingBlocks) {
@@ -2212,7 +2381,7 @@ var _test = async (blockNames, options) => {
2212
2381
  }
2213
2382
  const providerInfo = (await getProviderInfo(repo)).match(
2214
2383
  (val) => val,
2215
- (err) => program4.error(color12.red(err))
2384
+ (err) => program5.error(color12.red(err))
2216
2385
  );
2217
2386
  const manifestUrl = await providerInfo.provider.resolveRaw(
2218
2387
  providerInfo,
@@ -2220,7 +2389,7 @@ var _test = async (blockNames, options) => {
2220
2389
  );
2221
2390
  const categories = (await getManifest(manifestUrl)).match(
2222
2391
  (val) => val,
2223
- (err) => program4.error(color12.red(err))
2392
+ (err) => program5.error(color12.red(err))
2224
2393
  );
2225
2394
  for (const category of categories) {
2226
2395
  for (const block2 of category.blocks) {
@@ -2237,7 +2406,7 @@ var _test = async (blockNames, options) => {
2237
2406
  block = blocksMap.get(blockSpecifier);
2238
2407
  }
2239
2408
  if (!block) {
2240
- program4.error(
2409
+ program5.error(
2241
2410
  color12.red(`Invalid block! ${color12.bold(blockSpecifier)} does not exist!`)
2242
2411
  );
2243
2412
  }
@@ -2257,7 +2426,7 @@ var _test = async (blockNames, options) => {
2257
2426
  const response = await fetch(rawUrl);
2258
2427
  if (!response.ok) {
2259
2428
  loading.stop(color12.red(`Error fetching ${color12.bold(rawUrl.href)}`));
2260
- program4.error(color12.red(`There was an error trying to get ${specifier}`));
2429
+ program5.error(color12.red(`There was an error trying to get ${specifier}`));
2261
2430
  }
2262
2431
  return await response.text();
2263
2432
  };
@@ -2306,13 +2475,13 @@ var _test = async (blockNames, options) => {
2306
2475
  }
2307
2476
  }
2308
2477
  verbose("Beginning testing");
2309
- const pm = await detect2({ cwd: options.cwd });
2478
+ const pm = await detect3({ cwd: options.cwd });
2310
2479
  if (pm == null) {
2311
- program4.error(color12.red("Could not detect package manager"));
2480
+ program5.error(color12.red("Could not detect package manager"));
2312
2481
  }
2313
- const resolved = resolveCommand3(pm.agent, "execute", ["vitest", "run", tempTestDirectory]);
2482
+ const resolved = resolveCommand4(pm.agent, "execute", ["vitest", "run", tempTestDirectory]);
2314
2483
  if (resolved == null) {
2315
- program4.error(color12.red(`Could not resolve add command for '${pm.agent}'.`));
2484
+ program5.error(color12.red(`Could not resolve add command for '${pm.agent}'.`));
2316
2485
  }
2317
2486
  const { command, args } = resolved;
2318
2487
  const testCommand = `${command} ${args.join(" ")}`;
@@ -2337,7 +2506,7 @@ var _test = async (blockNames, options) => {
2337
2506
  } else {
2338
2507
  cleanUp();
2339
2508
  }
2340
- program4.error(color12.red(`Tests failed! Error ${err}`));
2509
+ program5.error(color12.red(`Tests failed! Error ${err}`));
2341
2510
  }
2342
2511
  };
2343
2512
 
@@ -2345,10 +2514,10 @@ var _test = async (blockNames, options) => {
2345
2514
  import fs11 from "node:fs";
2346
2515
  import { cancel as cancel5, confirm as confirm5, isCancel as isCancel5, multiselect as multiselect2, outro as outro6, spinner as spinner7 } from "@clack/prompts";
2347
2516
  import color13 from "chalk";
2348
- import { Command as Command6, program as program5 } from "commander";
2517
+ import { Command as Command6, program as program6 } from "commander";
2349
2518
  import { diffLines as diffLines2 } from "diff";
2350
- import { resolveCommand as resolveCommand4 } from "package-manager-detector/commands";
2351
- import { detect as detect3 } from "package-manager-detector/detect";
2519
+ import { resolveCommand as resolveCommand5 } from "package-manager-detector/commands";
2520
+ import { detect as detect4 } from "package-manager-detector/detect";
2352
2521
  import path11 from "pathe";
2353
2522
  import * as v10 from "valibot";
2354
2523
  var schema7 = v10.object({
@@ -2383,13 +2552,13 @@ var _update = async (blockNames, options) => {
2383
2552
  const loading = spinner7();
2384
2553
  const config = getConfig(options.cwd).match(
2385
2554
  (val) => val,
2386
- (err) => program5.error(color13.red(err))
2555
+ (err) => program6.error(color13.red(err))
2387
2556
  );
2388
2557
  let repoPaths = config.repos;
2389
2558
  if (options.repo) repoPaths = [options.repo];
2390
2559
  for (const blockSpecifier of blockNames) {
2391
2560
  if (blockSpecifier.startsWith("github")) {
2392
- program5.error(
2561
+ program6.error(
2393
2562
  color13.red(
2394
2563
  `Invalid value provided for block names \`${color13.bold(blockSpecifier)}\`. Block names are expected to be provided in the format of \`${color13.bold("<category>/<name>")}\``
2395
2564
  )
@@ -2412,7 +2581,7 @@ var _update = async (blockNames, options) => {
2412
2581
  (val) => val,
2413
2582
  ({ repo, message }) => {
2414
2583
  loading.stop(`Failed fetching blocks from ${color13.cyan(repo)}`);
2415
- program5.error(color13.red(message));
2584
+ program6.error(color13.red(message));
2416
2585
  }
2417
2586
  );
2418
2587
  if (!options.verbose) loading.stop(`Retrieved blocks from ${color13.cyan(repoPaths.join(", "))}`);
@@ -2442,9 +2611,9 @@ var _update = async (blockNames, options) => {
2442
2611
  verbose(`Preparing to update ${color13.cyan(updatingBlockNames.join(", "))}`);
2443
2612
  const updatingBlocks = (await resolveTree(updatingBlockNames, blocksMap, repoPaths)).match(
2444
2613
  (val) => val,
2445
- program5.error
2614
+ program6.error
2446
2615
  );
2447
- const pm = (await detect3({ cwd: process.cwd() }))?.agent ?? "npm";
2616
+ const pm = (await detect4({ cwd: options.cwd }))?.agent ?? "npm";
2448
2617
  const tasks = [];
2449
2618
  const devDeps = /* @__PURE__ */ new Set();
2450
2619
  const deps = /* @__PURE__ */ new Set();
@@ -2460,7 +2629,7 @@ var _update = async (blockNames, options) => {
2460
2629
  const response = await fetch(rawUrl);
2461
2630
  if (!response.ok) {
2462
2631
  loading.stop(color13.red(`Error fetching ${color13.bold(rawUrl.href)}`));
2463
- program5.error(color13.red(`There was an error trying to get ${fullSpecifier}`));
2632
+ program6.error(color13.red(`There was an error trying to get ${fullSpecifier}`));
2464
2633
  }
2465
2634
  return await response.text();
2466
2635
  };
@@ -2603,7 +2772,7 @@ ${prefix?.() ?? ""}
2603
2772
  },
2604
2773
  (err) => {
2605
2774
  if (!options.verbose) loading.stop("Failed to install dependencies");
2606
- program5.error(err);
2775
+ program6.error(err);
2607
2776
  }
2608
2777
  );
2609
2778
  }
@@ -2622,7 +2791,7 @@ ${prefix?.() ?? ""}
2622
2791
  },
2623
2792
  (err) => {
2624
2793
  if (!options.verbose) loading.stop("Failed to install dev dependencies");
2625
- program5.error(err);
2794
+ program6.error(err);
2626
2795
  }
2627
2796
  );
2628
2797
  }
@@ -2630,13 +2799,13 @@ ${prefix?.() ?? ""}
2630
2799
  let steps = [];
2631
2800
  if (!install) {
2632
2801
  if (deps.size > 0) {
2633
- const cmd = resolveCommand4(pm, "install", [...deps]);
2802
+ const cmd = resolveCommand5(pm, "install", [...deps]);
2634
2803
  steps.push(
2635
2804
  `Install dependencies \`${color13.cyan(`${cmd?.command} ${cmd?.args.join(" ")}`)}\``
2636
2805
  );
2637
2806
  }
2638
2807
  if (devDeps.size > 0) {
2639
- const cmd = resolveCommand4(pm, "install", [...devDeps, "-D"]);
2808
+ const cmd = resolveCommand5(pm, "install", [...devDeps, "-D"]);
2640
2809
  steps.push(
2641
2810
  `Install dev dependencies \`${color13.cyan(`${cmd?.command} ${cmd?.args.join(" ")}`)}\``
2642
2811
  );
@@ -2669,8 +2838,8 @@ var context = {
2669
2838
  },
2670
2839
  resolveRelativeToRoot
2671
2840
  };
2672
- program6.name(name).description(description).version(version).addCommand(add).addCommand(init).addCommand(test).addCommand(build).addCommand(update).addCommand(diff);
2673
- program6.parse();
2841
+ program7.name(name).description(description).version(version).addCommand(add).addCommand(init).addCommand(test).addCommand(build).addCommand(update).addCommand(diff);
2842
+ program7.parse();
2674
2843
  export {
2675
2844
  context
2676
2845
  };
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.4.1",
4
+ "version": "1.5.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "git+https://github.com/ieedan/jsrepo"
@@ -34,11 +34,11 @@
34
34
  "@types/node": "^22.9.0",
35
35
  "@types/validate-npm-package-name": "^4.0.2",
36
36
  "tsup": "^8.3.5",
37
- "typescript": "^5.6.3",
37
+ "typescript": "^5.7.2",
38
38
  "vitest": "^2.1.5"
39
39
  },
40
40
  "dependencies": {
41
- "@clack/prompts": "^0.8.1",
41
+ "@clack/prompts": "^0.8.2",
42
42
  "@vue/compiler-sfc": "^3.5.13",
43
43
  "ansi-regex": "^6.1.0",
44
44
  "chalk": "^5.3.0",
@@ -49,7 +49,7 @@
49
49
  "octokit": "^4.0.2",
50
50
  "package-manager-detector": "^0.2.4",
51
51
  "pathe": "^1.1.2",
52
- "svelte": "^5.2.3",
52
+ "svelte": "^5.2.7",
53
53
  "ts-morph": "^24.0.0",
54
54
  "valibot": "^0.42.1",
55
55
  "validate-npm-package-name": "^6.0.0"
@@ -194,7 +194,7 @@ const _add = async (blockNames: string[], options: Options) => {
194
194
  program.error
195
195
  );
196
196
 
197
- const pm = (await detect({ cwd: process.cwd() }))?.agent ?? 'npm';
197
+ const pm = (await detect({ cwd: options.cwd }))?.agent ?? 'npm';
198
198
 
199
199
  const tasks: Task[] = [];
200
200
 
@@ -1,18 +1,25 @@
1
1
  import fs from 'node:fs';
2
- import { cancel, confirm, isCancel, outro, spinner, text } from '@clack/prompts';
2
+ import { cancel, confirm, isCancel, outro, select, spinner, text } from '@clack/prompts';
3
3
  import color from 'chalk';
4
- import { Command } from 'commander';
4
+ import { Command, program } from 'commander';
5
+ import { detect, resolveCommand } from 'package-manager-detector';
5
6
  import path from 'pathe';
6
7
  import * as v from 'valibot';
7
8
  import { context } from '..';
9
+ import * as ascii from '../utils/ascii';
8
10
  import { CONFIG_NAME, type Config, getConfig } from '../utils/config';
9
- import { intro } from '../utils/prompts';
11
+ import { installDependencies } from '../utils/dependencies';
12
+ import { intro, nextSteps } from '../utils/prompts';
10
13
 
11
14
  const schema = v.object({
12
15
  path: v.optional(v.string()),
13
16
  repos: v.optional(v.array(v.string())),
14
17
  watermark: v.boolean(),
15
18
  tests: v.optional(v.boolean()),
19
+ project: v.optional(v.boolean()),
20
+ registry: v.optional(v.boolean()),
21
+ script: v.string(),
22
+ yes: v.boolean(),
16
23
  cwd: v.string(),
17
24
  });
18
25
 
@@ -20,25 +27,59 @@ type Options = v.InferInput<typeof schema>;
20
27
 
21
28
  const init = new Command('init')
22
29
  .description('Initializes your project with a configuration file.')
23
- .option('--path <path>', 'Path to install the blocks.')
30
+ .option('--path <path>', 'Path to install the blocks / Path to build the blocks from.')
24
31
  .option('--repos [repos...]', 'Repository to install the blocks from.')
25
32
  .option(
26
33
  '--no-watermark',
27
34
  'Will not add a watermark to each file upon adding it to your project.'
28
35
  )
29
36
  .option('--tests', 'Will include tests with the blocks.')
37
+ .option('-P, --project', 'Takes you through the steps to initialize a project.')
38
+ .option('-R, --registry', 'Takes you through the steps to initialize a registry.')
39
+ .option('--script <name>', 'The name of the build script. (For Registry setup)', 'build')
40
+ .option('-y, --yes', 'Skip confirmation prompt.', false)
30
41
  .option('--cwd <path>', 'The current working directory.', process.cwd())
31
42
  .action(async (opts) => {
32
43
  const options = v.parse(schema, opts);
33
44
 
34
45
  intro(context.package.version);
35
46
 
36
- await _init(options);
47
+ if (options.registry !== undefined && options.project !== undefined) {
48
+ program.error(
49
+ color.red(
50
+ `You cannot provide both ${color.bold('--project')} and ${color.bold('--registry')} at the same time.`
51
+ )
52
+ );
53
+ }
54
+
55
+ if (options.registry === undefined && options.project === undefined) {
56
+ const response = await select({
57
+ message: 'Initialize a project or registry?',
58
+ options: [
59
+ { value: 'project', label: 'project' },
60
+ { value: 'registry', label: 'registry' },
61
+ ],
62
+ initialValue: 'project',
63
+ });
64
+
65
+ if (isCancel(response)) {
66
+ cancel('Canceled!');
67
+ process.exit(0);
68
+ }
69
+
70
+ options.registry = response === 'registry';
71
+ }
72
+
73
+ if (options.registry) {
74
+ await _initRegistry(options);
75
+ } else {
76
+ await _initProject(options);
77
+ }
37
78
 
38
79
  outro(color.green('All done!'));
39
80
  });
40
81
 
41
- const _init = async (options: Options) => {
82
+ const _initProject = async (options: Options) => {
42
83
  const initialConfig = getConfig(options.cwd);
43
84
 
44
85
  const loading = spinner();
@@ -118,4 +159,183 @@ const _init = async (options: Options) => {
118
159
  loading.stop(`Wrote config to \`${CONFIG_NAME}\`.`);
119
160
  };
120
161
 
162
+ const _initRegistry = async (options: Options) => {
163
+ const loading = spinner();
164
+
165
+ if (!options.path) {
166
+ const response = await text({
167
+ message: 'Where are your blocks located?',
168
+ defaultValue: './blocks',
169
+ initialValue: './blocks',
170
+ placeholder: './blocks',
171
+ });
172
+
173
+ if (isCancel(response)) {
174
+ cancel('Canceled!');
175
+ process.exit(0);
176
+ }
177
+
178
+ options.path = response;
179
+ }
180
+
181
+ const packagePath = path.join(options.cwd, 'package.json');
182
+
183
+ if (!fs.existsSync(packagePath)) {
184
+ program.error(color.red(`Couldn't find your ${color.bold('package.json')}!`));
185
+ }
186
+
187
+ const pkg = JSON.parse(fs.readFileSync(packagePath).toString());
188
+
189
+ const scriptAlreadyExists =
190
+ pkg.scripts !== undefined && pkg.scripts[options.script] !== undefined;
191
+
192
+ if (!options.yes && scriptAlreadyExists) {
193
+ const response = await confirm({
194
+ message: `The \`${color.cyan(options.script)}\` already exists overwrite?`,
195
+ initialValue: false,
196
+ });
197
+
198
+ if (isCancel(response)) {
199
+ cancel('Canceled!');
200
+ process.exit(0);
201
+ }
202
+
203
+ if (!response) {
204
+ const response = await text({
205
+ message: 'What would you like to call the script?',
206
+ defaultValue: 'build:registry',
207
+ placeholder: 'build:registry',
208
+ initialValue: 'build:registry',
209
+ validate: (val) => {
210
+ if (val.trim().length === 0) return 'Please provide a value!';
211
+ },
212
+ });
213
+
214
+ if (isCancel(response)) {
215
+ cancel('Canceled!');
216
+ process.exit(0);
217
+ }
218
+
219
+ options.script = response;
220
+ }
221
+ }
222
+
223
+ const alreadyInstalled = pkg.devDependencies && pkg.devDependencies.jsrepo !== undefined;
224
+
225
+ let installAsDevDependency = options.yes || alreadyInstalled;
226
+
227
+ if (!options.yes && !alreadyInstalled) {
228
+ const response = await confirm({
229
+ message: `Add ${ascii.JSREPO} as a dev dependency?`,
230
+ initialValue: true,
231
+ });
232
+
233
+ if (isCancel(response)) {
234
+ cancel('Canceled!');
235
+ process.exit(0);
236
+ }
237
+
238
+ installAsDevDependency = response;
239
+ }
240
+
241
+ const pm = (await detect({ cwd: 'cwd' }))?.agent ?? 'npm';
242
+
243
+ let buildScript = '';
244
+
245
+ if (installAsDevDependency) {
246
+ buildScript += 'jsrepo build ';
247
+ } else {
248
+ const command = resolveCommand(pm, 'execute', ['jsrepo', 'build']);
249
+
250
+ if (!command) program.error(color.red(`Error resolving execute command for ${pm}`));
251
+
252
+ buildScript += `${command.command} ${command.args.join(' ')} `;
253
+ }
254
+
255
+ if (options.path !== './build') {
256
+ buildScript += `--dirs ${options.path}`;
257
+ }
258
+
259
+ if (pkg.scripts === undefined) {
260
+ pkg.scripts = {};
261
+ }
262
+
263
+ pkg.scripts[options.script] = buildScript;
264
+
265
+ loading.start(`Adding \`${color.cyan(options.script)}\` to scripts in package.json`);
266
+
267
+ try {
268
+ fs.writeFileSync(packagePath, JSON.stringify(pkg, null, '\t'));
269
+ } catch (err) {
270
+ program.error(color.red(`Error writing to \`${color.bold(packagePath)}\`. Error: ${err}`));
271
+ }
272
+
273
+ loading.stop(`Added \`${color.cyan(options.script)}\` to scripts in package.json`);
274
+
275
+ let installed = alreadyInstalled;
276
+
277
+ if (installAsDevDependency && !alreadyInstalled) {
278
+ let shouldInstall = options.yes;
279
+ if (!options.yes) {
280
+ const response = await confirm({
281
+ message: 'Install dependencies?',
282
+ initialValue: true,
283
+ });
284
+
285
+ if (isCancel(response)) {
286
+ cancel('Canceled!');
287
+ process.exit(0);
288
+ }
289
+
290
+ shouldInstall = response;
291
+ }
292
+
293
+ if (shouldInstall) {
294
+ loading.start(`Installing ${ascii.JSREPO}`);
295
+
296
+ const installedResult = await installDependencies({
297
+ pm,
298
+ deps: ['jsrepo'],
299
+ dev: true,
300
+ cwd: options.cwd,
301
+ });
302
+
303
+ installedResult.match(
304
+ () => loading.stop(`Installed ${ascii.JSREPO}.`),
305
+ (err) => {
306
+ loading.stop(`Failed to install ${ascii.JSREPO}.`);
307
+ program.error(err);
308
+ }
309
+ );
310
+
311
+ installed = true;
312
+ }
313
+ }
314
+
315
+ let steps: string[] = [];
316
+
317
+ if (!installed && installAsDevDependency) {
318
+ const cmd = resolveCommand(pm, 'install', ['jsrepo', '-D']);
319
+
320
+ steps.push(
321
+ `Install ${ascii.JSREPO} as a dev dependency \`${color.cyan(`${cmd?.command} ${cmd?.args.join(' ')}`)}\``
322
+ );
323
+ }
324
+
325
+ steps.push(`Add blocks to \`${color.cyan(options.path)}\`.`);
326
+
327
+ const runScript = resolveCommand(pm, 'run', [options.script]);
328
+
329
+ steps.push(
330
+ `Run \`${color.cyan(`${runScript?.command} ${runScript?.args.join(' ')}`)}\` to build the registry.`
331
+ );
332
+
333
+ // put steps with numbers above here
334
+ steps = steps.map((step, i) => `${i + 1}. ${step}`);
335
+
336
+ const next = nextSteps(steps);
337
+
338
+ process.stdout.write(next);
339
+ };
340
+
121
341
  export { init };
@@ -156,7 +156,7 @@ const _update = async (blockNames: string[], options: Options) => {
156
156
  program.error
157
157
  );
158
158
 
159
- const pm = (await detect({ cwd: process.cwd() }))?.agent ?? 'npm';
159
+ const pm = (await detect({ cwd: options.cwd }))?.agent ?? 'npm';
160
160
 
161
161
  const tasks: Task[] = [];
162
162
 
@@ -10,3 +10,5 @@ export const BOTTOM_LEFT_CORNER = color.gray('└');
10
10
 
11
11
  export const WARN = color.bgRgb(245, 149, 66).white('WARN');
12
12
  export const INFO = color.bgBlueBright.white('INFO');
13
+
14
+ export const JSREPO = color.hex('#f7df1e')('jsrepo');
@@ -138,12 +138,19 @@ const buildBlocksDirectory = (blocksPath: string, { cwd, excludeDeps }: Options)
138
138
  for (const f of blockFiles) {
139
139
  if (isTestFile(f)) continue;
140
140
 
141
+ if (fs.statSync(path.join(blockDir, f)).isDirectory()) {
142
+ console.warn(
143
+ `${ascii.VERTICAL_LINE} ${ascii.WARN} Skipped \`${color.bold(path.join(blockDir, f))}\` subdirectories are not currently supported!`
144
+ );
145
+ continue;
146
+ }
147
+
141
148
  const lang = languages.find((resolver) => resolver.matches(f));
142
149
 
143
150
  if (!lang) {
144
151
  console.warn(
145
- `${ascii.WARN} Skipped \`${color.bold(path.join(blockDir, f))}\` \`${color.bold(
146
- path.parse(file).ext
152
+ `${ascii.VERTICAL_LINE} ${ascii.WARN} Skipped \`${color.bold(path.join(blockDir, f))}\` \`*${color.bold(
153
+ path.parse(f).ext
147
154
  )}\` files are not currently supported!`
148
155
  );
149
156
  continue;