@pnpm/workspace.injected-deps-syncer 1100.0.26 → 1100.0.28
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/CHANGELOG.md +27 -0
- package/lib/DirPatcher.d.ts +66 -0
- package/lib/DirPatcher.js +141 -0
- package/lib/index.d.ts +6 -0
- package/package.json +10 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# @pnpm/workspace.injected-deps-syncer
|
|
2
2
|
|
|
3
|
+
## 1100.0.28
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Republished every package: the tarballs published by the v11.13.1 through v11.16.0 releases were missing most of their compiled files due to a packing bug [#13164](https://github.com/pnpm/pnpm/issues/13164).
|
|
8
|
+
|
|
9
|
+
- Updated dependencies:
|
|
10
|
+
- @pnpm/bins.linker@1100.0.22
|
|
11
|
+
- @pnpm/error@1100.1.0
|
|
12
|
+
- @pnpm/fetching.directory-fetcher@1100.0.25
|
|
13
|
+
- @pnpm/installing.modules-yaml@1100.0.12
|
|
14
|
+
- @pnpm/pkg-manifest.reader@1100.0.12
|
|
15
|
+
- @pnpm/types@1101.6.0
|
|
16
|
+
- @pnpm/workspace.projects-reader@1101.0.19
|
|
17
|
+
|
|
18
|
+
## 1100.0.27
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- Updated dependencies:
|
|
23
|
+
- @pnpm/bins.linker@1100.0.21
|
|
24
|
+
- @pnpm/fetching.directory-fetcher@1100.0.24
|
|
25
|
+
- @pnpm/installing.modules-yaml@1100.0.11
|
|
26
|
+
- @pnpm/pkg-manifest.reader@1100.0.11
|
|
27
|
+
- @pnpm/types@1101.5.0
|
|
28
|
+
- @pnpm/workspace.projects-reader@1101.0.18
|
|
29
|
+
|
|
3
30
|
## 1100.0.26
|
|
4
31
|
|
|
5
32
|
### Patch Changes
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
export declare const DIR: unique symbol;
|
|
3
|
+
export type File = number;
|
|
4
|
+
export type Dir = typeof DIR;
|
|
5
|
+
export type Value = File | Dir;
|
|
6
|
+
export type InodeMap = Record<string, Value>;
|
|
7
|
+
export interface DiffItemBase {
|
|
8
|
+
path: string;
|
|
9
|
+
oldValue?: Value;
|
|
10
|
+
newValue?: Value;
|
|
11
|
+
}
|
|
12
|
+
export interface AddedItem extends DiffItemBase {
|
|
13
|
+
path: string;
|
|
14
|
+
oldValue?: undefined;
|
|
15
|
+
newValue: Value;
|
|
16
|
+
}
|
|
17
|
+
export interface RemovedItem extends DiffItemBase {
|
|
18
|
+
path: string;
|
|
19
|
+
oldValue: Value;
|
|
20
|
+
newValue?: undefined;
|
|
21
|
+
}
|
|
22
|
+
export interface ModifiedItem extends DiffItemBase {
|
|
23
|
+
path: string;
|
|
24
|
+
oldValue: Value;
|
|
25
|
+
newValue: Value;
|
|
26
|
+
}
|
|
27
|
+
export interface DirDiff {
|
|
28
|
+
added: AddedItem[];
|
|
29
|
+
removed: RemovedItem[];
|
|
30
|
+
modified: ModifiedItem[];
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Get the difference between 2 files tree.
|
|
34
|
+
*
|
|
35
|
+
* The arrays in the resulting object are sorted in such a way that every directory paths are placed before
|
|
36
|
+
* the files it contains. This way, it would allow optimization for operations upon this diff.
|
|
37
|
+
* Note that when performing removal of removed files according to this diff, the `removed` array should be reversed first.
|
|
38
|
+
*/
|
|
39
|
+
export declare function diffDir(oldIndex: InodeMap, newIndex: InodeMap): DirDiff;
|
|
40
|
+
/**
|
|
41
|
+
* Apply a patch on a directory.
|
|
42
|
+
*
|
|
43
|
+
* The {@link optimizedDirPatch} is assumed to be already optimized (i.e. `removed` is already reversed).
|
|
44
|
+
*/
|
|
45
|
+
export declare function applyPatch(optimizedDirPatch: DirDiff, sourceDir: string, targetDir: string): Promise<void>;
|
|
46
|
+
export type ExtendFilesMapStats = Pick<fs.Stats, 'ino' | 'isFile' | 'isDirectory'>;
|
|
47
|
+
export interface ExtendFilesMapOptions {
|
|
48
|
+
/** Map relative path of each file to their real path */
|
|
49
|
+
filesMap: Map<string, string>;
|
|
50
|
+
/** Map relative path of each file to their stats */
|
|
51
|
+
filesStats?: Record<string, ExtendFilesMapStats | null>;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Convert a pair of a files index map, which is a map from relative path of each file to their real paths,
|
|
55
|
+
* and an optional file stats map, which is a map from relative path of each file to their stats,
|
|
56
|
+
* into an inodes map, which is a map from relative path of every file and directory to their inode type.
|
|
57
|
+
*/
|
|
58
|
+
export declare function extendFilesMap({ filesMap, filesStats }: ExtendFilesMapOptions): Promise<InodeMap>;
|
|
59
|
+
export declare class DirPatcher {
|
|
60
|
+
private readonly sourceDir;
|
|
61
|
+
private readonly targetDir;
|
|
62
|
+
private readonly patch;
|
|
63
|
+
private constructor();
|
|
64
|
+
static fromMultipleTargets(sourceDir: string, targetDirs: string[]): Promise<DirPatcher[]>;
|
|
65
|
+
apply(): Promise<void>;
|
|
66
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import util from 'node:util';
|
|
4
|
+
import { PnpmError } from '@pnpm/error';
|
|
5
|
+
import { fetchFromDir } from '@pnpm/fetching.directory-fetcher';
|
|
6
|
+
export const DIR = Symbol('Path is a directory');
|
|
7
|
+
// length comparison should place every directory before the files it contains because
|
|
8
|
+
// a directory path is always shorter than any file path it contains
|
|
9
|
+
const comparePaths = (a, b) => (a.split(/\\|\//).length - b.split(/\\|\//).length) || a.localeCompare(b);
|
|
10
|
+
/**
|
|
11
|
+
* Get the difference between 2 files tree.
|
|
12
|
+
*
|
|
13
|
+
* The arrays in the resulting object are sorted in such a way that every directory paths are placed before
|
|
14
|
+
* the files it contains. This way, it would allow optimization for operations upon this diff.
|
|
15
|
+
* Note that when performing removal of removed files according to this diff, the `removed` array should be reversed first.
|
|
16
|
+
*/
|
|
17
|
+
export function diffDir(oldIndex, newIndex) {
|
|
18
|
+
const oldPaths = Object.keys(oldIndex).sort(comparePaths);
|
|
19
|
+
const newPaths = Object.keys(newIndex).sort(comparePaths);
|
|
20
|
+
const removed = oldPaths
|
|
21
|
+
.filter(path => !(path in newIndex))
|
|
22
|
+
.map(path => ({ path, oldValue: oldIndex[path] }));
|
|
23
|
+
const added = newPaths
|
|
24
|
+
.filter(path => !(path in oldIndex))
|
|
25
|
+
.map(path => ({ path, newValue: newIndex[path] }));
|
|
26
|
+
const modified = oldPaths
|
|
27
|
+
.filter(path => path in newIndex && oldIndex[path] !== newIndex[path])
|
|
28
|
+
.map(path => ({ path, oldValue: oldIndex[path], newValue: newIndex[path] }));
|
|
29
|
+
return { added, removed, modified };
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Apply a patch on a directory.
|
|
33
|
+
*
|
|
34
|
+
* The {@link optimizedDirPatch} is assumed to be already optimized (i.e. `removed` is already reversed).
|
|
35
|
+
*/
|
|
36
|
+
export async function applyPatch(optimizedDirPatch, sourceDir, targetDir) {
|
|
37
|
+
async function addRecursive(sourcePath, targetPath, value) {
|
|
38
|
+
if (value === DIR) {
|
|
39
|
+
await fs.promises.mkdir(targetPath, { recursive: true });
|
|
40
|
+
}
|
|
41
|
+
else if (typeof value === 'number') {
|
|
42
|
+
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
|
|
43
|
+
await fs.promises.link(sourcePath, targetPath);
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
const _ = value; // static type guard
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
async function removeRecursive(targetPath) {
|
|
50
|
+
try {
|
|
51
|
+
await fs.promises.rm(targetPath, { recursive: true, force: true });
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
if (!util.types.isNativeError(error) || !('code' in error) || (error.code !== 'ENOENT')) {
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const adding = Promise.all(optimizedDirPatch.added.map(async (item) => {
|
|
60
|
+
const sourcePath = path.join(sourceDir, item.path);
|
|
61
|
+
const targetPath = path.join(targetDir, item.path);
|
|
62
|
+
await addRecursive(sourcePath, targetPath, item.newValue);
|
|
63
|
+
}));
|
|
64
|
+
const removing = Promise.all(optimizedDirPatch.removed.map(async (item) => {
|
|
65
|
+
const targetPath = path.join(targetDir, item.path);
|
|
66
|
+
await removeRecursive(targetPath);
|
|
67
|
+
}));
|
|
68
|
+
const modifying = Promise.all(optimizedDirPatch.modified.map(async (item) => {
|
|
69
|
+
const sourcePath = path.join(sourceDir, item.path);
|
|
70
|
+
const targetPath = path.join(targetDir, item.path);
|
|
71
|
+
if (item.oldValue === item.newValue)
|
|
72
|
+
return;
|
|
73
|
+
await removeRecursive(targetPath);
|
|
74
|
+
await addRecursive(sourcePath, targetPath, item.newValue);
|
|
75
|
+
}));
|
|
76
|
+
await Promise.all([adding, removing, modifying]);
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Convert a pair of a files index map, which is a map from relative path of each file to their real paths,
|
|
80
|
+
* and an optional file stats map, which is a map from relative path of each file to their stats,
|
|
81
|
+
* into an inodes map, which is a map from relative path of every file and directory to their inode type.
|
|
82
|
+
*/
|
|
83
|
+
export async function extendFilesMap({ filesMap, filesStats }) {
|
|
84
|
+
const result = {
|
|
85
|
+
'.': DIR,
|
|
86
|
+
};
|
|
87
|
+
function addInodeAndAncestors(relativePath, value) {
|
|
88
|
+
if (relativePath && relativePath !== '.' && !result[relativePath]) {
|
|
89
|
+
result[relativePath] = value;
|
|
90
|
+
addInodeAndAncestors(path.dirname(relativePath), DIR);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
await Promise.all(Array.from(filesMap.entries()).map(async ([relativePath, realPath]) => {
|
|
94
|
+
const stats = filesStats?.[relativePath] ?? await fs.promises.stat(realPath);
|
|
95
|
+
if (stats.isFile()) {
|
|
96
|
+
addInodeAndAncestors(relativePath, stats.ino);
|
|
97
|
+
}
|
|
98
|
+
else if (stats.isDirectory()) {
|
|
99
|
+
addInodeAndAncestors(relativePath, DIR);
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
throw new PnpmError('UNSUPPORTED_INODE_TYPE', `Filesystem inode at ${realPath} is neither a file, a directory, or a symbolic link`);
|
|
103
|
+
}
|
|
104
|
+
}));
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
export class DirPatcher {
|
|
108
|
+
sourceDir;
|
|
109
|
+
targetDir;
|
|
110
|
+
patch;
|
|
111
|
+
constructor(patch, sourceDir, targetDir) {
|
|
112
|
+
this.patch = patch;
|
|
113
|
+
this.sourceDir = sourceDir;
|
|
114
|
+
this.targetDir = targetDir;
|
|
115
|
+
}
|
|
116
|
+
static async fromMultipleTargets(sourceDir, targetDirs) {
|
|
117
|
+
const fetchOptions = {
|
|
118
|
+
resolveSymlinks: false,
|
|
119
|
+
};
|
|
120
|
+
async function loadMap(dir) {
|
|
121
|
+
const fetchResult = await fetchFromDir(dir, fetchOptions);
|
|
122
|
+
return [await extendFilesMap(fetchResult), dir];
|
|
123
|
+
}
|
|
124
|
+
const [[sourceMap], targetPairs] = await Promise.all([
|
|
125
|
+
loadMap(sourceDir),
|
|
126
|
+
Promise.all(targetDirs.map(loadMap)),
|
|
127
|
+
]);
|
|
128
|
+
return targetPairs.map(([targetMap, targetDir]) => {
|
|
129
|
+
const diff = diffDir(targetMap, sourceMap);
|
|
130
|
+
// Before reversal, every directory in `diff.removed` are placed before its files.
|
|
131
|
+
// After reversal, every file is place before its ancestors,
|
|
132
|
+
// leading to children being deleted before parents, optimizing performance.
|
|
133
|
+
diff.removed.reverse();
|
|
134
|
+
return new this(diff, sourceDir, targetDir);
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
async apply() {
|
|
138
|
+
await applyPatch(this.patch, this.sourceDir, this.targetDir);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=DirPatcher.js.map
|
package/lib/index.d.ts
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pnpm/workspace.injected-deps-syncer",
|
|
3
|
-
"version": "1100.0.
|
|
3
|
+
"version": "1100.0.28",
|
|
4
4
|
"description": "Update all injected replica of a workspace package",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pnpm",
|
|
@@ -27,14 +27,14 @@
|
|
|
27
27
|
"!*.map"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@pnpm/bins.linker": "1100.0.
|
|
31
|
-
"@pnpm/error": "1100.0
|
|
32
|
-
"@pnpm/fetching.directory-fetcher": "1100.0.
|
|
33
|
-
"@pnpm/installing.modules-yaml": "1100.0.
|
|
34
|
-
"@pnpm/pkg-manifest.reader": "1100.0.
|
|
35
|
-
"@pnpm/types": "1101.
|
|
30
|
+
"@pnpm/bins.linker": "1100.0.22",
|
|
31
|
+
"@pnpm/error": "1100.1.0",
|
|
32
|
+
"@pnpm/fetching.directory-fetcher": "1100.0.25",
|
|
33
|
+
"@pnpm/installing.modules-yaml": "1100.0.12",
|
|
34
|
+
"@pnpm/pkg-manifest.reader": "1100.0.12",
|
|
35
|
+
"@pnpm/types": "1101.6.0",
|
|
36
36
|
"@pnpm/util.lex-comparator": "^4.0.1",
|
|
37
|
-
"@pnpm/workspace.projects-reader": "1101.0.
|
|
37
|
+
"@pnpm/workspace.projects-reader": "1101.0.19",
|
|
38
38
|
"@types/normalize-path": "^3.0.2",
|
|
39
39
|
"normalize-path": "^3.0.0"
|
|
40
40
|
},
|
|
@@ -44,8 +44,8 @@
|
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@jest/globals": "30.4.1",
|
|
46
46
|
"@pnpm/logger": "1100.0.0",
|
|
47
|
-
"@pnpm/prepare": "1100.0.
|
|
48
|
-
"@pnpm/workspace.injected-deps-syncer": "1100.0.
|
|
47
|
+
"@pnpm/prepare": "1100.0.22",
|
|
48
|
+
"@pnpm/workspace.injected-deps-syncer": "1100.0.28"
|
|
49
49
|
},
|
|
50
50
|
"engines": {
|
|
51
51
|
"node": ">=22.13"
|