@penvhq/cli 0.9.5 → 0.10.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.cjs CHANGED
@@ -492,19 +492,12 @@ async function createSourceProvider(type, context) {
492
492
  return loadPluginProvider(type, context);
493
493
  }
494
494
  async function loadPluginProvider(type, context) {
495
- const resolved = resolvePlugin(type, context.root);
496
- if (resolved === void 0) {
497
- throw unknownProvider(type, context.environment);
498
- }
495
+ const path = resolveExtension(type, context.root, context.environment);
499
496
  let mod;
500
497
  try {
501
- mod = await importPlugin(resolved);
502
- } catch {
503
- throw new import_core4.PenvError(
504
- "PROVIDER_PLUGIN_LOAD",
505
- `The provider package \`${type}\` failed to load`,
506
- "It resolved but threw while importing. Check it builds and its dependencies are installed."
507
- );
498
+ mod = await importPlugin(path);
499
+ } catch (cause) {
500
+ throw providerLoadFailed(type, path, cause);
508
501
  }
509
502
  const factory = mod[PLUGIN_FACTORY_EXPORT];
510
503
  if (typeof factory !== "function") {
@@ -528,10 +521,42 @@ function assertProvidersRegistered(config, projectRoot, options) {
528
521
  if (ci && local.includes(provider.type)) {
529
522
  throw localExtensionInCi(provider.type, environment);
530
523
  }
531
- if (resolvePlugin(provider.type, projectRoot) === void 0) {
532
- throw unknownProvider(provider.type, environment);
524
+ resolveExtension(provider.type, projectRoot, environment, local);
525
+ }
526
+ }
527
+ function resolveExtension(type, projectRoot, environment, local = localExtensions(projectRoot)) {
528
+ const fromProject = resolvePlugin(type, projectRoot);
529
+ if (local.includes(type)) {
530
+ if (fromProject === void 0) {
531
+ throw localExtensionUnresolved(type, projectRoot, environment);
533
532
  }
533
+ return fromProject;
534
+ }
535
+ if (fromProject !== void 0) {
536
+ return fromProject;
534
537
  }
538
+ const version = pinnedVersion(type, projectRoot);
539
+ if (version === void 0) {
540
+ throw unknownProvider(type, environment);
541
+ }
542
+ const stored = storedExtension(type, version);
543
+ if (stored === void 0) {
544
+ throw extensionNotInstalled(type, version, environment);
545
+ }
546
+ return stored;
547
+ }
548
+ function pinnedVersion(type, projectRoot) {
549
+ let manifest;
550
+ try {
551
+ manifest = (0, import_core4.parseManifest)((0, import_node_fs3.readFileSync)((0, import_node_path3.join)(projectRoot, ...import_core4.MANIFEST_PATH.split("/")), "utf8"));
552
+ } catch {
553
+ return void 0;
554
+ }
555
+ return manifest.extensions[type]?.version;
556
+ }
557
+ function storedExtension(type, version) {
558
+ const entry = (0, import_core4.packageEntry)((0, import_core4.packageDir)((0, import_core4.penvHome)(process.env), "extensions", type, version));
559
+ return entry?.file;
535
560
  }
536
561
  function localExtensions(projectRoot) {
537
562
  let text;
@@ -583,13 +608,37 @@ function assertSatisfiesContract(provider, specifier) {
583
608
  }
584
609
  }
585
610
  }
611
+ function where(environment) {
612
+ return environment === void 0 ? "" : ` for environment ${environment}`;
613
+ }
586
614
  function unknownProvider(type, environment) {
587
615
  const preinstalled = [...REGISTRY.keys()].map((name) => `\`${name}\``).join(", ");
588
- const where = environment === void 0 ? "" : ` for environment ${environment}`;
589
616
  return new import_core4.PenvError(
590
617
  "UNKNOWN_PROVIDER",
591
- `The provider \`${type}\`${where} in penv.config.ts is not installed in this project`,
592
- `A provider's \`type\` is the package penv imports, so it has to resolve from this project: install it with \`npm i ${type}\`, or \u2014 if this repository is the one that builds it \u2014 run \`penv add --local ${type}\` once it is a dependency of the root. The CLI ships ${preinstalled} pre-installed.`
618
+ `The provider \`${type}\`${where(environment)} in penv.config.ts is nowhere penv looks for it`,
619
+ `Run \`penv add ${type}\` to pin a release, or \`penv add --local ${type}\` if this repository is the one that builds it. penv looks in ${import_core4.LOCAL_EXTENSIONS_PATH}, this project's node_modules, and then $PENV_HOME at the version ${import_core4.MANIFEST_PATH} pins. The CLI ships ${preinstalled} pre-installed.`
620
+ );
621
+ }
622
+ function extensionNotInstalled(type, version, environment) {
623
+ return new import_core4.PenvError(
624
+ "EXTENSION_NOT_INSTALLED",
625
+ `${import_core4.MANIFEST_PATH} pins \`${type}\` ${version}${where(environment)}, and it is not installed in ${(0, import_core4.penvHome)(process.env)}`,
626
+ "Run `penv install` \u2014 it downloads and verifies every version the manifest pins, extensions included."
627
+ );
628
+ }
629
+ function localExtensionUnresolved(type, projectRoot, environment) {
630
+ return new import_core4.PenvError(
631
+ "LOCAL_EXTENSION_UNRESOLVED",
632
+ `${import_core4.LOCAL_EXTENSIONS_PATH} records \`${type}\`${where(environment)} as a package this project develops, and it does not resolve from ${projectRoot}`,
633
+ `Add it as a dependency of the root (a workspace link is one) and run \`pnpm install\`, or drop the name from ${import_core4.LOCAL_EXTENSIONS_PATH} if this project no longer builds it.`
634
+ );
635
+ }
636
+ function providerLoadFailed(type, path, cause) {
637
+ const detail = cause instanceof Error ? cause.message : String(cause);
638
+ return new import_core4.PenvError(
639
+ "PROVIDER_PLUGIN_LOAD",
640
+ `The provider package \`${type}\` failed to load from ${path}: ${detail}`,
641
+ "penv imports that file exactly as it stands, with no transform, so it has to be built JavaScript with its dependencies installed."
593
642
  );
594
643
  }
595
644
 
@@ -4310,9 +4359,9 @@ function assertImportable(ref, variable) {
4310
4359
  `Filenames are split on \`.\`. Rename ${variable} in the source file, then import it again.`
4311
4360
  );
4312
4361
  }
