@savvy-web/tsdown-plugins 0.3.0 → 0.4.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/README.md CHANGED
@@ -48,6 +48,7 @@ export default defineConfig({
48
48
  - **Config validation** — the `ConfigValidator` Effect service (with `ConfigValidatorLive`) fast-fails on a bad `publishConfig.targets`, `exe` or `meta` config, raising the typed `ConfigValidationError`.
49
49
  - **dts tsconfig port** — `buildResolvedTsconfig` and `writeResolvedTsconfig` write a temp tsconfig with absolute paths so type declarations emit cleanly under pnpm symlinks.
50
50
  - **Per-target build loop** — `deriveTargetGroupOptions` and `buildTargetGroups` map a target to its `tsdown` options and run the build once per target, exposed as a helper so the escape hatch gets multi-target builds too. A `format` of `["esm", "cjs"]` (the `BuildFormat` type) derives a dual-format build — a require-able CJS output with default-export interop and `.d.cts` declarations alongside the ESM one. The `bundleNodeModules`, `bundledPackages` and `dtsExternals` options thread the dependency-bundling posture into both the JS and declaration passes. The `define` option forwards compile-time global replacements to both passes, merged with an auto-injected `process.env.__PACKAGE_VERSION__` constant.
51
+ - **Loose files** — `normalizeLooseFiles` resolves a `LooseFiles` map of literal output filenames to `NormalizedLooseFile` descriptors, inferring the module format from each `.mjs`/`.cjs` key and raising `ConfigValidationError` on a path separator, an unsupported extension or an ambiguous `.js`. `buildTargetGroups` takes the normalized form as its `looseFiles` option and emits one extra single-entry, bundled, declaration-free and manifest-free pass per file per target group, inheriting the group's bundling posture so each file is self-contained.
51
52
  - **Bundled declarations** — each target runs two `tsdown` passes: a JavaScript pass that preserves per-module output, then a declaration-only pass that rolls every re-exported type into a single `.d.ts` per public entry (`deriveDtsPassOptions`). Per-module JavaScript stays intact while consumers keep reaching re-exported types through your published subpaths.
52
53
  - **API Extractor meta** — `generateMeta` runs [API Extractor](https://api-extractor.com/) over a package's emitted `.d.ts` to write an api-model bundle (`.api.json`, `tsdoc-metadata.json`, resolved `tsconfig.json`); `normalizeMetaOptions` fills the `MetaOptions` defaults that drive it.
53
54
  - **Output reporter** — `renderReport` plus the `BuildReport` schema and a set of formatters (terminal, JSON, markdown, CI annotations, silent) render a build report for humans, agents or CI.
@@ -2,7 +2,7 @@ import { emitManifest } from "../manifest/emit-manifest.js";
2
2
  import { cjsDefaultInterop } from "./cjs-default-interop.js";
3
3
  import { nodeBuiltinDefaultInterop } from "./node-builtin-default-interop.js";
4
4
  import { syncPublicDir } from "./sync-public.js";
5
- import { deriveDtsPassOptions, deriveTargetGroupOptions } from "./target-groups.js";
5
+ import { deriveDtsPassOptions, deriveTargetGroupOptions, outDirFor } from "./target-groups.js";
6
6
  import { join } from "node:path";
7
7
 
8
8
  //#region src/build/build-target-groups.ts
@@ -127,6 +127,37 @@ async function buildTargetGroups(options) {
127
127
  plugins: [...dts.format.includes("cjs") ? [nodeBuiltinDefaultInterop(), cjsDefaultInterop()] : [], ...options.extraPlugins ?? []]
128
128
  });
129
129
  }
130
+ const looseOutDir = outDirFor(options.cwd, group.id);
131
+ const isProdGroup = group.id !== "dev";
132
+ const looseDeps = {
133
+ ...options.externals?.length ? { neverBundle: options.externals } : {},
134
+ ...options.bundle?.length ? { alwaysBundle: options.bundle } : {},
135
+ ...options.bundleNodeModules ? { skipNodeModulesBundle: false } : {}
136
+ };
137
+ for (const lf of options.looseFiles ?? []) {
138
+ const hasCjs = lf.format === "cjs";
139
+ await build({
140
+ config: false,
141
+ cwd: options.cwd,
142
+ entry: { [lf.entryName]: lf.source },
143
+ outDir: looseOutDir,
144
+ format: [lf.format],
145
+ platform: "node",
146
+ sourcemap: !isProdGroup,
147
+ minify: isProdGroup && (options.minify ?? false),
148
+ unbundle: false,
149
+ clean: false,
150
+ fixedExtension: lf.fixedExtension,
151
+ dts: false,
152
+ define: {
153
+ "process.env.__PACKAGE_VERSION__": JSON.stringify(options.version),
154
+ ...options.define
155
+ },
156
+ ...Object.keys(looseDeps).length > 0 ? { deps: looseDeps } : {},
157
+ ...hasCjs ? { cjsDefault: true } : {},
158
+ plugins: [...hasCjs ? [nodeBuiltinDefaultInterop(), cjsDefaultInterop()] : [], ...options.extraPlugins ?? []]
159
+ });
160
+ }
130
161
  }
