@reliverse/dler 2.0.9 → 2.0.12

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
@@ -4,69 +4,75 @@
4
4
 
5
5
  [Sponsor](https://github.com/sponsors/blefnk) — [Discord](https://discord.gg/Pb8uKbwpsJ) — [GitHub](https://github.com/reliverse/dler) — [NPM](https://npmjs.com/@reliverse/dler) — [Introduction](https://blefnk.reliverse.org/blog/articles/package-managers)
6
6
 
7
- ## Installation
7
+ ## CLI Installation
8
8
 
9
9
  ```bash
10
- bun add @reliverse/dler
10
+ # install as a dev dep:
11
+ bun add -D @reliverse/dler
12
+ # or, install globally:
13
+ bun i -g @reliverse/dler
11
14
  ```
12
15
 
13
- ## v2 Docs
16
+ ## CLI Usage
14
17
 
15
- Docs for v2 will be available soon. For now, you can read the v1 docs, or check alpha docs in [relidocs](./relidocs) directory in the root of the project. For example, you can [learn Dler CLI defaults](./relidocs/DEFAULTS.md) there.
18
+ ```bash
19
+ # when installed as a dev dep:
20
+ bun dler [command] [options]
21
+ # when installed globally:
22
+ dler [command] [options]
23
+ ```
16
24
 
17
- Note on `bun publish` and `bun tsc`: we don't display npm/tsc raw output, because both are not reliable for concurrent display, so we display them on our own.
25
+ ## Framework Installation
18
26
 
19
- ## v1 Docs
27
+ Both CLI and framework packages work independently, you're not required to install both.
20
28
 
21
- Visit [docs.reliverse.org/libraries/dler](https://docs.reliverse.org/libraries/dler) to learn how to install and use `@reliverse/dler` library.
29
+ ```bash
30
+ bun add @reliverse/dler-logger
31
+ ```
22
32
 
23
- ## Declaration Generation
33
+ ## Framework Usage
24
34
 
25
- Dler uses Rslib's recommended approach for TypeScript declaration generation, supporting both bundled and bundleless declarations.
35
+ ```ts
36
+ import { logger } from "@reliverse/dler-logger";
37
+ ```
26
38
 
27
- ### Optional Dependencies
39
+ ## Available Packages
40
+
41
+ 1. `@reliverse/dler-bump`
42
+ 2. `@reliverse/dler-build`
43
+ 3. `@reliverse/dler-config`
44
+ 4. `@reliverse/dler-helpers`
45
+ 5. `@reliverse/dler-colors`
46
+ 6. `@reliverse/dler-mapper`
47
+ 7. `@reliverse/dler-launcher`
48
+ 8. `@reliverse/dler-logger`
49
+ 9. `@reliverse/dler-matcher`
50
+ 10. `@reliverse/dler-pkg-tsc`
51
+ 11. `@reliverse/dler-prompt`
52
+ 12. `@reliverse/dler-spinner`
53
+ 13. `@reliverse/dler-publish`
54
+
55
+ ## Available CLI Commands
56
+
57
+ All `@reliverse/dler` v2+ commands support both monorepo (recommended) and single-repo (not tested too much yet) contexts.
58
+
59
+ 1. `dler build` can build packages as libraries, frontends (experimental), or standalone apps (experimental; already includes Bun, so the user doesn't even need to install it). Handles not only building, but also package.json modification, and other build-related tasks. Supports dler.ts configuration for per-package settings.
60
+ 2. `dler clean` nicely cleans up the codebase, with presets and with support for custom paths.
61
+ 3. `dler init` automatically generates a monorepo and the requested packages.
62
+ 4. `dler integrate` automatically installs and configures integrations like Next.js, Ultracite/Biome, etc.
63
+ 5. `dler perf` runs performance benchmarks for the requested target.
64
+ 6. `dler publish` publishes all packages to npm and jsr (soon). Handles version bumping, and different validations. Supports dler.ts configuration for per-package settings.
65
+ 7. `dler shell` uses Bun's `$`, making it handy for running cross-platform custom terminal commands.
66
+ 8. `dler tsc` finds TypeScript errors across all monorepo packages and shows only real ones (unlike the native `tsc`, which sometimes shows errors of its dependencies). It also has a `--copy-logs` flag that copies errors/warnings straight to your clipboard (with an inserted prompt for fixing them), so you can just hit Ctrl/Cmd+V and send it to AI.
67
+ 9. `dler update` updates the dependencies of all packages to the latest version (yes, even across the monorepo).
28
68
 
29
- For advanced declaration generation features, you can install these optional dependencies:
69
+ ## v2 Docs
30
70
 
31
- ```bash
32
- # For bundled declarations (single .d.ts file per package)
33
- bun add -D @microsoft/api-extractor
71
+ Docs for v2 will be available soon. For now, you can read the v1 docs, or check alpha docs in [relidocs](./relidocs) directory in the root of the project. For example, you can [learn Dler CLI defaults](./relidocs/DEFAULTS.md) there.
34
72
 
35
- # For experimental tsgo support (faster generation)
36
- bun add -D @typescript/native-preview
37
- ```
73
+ ## v1 Docs
38
74
 
39
- ### Configuration
40
-
41
- Configure declaration generation in your `dler.ts`:
42
-
43
- ```typescript
44
- export default defineConfig({
45
- build: {
46
- global: {
47
- dts: {
48
- enable: true,
49
- bundle: false, // Bundleless by default
50
- abortOnError: true,
51
- },
52
- },
53
- packages: {
54
- "my-library": {
55
- dts: {
56
- bundle: true, // Bundled declarations
57
- distPath: "types",
58
- },
59
- },
60
- "my-other-package": {
61
- dts: {
62
- tsgo: true, // Use experimental tsgo
63
- bundle: false,
64
- },
65
- },
66
- },
67
- },
68
- });
69
- ```
75
+ Visit [docs.reliverse.org/libraries/dler](https://docs.reliverse.org/libraries/dler) to learn how to install and use `@reliverse/dler` library.
70
76
 
71
77
  ## Contributing
72
78
 
@@ -82,6 +88,12 @@ bun install
82
88
 
83
89
  This monorepo was generated by dler init. It uses bun workspaces to manage multiple packages.
84
90
 
91
+ ## Locations
92
+
93
+ - `dler` (v2): `./cli`;
94
+ - `dler-v1`: `./deprecated` (contains both CLI and all-in-one library);
95
+ - packages: `./packages/*`;
96
+
85
97
  ### Scripts
86
98
 
87
99
  Run scripts across all workspaces:
@@ -0,0 +1,13 @@
1
+ export type CmdName = "rse" | "build" | "publish" | "deploy" | "native" | "update" | "agg" | "upgrade";
2
+ export declare const msgs: {
3
+ args: {
4
+ ci: string;
5
+ cwd: string;
6
+ dev: string;
7
+ };
8
+ cmds: Record<CmdName, string>;
9
+ info: {
10
+ ci: string;
11
+ dev: string;
12
+ };
13
+ };
@@ -0,0 +1,21 @@
1
+ export const msgs = {
2
+ args: {
3
+ ci: "Whether to run in CI mode (useful for GitHub Actions and other non-interactive environments)",
4
+ cwd: "The working directory to run the CLI in",
5
+ dev: "Whether to run in dev mode (useful only for debugging and Rse CLI contributors)"
6
+ },
7
+ cmds: {
8
+ rse: "Displays an interactive Rse CLI main menu. To see ALL available commands and their flags, run: rse --help",
9
+ build: "Build the project (without publishing or deploying)",
10
+ publish: "Build and publish the project to the NPM or JSR registry",
11
+ deploy: "Deploy the project to GitHub or/and Vercel",
12
+ native: "Run or install Rse CLI native binaries (kinds: bun, web)",
13
+ update: "Update all dependencies, even catalog deps, to their latest available versions",
14
+ agg: "Aggregate your project exports into a single file",
15
+ upgrade: "Upgrade your dev tools to the latest version (alias for `update --upgrade-tools`)"
16
+ },
17
+ info: {
18
+ ci: "CI mode was activated. Proceeding with: default values -> reliverse.ts overrides -> flags overrides.",
19
+ dev: "Running the CLI in dev mode."
20
+ }
21
+ };
@@ -48,8 +48,7 @@ const publishCmd = async (args) => {
48
48
  process.exit(1);
49
49
  }
50
50
  logger.success(
51
- `
52
- \u2705 All packages published successfully! (${results.successCount} packages)`
51
+ "\nAll packages published successfully!"
53
52
  );
54
53
  if (args.verbose) {
55
54
  for (const result of results.results) {
@@ -0,0 +1,2 @@
1
+ declare const _default: any;
2
+ export default _default;
@@ -0,0 +1,165 @@
1
+ import {
2
+ defineCmd,
3
+ defineCmdArgs,
4
+ defineCmdCfg
5
+ } from "@reliverse/dler-launcher";
6
+ import { logger } from "@reliverse/dler-logger";
7
+ import path from "path";
8
+ import {
9
+ checkPackageUpdatesForFile,
10
+ handleInstallation,
11
+ prepareAllUpdateCandidates,
12
+ updatePackageJsonFileDirectly,
13
+ validatePackageJson
14
+ } from "./impl.js";
15
+ import {
16
+ displayStructuredUpdateResults
17
+ } from "./utils.js";
18
+ import { msgs } from "../const.js";
19
+ import { getCurrentWorkingDirectory } from "@reliverse/dler-helpers";
20
+ const updateCmd = async (args) => {
21
+ try {
22
+ if (typeof process.versions.bun === "undefined") {
23
+ logger.error("This command requires Bun runtime. Sorry.");
24
+ process.exit(1);
25
+ }
26
+ const { dryRun, install, details, ignoreFields } = args;
27
+ const isDryRun = Boolean(dryRun);
28
+ const showDetails = Boolean(details);
29
+ const fieldsToIgnore = Array.isArray(ignoreFields) ? ignoreFields : [];
30
+ await validatePackageJson();
31
+ const { packageJsonFiles, fileDepsMap } = await prepareAllUpdateCandidates();
32
+ if (packageJsonFiles.length === 0) {
33
+ logger.log("No package.json files found");
34
+ return;
35
+ }
36
+ let totalUpdated = 0;
37
+ const allResults = [];
38
+ for (const packageJsonPath of packageJsonFiles) {
39
+ const fileDeps = fileDepsMap.get(packageJsonPath);
40
+ if (!fileDeps) continue;
41
+ const results = await checkPackageUpdatesForFile(fileDeps, args);
42
+ allResults.push(...results);
43
+ const toUpdate = results.filter(
44
+ (r) => r.updated && !r.error
45
+ );
46
+ if (toUpdate.length > 0) {
47
+ if (isDryRun) {
48
+ const relativePath = path.relative(process.cwd(), packageJsonPath);
49
+ logger.debug(
50
+ `Would update ${toUpdate.length} dependencies in ${relativePath}`
51
+ );
52
+ continue;
53
+ }
54
+ const updated = await updatePackageJsonFileDirectly(
55
+ packageJsonPath,
56
+ fileDeps,
57
+ toUpdate,
58
+ "^",
59
+ fieldsToIgnore
60
+ );
61
+ totalUpdated += updated;
62
+ if (updated > 0) {
63
+ const relativePath = path.relative(process.cwd(), packageJsonPath);
64
+ logger.debug(
65
+ `Updated ${updated} dependencies in ${relativePath}`
66
+ );
67
+ }
68
+ }
69
+ }
70
+ displayStructuredUpdateResults(
71
+ allResults,
72
+ packageJsonFiles,
73
+ fileDepsMap,
74
+ showDetails
75
+ );
76
+ if (totalUpdated === 0) {
77
+ if (isDryRun) {
78
+ logger.log("Dry run mode - no changes would be made");
79
+ } else {
80
+ logger.log("No dependencies to update");
81
+ }
82
+ return;
83
+ }
84
+ if (packageJsonFiles.length > 1) {
85
+ logger.log(
86
+ `Updated ${totalUpdated} dependencies across ${packageJsonFiles.length} package.json files`
87
+ );
88
+ } else {
89
+ logger.log(`Updated ${totalUpdated} dependencies`);
90
+ }
91
+ if (install) {
92
+ await handleInstallation();
93
+ } else {
94
+ logger.log(
95
+ "Run 'bun install' to apply the changes (use --install to do this automatically)"
96
+ );
97
+ }
98
+ } catch (error) {
99
+ logger.error(
100
+ `Failed to update dependencies: ${error instanceof Error ? error.message : String(error)}`
101
+ );
102
+ process.exit(1);
103
+ }
104
+ };
105
+ const updateCmdArgs = defineCmdArgs({
106
+ ci: {
107
+ type: "boolean",
108
+ description: msgs.args.ci,
109
+ default: !process.stdout.isTTY || !!process.env["CI"]
110
+ },
111
+ cwd: {
112
+ type: "string",
113
+ description: msgs.args.cwd,
114
+ default: getCurrentWorkingDirectory()
115
+ },
116
+ name: {
117
+ type: "string",
118
+ description: "Specific dependencies to update, supports glob patterns (e.g. '@types/*', 'react*')"
119
+ },
120
+ ignore: {
121
+ type: "string",
122
+ description: "Dependencies to exclude from updates, supports glob patterns (e.g. 'eslint-*', '@types/*')"
123
+ },
124
+ dryRun: {
125
+ type: "boolean",
126
+ description: "Preview updates without making changes"
127
+ },
128
+ install: {
129
+ type: "boolean",
130
+ description: "Run install after updating",
131
+ aliases: ["i"]
132
+ },
133
+ allowMajor: {
134
+ type: "boolean",
135
+ description: "Allow major version updates (default: true)",
136
+ default: true
137
+ },
138
+ details: {
139
+ type: "boolean",
140
+ description: "Show detailed dependency information (default: false)",
141
+ aliases: ["d"]
142
+ },
143
+ ignoreFields: {
144
+ type: "string",
145
+ description: "Dependency fields to ignore (e.g., 'peerDependencies,catalog')"
146
+ }
147
+ });
148
+ const updateCmdCfg = defineCmdCfg({
149
+ name: "update",
150
+ description: "Update all dependencies to their latest versions across all package.json files. Supports selective updates with glob patterns and comprehensive filtering options.",
151
+ examples: [
152
+ "dler update",
153
+ "dler update --install",
154
+ "dler update --dryRun",
155
+ "dler update --name @types/* --name react*",
156
+ 'dler update --ignore "eslint-*" --ignore "@babel/*"',
157
+ "dler update --no-allowMajor",
158
+ "dler update --details",
159
+ "dler update --ignoreFields peerDependencies",
160
+ "dler update --dryRun --install",
161
+ "dler update --name react --name react-dom --install",
162
+ "dler update --ignore @types/* --allowMajor"
163
+ ]
164
+ });
165
+ export default defineCmd(updateCmd, updateCmdArgs, updateCmdCfg);
@@ -0,0 +1,21 @@
1
+ import { type UpdateResult } from "./utils.js";
2
+ interface UpdateArgs {
3
+ ci?: boolean;
4
+ cwd?: string;
5
+ name?: string[];
6
+ ignore?: string[];
7
+ dryRun?: boolean;
8
+ install?: boolean;
9
+ allowMajor?: boolean;
10
+ concurrency?: number;
11
+ ignoreFields?: string[];
12
+ }
13
+ export declare function validatePackageJson(): Promise<string>;
14
+ export declare function prepareAllUpdateCandidates(): Promise<{
15
+ packageJsonFiles: string[];
16
+ fileDepsMap: Map<string, Record<string, any>>;
17
+ }>;
18
+ export declare function checkPackageUpdatesForFile(fileDepsMap: Record<string, any>, args: UpdateArgs): Promise<UpdateResult[]>;
19
+ export declare function updatePackageJsonFileDirectly(packageJsonPath: string, fileDepsMap: Record<string, any>, updatesToApply: UpdateResult[], savePrefix: string, fieldsToIgnore?: string[]): Promise<number>;
20
+ export declare function handleInstallation(): Promise<void>;
21
+ export {};
@@ -0,0 +1,157 @@
1
+ import path from "path";
2
+ import fs from "fs/promises";
3
+ import { logger } from "@reliverse/dler-logger";
4
+ import pMap from "@reliverse/dler-mapper";
5
+ import { Glob } from "bun";
6
+ import {
7
+ applyVersionUpdate,
8
+ checkPackageUpdate,
9
+ collectTargetDependencies,
10
+ prepareDependenciesForUpdate,
11
+ runInstallCommand
12
+ } from "./utils.js";
13
+ export async function validatePackageJson() {
14
+ const packageJsonPath = path.resolve(process.cwd(), "package.json");
15
+ try {
16
+ await fs.access(packageJsonPath);
17
+ } catch {
18
+ logger.error("No package.json found in current directory");
19
+ process.exit(1);
20
+ }
21
+ return packageJsonPath;
22
+ }
23
+ export async function prepareAllUpdateCandidates() {
24
+ const glob = new Glob("**/package.json");
25
+ const packageJsonFiles = [];
26
+ for await (const file of glob.scan({
27
+ cwd: process.cwd(),
28
+ onlyFiles: true
29
+ })) {
30
+ const fullPath = path.resolve(process.cwd(), file);
31
+ if (!file.includes("node_modules") && !file.includes("dist") && !file.includes("build") && !file.includes(".git") && !file.includes("coverage") && !file.includes(".next") && !file.includes(".nuxt") && !file.includes("out") && !file.includes("target") && !file.includes(".turbo")) {
32
+ packageJsonFiles.push(fullPath);
33
+ }
34
+ }
35
+ if (packageJsonFiles.length === 0) {
36
+ logger.warn("No package.json files found");
37
+ return { packageJsonFiles: [], fileDepsMap: /* @__PURE__ */ new Map() };
38
+ }
39
+ logger.debug(`Found ${packageJsonFiles.length} package.json files`);
40
+ const fileDepsMap = /* @__PURE__ */ new Map();
41
+ for (const packageJsonPath of packageJsonFiles) {
42
+ try {
43
+ const packageJson = JSON.parse(
44
+ await fs.readFile(packageJsonPath, "utf8")
45
+ );
46
+ const { map } = collectTargetDependencies(packageJson);
47
+ fileDepsMap.set(packageJsonPath, map);
48
+ } catch (error) {
49
+ logger.warn(
50
+ `Failed to process ${packageJsonPath}: ${error instanceof Error ? error.message : String(error)}`
51
+ );
52
+ }
53
+ }
54
+ logger.debug(
55
+ `Processing ${packageJsonFiles.length} package.json files`
56
+ );
57
+ return { packageJsonFiles, fileDepsMap };
58
+ }
59
+ export async function checkPackageUpdatesForFile(fileDepsMap, args) {
60
+ const options = {
61
+ allowMajor: !!args.allowMajor,
62
+ savePrefix: "^",
63
+ // Use default prefix
64
+ concurrency: args.concurrency || 5
65
+ };
66
+ const candidates = prepareDependenciesForUpdate(fileDepsMap, args);
67
+ if (candidates.length === 0) {
68
+ return [];
69
+ }
70
+ return await pMap(
71
+ candidates,
72
+ async (dep) => {
73
+ const depInfo = fileDepsMap[dep];
74
+ if (!depInfo?.versionSpec) {
75
+ return {
76
+ package: dep,
77
+ currentVersion: "unknown",
78
+ latestVersion: "unknown",
79
+ updated: false,
80
+ error: "Current version not found",
81
+ semverCompatible: false,
82
+ location: "unknown"
83
+ };
84
+ }
85
+ return checkPackageUpdate(
86
+ dep,
87
+ depInfo.versionSpec,
88
+ depInfo.locations,
89
+ options
90
+ );
91
+ },
92
+ { concurrency: args.concurrency || 5 }
93
+ );
94
+ }
95
+ export async function updatePackageJsonFileDirectly(packageJsonPath, fileDepsMap, updatesToApply, savePrefix, fieldsToIgnore = []) {
96
+ if (updatesToApply.length === 0) return 0;
97
+ try {
98
+ const packageJson = JSON.parse(
99
+ await fs.readFile(packageJsonPath, "utf8")
100
+ );
101
+ const updatedPackageJson = { ...packageJson };
102
+ for (const update of updatesToApply) {
103
+ const depInfo = fileDepsMap[update.package];
104
+ if (!depInfo) continue;
105
+ const locations = depInfo.locations || /* @__PURE__ */ new Set();
106
+ const shouldIgnore = Array.from(locations).some(
107
+ (location) => fieldsToIgnore.includes(String(location))
108
+ );
109
+ if (shouldIgnore) {
110
+ continue;
111
+ }
112
+ let newVersion;
113
+ if (locations.has("peerDependencies")) {
114
+ const currentVersion = String(
115
+ fileDepsMap[update.package]?.versionSpec || ""
116
+ );
117
+ if (currentVersion.startsWith(">=")) {
118
+ newVersion = `>=${update.latestVersion}`;
119
+ } else {
120
+ newVersion = savePrefix === "none" ? update.latestVersion : `${savePrefix}${update.latestVersion}`;
121
+ }
122
+ } else {
123
+ newVersion = savePrefix === "none" ? update.latestVersion : `${savePrefix}${update.latestVersion}`;
124
+ }
125
+ applyVersionUpdate(
126
+ updatedPackageJson,
127
+ update.package,
128
+ newVersion,
129
+ locations
130
+ );
131
+ }
132
+ await fs.writeFile(
133
+ packageJsonPath,
134
+ JSON.stringify(updatedPackageJson, null, 2) + "\n",
135
+ "utf8"
136
+ );
137
+ return updatesToApply.length;
138
+ } catch (error) {
139
+ logger.warn(
140
+ `Failed to update ${packageJsonPath}: ${error instanceof Error ? error.message : String(error)}`
141
+ );
142
+ return 0;
143
+ }
144
+ }
145
+ export async function handleInstallation() {
146
+ try {
147
+ await runInstallCommand();
148
+ logger.log("Installation completed successfully");
149
+ } catch (error) {
150
+ logger.warn(
151
+ `Install failed: ${error instanceof Error ? error.message : String(error)}`
152
+ );
153
+ logger.log(
154
+ "Run 'bun install' manually to apply the changes"
155
+ );
156
+ }
157
+ }
@@ -0,0 +1,78 @@
1
+ export interface UpdateResult {
2
+ package: string;
3
+ currentVersion: string;
4
+ latestVersion: string;
5
+ updated: boolean;
6
+ error?: string;
7
+ semverCompatible?: boolean;
8
+ location?: string;
9
+ }
10
+ export interface DependencyInfo {
11
+ versionSpec: string;
12
+ locations: Set<string>;
13
+ }
14
+ export interface PackageCheckOptions {
15
+ allowMajor: boolean;
16
+ savePrefix: string;
17
+ concurrency: number;
18
+ }
19
+ /**
20
+ * Check if a dependency is an npm alias (e.g., "npm:package-name@version")
21
+ */
22
+ export declare function isNpmAlias(versionSpec: string): boolean;
23
+ /**
24
+ * Check if a dependency is a workspace dependency (e.g., "workspace:*")
25
+ */
26
+ export declare function isWorkspaceDependency(versionSpec: string): boolean;
27
+ export declare function isCatalogReference(versionSpec: string): boolean;
28
+ export declare function isNonSemverSpecifier(versionSpec: string): boolean;
29
+ /**
30
+ * Check if a version update is semver-compatible with the current version range
31
+ * Note: Returns false for exact versions (handled separately in checkPackageUpdate)
32
+ */
33
+ export declare function isSemverCompatible(currentVersionRange: string, latestVersion: string): boolean;
34
+ /**
35
+ * Collect ALL dependencies from package.json.
36
+ * Returns a map of dependency name to its version and all locations where it appears.
37
+ */
38
+ export declare function collectTargetDependencies(pkg: any): {
39
+ map: Record<string, DependencyInfo>;
40
+ };
41
+ /**
42
+ * Apply a version update into all relevant places in package.json for a dependency.
43
+ */
44
+ export declare function applyVersionUpdate(pkg: any, depName: string, newVersion: string, locations: Set<string>): void;
45
+ /**
46
+ * Fallback function to fetch package version directly from npm registry
47
+ */
48
+ export declare function fetchVersionFromRegistry(packageName: string): Promise<string>;
49
+ /**
50
+ * Get latest version of a package
51
+ */
52
+ export declare function getLatestVersion(packageName: string): Promise<string>;
53
+ /**
54
+ * Check if a package needs updating and get update information
55
+ *
56
+ * Update behavior:
57
+ * - Gets latest version from registry (not just semver-compatible)
58
+ * - Exact versions (1.0.0): Always allow updates to latest
59
+ * - Prefixed versions (^1.0.0, ~1.0.0): Updates to latest if allowMajor=true (default)
60
+ * - When allowMajor=false: Only allows updates within semver range
61
+ */
62
+ export declare function checkPackageUpdate(packageName: string, versionSpec: string, locations: Set<string>, options: PackageCheckOptions): Promise<UpdateResult>;
63
+ /**
64
+ * Filter and prepare dependencies for updating with glob pattern support
65
+ */
66
+ export declare function prepareDependenciesForUpdate(allDepsMap: Record<string, DependencyInfo>, args: any): string[];
67
+ /**
68
+ * Update a single package.json file with new dependency versions
69
+ */
70
+ export declare function updatePackageJsonFile(packageJsonPath: string, dependencies: Record<string, DependencyInfo>, updatesToApply: UpdateResult[], savePrefix: string, fieldsToIgnore?: string[]): Promise<number>;
71
+ /**
72
+ * Display update results in a structured, file-by-file format
73
+ */
74
+ export declare function displayStructuredUpdateResults(results: UpdateResult[], packageJsonFiles: string[], fileDepsMap: Map<string, Record<string, any>>, showDetails?: boolean): void;
75
+ /**
76
+ * Run Bun install command
77
+ */
78
+ export declare function runInstallCommand(): Promise<void>;
@@ -0,0 +1,438 @@
1
+ import fs from "fs/promises";
2
+ import { logger } from "@reliverse/dler-logger";
3
+ import { $ } from "bun";
4
+ import path from "path";
5
+ import semver from "semver";
6
+ import zeptomatch from "@reliverse/dler-matcher";
7
+ export function isNpmAlias(versionSpec) {
8
+ return versionSpec.startsWith("npm:");
9
+ }
10
+ export function isWorkspaceDependency(versionSpec) {
11
+ return versionSpec.startsWith("workspace:");
12
+ }
13
+ export function isCatalogReference(versionSpec) {
14
+ return versionSpec.startsWith("catalog:");
15
+ }
16
+ export function isNonSemverSpecifier(versionSpec) {
17
+ return isNpmAlias(versionSpec) || isWorkspaceDependency(versionSpec) || isCatalogReference(versionSpec) || versionSpec.startsWith("git+") || versionSpec.startsWith("file:") || versionSpec.startsWith("link:") || versionSpec.startsWith("http:") || versionSpec.startsWith("https:");
18
+ }
19
+ export function isSemverCompatible(currentVersionRange, latestVersion) {
20
+ try {
21
+ if (isNpmAlias(currentVersionRange)) {
22
+ return false;
23
+ }
24
+ if (isWorkspaceDependency(currentVersionRange)) {
25
+ return false;
26
+ }
27
+ if (!currentVersionRange.startsWith("^") && !currentVersionRange.startsWith("~")) {
28
+ return false;
29
+ }
30
+ return semver.satisfies(latestVersion, currentVersionRange);
31
+ } catch {
32
+ return false;
33
+ }
34
+ }
35
+ export function collectTargetDependencies(pkg) {
36
+ const map = {};
37
+ const dependencies = pkg.dependencies || {};
38
+ const devDependencies = pkg.devDependencies || {};
39
+ const peerDependencies = pkg.peerDependencies || {};
40
+ const optionalDependencies = pkg.optionalDependencies || {};
41
+ for (const dep of Object.keys(dependencies)) {
42
+ const version = dependencies[dep];
43
+ if (!version) continue;
44
+ if (!map[dep]) map[dep] = { versionSpec: version, locations: /* @__PURE__ */ new Set() };
45
+ map[dep].versionSpec = version;
46
+ map[dep].locations.add("dependencies");
47
+ }
48
+ for (const dep of Object.keys(devDependencies)) {
49
+ const version = devDependencies[dep];
50
+ if (!version) continue;
51
+ if (!map[dep]) map[dep] = { versionSpec: version, locations: /* @__PURE__ */ new Set() };
52
+ map[dep].versionSpec = version;
53
+ map[dep].locations.add("devDependencies");
54
+ }
55
+ for (const dep of Object.keys(peerDependencies)) {
56
+ const version = peerDependencies[dep];
57
+ if (!version) continue;
58
+ if (!map[dep]) map[dep] = { versionSpec: version, locations: /* @__PURE__ */ new Set() };
59
+ map[dep].versionSpec = version;
60
+ map[dep].locations.add("peerDependencies");
61
+ }
62
+ for (const dep of Object.keys(optionalDependencies)) {
63
+ const version = optionalDependencies[dep];
64
+ if (!version) continue;
65
+ if (!map[dep]) map[dep] = { versionSpec: version, locations: /* @__PURE__ */ new Set() };
66
+ map[dep].versionSpec = version;
67
+ map[dep].locations.add("optionalDependencies");
68
+ }
69
+ const workspacesCatalog = pkg.workspaces?.catalog || {};
70
+ for (const dep of Object.keys(workspacesCatalog)) {
71
+ const version = workspacesCatalog[dep];
72
+ if (!version) continue;
73
+ if (!map[dep]) map[dep] = { versionSpec: version, locations: /* @__PURE__ */ new Set() };
74
+ map[dep].versionSpec = version;
75
+ map[dep].locations.add("catalog");
76
+ }
77
+ const workspacesCatalogs = pkg.workspaces?.catalogs || {};
78
+ for (const catalogName of Object.keys(workspacesCatalogs)) {
79
+ const catalog = workspacesCatalogs[catalogName] || {};
80
+ for (const dep of Object.keys(catalog)) {
81
+ const version = catalog[dep];
82
+ if (!version) continue;
83
+ if (!map[dep]) map[dep] = { versionSpec: version, locations: /* @__PURE__ */ new Set() };
84
+ map[dep].versionSpec = version;
85
+ map[dep].locations.add(`catalogs.${catalogName}`);
86
+ }
87
+ }
88
+ const topLevelCatalog = pkg.catalog || {};
89
+ for (const dep of Object.keys(topLevelCatalog)) {
90
+ const version = topLevelCatalog[dep];
91
+ if (!version) continue;
92
+ if (!map[dep]) map[dep] = { versionSpec: version, locations: /* @__PURE__ */ new Set() };
93
+ map[dep].versionSpec = version;
94
+ map[dep].locations.add("catalog");
95
+ }
96
+ const topLevelCatalogs = pkg.catalogs || {};
97
+ for (const catalogName of Object.keys(topLevelCatalogs)) {
98
+ const catalog = topLevelCatalogs[catalogName] || {};
99
+ for (const dep of Object.keys(catalog)) {
100
+ const version = catalog[dep];
101
+ if (!version) continue;
102
+ if (!map[dep]) map[dep] = { versionSpec: version, locations: /* @__PURE__ */ new Set() };
103
+ map[dep].versionSpec = version;
104
+ map[dep].locations.add(`catalogs.${catalogName}`);
105
+ }
106
+ }
107
+ return { map };
108
+ }
109
+ export function applyVersionUpdate(pkg, depName, newVersion, locations) {
110
+ if (locations.has("dependencies")) {
111
+ if (!pkg.dependencies) pkg.dependencies = {};
112
+ pkg.dependencies[depName] = newVersion;
113
+ }
114
+ if (locations.has("devDependencies")) {
115
+ if (!pkg.devDependencies) pkg.devDependencies = {};
116
+ pkg.devDependencies[depName] = newVersion;
117
+ }
118
+ if (locations.has("peerDependencies")) {
119
+ if (!pkg.peerDependencies) pkg.peerDependencies = {};
120
+ pkg.peerDependencies[depName] = newVersion;
121
+ }
122
+ if (locations.has("optionalDependencies")) {
123
+ if (!pkg.optionalDependencies) pkg.optionalDependencies = {};
124
+ pkg.optionalDependencies[depName] = newVersion;
125
+ }
126
+ const ensureWorkspaces = () => {
127
+ if (!pkg.workspaces) pkg.workspaces = {};
128
+ };
129
+ if (locations.has("catalog")) {
130
+ ensureWorkspaces();
131
+ if (!pkg.workspaces.catalog) pkg.workspaces.catalog = {};
132
+ pkg.workspaces.catalog[depName] = newVersion;
133
+ if (pkg.catalog) pkg.catalog[depName] = newVersion;
134
+ }
135
+ for (const loc of locations) {
136
+ const match = /^catalogs\.(.+)$/.exec(loc);
137
+ if (match) {
138
+ const catalogName = match[1] ?? "";
139
+ if (!catalogName) continue;
140
+ ensureWorkspaces();
141
+ if (!pkg.workspaces.catalogs)
142
+ pkg.workspaces.catalogs = {};
143
+ if (!pkg.workspaces.catalogs[catalogName])
144
+ pkg.workspaces.catalogs[catalogName] = {};
145
+ pkg.workspaces.catalogs[catalogName][depName] = newVersion;
146
+ if (pkg.catalogs && pkg.catalogs[catalogName]) {
147
+ pkg.catalogs[catalogName][depName] = newVersion;
148
+ }
149
+ }
150
+ }
151
+ }
152
+ export async function fetchVersionFromRegistry(packageName) {
153
+ const response = await fetch(
154
+ `https://registry.npmjs.org/${packageName}/latest`
155
+ );
156
+ if (!response.ok) {
157
+ throw new Error(`HTTP ${response.status}: ${response.statusText}`);
158
+ }
159
+ const data = await response.json();
160
+ return data.version;
161
+ }
162
+ export async function getLatestVersion(packageName) {
163
+ try {
164
+ return await fetchVersionFromRegistry(packageName);
165
+ } catch (error) {
166
+ throw new Error(
167
+ `Failed to get latest version for ${packageName}: ${error}`
168
+ );
169
+ }
170
+ }
171
+ export async function checkPackageUpdate(packageName, versionSpec, locations, options) {
172
+ try {
173
+ const latest = await getLatestVersion(packageName);
174
+ const cleanCurrent = versionSpec.replace(/^[\^~]/, "");
175
+ let isCompatible = isSemverCompatible(versionSpec, latest);
176
+ const isExact = !versionSpec.startsWith("^") && !versionSpec.startsWith("~");
177
+ if (isExact || !isCompatible && options.allowMajor) {
178
+ isCompatible = true;
179
+ }
180
+ return {
181
+ package: packageName,
182
+ currentVersion: cleanCurrent,
183
+ latestVersion: latest,
184
+ updated: latest !== cleanCurrent && isCompatible,
185
+ semverCompatible: isCompatible,
186
+ location: Array.from(locations).join(", ")
187
+ };
188
+ } catch (error) {
189
+ return {
190
+ package: packageName,
191
+ currentVersion: versionSpec,
192
+ latestVersion: versionSpec,
193
+ updated: false,
194
+ error: error instanceof Error ? error.message : String(error),
195
+ semverCompatible: false,
196
+ location: Array.from(locations).join(", ")
197
+ };
198
+ }
199
+ }
200
+ export function prepareDependenciesForUpdate(allDepsMap, args) {
201
+ const depsToUpdate = Object.keys(allDepsMap);
202
+ let filteredDeps = [];
203
+ if (args.name && args.name.length > 0) {
204
+ const namePatterns = args.name;
205
+ filteredDeps = depsToUpdate.filter((dep) => {
206
+ return namePatterns.some((pattern) => {
207
+ if (pattern.includes("*") || pattern.includes("?") || pattern.includes("[") || pattern.includes("{")) {
208
+ return zeptomatch.isMatch(pattern, dep);
209
+ }
210
+ return dep === pattern;
211
+ });
212
+ });
213
+ const exactMatches = filteredDeps.filter(
214
+ (dep) => namePatterns.includes(dep)
215
+ );
216
+ const patternMatches = filteredDeps.length - exactMatches.length;
217
+ if (patternMatches > 0) {
218
+ logger.debug(
219
+ `Found ${exactMatches.length} exact matches and ${patternMatches} pattern matches`
220
+ );
221
+ }
222
+ if (filteredDeps.length === 0) {
223
+ logger.warn(
224
+ `No dependencies found matching patterns: ${namePatterns.join(", ")}`
225
+ );
226
+ }
227
+ } else {
228
+ const ignoreList = args.ignore || [];
229
+ filteredDeps = depsToUpdate.filter((dep) => {
230
+ return !ignoreList.some((ignorePattern) => {
231
+ if (ignorePattern.includes("*") || ignorePattern.includes("?") || ignorePattern.includes("[") || ignorePattern.includes("{")) {
232
+ return zeptomatch.isMatch(ignorePattern, dep);
233
+ }
234
+ return dep === ignorePattern;
235
+ });
236
+ });
237
+ const ignoredCount = depsToUpdate.length - filteredDeps.length;
238
+ if (ignoredCount > 0 && ignoreList.length > 0) {
239
+ logger.debug(
240
+ `Ignored ${ignoredCount} dependencies matching ignore patterns`
241
+ );
242
+ }
243
+ }
244
+ const ignoreFields = args.ignoreFields || [];
245
+ if (ignoreFields.length > 0) {
246
+ filteredDeps = filteredDeps.filter((dep) => {
247
+ const locations = allDepsMap[dep]?.locations || /* @__PURE__ */ new Set();
248
+ return !Array.from(locations).some(
249
+ (location) => ignoreFields.includes(location)
250
+ );
251
+ });
252
+ const ignoredFieldsCount = depsToUpdate.length - filteredDeps.length;
253
+ if (ignoredFieldsCount > 0) {
254
+ logger.debug(
255
+ `Ignored ${ignoredFieldsCount} dependencies in ignored fields: ${ignoreFields.join(", ")}`
256
+ );
257
+ }
258
+ }
259
+ return filteredDeps.filter((dep) => {
260
+ const versionSpec = allDepsMap[dep]?.versionSpec ?? "";
261
+ if (!versionSpec) return false;
262
+ if (isNonSemverSpecifier(versionSpec)) return false;
263
+ return true;
264
+ });
265
+ }
266
+ export async function updatePackageJsonFile(packageJsonPath, dependencies, updatesToApply, savePrefix, fieldsToIgnore = []) {
267
+ if (updatesToApply.length === 0) return 0;
268
+ try {
269
+ const packageJson = JSON.parse(
270
+ await fs.readFile(packageJsonPath, "utf8")
271
+ );
272
+ const updatedPackageJson = { ...packageJson };
273
+ for (const update of updatesToApply) {
274
+ const depInfo = dependencies[update.package];
275
+ if (!depInfo) continue;
276
+ const locations = depInfo.locations || /* @__PURE__ */ new Set();
277
+ const shouldIgnore = Array.from(locations).some(
278
+ (location) => fieldsToIgnore.includes(location)
279
+ );
280
+ if (shouldIgnore) {
281
+ continue;
282
+ }
283
+ let newVersion;
284
+ if (locations.has("peerDependencies")) {
285
+ const currentVersion = dependencies[update.package]?.versionSpec || "";
286
+ if (currentVersion.startsWith(">=")) {
287
+ newVersion = `>=${update.latestVersion}`;
288
+ } else {
289
+ newVersion = savePrefix === "none" ? update.latestVersion : `${savePrefix}${update.latestVersion}`;
290
+ }
291
+ } else {
292
+ newVersion = savePrefix === "none" ? update.latestVersion : `${savePrefix}${update.latestVersion}`;
293
+ }
294
+ applyVersionUpdate(
295
+ updatedPackageJson,
296
+ update.package,
297
+ newVersion,
298
+ locations
299
+ );
300
+ }
301
+ await fs.writeFile(
302
+ packageJsonPath,
303
+ JSON.stringify(updatedPackageJson, null, 2) + "\n",
304
+ "utf8"
305
+ );
306
+ return updatesToApply.length;
307
+ } catch (error) {
308
+ logger.warn(
309
+ `Failed to update ${packageJsonPath}: ${error instanceof Error ? error.message : String(error)}`
310
+ );
311
+ return 0;
312
+ }
313
+ }
314
+ export function displayStructuredUpdateResults(results, packageJsonFiles, fileDepsMap, showDetails = false) {
315
+ const toUpdate = results.filter((r) => r.updated && !r.error);
316
+ const errors = results.filter((r) => r.error);
317
+ const upToDate = results.filter(
318
+ (r) => !r.updated && !r.error && r.semverCompatible
319
+ );
320
+ if (errors.length > 0) {
321
+ logger.warn(`Failed to check ${errors.length} dependencies:`);
322
+ for (const error of errors) {
323
+ logger.warn(` ${error.package} (${error.location}): ${error.error}`);
324
+ }
325
+ logger.log("");
326
+ }
327
+ if (!showDetails) {
328
+ if (toUpdate.length === 0) {
329
+ logger.log(
330
+ `All ${upToDate.length} dependencies are already up to date`
331
+ );
332
+ } else {
333
+ logger.log(
334
+ `${toUpdate.length} dependencies can be updated across ${packageJsonFiles.length} package.json files`
335
+ );
336
+ }
337
+ return;
338
+ }
339
+ const resultsByFile = /* @__PURE__ */ new Map();
340
+ for (const result of results) {
341
+ let filePath = "unknown";
342
+ for (const [pkgPath, deps] of fileDepsMap.entries()) {
343
+ if (deps[result.package]) {
344
+ filePath = pkgPath;
345
+ break;
346
+ }
347
+ }
348
+ if (!resultsByFile.has(filePath)) {
349
+ resultsByFile.set(filePath, []);
350
+ }
351
+ const fileResults = resultsByFile.get(filePath);
352
+ if (fileResults) {
353
+ fileResults.push(result);
354
+ }
355
+ }
356
+ for (const [filePath, fileResults] of resultsByFile.entries()) {
357
+ const relativePath = filePath !== "unknown" ? path.relative(process.cwd(), filePath) : "unknown";
358
+ logger.info(`${relativePath}`);
359
+ const byCategory = /* @__PURE__ */ new Map();
360
+ for (const result of fileResults) {
361
+ const category = result.location || "unknown";
362
+ if (!byCategory.has(category)) {
363
+ byCategory.set(category, []);
364
+ }
365
+ byCategory.get(category).push(result);
366
+ }
367
+ const upToDateInFile = fileResults.filter(
368
+ (r) => !r.updated && !r.error && r.semverCompatible
369
+ );
370
+ if (upToDateInFile.length > 0) {
371
+ logger.log(
372
+ ` * ${upToDateInFile.length} deps are already up to date`
373
+ );
374
+ }
375
+ const toUpdateInFile = fileResults.filter((r) => r.updated && !r.error);
376
+ if (toUpdateInFile.length > 0) {
377
+ logger.log(` * ${toUpdateInFile.length} deps can be updated:`);
378
+ const sortedCategories = Array.from(byCategory.entries()).sort(
379
+ ([a], [b]) => {
380
+ const order = {
381
+ catalog: 0,
382
+ dependencies: 1,
383
+ devDependencies: 2,
384
+ peerDependencies: 3,
385
+ optionalDependencies: 4
386
+ };
387
+ const aOrder = order[a] ?? 999;
388
+ const bOrder = order[b] ?? 999;
389
+ return aOrder - bOrder;
390
+ }
391
+ );
392
+ for (const [category, updates] of sortedCategories) {
393
+ const categoryUpdates = updates.filter((r) => r.updated && !r.error);
394
+ if (categoryUpdates.length > 0) {
395
+ let displayCategory = category;
396
+ if (category.startsWith("catalogs.")) {
397
+ displayCategory = `workspaces.${category}`;
398
+ } else if (category === "catalog") {
399
+ displayCategory = "workspaces.catalog";
400
+ }
401
+ logger.log(` - ${displayCategory}:`);
402
+ for (const update of categoryUpdates) {
403
+ logger.log(
404
+ ` ${update.package}: ${update.currentVersion} \u2192 ${update.latestVersion}`
405
+ );
406
+ }
407
+ }
408
+ }
409
+ }
410
+ const errorsInFile = fileResults.filter((r) => r.error);
411
+ if (errorsInFile.length > 0) {
412
+ logger.warn(` * ${errorsInFile.length} deps failed to check:`);
413
+ for (const error of errorsInFile) {
414
+ logger.warn(` ${error.package}: ${error.error}`);
415
+ }
416
+ }
417
+ logger.log("");
418
+ }
419
+ if (toUpdate.length === 0) {
420
+ logger.log(
421
+ `All ${upToDate.length} dependencies are already up to date`
422
+ );
423
+ } else {
424
+ logger.success(
425
+ `Summary: ${toUpdate.length} dependencies can be updated across ${packageJsonFiles.length} package.json files`
426
+ );
427
+ }
428
+ }
429
+ export async function runInstallCommand() {
430
+ try {
431
+ await $`bun install`.quiet();
432
+ } catch (error) {
433
+ logger.warn(
434
+ `Failed to run install command: ${error instanceof Error ? error.message : String(error)}`
435
+ );
436
+ throw error;
437
+ }
438
+ }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@reliverse/dler",
3
3
  "description": "@reliverse/dler is a framework which helps TypeScript and JavaScript developers create their libraries and CLI tools. It provides ready-to-use primitives, so you don't have to write them from scratch.",
4
4
  "author": "reliverse",
5
- "version": "2.0.9",
5
+ "version": "2.0.12",
6
6
  "private": false,
7
7
  "type": "module",
8
8
  "bin": {
@@ -10,17 +10,18 @@
10
10
  },
11
11
  "dependencies": {
12
12
  "c12": "^3.3.0",
13
+ "semver": "^7.7.3",
13
14
  "clipboardy": "^5.0.0",
14
- "@reliverse/dler-publish": "2.0.10",
15
- "@reliverse/dler-bump": "2.0.10",
16
- "@reliverse/dler-build": "2.0.10",
17
- "@reliverse/dler-logger": "2.0.10",
18
- "@reliverse/dler-matcher": "2.0.10",
19
- "@reliverse/dler-launcher": "2.0.10",
20
- "@reliverse/dler-prompt": "2.0.10",
21
- "@reliverse/dler-helpers": "2.0.10",
22
- "@reliverse/dler-pkg-tsc": "2.0.10",
23
- "@reliverse/dler-mapper": "2.0.10"
15
+ "@reliverse/dler-publish": "2.0.12",
16
+ "@reliverse/dler-bump": "2.0.12",
17
+ "@reliverse/dler-build": "2.0.12",
18
+ "@reliverse/dler-logger": "2.0.12",
19
+ "@reliverse/dler-matcher": "2.0.12",
20
+ "@reliverse/dler-launcher": "2.0.12",
21
+ "@reliverse/dler-prompt": "2.0.12",
22
+ "@reliverse/dler-helpers": "2.0.12",
23
+ "@reliverse/dler-pkg-tsc": "2.0.12",
24
+ "@reliverse/dler-mapper": "2.0.12"
24
25
  },
25
26
  "keywords": [
26
27
  "dler",