4313
- function assertNotReserved(ref, variable, where, config) {
4362
+ function assertNotReserved(ref, variable, where2, config) {
4314
4363
  if ((0, import_core22.isReservedToken)(ref.name, config)) {
4315
- throw new import_core22.ReservedTokenError("parameter", variable, where);
4364
+ throw new import_core22.ReservedTokenError("parameter", variable, where2);
4316
4365
  }
4317
4366
  }
4318
4367
  function assertRoundTrips(ref, variable, config) {
@@ -4329,12 +4378,12 @@ function assertRoundTrips(ref, variable, config) {
4329
4378
  `\`penv generate\` would write ${generated}, so anything reading \`process.env["${variable}"]\` would read \`undefined\`. Declare the name you want in the \`override\` block of penv.config.ts \u2014 \`override: { "${ref.name}": "${variable}" }\` \u2014 then import it again. Nothing was imported.`
4330
4379
  );
4331
4380
  }
4332
- function refsForEntries(entries, where, config) {
4381
+ function refsForEntries(entries, where2, config) {
4333
4382
  const refs = [];
4334
4383
  for (const entry of entries) {
4335
4384
  const ref = (0, import_core22.refFromVariable)(entry.key);
4336
4385
  assertImportable(ref, entry.key);
4337
- assertNotReserved(ref, entry.key, where, config);
4386
+ assertNotReserved(ref, entry.key, where2, config);
4338
4387
  assertRoundTrips(ref, entry.key, config);
4339
4388
  refs.push(ref);
4340
4389
  }
@@ -5324,7 +5373,7 @@ function writeTsconfigAlias(root, decisions = DEFAULT_DECISIONS) {
5324
5373
  const alias = decisions.alias;
5325
5374
  const imports = alias.startsWith(IMPORTS_PREFIX);
5326
5375
  const file = (0, import_node_path13.join)(root, imports ? PACKAGE_FILE : TSCONFIG_FILE);
5327
- const where = imports ? PACKAGE_FILE : TSCONFIG_FILE;
5376
+ const where2 = imports ? PACKAGE_FILE : TSCONFIG_FILE;
5328
5377
  if (!(0, import_node_fs13.existsSync)(file)) {
5329
5378
  if (imports) {
5330
5379
  return {
@@ -5347,7 +5396,7 @@ function writeTsconfigAlias(root, decisions = DEFAULT_DECISIONS) {
5347
5396
  return {
5348
5397
  target: "tsconfig",
5349
5398
  action: "conflicted",
5350
- text: `${where} already maps ${alias} to ${edit.conflict}`,
5399
+ text: `${where2} already maps ${alias} to ${edit.conflict}`,
5351
5400
  note: `(left alone \u2014 \`import { env } from "${alias}"\` will not reach ${decisions.schemaFile})`
5352
5401
  };
5353
5402
  }
@@ -5355,14 +5404,14 @@ function writeTsconfigAlias(root, decisions = DEFAULT_DECISIONS) {
5355
5404
  return {
5356
5405
  target: "tsconfig",
5357
5406
  action: "kept",
5358
- text: `Kept the ${alias} alias in ${where}`
5407
+ text: `Kept the ${alias} alias in ${where2}`
5359
5408
  };
5360
5409
  }
5361
5410
  (0, import_node_fs13.writeFileSync)(file, edit.source, "utf8");
5362
5411
  return {
5363
5412
  target: "tsconfig",
5364
5413
  action: "updated",
5365
- text: `Added ${alias} alias to ${where}`
5414
+ text: `Added ${alias} alias to ${where2}`
5366
5415
  };
5367
5416
  }
5368
5417
  function writeGitignore(root, decisions = DEFAULT_DECISIONS) {