131
162
  }
132
163
 
@@ -0,0 +1,57 @@
1
+ import { ConfigValidationError } from "../errors.js";
2
+ import { basename, extname } from "node:path";
3
+
4
+ //#region src/build/loose-files.ts
5
+ /** Extension to its implied format; `.js` is ambiguous (undefined). */
6
+ const EXT_FORMAT = {
7
+ ".mjs": "esm",
8
+ ".cjs": "cjs",
9
+ ".js": void 0
10
+ };
11
+ /**
12
+ * Resolve a `looseFiles` map into normalized build descriptors. Pure (no filesystem):
13
+ * a missing `source` is surfaced later by tsdown's entry resolution. Throws
14
+ * {@link ConfigValidationError} on any structural problem so the bundler's ConfigValidator
15
+ * surfaces it as a typed, fast-fail config error.
16
+ */
17
+ function normalizeLooseFiles(files) {
18
+ const out = [];
19
+ for (const [outFile, raw] of Object.entries(files)) {
20
+ if (basename(outFile) !== outFile) throw new ConfigValidationError({
21
+ path: `looseFiles."${outFile}"`,
22
+ reason: "a loose file must be a root-level filename with no path separator"
23
+ });
24
+ const ext = extname(outFile);
25
+ if (!(ext in EXT_FORMAT)) throw new ConfigValidationError({
26
+ path: `looseFiles."${outFile}"`,
27
+ reason: `unsupported output extension "${ext}" — use .mjs, .cjs, or .js`
28
+ });
29
+ const source = typeof raw === "string" ? raw : raw.source;
30
+ const explicit = typeof raw === "string" ? void 0 : raw.format;
31
+ const inferred = EXT_FORMAT[ext];
32
+ if (inferred !== void 0 && explicit !== void 0 && explicit !== inferred) throw new ConfigValidationError({
33
+ path: `looseFiles."${outFile}".format`,
34
+ reason: `format "${explicit}" contradicts the "${ext}" extension (which implies "${inferred}")`
35
+ });
36
+ if (inferred === void 0 && explicit === void 0) throw new ConfigValidationError({
37
+ path: `looseFiles."${outFile}".format`,
38
+ reason: "a \".js\" output is format-ambiguous — set format: \"esm\""
39
+ });
40
+ const format = inferred ?? explicit;
41
+ if (ext === ".js" && format === "cjs") throw new ConfigValidationError({
42
+ path: `looseFiles."${outFile}"`,
43
+ reason: "a CJS file named \".js\" is not supported yet — name it \".cjs\""
44
+ });
45
+ out.push({
46
+ outFile,
47
+ entryName: basename(outFile, ext),
48
+ source,
49
+ format,
50
+ fixedExtension: ext !== ".js"
51
+ });
52
+ }
53
+ return out;
54
+ }
55
+
56
+ //#endregion
57
+ export { normalizeLooseFiles };
@@ -1,6 +1,7 @@
1
1
  import { join } from "node:path";
2
2
 
3
3
  //#region src/build/target-groups.ts
4
+ /** The output dir for a group: dev -> dist/dev/pkg, prod -> dist/prod/<group>/pkg. */
4
5
  const outDirFor = (cwd, group) => group === "dev" ? join(cwd, "dist/dev/pkg") : join(cwd, "dist/prod", group, "pkg");
