@savvy-web/rslib-builder 0.10.0 → 0.11.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/README.md +15 -96
- package/index.d.ts +70 -5
- package/index.js +159 -87
- package/package.json +6 -3
package/README.md
CHANGED
|
@@ -8,126 +8,45 @@ Build modern ESM Node.js libraries with minimal configuration. Handles
|
|
|
8
8
|
TypeScript declarations, package.json transformations, and PNPM workspace
|
|
9
9
|
resolution automatically.
|
|
10
10
|
|
|
11
|
-
Building TypeScript packages for npm involves repetitive setup: configuring
|
|
12
|
-
bundlers, generating declarations, transforming package.json exports, and
|
|
13
|
-
resolving workspace references. rslib-builder handles these tasks so you can
|
|
14
|
-
focus on your code.
|
|
15
|
-
|
|
16
11
|
## Features
|
|
17
12
|
|
|
18
|
-
- **Zero
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
with per-entry overrides for virtual entries
|
|
29
|
-
- **PNPM Integration** - Automatically resolves `catalog:` and `workspace:`
|
|
30
|
-
references
|
|
31
|
-
- **Package.json Transform** - Converts `.ts` exports to `.js`, generates files
|
|
32
|
-
array, removes dev-only fields
|
|
33
|
-
- **TSDoc Validation** - Pre-build TSDoc validation with automatic public API discovery
|
|
34
|
-
- **API Model Generation** - Optional API model and resolved tsconfig output for
|
|
35
|
-
documentation tooling
|
|
36
|
-
- **Extensible** - Add custom RSlib/Rsbuild plugins for advanced use cases
|
|
37
|
-
|
|
38
|
-
## Prerequisites
|
|
39
|
-
|
|
40
|
-
- Node.js 24.x or later
|
|
41
|
-
- pnpm 10.x or later
|
|
42
|
-
- TypeScript 5.9.x or later
|
|
13
|
+
- **Zero-Config Entry Detection** - Auto-discovers entry points from package.json
|
|
14
|
+
exports, no manual configuration needed
|
|
15
|
+
- **10-100x Faster Types** - Uses tsgo (native TypeScript compiler) with API
|
|
16
|
+
Extractor for bundled, clean public API declarations
|
|
17
|
+
- **Production-Ready Transforms** - Converts `.ts` exports to `.js`, resolves
|
|
18
|
+
PNPM `catalog:` and `workspace:` references, generates files array
|
|
19
|
+
- **Multi-Target Builds** - Separate dev (with source maps) and npm (optimized)
|
|
20
|
+
outputs from a single configuration
|
|
21
|
+
- **TSDoc Validation** - Pre-build documentation validation with automatic
|
|
22
|
+
public API discovery
|
|
43
23
|
|
|
44
24
|
## Installation
|
|
45
25
|
|
|
46
26
|
```bash
|
|
47
|
-
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
### Peer Dependencies
|
|
51
|
-
|
|
52
|
-
Install the required peer dependencies:
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
pnpm add -D @rslib/core @microsoft/api-extractor @typescript/native-preview
|
|
27
|
+
npm install --save-dev @savvy-web/rslib-builder @rslib/core @microsoft/api-extractor @typescript/native-preview
|
|
56
28
|
```
|
|
57
29
|
|
|
58
30
|
## Quick Start
|
|
59
31
|
|
|
60
|
-
Extend the provided tsconfig for optimal settings:
|
|
61
|
-
|
|
62
|
-
```jsonc
|
|
63
|
-
// tsconfig.json
|
|
64
|
-
{
|
|
65
|
-
"extends": "@savvy-web/rslib-builder/tsconfig/ecma/lib.json"
|
|
66
|
-
}
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
Create an `rslib.config.ts` in your project root:
|
|
70
|
-
|
|
71
32
|
```typescript
|
|
33
|
+
// rslib.config.ts
|
|
72
34
|
import { NodeLibraryBuilder } from '@savvy-web/rslib-builder';
|
|
73
35
|
|
|
74
36
|
export default NodeLibraryBuilder.create({
|
|
75
37
|
externals: ['@rslib/core'],
|
|
76
|
-
transform({ pkg, target }) {
|
|
77
|
-
if (target === 'npm') {
|
|
78
|
-
delete pkg.devDependencies;
|
|
79
|
-
}
|
|
80
|
-
return pkg;
|
|
81
|
-
},
|
|
82
38
|
});
|
|
83
39
|
```
|
|
84
40
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
```json
|
|
88
|
-
{
|
|
89
|
-
"scripts": {
|
|
90
|
-
"build": "rslib build --env-mode dev",
|
|
91
|
-
"build:npm": "rslib build --env-mode npm"
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
```
|
|
41
|
+
Build with `rslib build --env-mode dev` or `rslib build --env-mode npm`.
|
|
95
42
|
|
|
96
43
|
## Documentation
|
|
97
44
|
|
|
98
|
-
For
|
|
99
|
-
|
|
100
|
-
- [Getting Started](./docs/guides/getting-started.md) - Installation and setup
|
|
101
|
-
- [Configuration](./docs/guides/configuration.md) - All options explained
|
|
102
|
-
- [Plugin System](./docs/guides/plugins.md) - Built-in and custom plugins
|
|
103
|
-
- [Architecture](./docs/architecture/overview.md) - How it works internally
|
|
104
|
-
- [Troubleshooting](./docs/troubleshooting.md) - Common issues and solutions
|
|
105
|
-
|
|
106
|
-
## Example
|
|
107
|
-
|
|
108
|
-
This package builds itself using its own `NodeLibraryBuilder`. See
|
|
109
|
-
[`rslib.config.ts`](./rslib.config.ts) for a production example.
|
|
110
|
-
|
|
111
|
-
## Support
|
|
112
|
-
|
|
113
|
-
This software is provided as-is under the MIT License with no warranty or
|
|
114
|
-
support guarantees. While we welcome bug reports and feature requests via
|
|
115
|
-
GitHub Issues, we cannot guarantee response times or resolution.
|
|
116
|
-
|
|
117
|
-
For security vulnerabilities, please see [SECURITY.md](./SECURITY.md).
|
|
118
|
-
|
|
119
|
-
## Links
|
|
120
|
-
|
|
121
|
-
- [RSlib Documentation](https://rslib.dev/)
|
|
122
|
-
- [Rsbuild Plugin API](https://rsbuild.dev/plugins/dev/core)
|
|
123
|
-
- [API Extractor](https://api-extractor.com/)
|
|
124
|
-
- [PNPM Workspace](https://pnpm.io/workspaces)
|
|
125
|
-
- [PNPM Catalogs](https://pnpm.io/catalogs)
|
|
45
|
+
For configuration options, API reference, and advanced usage, see [docs](./docs/).
|
|
126
46
|
|
|
127
47
|
## Contributing
|
|
128
48
|
|
|
129
|
-
|
|
130
|
-
and guidelines.
|
|
49
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md) for development setup and guidelines.
|
|
131
50
|
|
|
132
51
|
## License
|
|
133
52
|
|
package/index.d.ts
CHANGED
|
@@ -1206,6 +1206,27 @@ export declare class NodeLibraryBuilder {
|
|
|
1206
1206
|
}
|
|
1207
1207
|
|
|
1208
1208
|
/**
|
|
1209
|
+
* Configuration options for the NodeLibraryBuilder.
|
|
1210
|
+
*
|
|
1211
|
+
* @remarks
|
|
1212
|
+
* All options are optional with sensible defaults. The most commonly customized options are:
|
|
1213
|
+
* - `externals`: For dependencies that should remain external
|
|
1214
|
+
* - `dtsBundledPackages`: For inlining type definitions
|
|
1215
|
+
* - `transform`: For custom package.json modifications
|
|
1216
|
+
*
|
|
1217
|
+
* @example
|
|
1218
|
+
* ```typescript
|
|
1219
|
+
* import type { NodeLibraryBuilderOptions } from '@savvy-web/rslib-builder';
|
|
1220
|
+
*
|
|
1221
|
+
* const options: NodeLibraryBuilderOptions = {
|
|
1222
|
+
* externals: ['@rslib/core'],
|
|
1223
|
+
* dtsBundledPackages: ['picocolors'],
|
|
1224
|
+
* apiModel: {
|
|
1225
|
+
* localPaths: ['../docs/packages/my-package'],
|
|
1226
|
+
* },
|
|
1227
|
+
* };
|
|
1228
|
+
* ```
|
|
1229
|
+
*
|
|
1209
1230
|
* @public
|
|
1210
1231
|
*/
|
|
1211
1232
|
export declare interface NodeLibraryBuilderOptions {
|
|
@@ -1287,11 +1308,46 @@ export declare interface NodeLibraryBuilderOptions {
|
|
|
1287
1308
|
* ```
|
|
1288
1309
|
*/
|
|
1289
1310
|
exportsAsIndexes?: boolean;
|
|
1311
|
+
/**
|
|
1312
|
+
* Patterns for files to copy to the output directory.
|
|
1313
|
+
*
|
|
1314
|
+
* @remarks
|
|
1315
|
+
* Supports both string paths and detailed configuration objects.
|
|
1316
|
+
* A `public/` directory in the project root is automatically added if it exists.
|
|
1317
|
+
*
|
|
1318
|
+
* @defaultValue `[]`
|
|
1319
|
+
*/
|
|
1290
1320
|
copyPatterns: (string | CopyPatternConfig)[];
|
|
1291
|
-
/**
|
|
1321
|
+
/**
|
|
1322
|
+
* Additional Rsbuild plugins to include in the build.
|
|
1323
|
+
*
|
|
1324
|
+
* @remarks
|
|
1325
|
+
* These plugins run after the built-in plugins (AutoEntryPlugin, DtsPlugin, etc.).
|
|
1326
|
+
*
|
|
1327
|
+
* @defaultValue `[]`
|
|
1328
|
+
*/
|
|
1292
1329
|
plugins: RsbuildPlugin[];
|
|
1330
|
+
/**
|
|
1331
|
+
* Compile-time constants for code replacement.
|
|
1332
|
+
*
|
|
1333
|
+
* @remarks
|
|
1334
|
+
* Values are stringified and replaced in the source code during bundling.
|
|
1335
|
+
* The `process.env.__PACKAGE_VERSION__` constant is automatically defined.
|
|
1336
|
+
*
|
|
1337
|
+
* @see {@link https://rsbuild.dev/config/source/define | Rsbuild define documentation}
|
|
1338
|
+
*
|
|
1339
|
+
* @defaultValue `{}`
|
|
1340
|
+
*/
|
|
1293
1341
|
define: SourceConfig["define"];
|
|
1294
|
-
/**
|
|
1342
|
+
/**
|
|
1343
|
+
* Path to the TypeScript configuration file for the build.
|
|
1344
|
+
*
|
|
1345
|
+
* @remarks
|
|
1346
|
+
* If not specified, the plugin searches for `tsconfig.json` in the project root.
|
|
1347
|
+
* A temporary tsconfig is generated for declaration generation regardless of this setting.
|
|
1348
|
+
*
|
|
1349
|
+
* @defaultValue `undefined` (auto-detected)
|
|
1350
|
+
*/
|
|
1295
1351
|
tsconfigPath: string | undefined;
|
|
1296
1352
|
/** Build targets to include (default: ["dev", "npm"]) */
|
|
1297
1353
|
targets?: BuildTarget[];
|
|
@@ -1872,7 +1928,6 @@ export declare type PackageJson = JsonObject & PackageJson.NodeJsStandard & Pack
|
|
|
1872
1928
|
*
|
|
1873
1929
|
* - Consumes `entrypoints` map from AutoEntryPlugin
|
|
1874
1930
|
* - Consumes `exportToOutputMap` for exportsAsIndexes mode
|
|
1875
|
-
* - Exposes `files-cache` for asset caching
|
|
1876
1931
|
* - Consumes `use-rollup-types` flag from DtsPlugin
|
|
1877
1932
|
*
|
|
1878
1933
|
* @param options - Plugin configuration options
|
|
@@ -3078,12 +3133,22 @@ export declare class TsconfigResolver {
|
|
|
3078
3133
|
|
|
3079
3134
|
/**
|
|
3080
3135
|
* Options for the VirtualEntryPlugin.
|
|
3136
|
+
*
|
|
3137
|
+
* @remarks
|
|
3138
|
+
* Virtual entries are used for special files that need bundling but should not
|
|
3139
|
+
* generate type declarations or appear in package.json exports. Common use cases
|
|
3140
|
+
* include pnpmfile.cjs or other configuration files.
|
|
3141
|
+
*
|
|
3081
3142
|
* @public
|
|
3082
3143
|
*/
|
|
3083
3144
|
export declare interface VirtualEntryPluginOptions {
|
|
3084
3145
|
/**
|
|
3085
|
-
* Set of virtual entry names (without extensions).
|
|
3086
|
-
*
|
|
3146
|
+
* Set of virtual entry names (without file extensions).
|
|
3147
|
+
*
|
|
3148
|
+
* @remarks
|
|
3149
|
+
* These names are exposed to DtsPlugin to skip type generation.
|
|
3150
|
+
* For example, if `virtualEntryNames` contains `"pnpmfile"`, the
|
|
3151
|
+
* entry `pnpmfile.cjs` will be bundled but no `pnpmfile.d.ts` will be generated.
|
|
3087
3152
|
*/
|
|
3088
3153
|
virtualEntryNames: Set<string>;
|
|
3089
3154
|
}
|
package/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { defineConfig } from "@rslib/core";
|
|
|
5
5
|
import { access, copyFile, mkdir, readFile, readdir, rm, stat, unlink as promises_unlink, writeFile } from "node:fs/promises";
|
|
6
6
|
import { logger as core_logger } from "@rsbuild/core";
|
|
7
7
|
import picocolors from "picocolors";
|
|
8
|
-
import { getWorkspaceManagerRoot } from "workspace-tools";
|
|
8
|
+
import { getCatalogs, getWorkspaceManagerAndRoot, getWorkspaceManagerRoot } from "workspace-tools";
|
|
9
9
|
import { spawn } from "node:child_process";
|
|
10
10
|
import { StandardTags, Standardization, TSDocTagSyntaxKind } from "@microsoft/tsdoc";
|
|
11
11
|
import deep_equal from "deep-equal";
|
|
@@ -13,8 +13,11 @@ import typescript, { ImportsNotUsedAsValues, JsxEmit, ModuleDetectionKind, Modul
|
|
|
13
13
|
import { createRequire } from "node:module";
|
|
14
14
|
import { inspect } from "node:util";
|
|
15
15
|
import sort_package_json from "sort-package-json";
|
|
16
|
+
import { getCatalogsFromWorkspaceManifest } from "@pnpm/catalogs.config";
|
|
17
|
+
import { parseCatalogProtocol } from "@pnpm/catalogs.protocol-parser";
|
|
16
18
|
import { createExportableManifest } from "@pnpm/exportable-manifest";
|
|
17
|
-
import {
|
|
19
|
+
import { readWantedLockfile } from "@pnpm/lockfile.fs";
|
|
20
|
+
import { readWorkspaceManifest } from "@pnpm/workspace.read-manifest";
|
|
18
21
|
const { cyan: cyan, dim: dim, bold: bold } = picocolors;
|
|
19
22
|
function formatTime(ms) {
|
|
20
23
|
if (ms < 1000) return `${ms}ms`;
|
|
@@ -310,21 +313,6 @@ class TSConfigFile {
|
|
|
310
313
|
}
|
|
311
314
|
}
|
|
312
315
|
class LibraryTSConfigFile extends TSConfigFile {
|
|
313
|
-
bundle(target) {
|
|
314
|
-
const config = transformStringsDeep(this.config, (str)=>str.replace("${configDir}", "../../../../../.."));
|
|
315
|
-
const include = config.include?.filter((pattern)=>pattern.includes("/src/") || pattern.includes("/types/") || pattern.includes("/public/") || pattern.includes("package.json")).filter((pattern)=>!pattern.includes(".tsx") && !pattern.includes(".cts"));
|
|
316
|
-
return {
|
|
317
|
-
...config,
|
|
318
|
-
compilerOptions: {
|
|
319
|
-
...config.compilerOptions,
|
|
320
|
-
outDir: "dist",
|
|
321
|
-
tsBuildInfoFile: `${process.cwd()}/dist/.tsbuildinfo.${target}.bundle`
|
|
322
|
-
},
|
|
323
|
-
...void 0 !== include && include.length > 0 ? {
|
|
324
|
-
include
|
|
325
|
-
} : {}
|
|
326
|
-
};
|
|
327
|
-
}
|
|
328
316
|
writeBundleTempConfig(_target) {
|
|
329
317
|
const cwd = process.cwd();
|
|
330
318
|
const baseConfig = this.config;
|
|
@@ -1576,75 +1564,76 @@ const FilesArrayPlugin = (options)=>({
|
|
|
1576
1564
|
});
|
|
1577
1565
|
const CATALOG_PREFIX = "catalog:";
|
|
1578
1566
|
const WORKSPACE_PREFIX = "workspace:";
|
|
1579
|
-
class
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
cachedWorkspaceRoot = null;
|
|
1567
|
+
class WorkspaceCatalog {
|
|
1568
|
+
catalogsCache = null;
|
|
1569
|
+
cachedWorkspaceInfo = null;
|
|
1583
1570
|
clearCache() {
|
|
1584
|
-
this.
|
|
1585
|
-
this.
|
|
1586
|
-
this.cachedWorkspaceRoot = null;
|
|
1571
|
+
this.catalogsCache = null;
|
|
1572
|
+
this.cachedWorkspaceInfo = null;
|
|
1587
1573
|
}
|
|
1588
|
-
async
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
if (!this.cachedWorkspaceRoot) throw new Error("Could not find workspace root - ensure you're in a workspace");
|
|
1593
|
-
}
|
|
1594
|
-
const workspaceFile = external_node_path_resolve(this.cachedWorkspaceRoot, "pnpm-workspace.yaml");
|
|
1595
|
-
const stats = await stat(workspaceFile);
|
|
1596
|
-
const currentMtime = stats.mtime.getTime();
|
|
1597
|
-
if (null !== this.catalogCache && this.catalogCacheMtime === currentMtime) return this.catalogCache;
|
|
1598
|
-
const content = await readFile(workspaceFile, "utf-8");
|
|
1599
|
-
const workspace = parse(content);
|
|
1600
|
-
this.catalogCache = workspace.catalog ?? {};
|
|
1601
|
-
this.catalogCacheMtime = currentMtime;
|
|
1602
|
-
return this.catalogCache;
|
|
1603
|
-
} catch (error) {
|
|
1604
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1574
|
+
async getCatalogs() {
|
|
1575
|
+
if (null !== this.catalogsCache) return this.catalogsCache;
|
|
1576
|
+
const workspaceInfo = this.getWorkspaceInfo();
|
|
1577
|
+
if (!workspaceInfo) {
|
|
1605
1578
|
const logger = createEnvLogger("catalog");
|
|
1606
|
-
|
|
1607
|
-
logger.error("Failed to read pnpm catalog: workspace configuration not found");
|
|
1608
|
-
logger.error(" -> Ensure you're in a pnpm workspace with proper configuration");
|
|
1609
|
-
} else if (errorMessage.includes("YAML")) {
|
|
1610
|
-
logger.error("Failed to read pnpm catalog: Invalid YAML syntax in workspace configuration");
|
|
1611
|
-
logger.error(" -> Check workspace configuration file syntax");
|
|
1612
|
-
} else logger.error(`Failed to read pnpm catalog from pnpm-workspace.yaml: ${errorMessage}`);
|
|
1579
|
+
logger.error("Could not find workspace root - ensure you're in a workspace");
|
|
1613
1580
|
return {};
|
|
1614
1581
|
}
|
|
1582
|
+
const { manager, root } = workspaceInfo;
|
|
1583
|
+
if ("pnpm" === manager) this.catalogsCache = await this.readPnpmCatalogs(root);
|
|
1584
|
+
else if ("yarn" === manager) this.catalogsCache = this.readYarnCatalogs(root);
|
|
1585
|
+
else this.catalogsCache = {};
|
|
1586
|
+
return this.catalogsCache;
|
|
1615
1587
|
}
|
|
1616
1588
|
async resolvePackageJson(packageJson, dir = process.cwd()) {
|
|
1617
|
-
const
|
|
1589
|
+
const workspaceInfo = this.getWorkspaceInfo();
|
|
1590
|
+
const loggerName = workspaceInfo?.manager === "yarn" ? "yarn" : "pnpm";
|
|
1591
|
+
const logger = createEnvLogger(loggerName);
|
|
1618
1592
|
try {
|
|
1619
|
-
const
|
|
1620
|
-
const catalogDeps = this.
|
|
1593
|
+
const catalogs = await this.getCatalogs();
|
|
1594
|
+
const catalogDeps = this.collectCatalogDependencies(packageJson);
|
|
1621
1595
|
const workspaceDeps = this.collectDependencies(packageJson, WORKSPACE_PREFIX);
|
|
1622
1596
|
const hasCatalogDeps = catalogDeps.length > 0;
|
|
1623
1597
|
const hasWorkspaceDeps = workspaceDeps.length > 0;
|
|
1624
|
-
if (hasCatalogDeps
|
|
1625
|
-
const
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1598
|
+
if (hasCatalogDeps) {
|
|
1599
|
+
const missingCatalogs = this.findMissingCatalogs(catalogDeps, catalogs);
|
|
1600
|
+
if (missingCatalogs.size > 0) {
|
|
1601
|
+
const available = Object.keys(catalogs).join(", ") || "none";
|
|
1602
|
+
const error = `Catalog(s) not found: ${[
|
|
1603
|
+
...missingCatalogs
|
|
1604
|
+
].join(", ")}. Available: ${available}`;
|
|
1605
|
+
logger.error(error);
|
|
1606
|
+
logger.error(" -> Catalog dependencies found:");
|
|
1607
|
+
for (const { field, dependency, version, catalogName } of catalogDeps)if (missingCatalogs.has(catalogName)) logger.error(` - ${field}.${dependency}: ${version}`);
|
|
1608
|
+
throw new Error(error);
|
|
1609
|
+
}
|
|
1610
|
+
logger.info(`Resolving ${catalogDeps.length} ${CATALOG_PREFIX} dependencies`);
|
|
1630
1611
|
}
|
|
1631
|
-
if (hasCatalogDeps) logger.info(`Resolving ${catalogDeps.length} ${CATALOG_PREFIX} dependencies`);
|
|
1632
1612
|
if (hasWorkspaceDeps) logger.info(`Resolving ${workspaceDeps.length} ${WORKSPACE_PREFIX} dependencies`);
|
|
1633
1613
|
const result = await createExportableManifest(dir, packageJson, {
|
|
1634
|
-
catalogs
|
|
1635
|
-
default: catalog
|
|
1636
|
-
}
|
|
1614
|
+
catalogs
|
|
1637
1615
|
});
|
|
1638
|
-
if (hasCatalogDeps || hasWorkspaceDeps)
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1616
|
+
if (hasCatalogDeps || hasWorkspaceDeps) {
|
|
1617
|
+
const allDeps = [
|
|
1618
|
+
...catalogDeps.map((d)=>({
|
|
1619
|
+
field: d.field,
|
|
1620
|
+
dependency: d.dependency,
|
|
1621
|
+
source: "default" === d.catalogName ? "catalog:" : `catalog:${d.catalogName}`
|
|
1622
|
+
})),
|
|
1623
|
+
...workspaceDeps.map((d)=>({
|
|
1624
|
+
field: d.field,
|
|
1625
|
+
dependency: d.dependency,
|
|
1626
|
+
source: "workspace:"
|
|
1627
|
+
}))
|
|
1628
|
+
];
|
|
1629
|
+
this.logResolvedDependencies(result, allDeps, logger);
|
|
1630
|
+
}
|
|
1642
1631
|
this.validateNoUnresolvedReferences(result, logger);
|
|
1643
1632
|
return result;
|
|
1644
1633
|
} catch (error) {
|
|
1645
1634
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
1646
|
-
if (errorMessage.startsWith("Transformation failed:") || errorMessage.
|
|
1647
|
-
logger.error(`Failed to apply
|
|
1635
|
+
if (errorMessage.startsWith("Transformation failed:") || errorMessage.startsWith("Catalog(s) not found:")) throw error;
|
|
1636
|
+
logger.error(`Failed to apply transformations for directory ${dir}: ${errorMessage}`);
|
|
1648
1637
|
if (errorMessage.includes("catalog")) {
|
|
1649
1638
|
logger.error(` -> Catalog resolution failed - check workspace configuration and ${CATALOG_PREFIX} dependencies`);
|
|
1650
1639
|
throw new Error("Catalog resolution failed");
|
|
@@ -1658,8 +1647,89 @@ class PnpmCatalog {
|
|
|
1658
1647
|
throw new Error(`Manifest processing failed: ${errorMessage}`);
|
|
1659
1648
|
}
|
|
1660
1649
|
logger.error(" -> Cannot proceed with invalid package.json transformations");
|
|
1661
|
-
throw new Error(`
|
|
1650
|
+
throw new Error(`Transformation failed: ${errorMessage}`);
|
|
1651
|
+
}
|
|
1652
|
+
}
|
|
1653
|
+
getWorkspaceInfo() {
|
|
1654
|
+
if (null !== this.cachedWorkspaceInfo) return this.cachedWorkspaceInfo;
|
|
1655
|
+
const info = getWorkspaceManagerAndRoot(process.cwd());
|
|
1656
|
+
this.cachedWorkspaceInfo = info ?? null;
|
|
1657
|
+
return this.cachedWorkspaceInfo;
|
|
1658
|
+
}
|
|
1659
|
+
async readPnpmCatalogs(workspaceRoot) {
|
|
1660
|
+
const lockfileCatalogs = await this.readPnpmLockfileCatalogs(workspaceRoot);
|
|
1661
|
+
if (Object.keys(lockfileCatalogs).length > 0) return lockfileCatalogs;
|
|
1662
|
+
return this.readPnpmWorkspaceCatalogs(workspaceRoot);
|
|
1663
|
+
}
|
|
1664
|
+
async readPnpmLockfileCatalogs(workspaceRoot) {
|
|
1665
|
+
try {
|
|
1666
|
+
const lockfile = await readWantedLockfile(workspaceRoot, {
|
|
1667
|
+
ignoreIncompatible: true
|
|
1668
|
+
});
|
|
1669
|
+
if (!lockfile?.catalogs) return {};
|
|
1670
|
+
return this.convertLockfileCatalogs(lockfile.catalogs);
|
|
1671
|
+
} catch {
|
|
1672
|
+
return {};
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
async readPnpmWorkspaceCatalogs(workspaceRoot) {
|
|
1676
|
+
try {
|
|
1677
|
+
const manifest = await readWorkspaceManifest(workspaceRoot);
|
|
1678
|
+
return getCatalogsFromWorkspaceManifest(manifest);
|
|
1679
|
+
} catch {
|
|
1680
|
+
return {};
|
|
1681
|
+
}
|
|
1682
|
+
}
|
|
1683
|
+
readYarnCatalogs(workspaceRoot) {
|
|
1684
|
+
const catalogs = getCatalogs(workspaceRoot, "yarn");
|
|
1685
|
+
if (!catalogs) return {};
|
|
1686
|
+
return this.convertWorkspaceToolsCatalogs(catalogs);
|
|
1687
|
+
}
|
|
1688
|
+
convertLockfileCatalogs(snapshots) {
|
|
1689
|
+
const result = {};
|
|
1690
|
+
for (const [name, entries] of Object.entries(snapshots)){
|
|
1691
|
+
result[name] = {};
|
|
1692
|
+
for (const [dep, entry] of Object.entries(entries))result[name][dep] = entry.specifier;
|
|
1693
|
+
}
|
|
1694
|
+
return result;
|
|
1695
|
+
}
|
|
1696
|
+
convertWorkspaceToolsCatalogs(catalogs) {
|
|
1697
|
+
const result = {};
|
|
1698
|
+
if (catalogs.default) result.default = {
|
|
1699
|
+
...catalogs.default
|
|
1700
|
+
};
|
|
1701
|
+
if (catalogs.named) for (const [name, catalog] of Object.entries(catalogs.named))result[name] = {
|
|
1702
|
+
...catalog
|
|
1703
|
+
};
|
|
1704
|
+
return result;
|
|
1705
|
+
}
|
|
1706
|
+
collectCatalogDependencies(packageJson) {
|
|
1707
|
+
const deps = [];
|
|
1708
|
+
const fields = [
|
|
1709
|
+
"dependencies",
|
|
1710
|
+
"devDependencies",
|
|
1711
|
+
"peerDependencies",
|
|
1712
|
+
"optionalDependencies"
|
|
1713
|
+
];
|
|
1714
|
+
for (const field of fields){
|
|
1715
|
+
const fieldDeps = packageJson[field];
|
|
1716
|
+
if (fieldDeps) for (const [dependency, version] of Object.entries(fieldDeps)){
|
|
1717
|
+
if ("string" != typeof version || !version.startsWith(CATALOG_PREFIX)) continue;
|
|
1718
|
+
const catalogName = parseCatalogProtocol(version);
|
|
1719
|
+
if (catalogName) deps.push({
|
|
1720
|
+
field,
|
|
1721
|
+
dependency,
|
|
1722
|
+
version,
|
|
1723
|
+
catalogName
|
|
1724
|
+
});
|
|
1725
|
+
}
|
|
1662
1726
|
}
|
|
1727
|
+
return deps;
|
|
1728
|
+
}
|
|
1729
|
+
findMissingCatalogs(deps, catalogs) {
|
|
1730
|
+
const missing = new Set();
|
|
1731
|
+
for (const { catalogName } of deps)if (!catalogs[catalogName]) missing.add(catalogName);
|
|
1732
|
+
return missing;
|
|
1663
1733
|
}
|
|
1664
1734
|
collectDependencies(packageJson, prefix) {
|
|
1665
1735
|
const deps = [];
|
|
@@ -1683,28 +1753,35 @@ class PnpmCatalog {
|
|
|
1683
1753
|
}
|
|
1684
1754
|
logResolvedDependencies(resultPkg, originalDeps, logger) {
|
|
1685
1755
|
const allResolved = {};
|
|
1686
|
-
for (const { field, dependency } of originalDeps){
|
|
1756
|
+
for (const { field, dependency, source } of originalDeps){
|
|
1687
1757
|
const deps = resultPkg[field];
|
|
1688
1758
|
if (deps?.[dependency]) {
|
|
1689
1759
|
if (!allResolved[field]) allResolved[field] = [];
|
|
1690
1760
|
allResolved[field].push({
|
|
1691
1761
|
dependency,
|
|
1692
|
-
version: deps[dependency]
|
|
1762
|
+
version: deps[dependency],
|
|
1763
|
+
source
|
|
1693
1764
|
});
|
|
1694
1765
|
}
|
|
1695
1766
|
}
|
|
1696
1767
|
if (Object.keys(allResolved).length > 0) {
|
|
1697
|
-
logger.info("Resolved dependencies:");
|
|
1768
|
+
logger.global.info("Resolved dependencies:");
|
|
1698
1769
|
for (const [field, deps] of Object.entries(allResolved)){
|
|
1699
|
-
logger.info(`- ${field}:`);
|
|
1700
|
-
for (const { dependency, version } of deps)logger.info(` ${dependency}: ${version}`);
|
|
1770
|
+
logger.global.info(`- ${field}:`);
|
|
1771
|
+
for (const { dependency, version, source } of deps)logger.global.info(` ${dependency}: ${version} (${source})`);
|
|
1701
1772
|
}
|
|
1702
1773
|
}
|
|
1703
1774
|
}
|
|
1704
1775
|
validateNoUnresolvedReferences(resultPkg, logger) {
|
|
1776
|
+
const unresolvedCatalog = this.collectCatalogDependencies(resultPkg);
|
|
1777
|
+
const unresolvedWorkspace = this.collectDependencies(resultPkg, WORKSPACE_PREFIX);
|
|
1705
1778
|
const unresolvedDeps = [
|
|
1706
|
-
...
|
|
1707
|
-
|
|
1779
|
+
...unresolvedCatalog.map((d)=>({
|
|
1780
|
+
field: d.field,
|
|
1781
|
+
dependency: d.dependency,
|
|
1782
|
+
version: d.version
|
|
1783
|
+
})),
|
|
1784
|
+
...unresolvedWorkspace
|
|
1708
1785
|
];
|
|
1709
1786
|
if (unresolvedDeps.length > 0) {
|
|
1710
1787
|
const catalogRefs = unresolvedDeps.filter((dep)=>dep.version.startsWith(CATALOG_PREFIX));
|
|
@@ -1721,10 +1798,8 @@ class PnpmCatalog {
|
|
|
1721
1798
|
}
|
|
1722
1799
|
}
|
|
1723
1800
|
}
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
if (!defaultInstance) defaultInstance = new PnpmCatalog();
|
|
1727
|
-
return defaultInstance;
|
|
1801
|
+
function createWorkspaceCatalog() {
|
|
1802
|
+
return new WorkspaceCatalog();
|
|
1728
1803
|
}
|
|
1729
1804
|
function transformExportPath(path, processTSExports = true, collapseIndex = false) {
|
|
1730
1805
|
let transformedPath = path;
|
|
@@ -1829,8 +1904,9 @@ function applyRslibTransformations(packageJson, originalPackageJson, processTSEx
|
|
|
1829
1904
|
});
|
|
1830
1905
|
return sort_package_json(processedManifest);
|
|
1831
1906
|
}
|
|
1832
|
-
async function applyPnpmTransformations(packageJson, dir = process.cwd()) {
|
|
1833
|
-
|
|
1907
|
+
async function applyPnpmTransformations(packageJson, dir = process.cwd(), catalog) {
|
|
1908
|
+
const workspaceCatalog = catalog ?? createWorkspaceCatalog();
|
|
1909
|
+
return workspaceCatalog.resolvePackageJson(packageJson, dir);
|
|
1834
1910
|
}
|
|
1835
1911
|
async function buildPackageJson(packageJson, isProduction = false, processTSExports = true, entrypoints, exportToOutputMap, bundle, transform) {
|
|
1836
1912
|
let result;
|
|
@@ -1841,12 +1917,9 @@ async function buildPackageJson(packageJson, isProduction = false, processTSExpo
|
|
|
1841
1917
|
if (transform) result = transform(result);
|
|
1842
1918
|
return result;
|
|
1843
1919
|
}
|
|
1844
|
-
const PackageJsonTransformPlugin = (options = {})=>{
|
|
1845
|
-
const cache = new Map();
|
|
1846
|
-
return {
|
|
1920
|
+
const PackageJsonTransformPlugin = (options = {})=>({
|
|
1847
1921
|
name: "package-json-processor",
|
|
1848
1922
|
setup (api) {
|
|
1849
|
-
api.expose("files-cache", cache);
|
|
1850
1923
|
let filesArray = api.useExposed("files-array");
|
|
1851
1924
|
if (!filesArray) {
|
|
1852
1925
|
filesArray = new Set();
|
|
@@ -1895,8 +1968,7 @@ const PackageJsonTransformPlugin = (options = {})=>{
|
|
|
1895
1968
|
}
|
|
1896
1969
|
});
|
|
1897
1970
|
}
|
|
1898
|
-
};
|
|
1899
|
-
};
|
|
1971
|
+
});
|
|
1900
1972
|
class ImportGraph {
|
|
1901
1973
|
options;
|
|
1902
1974
|
sys;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@savvy-web/rslib-builder",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "RSlib-based build system for Node.js libraries with automatic package.json transformation, TypeScript declaration bundling, and multi-target support",
|
|
6
6
|
"keywords": [
|
|
@@ -45,7 +45,11 @@
|
|
|
45
45
|
"dependencies": {
|
|
46
46
|
"@microsoft/tsdoc": "^0.16.0",
|
|
47
47
|
"@microsoft/tsdoc-config": "^0.18.0",
|
|
48
|
+
"@pnpm/catalogs.config": "^1000.0.5",
|
|
49
|
+
"@pnpm/catalogs.protocol-parser": "^1001.0.0",
|
|
48
50
|
"@pnpm/exportable-manifest": "^1000.3.1",
|
|
51
|
+
"@pnpm/lockfile.fs": "^1001.1.29",
|
|
52
|
+
"@pnpm/workspace.read-manifest": "^1000.2.10",
|
|
49
53
|
"@typescript-eslint/parser": "^8.53.1",
|
|
50
54
|
"deep-equal": "^2.2.3",
|
|
51
55
|
"eslint": "^9.39.2",
|
|
@@ -54,8 +58,7 @@
|
|
|
54
58
|
"picocolors": "^1.1.1",
|
|
55
59
|
"sort-package-json": "^3.6.1",
|
|
56
60
|
"tmp": "^0.2.5",
|
|
57
|
-
"workspace-tools": "^0.41.0"
|
|
58
|
-
"yaml": "^2.8.2"
|
|
61
|
+
"workspace-tools": "^0.41.0"
|
|
59
62
|
},
|
|
60
63
|
"peerDependencies": {
|
|
61
64
|
"@microsoft/api-extractor": "^7.55.2",
|