5
6
  /** Derive the JS-pass tsdown options for one TargetGroup (per-module JS, no dts). */
6
7
  function deriveTargetGroupOptions(options) {
@@ -55,4 +56,4 @@ function deriveDtsPassOptions(options) {
55
56
  }
56
57
 
57
58
  //#endregion
58
- export { deriveDtsPassOptions, deriveTargetGroupOptions };
59
+ export { deriveDtsPassOptions, deriveTargetGroupOptions, outDirFor };
@@ -1,5 +1,6 @@
1
- import { ConfigValidator } from "./ConfigValidator.js";
2
1
  import { ConfigValidationError } from "../errors.js";
2
+ import { normalizeLooseFiles } from "../build/loose-files.js";
3
+ import { ConfigValidator } from "./ConfigValidator.js";
3
4
  import { normalizeExeOptions } from "../exe/config.js";
4
5
  import { resolveTargets } from "../targets/resolve-targets.js";
5
6
  import { Effect, Layer } from "effect";
@@ -47,6 +48,7 @@ function check(input) {
47
48
  reason: `"${p}" exists but is not a directory`
48
49
  });
49
50
  }
51
+ if (input.looseFiles !== void 0) normalizeLooseFiles(input.looseFiles);
50
52
  }
51
53
  /** Live ConfigValidator: wraps the synchronous rule set, surfacing ConfigValidationError as a typed Effect failure. */
52
54
  const ConfigValidatorLive = Layer.succeed(ConfigValidator, { validate: (input) => Effect.try({
package/index.d.ts CHANGED
@@ -233,6 +233,40 @@ interface DerivedTsdownOptions {
233
233
  /** Derive the JS-pass tsdown options for one TargetGroup (per-module JS, no dts). */
234
234
  declare function deriveTargetGroupOptions(options: DeriveOptions): DerivedTsdownOptions;
235
235
  //#endregion
236
+ //#region src/build/loose-files.d.ts
237
+ /** One standalone bundled output file, declared by its literal output filename. */
238
+ interface LooseFileSpec {
239
+ /** Source module to bundle into the file. */
240
+ readonly source: string;
241
+ /** Module format. Required only for an ambiguous `.js` key; inferred from `.mjs`/`.cjs`. */
242
+ readonly format?: BuildFormat | undefined;
243
+ }
244
+ /** Map of literal output filename to its source (bare string) or a `{ source, format }` spec. */
245
+ type LooseFiles = Record<string, string | LooseFileSpec>;
246
+ /** A loose file resolved to a concrete build descriptor. */
247
+ interface NormalizedLooseFile {
248
+ /** Literal output filename written into the package dir, e.g. `pnpmfile.mjs`. */
249
+ readonly outFile: string;
250
+ /** tsdown entry name (outFile without its extension), e.g. `pnpmfile`. */
251
+ readonly entryName: string;
252
+ /** Source module to bundle. */
253
+ readonly source: string;
254
+ /** Resolved module format. */
255
+ readonly format: BuildFormat;
256
+ /**
257
+ * Whether tsdown should use fixed extensions. `.mjs`/`.cjs` need `true` (tsdown derives
258
+ * `.mjs` for esm and `.cjs` for cjs); a `.js` + esm output needs `false` (tsdown derives `.js`).
259
+ */
260
+ readonly fixedExtension: boolean;
261
+ }
262
+ /**
263
+ * Resolve a `looseFiles` map into normalized build descriptors. Pure (no filesystem):
264
+ * a missing `source` is surfaced later by tsdown's entry resolution. Throws
265
+ * {@link ConfigValidationError} on any structural problem so the bundler's ConfigValidator
266
+ * surfaces it as a typed, fast-fail config error.
267
+ */
268
+ declare function normalizeLooseFiles(files: LooseFiles): ReadonlyArray<NormalizedLooseFile>;
269
+ //#endregion
236
270
  //#region src/build/build-target-groups.d.ts
237
271
  /** Signature compatible with tsdown's `build(inlineConfig)`. */
238
272
  type TsdownBuild = (config: Record<string, unknown>) => Promise<unknown>;
@@ -327,6 +361,14 @@ interface BuildTargetGroupsOptions {
327
361
  * otherwise ESM-only package). The base `entry` must already EXCLUDE these entries.
328
362
  */
329
363
  readonly overrides?: ReadonlyArray<EntryOverride> | undefined;
364
+ /**
365
+ * Standalone bundled output files emitted at literal paths into each group's pkg/ dir,
366
+ * outside the exports/dts/meta graph (e.g. pnpm config-dependency pnpmfiles). Each runs as
367
+ * one extra single-entry, bundled (unbundle:false), no-dts, no-manifest pass per group,
368
+ * inheriting the group's bundleNodeModules/bundle/externals posture so the file is
369
+ * self-contained. Caller passes the normalized form (see normalizeLooseFiles).
370
+ */
371
+ readonly looseFiles?: ReadonlyArray<NormalizedLooseFile> | undefined;
330
372
  /**
331
373
  * Which export keys get a CJS `require` condition in the emitted manifest. Pass a Set
332
374
  * when overrides give different entries different formats; omit for the uniform
@@ -630,6 +672,8 @@ interface ValidationInput {
630
672
  readonly cpu: ReadonlyArray<string>;
631
673
  } | undefined;
632
674
  readonly meta?: MetaOptions | undefined;
675
+ /** Standalone bundled output files; validated structurally (extension/format) before any build. */
676
+ readonly looseFiles?: LooseFiles | undefined;
633
677
  }
634
678
  declare const ConfigValidator_base: Context.TagClass<ConfigValidator, "@savvy-web/tsdown-plugins/ConfigValidator", {
635
679
  readonly validate: (input: ValidationInput) => Effect.Effect<void, ConfigValidationError>;
@@ -1465,5 +1509,5 @@ declare function resolveTargets(options: {
1465
1509
  baseName: string;
1466
1510
  }): TargetResolution;
1467
1511
  //#endregion
1468
- export { type BuildEmittedManifestOptions, type BuildFormat, type BuildGroupSpec, type BuildReport, BuildReport as BuildReportSchema, type BuildTargetGroupsOptions, CatalogAssemblyError, CatalogResolutionError, CiAnnotationsFormatter, ConfigValidationError, ConfigValidator, ConfigValidatorLive, DEFAULT_EXE_NODE_VERSION, type DeriveOptions, type DerivedTsdownOptions, type DualExports, type EmitManifestOptions, type EntryOverride, type Environment, EnvironmentDetector, EnvironmentDetectorLive, type ExeBuild, type ExeConfig, type ExeSeaConfig, type ExeTarget, type ExeTargetInput, type Executor, ExecutorResolver, ExecutorResolverLive, type ExtractOptions, type ExtractResult, FormatSelector, FormatSelectorLive, type Formatter, type FormatterContext, type GenerateMetaOptions, type Json, JsonFormatter, type JsxConfig, type ManifestLike, MarkdownFormatter, MetaGenerationError, type MetaOptions, type MetaResult, type NormalizedExe, type NormalizedMeta, type OutputFormat, OutputRenderer, OutputRendererLive, type PackageJsonEntriesOptions, type PackageJsonLike, type PkgOsCpu, type PortableTsconfig, type PublishTargetObject, type PublishTargetValue, type PublishTargets, type RenderReportOptions, type RenderedOutput, ReportPipelineLive, ReportTimings, type ResolvedCompilerOptions, type ResolvedGroup, type ResolvedTarget, type ResolvedTsconfig, type ResolvedTsconfigOptions, type RunExeBuildOptions, SilentFormatter, type TargetGroupId, type TargetGroupRef, type TargetGroupReport, TargetGroupReport as TargetGroupReportSchema, type TargetResolution, TerminalFormatter, type Timer, type TransformManifestOptions, type TsconfigJsx, TsconfigResolver, type TsdocOptions, type TsdocTagDefinition, type TsdownBuild, type ValidationInput, type WarningSuppressionRule, buildEmittedManifest, buildResolvedTsconfig, buildTargetGroups, cjsDefaultInterop, createEntryName, createTimer, defaultManifestTransform, deriveTargetGroupOptions, emitManifest, extractEntries, formatTime, generateBuildReportSchema, generateMeta, isTargetObject, nodeBuiltinDefaultInterop, normalizeBinPaths, normalizeExeOptions, normalizeMetaOptions, packageJsonEntries, readTsconfigJsx, removeDeclarationMaps, renderReport, resolveJsxConfig, resolveManifest, resolvePortableTsconfig, resolveTargets, runExeBuild, syncPublicDir, transformBin, transformExports, transformManifest, writeResolvedTsconfig, writeTargetsBinding };
1512
+ export { type BuildEmittedManifestOptions, type BuildFormat, type BuildGroupSpec, type BuildReport, BuildReport as BuildReportSchema, type BuildTargetGroupsOptions, CatalogAssemblyError, CatalogResolutionError, CiAnnotationsFormatter, ConfigValidationError, ConfigValidator, ConfigValidatorLive, DEFAULT_EXE_NODE_VERSION, type DeriveOptions, type DerivedTsdownOptions, type DualExports, type EmitManifestOptions, type EntryOverride, type Environment, EnvironmentDetector, EnvironmentDetectorLive, type ExeBuild, type ExeConfig, type ExeSeaConfig, type ExeTarget, type ExeTargetInput, type Executor, ExecutorResolver, ExecutorResolverLive, type ExtractOptions, type ExtractResult, FormatSelector, FormatSelectorLive, type Formatter, type FormatterContext, type GenerateMetaOptions, type Json, JsonFormatter, type JsxConfig, type LooseFileSpec, type LooseFiles, type ManifestLike, MarkdownFormatter, MetaGenerationError, type MetaOptions, type MetaResult, type NormalizedExe, type NormalizedLooseFile, type NormalizedMeta, type OutputFormat, OutputRenderer, OutputRendererLive, type PackageJsonEntriesOptions, type PackageJsonLike, type PkgOsCpu, type PortableTsconfig, type PublishTargetObject, type PublishTargetValue, type PublishTargets, type RenderReportOptions, type RenderedOutput, ReportPipelineLive, ReportTimings, type ResolvedCompilerOptions, type ResolvedGroup, type ResolvedTarget, type ResolvedTsconfig, type ResolvedTsconfigOptions, type RunExeBuildOptions, SilentFormatter, type TargetGroupId, type TargetGroupRef, type TargetGroupReport, TargetGroupReport as TargetGroupReportSchema, type TargetResolution, TerminalFormatter, type Timer, type TransformManifestOptions, type TsconfigJsx, TsconfigResolver, type TsdocOptions, type TsdocTagDefinition, type TsdownBuild, type ValidationInput, type WarningSuppressionRule, buildEmittedManifest, buildResolvedTsconfig, buildTargetGroups, cjsDefaultInterop, createEntryName, createTimer, defaultManifestTransform, deriveTargetGroupOptions, emitManifest, extractEntries, formatTime, generateBuildReportSchema, generateMeta, isTargetObject, nodeBuiltinDefaultInterop, normalizeBinPaths, normalizeExeOptions, normalizeLooseFiles, normalizeMetaOptions, packageJsonEntries, readTsconfigJsx, removeDeclarationMaps, renderReport, resolveJsxConfig, resolveManifest, resolvePortableTsconfig, resolveTargets, runExeBuild, syncPublicDir, transformBin, transformExports, transformManifest, writeResolvedTsconfig, writeTargetsBinding };
1469
1513
  //# sourceMappingURL=index.d.ts.map
package/index.js CHANGED
@@ -7,9 +7,10 @@ import { nodeBuiltinDefaultInterop } from "./build/node-builtin-default-interop.
7
7
  import { syncPublicDir } from "./build/sync-public.js";
8
8
  import { deriveTargetGroupOptions } from "./build/target-groups.js";
9
9
  import { buildTargetGroups } from "./build/build-target-groups.js";
10
+ import { ConfigValidationError, MetaGenerationError } from "./errors.js";
11
+ import { normalizeLooseFiles } from "./build/loose-files.js";
10
12
  import { removeDeclarationMaps } from "./build/strip-maps.js";
11
13
  import { ConfigValidator } from "./config-validation/ConfigValidator.js";
12
- import { ConfigValidationError, MetaGenerationError } from "./errors.js";
13
14
  import { DEFAULT_EXE_NODE_VERSION, normalizeExeOptions } from "./exe/config.js";
14
15
  import { isTargetObject } from "./targets/config.js";
15
16
  import { resolveTargets } from "./targets/resolve-targets.js";
@@ -41,4 +42,4 @@ import { generateBuildReportSchema } from "./report/schema-export.js";
41
42
  import { writeTargetsBinding } from "./targets/binding.js";
42
43
  import { CatalogAssemblyError, CatalogResolutionError } from "workspaces-effect";
43
44
 
44
- export { BuildReport as BuildReportSchema, CatalogAssemblyError, CatalogResolutionError, CiAnnotationsFormatter, ConfigValidationError, ConfigValidator, ConfigValidatorLive, DEFAULT_EXE_NODE_VERSION, EnvironmentDetector, EnvironmentDetectorLive, ExecutorResolver, ExecutorResolverLive, FormatSelector, FormatSelectorLive, JsonFormatter, MarkdownFormatter, MetaGenerationError, OutputRenderer, OutputRendererLive, ReportPipelineLive, ReportTimings, SilentFormatter, TargetGroupReport as TargetGroupReportSchema, TerminalFormatter, TsconfigResolver, buildEmittedManifest, buildResolvedTsconfig, buildTargetGroups, cjsDefaultInterop, createEntryName, createTimer, defaultManifestTransform, deriveTargetGroupOptions, emitManifest, extractEntries, formatTime, generateBuildReportSchema, generateMeta, isTargetObject, nodeBuiltinDefaultInterop, normalizeBinPaths, normalizeExeOptions, normalizeMetaOptions, packageJsonEntries, readTsconfigJsx, removeDeclarationMaps, renderReport, resolveJsxConfig, resolveManifest, resolvePortableTsconfig, resolveTargets, runExeBuild, syncPublicDir, transformBin, transformExports, transformManifest, writeResolvedTsconfig, writeTargetsBinding };
45
+ export { BuildReport as BuildReportSchema, CatalogAssemblyError, CatalogResolutionError, CiAnnotationsFormatter, ConfigValidationError, ConfigValidator, ConfigValidatorLive, DEFAULT_EXE_NODE_VERSION, EnvironmentDetector, EnvironmentDetectorLive, ExecutorResolver, ExecutorResolverLive, FormatSelector, FormatSelectorLive, JsonFormatter, MarkdownFormatter, MetaGenerationError, OutputRenderer, OutputRendererLive, ReportPipelineLive, ReportTimings, SilentFormatter, TargetGroupReport as TargetGroupReportSchema, TerminalFormatter, TsconfigResolver, buildEmittedManifest, buildResolvedTsconfig, buildTargetGroups, cjsDefaultInterop, createEntryName, createTimer, defaultManifestTransform, deriveTargetGroupOptions, emitManifest, extractEntries, formatTime, generateBuildReportSchema, generateMeta, isTargetObject, nodeBuiltinDefaultInterop, normalizeBinPaths, normalizeExeOptions, normalizeLooseFiles, normalizeMetaOptions, packageJsonEntries, readTsconfigJsx, removeDeclarationMaps, renderReport, resolveJsxConfig, resolveManifest, resolvePortableTsconfig, resolveTargets, runExeBuild, syncPublicDir, transformBin, transformExports, transformManifest, writeResolvedTsconfig, writeTargetsBinding };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@savvy-web/tsdown-plugins",
3
- "version": "0.3.0",
3
+ "version": "0.4.1",
4
4
  "private": false,
5
5
  "description": "Interface-only tsdown/rolldown plugin pack powering @savvy-web/bundler",
6
6
  "homepage": "https://github.com/savvy-web/systems/tree/main/packages/tsdown-plugins",
@@ -28,12 +28,12 @@
28
28
  "./package.json": "./package.json"
29
29
  },
30
30
  "dependencies": {
31
- "@effect/platform-node": "^0.106.0",
32
- "@microsoft/api-extractor": "^7.58.7",
31
+ "@effect/platform-node": "^0.107.0",
32
+ "@microsoft/api-extractor": "^7.58.8",
33
33
  "@microsoft/tsdoc": "^0.16.0",
34
34
  "@microsoft/tsdoc-config": "^0.18.1",
35
35
  "deep-equal": "^2.2.3",
36
- "json-schema-effect": "^0.2.1",
36
+ "json-schema-effect": "^0.2.2",
37
37
  "picocolors": "^1.1.1",
38
38
  "sort-package-json": "^4.0.0",
39
39
  "std-env": "^4.1.0",