npm-needs-publish 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/comparators/file-content.d.cts +7 -0
- package/dist/cjs/comparators/file-content.d.ts +7 -0
- package/dist/cjs/comparators/file-content.js +33 -2
- package/dist/cjs/comparators/file-content.js.map +1 -1
- package/dist/cjs/comparators/index.d.cts +1 -1
- package/dist/cjs/comparators/index.d.ts +1 -1
- package/dist/cjs/comparators/index.js +3 -0
- package/dist/cjs/comparators/index.js.map +1 -1
- package/dist/cjs/index.d.cts +1 -0
- package/dist/cjs/index.d.ts +1 -0
- package/dist/cjs/index.js +4 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/needs-publish.d.cts +1 -2
- package/dist/cjs/needs-publish.d.ts +1 -2
- package/dist/cjs/needs-publish.js +67 -63
- package/dist/cjs/needs-publish.js.map +1 -1
- package/dist/esm/comparators/file-content.d.ts +7 -0
- package/dist/esm/comparators/file-content.js +17 -2
- package/dist/esm/comparators/file-content.js.map +1 -1
- package/dist/esm/comparators/index.d.ts +1 -1
- package/dist/esm/comparators/index.js +1 -1
- package/dist/esm/comparators/index.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/needs-publish.d.ts +1 -2
- package/dist/esm/needs-publish.js +9 -16
- package/dist/esm/needs-publish.js.map +1 -1
- package/package.json +24 -25
|
@@ -27,3 +27,10 @@ export declare function getFileChangeSummary(changes: FileChange[]): string;
|
|
|
27
27
|
* Check if changes are only in package.json
|
|
28
28
|
*/
|
|
29
29
|
export declare function isOnlyPackageJsonChange(changes: FileChange[]): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Extract package.json from a tarball
|
|
32
|
+
*
|
|
33
|
+
* @param tarball - Tarball as Buffer (gzipped)
|
|
34
|
+
* @returns Parsed package.json object
|
|
35
|
+
*/
|
|
36
|
+
export declare function extractPackageJson(tarball: Buffer): Promise<unknown>;
|
|
@@ -27,3 +27,10 @@ export declare function getFileChangeSummary(changes: FileChange[]): string;
|
|
|
27
27
|
* Check if changes are only in package.json
|
|
28
28
|
*/
|
|
29
29
|
export declare function isOnlyPackageJsonChange(changes: FileChange[]): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Extract package.json from a tarball
|
|
32
|
+
*
|
|
33
|
+
* @param tarball - Tarball as Buffer (gzipped)
|
|
34
|
+
* @returns Parsed package.json object
|
|
35
|
+
*/
|
|
36
|
+
export declare function extractPackageJson(tarball: Buffer): Promise<unknown>;
|
|
@@ -19,6 +19,9 @@ _export(exports, {
|
|
|
19
19
|
get comparePackageFiles () {
|
|
20
20
|
return comparePackageFiles;
|
|
21
21
|
},
|
|
22
|
+
get extractPackageJson () {
|
|
23
|
+
return extractPackageJson;
|
|
24
|
+
},
|
|
22
25
|
get getFileChangeSummary () {
|
|
23
26
|
return getFileChangeSummary;
|
|
24
27
|
},
|
|
@@ -32,7 +35,7 @@ _export(exports, {
|
|
|
32
35
|
var _crypto = /*#__PURE__*/ _interop_require_default(require("crypto"));
|
|
33
36
|
var _module = /*#__PURE__*/ _interop_require_default(require("module"));
|
|
34
37
|
var _stream = require("stream");
|
|
35
|
-
var
|
|
38
|
+
var _util = require("util");
|
|
36
39
|
var _zlib = /*#__PURE__*/ _interop_require_default(require("zlib"));
|
|
37
40
|
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
|
|
38
41
|
try {
|
|
@@ -159,6 +162,7 @@ function _ts_generator(thisArg, body) {
|
|
|
159
162
|
};
|
|
160
163
|
}
|
|
161
164
|
}
|
|
165
|
+
var pipeline = (0, _util.promisify)(_stream.pipeline);
|
|
162
166
|
var _require = typeof require === 'undefined' ? _module.default.createRequire(require("url").pathToFileURL(__filename).toString()) : require;
|
|
163
167
|
// Lazy load tar
|
|
164
168
|
var _tar = null;
|
|
@@ -285,7 +289,7 @@ function comparePackageFiles(localTarball, registryTarball) {
|
|
|
285
289
|
// Process the tarball
|
|
286
290
|
return [
|
|
287
291
|
4,
|
|
288
|
-
|
|
292
|
+
pipeline(_stream.Readable.from(tarball), _zlib.default.createGunzip(), parser)
|
|
289
293
|
];
|
|
290
294
|
case 1:
|
|
291
295
|
_state.sent();
|
|
@@ -341,4 +345,31 @@ function isOnlyPackageJsonChange(changes) {
|
|
|
341
345
|
}
|
|
342
346
|
return true;
|
|
343
347
|
}
|
|
348
|
+
function extractPackageJson(tarball) {
|
|
349
|
+
return _async_to_generator(function() {
|
|
350
|
+
var files, pkgJsonPath;
|
|
351
|
+
return _ts_generator(this, function(_state) {
|
|
352
|
+
switch(_state.label){
|
|
353
|
+
case 0:
|
|
354
|
+
return [
|
|
355
|
+
4,
|
|
356
|
+
extractTarball(tarball)
|
|
357
|
+
];
|
|
358
|
+
case 1:
|
|
359
|
+
files = _state.sent();
|
|
360
|
+
// Look for package.json in the tarball
|
|
361
|
+
pkgJsonPath = Object.keys(files).find(function(p) {
|
|
362
|
+
return p === 'package/package.json' || p.indexOf('/package.json') === p.length - 13;
|
|
363
|
+
});
|
|
364
|
+
if (!pkgJsonPath || !files[pkgJsonPath]) {
|
|
365
|
+
throw new Error('package.json not found in tarball');
|
|
366
|
+
}
|
|
367
|
+
return [
|
|
368
|
+
2,
|
|
369
|
+
JSON.parse(files[pkgJsonPath].toString('utf8'))
|
|
370
|
+
];
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
})();
|
|
374
|
+
}
|
|
344
375
|
/* CJS INTEROP */ if (exports.__esModule && exports.default) { try { Object.defineProperty(exports.default, '__esModule', { value: true }); for (var key in exports) { exports.default[key] = exports[key]; } } catch (_) {}; module.exports = exports.default; }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/npm/npm-needs-publish/src/comparators/file-content.ts"],"sourcesContent":["/**\n * File content comparison for package tarballs\n *\n * Compares files between local and registry tarballs:\n * 1. Fast path: Compare tarball hashes\n * 2. If different: Extract and compare file-by-file\n * 3. Special handling for package.json (semantic comparison elsewhere)\n */\n\nimport crypto from 'crypto';\nimport Module from 'module';\nimport { Readable } from 'stream';\nimport { pipeline } from 'stream/promises';\nimport zlib from 'zlib';\nimport type { FileChange, FileComparison } from '../types.ts';\n\nconst _require = typeof require === 'undefined' ? Module.createRequire(import.meta.url) : require;\n\n// Lazy load tar\nlet _tar: typeof import('tar') | null = null;\n\nfunction getTar(): typeof import('tar') {\n if (!_tar) {\n _tar = _require('tar');\n }\n return _tar;\n}\n\n/**\n * Compare package files from two tarballs\n *\n * @param localTarball - Local package tarball as Buffer\n * @param registryTarball - Registry package tarball as Buffer\n * @returns File comparison result\n */\nexport async function comparePackageFiles(localTarball: Buffer, registryTarball: Buffer): Promise<FileComparison> {\n // Fast path: identical tarballs\n const localHash = hashBuffer(localTarball);\n const registryHash = hashBuffer(registryTarball);\n\n if (localHash === registryHash) {\n return {\n identical: true,\n fileChanges: [],\n packageJsonOnly: false,\n };\n }\n\n // Extract both tarballs to memory\n const localFiles = await extractTarball(localTarball);\n const registryFiles = await extractTarball(registryTarball);\n\n const changes: FileChange[] = [];\n\n // Build combined set of all paths\n const allPaths: Record<string, boolean> = {};\n const localKeys = Object.keys(localFiles);\n for (let i = 0; i < localKeys.length; i++) {\n allPaths[localKeys[i]] = true;\n }\n const registryKeys = Object.keys(registryFiles);\n for (let i = 0; i < registryKeys.length; i++) {\n allPaths[registryKeys[i]] = true;\n }\n\n let onlyPackageJsonDiffers = true;\n\n const pathKeys = Object.keys(allPaths);\n for (let i = 0; i < pathKeys.length; i++) {\n const filePath = pathKeys[i];\n const isPackageJson = filePath === 'package/package.json' || filePath.indexOf('/package.json') === filePath.length - 13;\n const localContent = localFiles[filePath];\n const registryContent = registryFiles[filePath];\n\n if (!registryContent) {\n // File added\n changes.push({ path: filePath, action: 'added' });\n if (!isPackageJson) onlyPackageJsonDiffers = false;\n } else if (!localContent) {\n // File removed\n changes.push({ path: filePath, action: 'removed' });\n if (!isPackageJson) onlyPackageJsonDiffers = false;\n } else if (!buffersEqual(localContent, registryContent)) {\n // File modified\n changes.push({ path: filePath, action: 'modified' });\n if (!isPackageJson) onlyPackageJsonDiffers = false;\n }\n }\n\n return {\n identical: changes.length === 0,\n fileChanges: changes,\n packageJsonOnly: onlyPackageJsonDiffers && changes.length > 0,\n };\n}\n\n/**\n * Extract tarball contents to memory\n *\n * @param tarball - Tarball as Buffer (gzipped)\n * @returns Map of file paths to content buffers\n */\nasync function extractTarball(tarball: Buffer): Promise<Record<string, Buffer>> {\n const files: Record<string, Buffer> = {};\n const tar = getTar();\n\n // Create a parser that collects file contents\n const parser = new tar.Parser({\n onReadEntry: (entry) => {\n if (entry.type === 'File') {\n const chunks: Buffer[] = [];\n\n entry.on('data', (chunk: Buffer) => {\n chunks.push(chunk);\n });\n\n entry.on('end', () => {\n files[entry.path] = Buffer.concat(chunks);\n });\n } else {\n // Drain non-file entries (directories, etc.)\n entry.resume();\n }\n },\n });\n\n // Process the tarball\n await pipeline(Readable.from(tarball), zlib.createGunzip(), parser);\n\n return files;\n}\n\n/**\n * Hash a buffer using SHA-512\n */\nexport function hashBuffer(buffer: Buffer): string {\n return crypto.createHash('sha512').update(buffer).digest('base64');\n}\n\n/**\n * Compare two buffers for equality\n */\nfunction buffersEqual(a: Buffer, b: Buffer): boolean {\n if (a.length !== b.length) return false;\n return crypto.timingSafeEqual(a, b);\n}\n\n/**\n * Get a summary of file changes\n */\nexport function getFileChangeSummary(changes: FileChange[]): string {\n if (changes.length === 0) {\n return 'No file changes';\n }\n\n const added = changes.filter((c) => c.action === 'added');\n const removed = changes.filter((c) => c.action === 'removed');\n const modified = changes.filter((c) => c.action === 'modified');\n\n const parts: string[] = [];\n\n if (added.length > 0) {\n parts.push(`${added.length} added`);\n }\n if (removed.length > 0) {\n parts.push(`${removed.length} removed`);\n }\n if (modified.length > 0) {\n parts.push(`${modified.length} modified`);\n }\n\n return `Files: ${parts.join(', ')} (${changes.length} total)`;\n}\n\n/**\n * Check if changes are only in package.json\n */\nexport function isOnlyPackageJsonChange(changes: FileChange[]): boolean {\n if (changes.length === 0) return false;\n\n for (let i = 0; i < changes.length; i++) {\n const path = changes[i].path;\n if (path !== 'package/package.json' && path.indexOf('/package.json') !== path.length - 13) {\n return false;\n }\n }\n return true;\n}\n"],"names":["comparePackageFiles","getFileChangeSummary","hashBuffer","isOnlyPackageJsonChange","_require","require","Module","createRequire","_tar","getTar","localTarball","registryTarball","localHash","registryHash","localFiles","registryFiles","changes","allPaths","localKeys","i","registryKeys","onlyPackageJsonDiffers","pathKeys","filePath","isPackageJson","localContent","registryContent","identical","fileChanges","packageJsonOnly","extractTarball","Object","keys","length","indexOf","push","path","action","buffersEqual","tarball","files","tar","parser","Parser","onReadEntry","entry","type","chunks","on","chunk","Buffer","concat","resume","pipeline","Readable","from","zlib","createGunzip","buffer","crypto","createHash","update","digest","a","b","timingSafeEqual","added","filter","c","removed","modified","parts","join"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/npm/npm-needs-publish/src/comparators/file-content.ts"],"sourcesContent":["/**\n * File content comparison for package tarballs\n *\n * Compares files between local and registry tarballs:\n * 1. Fast path: Compare tarball hashes\n * 2. If different: Extract and compare file-by-file\n * 3. Special handling for package.json (semantic comparison elsewhere)\n */\n\nimport crypto from 'crypto';\nimport Module from 'module';\nimport { pipeline as pipelineCb, Readable } from 'stream';\nimport { promisify } from 'util';\nimport zlib from 'zlib';\n\nconst pipeline = promisify(pipelineCb);\n\nimport type { FileChange, FileComparison } from '../types.ts';\n\nconst _require = typeof require === 'undefined' ? Module.createRequire(import.meta.url) : require;\n\n// Lazy load tar\nlet _tar: typeof import('tar') | null = null;\n\nfunction getTar(): typeof import('tar') {\n if (!_tar) {\n _tar = _require('tar');\n }\n return _tar;\n}\n\n/**\n * Compare package files from two tarballs\n *\n * @param localTarball - Local package tarball as Buffer\n * @param registryTarball - Registry package tarball as Buffer\n * @returns File comparison result\n */\nexport async function comparePackageFiles(localTarball: Buffer, registryTarball: Buffer): Promise<FileComparison> {\n // Fast path: identical tarballs\n const localHash = hashBuffer(localTarball);\n const registryHash = hashBuffer(registryTarball);\n\n if (localHash === registryHash) {\n return {\n identical: true,\n fileChanges: [],\n packageJsonOnly: false,\n };\n }\n\n // Extract both tarballs to memory\n const localFiles = await extractTarball(localTarball);\n const registryFiles = await extractTarball(registryTarball);\n\n const changes: FileChange[] = [];\n\n // Build combined set of all paths\n const allPaths: Record<string, boolean> = {};\n const localKeys = Object.keys(localFiles);\n for (let i = 0; i < localKeys.length; i++) {\n allPaths[localKeys[i]] = true;\n }\n const registryKeys = Object.keys(registryFiles);\n for (let i = 0; i < registryKeys.length; i++) {\n allPaths[registryKeys[i]] = true;\n }\n\n let onlyPackageJsonDiffers = true;\n\n const pathKeys = Object.keys(allPaths);\n for (let i = 0; i < pathKeys.length; i++) {\n const filePath = pathKeys[i];\n const isPackageJson = filePath === 'package/package.json' || filePath.indexOf('/package.json') === filePath.length - 13;\n const localContent = localFiles[filePath];\n const registryContent = registryFiles[filePath];\n\n if (!registryContent) {\n // File added\n changes.push({ path: filePath, action: 'added' });\n if (!isPackageJson) onlyPackageJsonDiffers = false;\n } else if (!localContent) {\n // File removed\n changes.push({ path: filePath, action: 'removed' });\n if (!isPackageJson) onlyPackageJsonDiffers = false;\n } else if (!buffersEqual(localContent, registryContent)) {\n // File modified\n changes.push({ path: filePath, action: 'modified' });\n if (!isPackageJson) onlyPackageJsonDiffers = false;\n }\n }\n\n return {\n identical: changes.length === 0,\n fileChanges: changes,\n packageJsonOnly: onlyPackageJsonDiffers && changes.length > 0,\n };\n}\n\n/**\n * Extract tarball contents to memory\n *\n * @param tarball - Tarball as Buffer (gzipped)\n * @returns Map of file paths to content buffers\n */\nasync function extractTarball(tarball: Buffer): Promise<Record<string, Buffer>> {\n const files: Record<string, Buffer> = {};\n const tar = getTar();\n\n // Create a parser that collects file contents\n const parser = new tar.Parser({\n onReadEntry: (entry) => {\n if (entry.type === 'File') {\n const chunks: Buffer[] = [];\n\n entry.on('data', (chunk: Buffer) => {\n chunks.push(chunk);\n });\n\n entry.on('end', () => {\n files[entry.path] = Buffer.concat(chunks);\n });\n } else {\n // Drain non-file entries (directories, etc.)\n entry.resume();\n }\n },\n });\n\n // Process the tarball\n await pipeline(Readable.from(tarball), zlib.createGunzip(), parser);\n\n return files;\n}\n\n/**\n * Hash a buffer using SHA-512\n */\nexport function hashBuffer(buffer: Buffer): string {\n return crypto.createHash('sha512').update(buffer).digest('base64');\n}\n\n/**\n * Compare two buffers for equality\n */\nfunction buffersEqual(a: Buffer, b: Buffer): boolean {\n if (a.length !== b.length) return false;\n return crypto.timingSafeEqual(a, b);\n}\n\n/**\n * Get a summary of file changes\n */\nexport function getFileChangeSummary(changes: FileChange[]): string {\n if (changes.length === 0) {\n return 'No file changes';\n }\n\n const added = changes.filter((c) => c.action === 'added');\n const removed = changes.filter((c) => c.action === 'removed');\n const modified = changes.filter((c) => c.action === 'modified');\n\n const parts: string[] = [];\n\n if (added.length > 0) {\n parts.push(`${added.length} added`);\n }\n if (removed.length > 0) {\n parts.push(`${removed.length} removed`);\n }\n if (modified.length > 0) {\n parts.push(`${modified.length} modified`);\n }\n\n return `Files: ${parts.join(', ')} (${changes.length} total)`;\n}\n\n/**\n * Check if changes are only in package.json\n */\nexport function isOnlyPackageJsonChange(changes: FileChange[]): boolean {\n if (changes.length === 0) return false;\n\n for (let i = 0; i < changes.length; i++) {\n const path = changes[i].path;\n if (path !== 'package/package.json' && path.indexOf('/package.json') !== path.length - 13) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Extract package.json from a tarball\n *\n * @param tarball - Tarball as Buffer (gzipped)\n * @returns Parsed package.json object\n */\nexport async function extractPackageJson(tarball: Buffer): Promise<unknown> {\n const files = await extractTarball(tarball);\n\n // Look for package.json in the tarball\n const pkgJsonPath = Object.keys(files).find((p) => p === 'package/package.json' || p.indexOf('/package.json') === p.length - 13);\n\n if (!pkgJsonPath || !files[pkgJsonPath]) {\n throw new Error('package.json not found in tarball');\n }\n\n return JSON.parse(files[pkgJsonPath].toString('utf8'));\n}\n"],"names":["comparePackageFiles","extractPackageJson","getFileChangeSummary","hashBuffer","isOnlyPackageJsonChange","pipeline","promisify","pipelineCb","_require","require","Module","createRequire","_tar","getTar","localTarball","registryTarball","localHash","registryHash","localFiles","registryFiles","changes","allPaths","localKeys","i","registryKeys","onlyPackageJsonDiffers","pathKeys","filePath","isPackageJson","localContent","registryContent","identical","fileChanges","packageJsonOnly","extractTarball","Object","keys","length","indexOf","push","path","action","buffersEqual","tarball","files","tar","parser","Parser","onReadEntry","entry","type","chunks","on","chunk","Buffer","concat","resume","Readable","from","zlib","createGunzip","buffer","crypto","createHash","update","digest","a","b","timingSafeEqual","added","filter","c","removed","modified","parts","join","pkgJsonPath","find","p","Error","JSON","parse","toString"],"mappings":"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"}
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
* Comparators - Core comparison logic for npm-needs-publish
|
|
3
3
|
*/
|
|
4
4
|
export { compareDependencies, getDependencyChangeSummary, hasSignificantDependencyChanges, } from './dependency.js';
|
|
5
|
-
export { comparePackageFiles, getFileChangeSummary, hashBuffer, isOnlyPackageJsonChange, } from './file-content.js';
|
|
5
|
+
export { comparePackageFiles, extractPackageJson, getFileChangeSummary, hashBuffer, isOnlyPackageJsonChange, } from './file-content.js';
|
|
6
6
|
export { comparePackageJson, isSignificantField, } from './package-json.js';
|
|
7
7
|
export { compareVersionSpecifiers, comparisonToSemanticChange, parseVersionSpecifier, type SemanticChangeOptions, } from './version-specifier.js';
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
* Comparators - Core comparison logic for npm-needs-publish
|
|
3
3
|
*/
|
|
4
4
|
export { compareDependencies, getDependencyChangeSummary, hasSignificantDependencyChanges, } from './dependency.js';
|
|
5
|
-
export { comparePackageFiles, getFileChangeSummary, hashBuffer, isOnlyPackageJsonChange, } from './file-content.js';
|
|
5
|
+
export { comparePackageFiles, extractPackageJson, getFileChangeSummary, hashBuffer, isOnlyPackageJsonChange, } from './file-content.js';
|
|
6
6
|
export { comparePackageJson, isSignificantField, } from './package-json.js';
|
|
7
7
|
export { compareVersionSpecifiers, comparisonToSemanticChange, parseVersionSpecifier, type SemanticChangeOptions, } from './version-specifier.js';
|
|
@@ -26,6 +26,9 @@ _export(exports, {
|
|
|
26
26
|
get comparisonToSemanticChange () {
|
|
27
27
|
return _versionspecifierts.comparisonToSemanticChange;
|
|
28
28
|
},
|
|
29
|
+
get extractPackageJson () {
|
|
30
|
+
return _filecontentts.extractPackageJson;
|
|
31
|
+
},
|
|
29
32
|
get getDependencyChangeSummary () {
|
|
30
33
|
return _dependencyts.getDependencyChangeSummary;
|
|
31
34
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/npm/npm-needs-publish/src/comparators/index.ts"],"sourcesContent":["/**\n * Comparators - Core comparison logic for npm-needs-publish\n */\n\nexport {\n compareDependencies,\n getDependencyChangeSummary,\n hasSignificantDependencyChanges,\n} from './dependency.ts';\nexport {\n comparePackageFiles,\n getFileChangeSummary,\n hashBuffer,\n isOnlyPackageJsonChange,\n} from './file-content.ts';\n\nexport {\n comparePackageJson,\n isSignificantField,\n} from './package-json.ts';\nexport {\n compareVersionSpecifiers,\n comparisonToSemanticChange,\n parseVersionSpecifier,\n type SemanticChangeOptions,\n} from './version-specifier.ts';\n"],"names":["compareDependencies","comparePackageFiles","comparePackageJson","compareVersionSpecifiers","comparisonToSemanticChange","getDependencyChangeSummary","getFileChangeSummary","hasSignificantDependencyChanges","hashBuffer","isOnlyPackageJsonChange","isSignificantField","parseVersionSpecifier"],"mappings":"AAAA;;CAEC;;;;;;;;;;;QAGCA;eAAAA,iCAAmB;;QAKnBC;eAAAA,kCAAmB;;
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/npm/npm-needs-publish/src/comparators/index.ts"],"sourcesContent":["/**\n * Comparators - Core comparison logic for npm-needs-publish\n */\n\nexport {\n compareDependencies,\n getDependencyChangeSummary,\n hasSignificantDependencyChanges,\n} from './dependency.ts';\nexport {\n comparePackageFiles,\n extractPackageJson,\n getFileChangeSummary,\n hashBuffer,\n isOnlyPackageJsonChange,\n} from './file-content.ts';\n\nexport {\n comparePackageJson,\n isSignificantField,\n} from './package-json.ts';\nexport {\n compareVersionSpecifiers,\n comparisonToSemanticChange,\n parseVersionSpecifier,\n type SemanticChangeOptions,\n} from './version-specifier.ts';\n"],"names":["compareDependencies","comparePackageFiles","comparePackageJson","compareVersionSpecifiers","comparisonToSemanticChange","extractPackageJson","getDependencyChangeSummary","getFileChangeSummary","hasSignificantDependencyChanges","hashBuffer","isOnlyPackageJsonChange","isSignificantField","parseVersionSpecifier"],"mappings":"AAAA;;CAEC;;;;;;;;;;;QAGCA;eAAAA,iCAAmB;;QAKnBC;eAAAA,kCAAmB;;QAQnBC;eAAAA,iCAAkB;;QAIlBC;eAAAA,4CAAwB;;QACxBC;eAAAA,8CAA0B;;QAZ1BC;eAAAA,iCAAkB;;QALlBC;eAAAA,wCAA0B;;QAM1BC;eAAAA,mCAAoB;;QALpBC;eAAAA,6CAA+B;;QAM/BC;eAAAA,yBAAU;;QACVC;eAAAA,sCAAuB;;QAKvBC;eAAAA,iCAAkB;;QAKlBC;eAAAA,yCAAqB;;;4BAhBhB;6BAOA;6BAKA;kCAMA"}
|
package/dist/cjs/index.d.cts
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
* ```
|
|
19
19
|
*/
|
|
20
20
|
export { compareDependencies } from './comparators/dependency.js';
|
|
21
|
+
export { extractPackageJson } from './comparators/file-content.js';
|
|
21
22
|
export { comparePackageJson } from './comparators/package-json.js';
|
|
22
23
|
export { compareVersionSpecifiers, comparisonToSemanticChange, parseVersionSpecifier, type SemanticChangeOptions } from './comparators/version-specifier.js';
|
|
23
24
|
export { type NeedsPublishCallback, needsPublish, needsPublishCb } from './needs-publish.js';
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
* ```
|
|
19
19
|
*/
|
|
20
20
|
export { compareDependencies } from './comparators/dependency.js';
|
|
21
|
+
export { extractPackageJson } from './comparators/file-content.js';
|
|
21
22
|
export { comparePackageJson } from './comparators/package-json.js';
|
|
22
23
|
export { compareVersionSpecifiers, comparisonToSemanticChange, parseVersionSpecifier, type SemanticChangeOptions } from './comparators/version-specifier.js';
|
|
23
24
|
export { type NeedsPublishCallback, needsPublish, needsPublishCb } from './needs-publish.js';
|
package/dist/cjs/index.js
CHANGED
|
@@ -40,6 +40,9 @@ _export(exports, {
|
|
|
40
40
|
get comparisonToSemanticChange () {
|
|
41
41
|
return _versionspecifierts.comparisonToSemanticChange;
|
|
42
42
|
},
|
|
43
|
+
get extractPackageJson () {
|
|
44
|
+
return _filecontentts.extractPackageJson;
|
|
45
|
+
},
|
|
43
46
|
get needsPublish () {
|
|
44
47
|
return _needspublishts.needsPublish;
|
|
45
48
|
},
|
|
@@ -51,6 +54,7 @@ _export(exports, {
|
|
|
51
54
|
}
|
|
52
55
|
});
|
|
53
56
|
var _dependencyts = require("./comparators/dependency.js");
|
|
57
|
+
var _filecontentts = require("./comparators/file-content.js");
|
|
54
58
|
var _packagejsonts = require("./comparators/package-json.js");
|
|
55
59
|
var _versionspecifierts = require("./comparators/version-specifier.js");
|
|
56
60
|
var _needspublishts = require("./needs-publish.js");
|
package/dist/cjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/npm/npm-needs-publish/src/index.ts"],"sourcesContent":["/**\n * npm-needs-publish\n *\n * Smart publish detection for npm packages - semantic package.json comparison\n * with semver-aware dependency analysis\n *\n * @example\n * ```typescript\n * import { needsPublish } from 'npm-needs-publish';\n *\n * const result = await needsPublish({ cwd: process.cwd() });\n * if (result.needsPublish) {\n * console.log('Publish needed:', result.reason);\n * // Proceed with npm publish\n * } else {\n * console.log('No publish needed:', result.reason);\n * }\n * ```\n */\n\n// Comparators\nexport { compareDependencies } from './comparators/dependency.ts';\nexport { comparePackageJson } from './comparators/package-json.ts';\nexport { compareVersionSpecifiers, comparisonToSemanticChange, parseVersionSpecifier, type SemanticChangeOptions } from './comparators/version-specifier.ts';\n// Main API\nexport { type NeedsPublishCallback, needsPublish, needsPublishCb } from './needs-publish.ts';\n\n// Types\nexport type {\n ChangeDetail,\n CompareOptions,\n CompareSpecifierOptions,\n DependencyChange,\n DependencyCompareOptions,\n DependencyComparison,\n FieldChange,\n FileChange,\n FileComparison,\n NeedsPublishOptions,\n NeedsPublishResult,\n PackageJson,\n PackageJsonComparison,\n ParsedVersionSpecifier,\n SemanticChange,\n SpecifierComparison,\n VersionSpecifierType,\n} from './types.ts';\n"],"names":["compareDependencies","comparePackageJson","compareVersionSpecifiers","comparisonToSemanticChange","needsPublish","needsPublishCb","parseVersionSpecifier"],"mappings":"AAAA;;;;;;;;;;;;;;;;;;CAkBC,GAED,cAAc;;;;;;;;;;;;QACLA;eAAAA,iCAAmB;;
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/npm/npm-needs-publish/src/index.ts"],"sourcesContent":["/**\n * npm-needs-publish\n *\n * Smart publish detection for npm packages - semantic package.json comparison\n * with semver-aware dependency analysis\n *\n * @example\n * ```typescript\n * import { needsPublish } from 'npm-needs-publish';\n *\n * const result = await needsPublish({ cwd: process.cwd() });\n * if (result.needsPublish) {\n * console.log('Publish needed:', result.reason);\n * // Proceed with npm publish\n * } else {\n * console.log('No publish needed:', result.reason);\n * }\n * ```\n */\n\n// Comparators\nexport { compareDependencies } from './comparators/dependency.ts';\nexport { extractPackageJson } from './comparators/file-content.ts';\nexport { comparePackageJson } from './comparators/package-json.ts';\nexport { compareVersionSpecifiers, comparisonToSemanticChange, parseVersionSpecifier, type SemanticChangeOptions } from './comparators/version-specifier.ts';\n// Main API\nexport { type NeedsPublishCallback, needsPublish, needsPublishCb } from './needs-publish.ts';\n\n// Types\nexport type {\n ChangeDetail,\n CompareOptions,\n CompareSpecifierOptions,\n DependencyChange,\n DependencyCompareOptions,\n DependencyComparison,\n FieldChange,\n FileChange,\n FileComparison,\n NeedsPublishOptions,\n NeedsPublishResult,\n PackageJson,\n PackageJsonComparison,\n ParsedVersionSpecifier,\n SemanticChange,\n SpecifierComparison,\n VersionSpecifierType,\n} from './types.ts';\n"],"names":["compareDependencies","comparePackageJson","compareVersionSpecifiers","comparisonToSemanticChange","extractPackageJson","needsPublish","needsPublishCb","parseVersionSpecifier"],"mappings":"AAAA;;;;;;;;;;;;;;;;;;CAkBC,GAED,cAAc;;;;;;;;;;;;QACLA;eAAAA,iCAAmB;;QAEnBC;eAAAA,iCAAkB;;QAClBC;eAAAA,4CAAwB;;QAAEC;eAAAA,8CAA0B;;QAFpDC;eAAAA,iCAAkB;;QAISC;eAAAA,4BAAY;;QAAEC;eAAAA,8BAAc;;QAFDC;eAAAA,yCAAqB;;;4BAHhD;6BACD;6BACA;kCACqF;8BAEhD"}
|
|
@@ -15,8 +15,7 @@ import type { NeedsPublishOptions, NeedsPublishResult } from './types.js';
|
|
|
15
15
|
*/
|
|
16
16
|
export type NeedsPublishCallback = (error: Error | null, result?: NeedsPublishResult) => void;
|
|
17
17
|
/**
|
|
18
|
-
* Callback-based needsPublish
|
|
19
|
-
* Uses worker for older Node versions, runs locally on Node 14+
|
|
18
|
+
* Callback-based needsPublish
|
|
20
19
|
*/
|
|
21
20
|
export declare function needsPublishCb(options: NeedsPublishOptions, callback: NeedsPublishCallback): void;
|
|
22
21
|
/**
|
|
@@ -15,8 +15,7 @@ import type { NeedsPublishOptions, NeedsPublishResult } from './types.js';
|
|
|
15
15
|
*/
|
|
16
16
|
export type NeedsPublishCallback = (error: Error | null, result?: NeedsPublishResult) => void;
|
|
17
17
|
/**
|
|
18
|
-
* Callback-based needsPublish
|
|
19
|
-
* Uses worker for older Node versions, runs locally on Node 14+
|
|
18
|
+
* Callback-based needsPublish
|
|
20
19
|
*/
|
|
21
20
|
export declare function needsPublishCb(options: NeedsPublishOptions, callback: NeedsPublishCallback): void;
|
|
22
21
|
/**
|
|
@@ -29,8 +29,6 @@ _export(exports, {
|
|
|
29
29
|
var _fs = /*#__PURE__*/ _interop_require_default(require("fs"));
|
|
30
30
|
var _module = /*#__PURE__*/ _interop_require_default(require("module"));
|
|
31
31
|
var _path = /*#__PURE__*/ _interop_require_default(require("path"));
|
|
32
|
-
var _tsdslib = require("tsds-lib");
|
|
33
|
-
var _url = /*#__PURE__*/ _interop_require_default(require("url"));
|
|
34
32
|
var _compatts = require("./compat.js");
|
|
35
33
|
function _array_like_to_array(arr, len) {
|
|
36
34
|
if (len == null || len > arr.length) len = arr.length;
|
|
@@ -251,16 +249,8 @@ function _ts_generator(thisArg, body) {
|
|
|
251
249
|
};
|
|
252
250
|
}
|
|
253
251
|
}
|
|
254
|
-
// Version check for worker pattern - use worker for Node < 14
|
|
255
|
-
var major = +process.versions.node.split('.')[0];
|
|
256
|
-
var version = major > 14 ? 'local' : 'stable';
|
|
257
252
|
var _require = typeof require === 'undefined' ? _module.default.createRequire(require("url").pathToFileURL(__filename).toString()) : require;
|
|
258
|
-
|
|
259
|
-
var dist = _path.default.join(__dirname, '..');
|
|
260
|
-
var workerWrapper = (0, _tsdslib.wrapWorker)(_path.default.join(dist, 'cjs', 'needs-publish.js'));
|
|
261
|
-
/**
|
|
262
|
-
* Worker function that runs on Node 14+
|
|
263
|
-
*/ function worker(options, callback) {
|
|
253
|
+
function needsPublishImpl(options, callback) {
|
|
264
254
|
var cwd = options.cwd || process.cwd();
|
|
265
255
|
// Load local package.json
|
|
266
256
|
var localPkg = options.package || JSON.parse(_fs.default.readFileSync(_path.default.join(cwd, 'package.json'), 'utf8'));
|
|
@@ -274,7 +264,7 @@ var workerWrapper = (0, _tsdslib.wrapWorker)(_path.default.join(dist, 'cjs', 'ne
|
|
|
274
264
|
}
|
|
275
265
|
(function() {
|
|
276
266
|
return _async_to_generator(function() {
|
|
277
|
-
var pacote, Arborist, npa, execFile, promisify, execFileAsync, _ref, comparePackageFiles, comparePackageJson, hashBuffer, registry, scope, stdout, e, registryPkg, registryTarball, _packument_disttags, _registryPkg_dist, _registryPkg_dist1, packument, latestVersion, tarballUrl, err, error, localTarball, spec, manifest, err1, error1, localHash, registryHash, fileComparison, pkgJsonComparison, changes;
|
|
267
|
+
var pacote, Arborist, npa, execFile, promisify, execFileAsync, _ref, comparePackageFiles, comparePackageJson, extractPackageJson, hashBuffer, registry, scope, stdout, e, registryPkg, registryTarball, _packument_disttags, _registryPkg_dist, _registryPkg_dist1, packument, latestVersion, tarballUrl, err, error, localTarball, spec, manifest, err1, error1, localHash, registryHash, fileComparison, localTarballPkg, registryTarballPkg, pkgJsonComparison, changes;
|
|
278
268
|
return _ts_generator(this, function(_state) {
|
|
279
269
|
switch(_state.label){
|
|
280
270
|
case 0:
|
|
@@ -291,7 +281,7 @@ var workerWrapper = (0, _tsdslib.wrapWorker)(_path.default.join(dist, 'cjs', 'ne
|
|
|
291
281
|
})
|
|
292
282
|
];
|
|
293
283
|
case 1:
|
|
294
|
-
_ref = _state.sent(), comparePackageFiles = _ref.comparePackageFiles, comparePackageJson = _ref.comparePackageJson, hashBuffer = _ref.hashBuffer;
|
|
284
|
+
_ref = _state.sent(), comparePackageFiles = _ref.comparePackageFiles, comparePackageJson = _ref.comparePackageJson, extractPackageJson = _ref.extractPackageJson, hashBuffer = _ref.hashBuffer;
|
|
295
285
|
// Get registry URL for scoped packages
|
|
296
286
|
registry = options.registry;
|
|
297
287
|
if (!!registry) return [
|
|
@@ -511,61 +501,75 @@ var workerWrapper = (0, _tsdslib.wrapWorker)(_path.default.join(dist, 'cjs', 'ne
|
|
|
511
501
|
2
|
|
512
502
|
];
|
|
513
503
|
}
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
2
|
|
538
|
-
];
|
|
539
|
-
}
|
|
540
|
-
// Build changes list
|
|
541
|
-
changes = _to_consumable_array(pkgJsonComparison.fieldChanges.map(function(fc) {
|
|
542
|
-
return {
|
|
543
|
-
type: 'field',
|
|
544
|
-
field: fc.field,
|
|
545
|
-
oldValue: fc.oldValue,
|
|
546
|
-
newValue: fc.newValue,
|
|
547
|
-
significance: fc.significance
|
|
548
|
-
};
|
|
549
|
-
})).concat(_to_consumable_array(pkgJsonComparison.dependencyChanges.filter(function(dc) {
|
|
550
|
-
return dc.semanticChange !== 'equivalent' && dc.semanticChange !== 'none';
|
|
551
|
-
}).map(function(dc) {
|
|
552
|
-
return {
|
|
553
|
-
type: 'dependency',
|
|
554
|
-
field: "".concat(dc.type, ".").concat(dc.name),
|
|
555
|
-
oldValue: dc.oldSpec,
|
|
556
|
-
newValue: dc.newSpec,
|
|
557
|
-
significance: 'significant'
|
|
558
|
-
};
|
|
559
|
-
})));
|
|
504
|
+
if (!(fileComparison.packageJsonOnly && !options.packageJsonOnly)) return [
|
|
505
|
+
3,
|
|
506
|
+
17
|
|
507
|
+
];
|
|
508
|
+
return [
|
|
509
|
+
4,
|
|
510
|
+
extractPackageJson(localTarball)
|
|
511
|
+
];
|
|
512
|
+
case 15:
|
|
513
|
+
localTarballPkg = _state.sent();
|
|
514
|
+
return [
|
|
515
|
+
4,
|
|
516
|
+
extractPackageJson(registryTarball)
|
|
517
|
+
];
|
|
518
|
+
case 16:
|
|
519
|
+
registryTarballPkg = _state.sent();
|
|
520
|
+
pkgJsonComparison = comparePackageJson(localTarballPkg, registryTarballPkg, {
|
|
521
|
+
includeOptionalDeps: options.includeOptionalDeps,
|
|
522
|
+
additionalSignificantFields: options.additionalSignificantFields,
|
|
523
|
+
ignoreFields: options.ignoreFields,
|
|
524
|
+
treatNarrowingAsEquivalent: options.treatNarrowingAsEquivalent
|
|
525
|
+
});
|
|
526
|
+
if (!pkgJsonComparison.hasSignificantChanges) {
|
|
560
527
|
callback(null, {
|
|
561
|
-
needsPublish:
|
|
562
|
-
reason:
|
|
563
|
-
changes:
|
|
528
|
+
needsPublish: false,
|
|
529
|
+
reason: 'Package.json changes are not significant for consumers',
|
|
530
|
+
changes: pkgJsonComparison.fieldChanges.map(function(fc) {
|
|
531
|
+
return {
|
|
532
|
+
type: 'field',
|
|
533
|
+
field: fc.field,
|
|
534
|
+
oldValue: fc.oldValue,
|
|
535
|
+
newValue: fc.newValue,
|
|
536
|
+
significance: 'informational'
|
|
537
|
+
};
|
|
538
|
+
})
|
|
564
539
|
});
|
|
565
540
|
return [
|
|
566
541
|
2
|
|
567
542
|
];
|
|
568
543
|
}
|
|
544
|
+
// Build changes list
|
|
545
|
+
changes = _to_consumable_array(pkgJsonComparison.fieldChanges.map(function(fc) {
|
|
546
|
+
return {
|
|
547
|
+
type: 'field',
|
|
548
|
+
field: fc.field,
|
|
549
|
+
oldValue: fc.oldValue,
|
|
550
|
+
newValue: fc.newValue,
|
|
551
|
+
significance: fc.significance
|
|
552
|
+
};
|
|
553
|
+
})).concat(_to_consumable_array(pkgJsonComparison.dependencyChanges.filter(function(dc) {
|
|
554
|
+
return dc.semanticChange !== 'equivalent' && dc.semanticChange !== 'none';
|
|
555
|
+
}).map(function(dc) {
|
|
556
|
+
return {
|
|
557
|
+
type: 'dependency',
|
|
558
|
+
field: "".concat(dc.type, ".").concat(dc.name),
|
|
559
|
+
oldValue: dc.oldSpec,
|
|
560
|
+
newValue: dc.newSpec,
|
|
561
|
+
significance: 'significant'
|
|
562
|
+
};
|
|
563
|
+
})));
|
|
564
|
+
callback(null, {
|
|
565
|
+
needsPublish: true,
|
|
566
|
+
reason: pkgJsonComparison.summary,
|
|
567
|
+
changes: changes
|
|
568
|
+
});
|
|
569
|
+
return [
|
|
570
|
+
2
|
|
571
|
+
];
|
|
572
|
+
case 17:
|
|
569
573
|
// Step 7: Other files changed
|
|
570
574
|
callback(null, {
|
|
571
575
|
needsPublish: true,
|
|
@@ -587,7 +591,7 @@ var workerWrapper = (0, _tsdslib.wrapWorker)(_path.default.join(dist, 'cjs', 'ne
|
|
|
587
591
|
})().catch(callback);
|
|
588
592
|
}
|
|
589
593
|
function needsPublishCb(options, callback) {
|
|
590
|
-
|
|
594
|
+
needsPublishImpl(options, callback);
|
|
591
595
|
}
|
|
592
596
|
function needsPublish() {
|
|
593
597
|
var options = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/npm/npm-needs-publish/src/needs-publish.ts"],"sourcesContent":["/**\n * Main orchestration logic for npm-needs-publish\n *\n * Algorithm:\n * 1. Fetch registry packument → if E404, return needsPublish=true (first publish)\n * 2. Version check → if different, return needsPublish=true (intentional bump)\n * 3. Fast hash check → if identical, return needsPublish=false (no changes)\n * 4. Extract both tarballs, compare file-by-file (excluding package.json)\n * 5. If non-package.json files differ → return needsPublish=true\n * 6. If only package.json differs → do semantic comparison\n */\n\nimport fs from 'fs';\nimport Module from 'module';\nimport path from 'path';\nimport { wrapWorker } from 'tsds-lib';\nimport url from 'url';\nimport { stringStartsWith } from './compat.ts';\nimport type { ChangeDetail, NeedsPublishOptions, NeedsPublishResult, PackageJson } from './types.ts';\n\n// Version check for worker pattern - use worker for Node < 14\nconst major = +process.versions.node.split('.')[0];\nconst version = major > 14 ? 'local' : 'stable';\nconst _require = typeof require === 'undefined' ? Module.createRequire(import.meta.url) : require;\nconst __dirname = path.dirname(typeof __filename === 'undefined' ? url.fileURLToPath(import.meta.url) : __filename);\nconst dist = path.join(__dirname, '..');\nconst workerWrapper = wrapWorker(path.join(dist, 'cjs', 'needs-publish.js'));\n\n/**\n * Callback type for needsPublish\n */\nexport type NeedsPublishCallback = (error: Error | null, result?: NeedsPublishResult) => void;\n\n/**\n * Worker function that runs on Node 14+\n */\nfunction worker(options: NeedsPublishOptions, callback: NeedsPublishCallback): undefined {\n const cwd = options.cwd || process.cwd();\n\n // Load local package.json\n const localPkg: PackageJson = options.package || JSON.parse(fs.readFileSync(path.join(cwd, 'package.json'), 'utf8'));\n\n // Skip private packages\n if (localPkg.private) {\n callback(null, {\n needsPublish: false,\n reason: 'Package is private',\n });\n return;\n }\n\n (async () => {\n const pacote = _require('pacote');\n const Arborist = _require('@npmcli/arborist');\n const npa = _require('npm-package-arg');\n const { execFile } = _require('child_process');\n const { promisify } = _require('util');\n const execFileAsync = promisify(execFile);\n\n // Dynamic import for comparators (they use modern features)\n const { comparePackageFiles, comparePackageJson, hashBuffer } = await import('./comparators/index.ts');\n\n // Get registry URL for scoped packages\n let registry: string | undefined = options.registry;\n if (!registry) {\n const scope = stringStartsWith(localPkg.name, '@') ? localPkg.name.split('/')[0] : undefined;\n if (scope) {\n try {\n const { stdout } = await execFileAsync('npm', ['config', 'get', `${scope}:registry`]);\n registry = stdout.trim();\n if (registry === 'undefined') registry = undefined;\n } catch {\n // Fallback to default registry\n }\n }\n }\n\n // Step 1: Try to fetch registry packument\n let registryPkg: PackageJson;\n let registryTarball: Buffer;\n\n try {\n const packument = await pacote.packument(localPkg.name, {\n Arborist,\n ...(registry && { registry }),\n });\n\n const latestVersion = packument['dist-tags']?.latest;\n if (!latestVersion) {\n callback(null, {\n needsPublish: true,\n reason: 'No latest version found in registry (first publish)',\n changes: [{ type: 'first-publish', significance: 'critical' }],\n });\n return;\n }\n\n registryPkg = packument.versions[latestVersion] as unknown as PackageJson;\n\n // Step 2: Version comparison (fast path)\n if (localPkg.version !== latestVersion) {\n callback(null, {\n needsPublish: true,\n reason: `Version differs (local: ${localPkg.version}, registry: ${latestVersion})`,\n changes: [\n {\n type: 'version',\n field: 'version',\n oldValue: latestVersion,\n newValue: localPkg.version,\n significance: 'critical',\n },\n ],\n });\n return;\n }\n\n // Fetch registry tarball for comparison\n const tarballUrl = registryPkg.dist?.tarball;\n if (!tarballUrl) {\n callback(null, {\n needsPublish: true,\n reason: 'Registry package has no tarball URL',\n changes: [{ type: 'first-publish', significance: 'critical' }],\n });\n return;\n }\n\n registryTarball = await pacote.tarball(tarballUrl, {\n Arborist,\n integrity: registryPkg.dist?.integrity,\n });\n } catch (err: unknown) {\n const error = err as { code?: string; message?: string };\n // Package not found in registry (first publish)\n if (error.code === 'E404') {\n callback(null, {\n needsPublish: true,\n reason: 'Package not found in registry (first publish)',\n changes: [{ type: 'first-publish', significance: 'critical' }],\n });\n return;\n }\n // Unknown error - assume changed to be safe\n callback(null, {\n needsPublish: true,\n reason: `Error checking registry: ${error.message || 'Unknown error'}`,\n });\n return;\n }\n\n // Step 3: Pack local package\n let localTarball: Buffer;\n try {\n const spec = npa(cwd);\n const manifest = await pacote.manifest(spec, { Arborist });\n localTarball = await pacote.tarball(manifest._resolved, {\n Arborist,\n integrity: manifest._integrity,\n });\n } catch (err: unknown) {\n const error = err as { message?: string };\n callback(null, {\n needsPublish: true,\n reason: `Error packing local package: ${error.message || 'Unknown error'}`,\n });\n return;\n }\n\n // Step 4: Fast hash comparison\n const localHash = hashBuffer(localTarball);\n const registryHash = hashBuffer(registryTarball);\n\n if (localHash === registryHash) {\n callback(null, {\n needsPublish: false,\n reason: `No changes detected (hash: ${localHash.substring(0, 16)}...)`,\n });\n return;\n }\n\n // Step 5: File-by-file comparison\n const fileComparison = await comparePackageFiles(localTarball, registryTarball);\n\n if (fileComparison.identical) {\n // Hash mismatch but files identical - likely tarball metadata difference\n callback(null, {\n needsPublish: false,\n reason: 'Files identical (tarball metadata differs)',\n });\n return;\n }\n\n // Step 6: If only package.json differs, do semantic comparison\n if (fileComparison.packageJsonOnly && !options.packageJsonOnly) {\n const pkgJsonComparison = comparePackageJson(localPkg, registryPkg, {\n includeOptionalDeps: options.includeOptionalDeps,\n additionalSignificantFields: options.additionalSignificantFields,\n ignoreFields: options.ignoreFields,\n treatNarrowingAsEquivalent: options.treatNarrowingAsEquivalent,\n });\n\n if (!pkgJsonComparison.hasSignificantChanges) {\n callback(null, {\n needsPublish: false,\n reason: 'Package.json changes are not significant for consumers',\n changes: pkgJsonComparison.fieldChanges.map((fc) => ({\n type: 'field' as const,\n field: fc.field,\n oldValue: fc.oldValue,\n newValue: fc.newValue,\n significance: 'informational' as const,\n })),\n });\n return;\n }\n\n // Build changes list\n const changes: ChangeDetail[] = [\n ...pkgJsonComparison.fieldChanges.map((fc) => ({\n type: 'field' as const,\n field: fc.field,\n oldValue: fc.oldValue,\n newValue: fc.newValue,\n significance: fc.significance,\n })),\n ...pkgJsonComparison.dependencyChanges\n .filter((dc) => dc.semanticChange !== 'equivalent' && dc.semanticChange !== 'none')\n .map((dc) => ({\n type: 'dependency' as const,\n field: `${dc.type}.${dc.name}`,\n oldValue: dc.oldSpec,\n newValue: dc.newSpec,\n significance: 'significant' as const,\n })),\n ];\n\n callback(null, {\n needsPublish: true,\n reason: pkgJsonComparison.summary,\n changes,\n });\n return;\n }\n\n // Step 7: Other files changed\n callback(null, {\n needsPublish: true,\n reason: `Code changes detected (${fileComparison.fileChanges.length} files changed)`,\n changes: fileComparison.fileChanges.map((fc) => ({\n type: 'file' as const,\n field: fc.path,\n significance: 'significant' as const,\n })),\n });\n })().catch(callback);\n}\n\n/**\n * Callback-based needsPublish - works on Node 0.8+\n * Uses worker for older Node versions, runs locally on Node 14+\n */\nexport function needsPublishCb(options: NeedsPublishOptions, callback: NeedsPublishCallback): void {\n version !== 'local' ? workerWrapper(version, options, callback) : worker(options, callback);\n}\n\n/**\n * Determine if a package needs to be published to npm.\n *\n * @example\n * ```ts\n * import { needsPublish } from 'npm-needs-publish';\n *\n * const result = await needsPublish({ cwd: process.cwd() });\n * if (result.needsPublish) {\n * console.log('Publish needed:', result.reason);\n * }\n * ```\n */\nexport function needsPublish(options: NeedsPublishOptions = {}): Promise<NeedsPublishResult> {\n return new Promise((resolve, reject) => {\n needsPublishCb(options, (error, result) => {\n if (error) reject(error);\n else if (result) resolve(result);\n else reject(new Error('No result returned'));\n });\n });\n}\n"],"names":["needsPublish","needsPublishCb","major","process","versions","node","split","version","_require","require","Module","createRequire","__dirname","path","dirname","__filename","url","fileURLToPath","dist","join","workerWrapper","wrapWorker","worker","options","callback","cwd","localPkg","package","JSON","parse","fs","readFileSync","private","reason","pacote","Arborist","npa","execFile","promisify","execFileAsync","comparePackageFiles","comparePackageJson","hashBuffer","registry","scope","stdout","registryPkg","registryTarball","packument","latestVersion","tarballUrl","err","error","localTarball","spec","manifest","localHash","registryHash","fileComparison","pkgJsonComparison","changes","stringStartsWith","name","undefined","trim","latest","type","significance","field","oldValue","newValue","tarball","integrity","code","message","_resolved","_integrity","substring","identical","packageJsonOnly","includeOptionalDeps","additionalSignificantFields","ignoreFields","treatNarrowingAsEquivalent","hasSignificantChanges","fieldChanges","map","fc","dependencyChanges","filter","dc","semanticChange","oldSpec","newSpec","summary","fileChanges","length","catch","Promise","resolve","reject","result","Error"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/npm/npm-needs-publish/src/needs-publish.ts"],"sourcesContent":["/**\n * Main orchestration logic for npm-needs-publish\n *\n * Algorithm:\n * 1. Fetch registry packument → if E404, return needsPublish=true (first publish)\n * 2. Version check → if different, return needsPublish=true (intentional bump)\n * 3. Fast hash check → if identical, return needsPublish=false (no changes)\n * 4. Extract both tarballs, compare file-by-file (excluding package.json)\n * 5. If non-package.json files differ → return needsPublish=true\n * 6. If only package.json differs → do semantic comparison\n */\n\nimport fs from 'fs';\nimport Module from 'module';\nimport path from 'path';\nimport { stringStartsWith } from './compat.ts';\nimport type { ChangeDetail, NeedsPublishOptions, NeedsPublishResult, PackageJson } from './types.ts';\n\nconst _require = typeof require === 'undefined' ? Module.createRequire(import.meta.url) : require;\n\n/**\n * Callback type for needsPublish\n */\nexport type NeedsPublishCallback = (error: Error | null, result?: NeedsPublishResult) => void;\n\nfunction needsPublishImpl(options: NeedsPublishOptions, callback: NeedsPublishCallback): undefined {\n const cwd = options.cwd || process.cwd();\n\n // Load local package.json\n const localPkg: PackageJson = options.package || JSON.parse(fs.readFileSync(path.join(cwd, 'package.json'), 'utf8'));\n\n // Skip private packages\n if (localPkg.private) {\n callback(null, {\n needsPublish: false,\n reason: 'Package is private',\n });\n return;\n }\n\n (async () => {\n const pacote = _require('pacote');\n const Arborist = _require('@npmcli/arborist');\n const npa = _require('npm-package-arg');\n const { execFile } = _require('child_process');\n const { promisify } = _require('util');\n const execFileAsync = promisify(execFile);\n\n // Dynamic import for comparators (they use modern features)\n const { comparePackageFiles, comparePackageJson, extractPackageJson, hashBuffer } = await import('./comparators/index.ts');\n\n // Get registry URL for scoped packages\n let registry: string | undefined = options.registry;\n if (!registry) {\n const scope = stringStartsWith(localPkg.name, '@') ? localPkg.name.split('/')[0] : undefined;\n if (scope) {\n try {\n const { stdout } = await execFileAsync('npm', ['config', 'get', `${scope}:registry`]);\n registry = stdout.trim();\n if (registry === 'undefined') registry = undefined;\n } catch {\n // Fallback to default registry\n }\n }\n }\n\n // Step 1: Try to fetch registry packument\n let registryPkg: PackageJson;\n let registryTarball: Buffer;\n\n try {\n const packument = await pacote.packument(localPkg.name, {\n Arborist,\n ...(registry && { registry }),\n });\n\n const latestVersion = packument['dist-tags']?.latest;\n if (!latestVersion) {\n callback(null, {\n needsPublish: true,\n reason: 'No latest version found in registry (first publish)',\n changes: [{ type: 'first-publish', significance: 'critical' }],\n });\n return;\n }\n\n registryPkg = packument.versions[latestVersion] as unknown as PackageJson;\n\n // Step 2: Version comparison (fast path)\n if (localPkg.version !== latestVersion) {\n callback(null, {\n needsPublish: true,\n reason: `Version differs (local: ${localPkg.version}, registry: ${latestVersion})`,\n changes: [\n {\n type: 'version',\n field: 'version',\n oldValue: latestVersion,\n newValue: localPkg.version,\n significance: 'critical',\n },\n ],\n });\n return;\n }\n\n // Fetch registry tarball for comparison\n const tarballUrl = registryPkg.dist?.tarball;\n if (!tarballUrl) {\n callback(null, {\n needsPublish: true,\n reason: 'Registry package has no tarball URL',\n changes: [{ type: 'first-publish', significance: 'critical' }],\n });\n return;\n }\n\n registryTarball = await pacote.tarball(tarballUrl, {\n Arborist,\n integrity: registryPkg.dist?.integrity,\n });\n } catch (err: unknown) {\n const error = err as { code?: string; message?: string };\n // Package not found in registry (first publish)\n if (error.code === 'E404') {\n callback(null, {\n needsPublish: true,\n reason: 'Package not found in registry (first publish)',\n changes: [{ type: 'first-publish', significance: 'critical' }],\n });\n return;\n }\n // Unknown error - assume changed to be safe\n callback(null, {\n needsPublish: true,\n reason: `Error checking registry: ${error.message || 'Unknown error'}`,\n });\n return;\n }\n\n // Step 3: Pack local package\n let localTarball: Buffer;\n try {\n const spec = npa(cwd);\n const manifest = await pacote.manifest(spec, { Arborist });\n localTarball = await pacote.tarball(manifest._resolved, {\n Arborist,\n integrity: manifest._integrity,\n });\n } catch (err: unknown) {\n const error = err as { message?: string };\n callback(null, {\n needsPublish: true,\n reason: `Error packing local package: ${error.message || 'Unknown error'}`,\n });\n return;\n }\n\n // Step 4: Fast hash comparison\n const localHash = hashBuffer(localTarball);\n const registryHash = hashBuffer(registryTarball);\n\n if (localHash === registryHash) {\n callback(null, {\n needsPublish: false,\n reason: `No changes detected (hash: ${localHash.substring(0, 16)}...)`,\n });\n return;\n }\n\n // Step 5: File-by-file comparison\n const fileComparison = await comparePackageFiles(localTarball, registryTarball);\n\n if (fileComparison.identical) {\n // Hash mismatch but files identical - likely tarball metadata difference\n callback(null, {\n needsPublish: false,\n reason: 'Files identical (tarball metadata differs)',\n });\n return;\n }\n\n // Step 6: If only package.json differs, do semantic comparison\n if (fileComparison.packageJsonOnly && !options.packageJsonOnly) {\n // Extract package.json from both tarballs for accurate comparison\n // (packument metadata is missing fields like 'files')\n const localTarballPkg = (await extractPackageJson(localTarball)) as PackageJson;\n const registryTarballPkg = (await extractPackageJson(registryTarball)) as PackageJson;\n\n const pkgJsonComparison = comparePackageJson(localTarballPkg, registryTarballPkg, {\n includeOptionalDeps: options.includeOptionalDeps,\n additionalSignificantFields: options.additionalSignificantFields,\n ignoreFields: options.ignoreFields,\n treatNarrowingAsEquivalent: options.treatNarrowingAsEquivalent,\n });\n\n if (!pkgJsonComparison.hasSignificantChanges) {\n callback(null, {\n needsPublish: false,\n reason: 'Package.json changes are not significant for consumers',\n changes: pkgJsonComparison.fieldChanges.map((fc) => ({\n type: 'field' as const,\n field: fc.field,\n oldValue: fc.oldValue,\n newValue: fc.newValue,\n significance: 'informational' as const,\n })),\n });\n return;\n }\n\n // Build changes list\n const changes: ChangeDetail[] = [\n ...pkgJsonComparison.fieldChanges.map((fc) => ({\n type: 'field' as const,\n field: fc.field,\n oldValue: fc.oldValue,\n newValue: fc.newValue,\n significance: fc.significance,\n })),\n ...pkgJsonComparison.dependencyChanges\n .filter((dc) => dc.semanticChange !== 'equivalent' && dc.semanticChange !== 'none')\n .map((dc) => ({\n type: 'dependency' as const,\n field: `${dc.type}.${dc.name}`,\n oldValue: dc.oldSpec,\n newValue: dc.newSpec,\n significance: 'significant' as const,\n })),\n ];\n\n callback(null, {\n needsPublish: true,\n reason: pkgJsonComparison.summary,\n changes,\n });\n return;\n }\n\n // Step 7: Other files changed\n callback(null, {\n needsPublish: true,\n reason: `Code changes detected (${fileComparison.fileChanges.length} files changed)`,\n changes: fileComparison.fileChanges.map((fc) => ({\n type: 'file' as const,\n field: fc.path,\n significance: 'significant' as const,\n })),\n });\n })().catch(callback);\n}\n\n/**\n * Callback-based needsPublish\n */\nexport function needsPublishCb(options: NeedsPublishOptions, callback: NeedsPublishCallback): void {\n needsPublishImpl(options, callback);\n}\n\n/**\n * Determine if a package needs to be published to npm.\n *\n * @example\n * ```ts\n * import { needsPublish } from 'npm-needs-publish';\n *\n * const result = await needsPublish({ cwd: process.cwd() });\n * if (result.needsPublish) {\n * console.log('Publish needed:', result.reason);\n * }\n * ```\n */\nexport function needsPublish(options: NeedsPublishOptions = {}): Promise<NeedsPublishResult> {\n return new Promise((resolve, reject) => {\n needsPublishCb(options, (error, result) => {\n if (error) reject(error);\n else if (result) resolve(result);\n else reject(new Error('No result returned'));\n });\n });\n}\n"],"names":["needsPublish","needsPublishCb","_require","require","Module","createRequire","needsPublishImpl","options","callback","cwd","process","localPkg","package","JSON","parse","fs","readFileSync","path","join","private","reason","pacote","Arborist","npa","execFile","promisify","execFileAsync","comparePackageFiles","comparePackageJson","extractPackageJson","hashBuffer","registry","scope","stdout","registryPkg","registryTarball","packument","latestVersion","tarballUrl","err","error","localTarball","spec","manifest","localHash","registryHash","fileComparison","localTarballPkg","registryTarballPkg","pkgJsonComparison","changes","stringStartsWith","name","split","undefined","trim","latest","type","significance","versions","version","field","oldValue","newValue","dist","tarball","integrity","code","message","_resolved","_integrity","substring","identical","packageJsonOnly","includeOptionalDeps","additionalSignificantFields","ignoreFields","treatNarrowingAsEquivalent","hasSignificantChanges","fieldChanges","map","fc","dependencyChanges","filter","dc","semanticChange","oldSpec","newSpec","summary","fileChanges","length","catch","Promise","resolve","reject","result","Error"],"mappings":"AAAA;;;;;;;;;;CAUC;;;;;;;;;;;QAsQeA;eAAAA;;QAjBAC;eAAAA;;;yDAnPD;6DACI;2DACF;wBACgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGjC,IAAMC,WAAW,OAAOC,YAAY,cAAcC,eAAM,CAACC,aAAa,CAAC,uDAAmBF;AAO1F,SAASG,iBAAiBC,OAA4B,EAAEC,QAA8B;IACpF,IAAMC,MAAMF,QAAQE,GAAG,IAAIC,QAAQD,GAAG;IAEtC,0BAA0B;IAC1B,IAAME,WAAwBJ,QAAQK,OAAO,IAAIC,KAAKC,KAAK,CAACC,WAAE,CAACC,YAAY,CAACC,aAAI,CAACC,IAAI,CAACT,KAAK,iBAAiB;IAE5G,wBAAwB;IACxB,IAAIE,SAASQ,OAAO,EAAE;QACpBX,SAAS,MAAM;YACbR,cAAc;YACdoB,QAAQ;QACV;QACA;IACF;IAEC,CAAA;;gBACOC,QACAC,UACAC,KACEC,UACAC,WACFC,eAG8E,MAA5EC,qBAAqBC,oBAAoBC,oBAAoBC,YAGjEC,UAEIC,OAGMC,WAUVC,aACAC,iBAQoBC,qBA+BHF,mBAYNA,oBAhDPE,WAKAC,eA+BAC,YAcCC,KACDC,OAmBJC,cAEIC,MACAC,UAKCJ,MACDC,QASFI,WACAC,cAWAC,gBAeEC,iBACAC,oBAEAC,mBAuBAC;;;;wBA3KF7B,SAASnB,SAAS;wBAClBoB,WAAWpB,SAAS;wBACpBqB,MAAMrB,SAAS;wBACbsB,WAAatB,SAAS,iBAAtBsB;wBACAC,YAAcvB,SAAS,QAAvBuB;wBACFC,gBAAgBD,UAAUD;wBAGoD;;4BAAM;+EAAA,QAAO;;;;wBAAb,OAAA,eAA5EG,sBAA4E,KAA5EA,qBAAqBC,qBAAuD,KAAvDA,oBAAoBC,qBAAmC,KAAnCA,oBAAoBC,aAAe,KAAfA;wBAErE,uCAAuC;wBACnCC,WAA+BxB,QAAQwB,QAAQ;6BAC/C,CAACA,UAAD;;;;wBACIC,QAAQmB,IAAAA,0BAAgB,EAACxC,SAASyC,IAAI,EAAE,OAAOzC,SAASyC,IAAI,CAACC,KAAK,CAAC,IAAI,CAAC,EAAE,GAAGC;6BAC/EtB,OAAAA;;;;;;;;;;;;wBAEmB;;4BAAMN,cAAc;gCAAQ;gCAAU;gCAAQ,GAAQ,OAANM,OAAM;;;;wBAAjEC,SAAW,cAAXA;wBACRF,WAAWE,OAAOsB,IAAI;wBACtB,IAAIxB,aAAa,aAAaA,WAAWuB;;;;;;;;;;;;;;;;;;wBAY3B;;4BAAMjC,OAAOe,SAAS,CAACzB,SAASyC,IAAI,EAAE;gCACtD9B,UAAAA;+BACIS,YAAY;gCAAEA,UAAAA;4BAAS;;;wBAFvBK,YAAY;wBAKZC,iBAAgBD,sBAAAA,SAAS,CAAC,YAAY,cAAtBA,0CAAAA,oBAAwBoB,MAAM;wBACpD,IAAI,CAACnB,eAAe;4BAClB7B,SAAS,MAAM;gCACbR,cAAc;gCACdoB,QAAQ;gCACR8B,OAAO;oCAAG;wCAAEO,MAAM;wCAAiBC,cAAc;oCAAW;;4BAC9D;4BACA;;;wBACF;wBAEAxB,cAAcE,UAAUuB,QAAQ,CAACtB,cAAc;wBAE/C,yCAAyC;wBACzC,IAAI1B,SAASiD,OAAO,KAAKvB,eAAe;4BACtC7B,SAAS,MAAM;gCACbR,cAAc;gCACdoB,QAAQ,AAAC,2BAAyDiB,OAA/B1B,SAASiD,OAAO,EAAC,gBAA4B,OAAdvB,eAAc;gCAChFa,OAAO;oCACL;wCACEO,MAAM;wCACNI,OAAO;wCACPC,UAAUzB;wCACV0B,UAAUpD,SAASiD,OAAO;wCAC1BF,cAAc;oCAChB;;4BAEJ;4BACA;;;wBACF;wBAEA,wCAAwC;wBAClCpB,cAAaJ,oBAAAA,YAAY8B,IAAI,cAAhB9B,wCAAAA,kBAAkB+B,OAAO;wBAC5C,IAAI,CAAC3B,YAAY;4BACf9B,SAAS,MAAM;gCACbR,cAAc;gCACdoB,QAAQ;gCACR8B,OAAO;oCAAG;wCAAEO,MAAM;wCAAiBC,cAAc;oCAAW;;4BAC9D;4BACA;;;wBACF;wBAEkB;;4BAAMrC,OAAO4C,OAAO,CAAC3B,YAAY;gCACjDhB,UAAAA;gCACA4C,SAAS,GAAEhC,qBAAAA,YAAY8B,IAAI,cAAhB9B,yCAAAA,mBAAkBgC,SAAS;4BACxC;;;wBAHA/B,kBAAkB;;;;;;wBAIXI;wBACDC,QAAQD;wBACd,gDAAgD;wBAChD,IAAIC,MAAM2B,IAAI,KAAK,QAAQ;4BACzB3D,SAAS,MAAM;gCACbR,cAAc;gCACdoB,QAAQ;gCACR8B,OAAO;oCAAG;wCAAEO,MAAM;wCAAiBC,cAAc;oCAAW;;4BAC9D;4BACA;;;wBACF;wBACA,4CAA4C;wBAC5ClD,SAAS,MAAM;4BACbR,cAAc;4BACdoB,QAAQ,AAAC,4BAA4D,OAAjCoB,MAAM4B,OAAO,IAAI;wBACvD;wBACA;;;;;;;;;;wBAMM1B,OAAOnB,IAAId;wBACA;;4BAAMY,OAAOsB,QAAQ,CAACD,MAAM;gCAAEpB,UAAAA;4BAAS;;;wBAAlDqB,WAAW;wBACF;;4BAAMtB,OAAO4C,OAAO,CAACtB,SAAS0B,SAAS,EAAE;gCACtD/C,UAAAA;gCACA4C,WAAWvB,SAAS2B,UAAU;4BAChC;;;wBAHA7B,eAAe;;;;;;wBAIRF;wBACDC,SAAQD;wBACd/B,SAAS,MAAM;4BACbR,cAAc;4BACdoB,QAAQ,AAAC,gCAAgE,OAAjCoB,OAAM4B,OAAO,IAAI;wBAC3D;wBACA;;;;wBAGF,+BAA+B;wBACzBxB,YAAYd,WAAWW;wBACvBI,eAAef,WAAWK;wBAEhC,IAAIS,cAAcC,cAAc;4BAC9BrC,SAAS,MAAM;gCACbR,cAAc;gCACdoB,QAAQ,AAAC,8BAAwD,OAA3BwB,UAAU2B,SAAS,CAAC,GAAG,KAAI;4BACnE;4BACA;;;wBACF;wBAGuB;;4BAAM5C,oBAAoBc,cAAcN;;;wBAAzDW,iBAAiB;wBAEvB,IAAIA,eAAe0B,SAAS,EAAE;4BAC5B,yEAAyE;4BACzEhE,SAAS,MAAM;gCACbR,cAAc;gCACdoB,QAAQ;4BACV;4BACA;;;wBACF;6BAGI0B,CAAAA,eAAe2B,eAAe,IAAI,CAAClE,QAAQkE,eAAe,AAAD,GAAzD3B;;;;wBAGuB;;4BAAMjB,mBAAmBY;;;wBAA5CM,kBAAmB;wBACG;;4BAAMlB,mBAAmBM;;;wBAA/Ca,qBAAsB;wBAEtBC,oBAAoBrB,mBAAmBmB,iBAAiBC,oBAAoB;4BAChF0B,qBAAqBnE,QAAQmE,mBAAmB;4BAChDC,6BAA6BpE,QAAQoE,2BAA2B;4BAChEC,cAAcrE,QAAQqE,YAAY;4BAClCC,4BAA4BtE,QAAQsE,0BAA0B;wBAChE;wBAEA,IAAI,CAAC5B,kBAAkB6B,qBAAqB,EAAE;4BAC5CtE,SAAS,MAAM;gCACbR,cAAc;gCACdoB,QAAQ;gCACR8B,SAASD,kBAAkB8B,YAAY,CAACC,GAAG,CAAC,SAACC;2CAAQ;wCACnDxB,MAAM;wCACNI,OAAOoB,GAAGpB,KAAK;wCACfC,UAAUmB,GAAGnB,QAAQ;wCACrBC,UAAUkB,GAAGlB,QAAQ;wCACrBL,cAAc;oCAChB;;4BACF;4BACA;;;wBACF;wBAEA,qBAAqB;wBACfR,UAA0B,AAC9B,qBAAGD,kBAAkB8B,YAAY,CAACC,GAAG,CAAC,SAACC;mCAAQ;gCAC7CxB,MAAM;gCACNI,OAAOoB,GAAGpB,KAAK;gCACfC,UAAUmB,GAAGnB,QAAQ;gCACrBC,UAAUkB,GAAGlB,QAAQ;gCACrBL,cAAcuB,GAAGvB,YAAY;4BAC/B;mCACA,qBAAGT,kBAAkBiC,iBAAiB,CACnCC,MAAM,CAAC,SAACC;mCAAOA,GAAGC,cAAc,KAAK,gBAAgBD,GAAGC,cAAc,KAAK;2BAC3EL,GAAG,CAAC,SAACI;mCAAQ;gCACZ3B,MAAM;gCACNI,OAAO,AAAC,GAAauB,OAAXA,GAAG3B,IAAI,EAAC,KAAW,OAAR2B,GAAGhC,IAAI;gCAC5BU,UAAUsB,GAAGE,OAAO;gCACpBvB,UAAUqB,GAAGG,OAAO;gCACpB7B,cAAc;4BAChB;;wBAGJlD,SAAS,MAAM;4BACbR,cAAc;4BACdoB,QAAQ6B,kBAAkBuC,OAAO;4BACjCtC,SAAAA;wBACF;wBACA;;;;wBAGF,8BAA8B;wBAC9B1C,SAAS,MAAM;4BACbR,cAAc;4BACdoB,QAAQ,AAAC,0BAA2D,OAAlC0B,eAAe2C,WAAW,CAACC,MAAM,EAAC;4BACpExC,SAASJ,eAAe2C,WAAW,CAACT,GAAG,CAAC,SAACC;uCAAQ;oCAC/CxB,MAAM;oCACNI,OAAOoB,GAAGhE,IAAI;oCACdyC,cAAc;gCAChB;;wBACF;;;;;;QACF;KAAA,IAAKiC,KAAK,CAACnF;AACb;AAKO,SAASP,eAAeM,OAA4B,EAAEC,QAA8B;IACzFF,iBAAiBC,SAASC;AAC5B;AAeO,SAASR;QAAaO,UAAAA,iEAA+B,CAAC;IAC3D,OAAO,IAAIqF,QAAQ,SAACC,SAASC;QAC3B7F,eAAeM,SAAS,SAACiC,OAAOuD;YAC9B,IAAIvD,OAAOsD,OAAOtD;iBACb,IAAIuD,QAAQF,QAAQE;iBACpBD,OAAO,IAAIE,MAAM;QACxB;IACF;AACF"}
|
|
@@ -27,3 +27,10 @@ export declare function getFileChangeSummary(changes: FileChange[]): string;
|
|
|
27
27
|
* Check if changes are only in package.json
|
|
28
28
|
*/
|
|
29
29
|
export declare function isOnlyPackageJsonChange(changes: FileChange[]): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Extract package.json from a tarball
|
|
32
|
+
*
|
|
33
|
+
* @param tarball - Tarball as Buffer (gzipped)
|
|
34
|
+
* @returns Parsed package.json object
|
|
35
|
+
*/
|
|
36
|
+
export declare function extractPackageJson(tarball: Buffer): Promise<unknown>;
|
|
@@ -7,9 +7,10 @@
|
|
|
7
7
|
* 3. Special handling for package.json (semantic comparison elsewhere)
|
|
8
8
|
*/ import crypto from 'crypto';
|
|
9
9
|
import Module from 'module';
|
|
10
|
-
import { Readable } from 'stream';
|
|
11
|
-
import {
|
|
10
|
+
import { pipeline as pipelineCb, Readable } from 'stream';
|
|
11
|
+
import { promisify } from 'util';
|
|
12
12
|
import zlib from 'zlib';
|
|
13
|
+
const pipeline = promisify(pipelineCb);
|
|
13
14
|
const _require = typeof require === 'undefined' ? Module.createRequire(import.meta.url) : require;
|
|
14
15
|
// Lazy load tar
|
|
15
16
|
let _tar = null;
|
|
@@ -159,3 +160,17 @@ function getTar() {
|
|
|
159
160
|
}
|
|
160
161
|
return true;
|
|
161
162
|
}
|
|
163
|
+
/**
|
|
164
|
+
* Extract package.json from a tarball
|
|
165
|
+
*
|
|
166
|
+
* @param tarball - Tarball as Buffer (gzipped)
|
|
167
|
+
* @returns Parsed package.json object
|
|
168
|
+
*/ export async function extractPackageJson(tarball) {
|
|
169
|
+
const files = await extractTarball(tarball);
|
|
170
|
+
// Look for package.json in the tarball
|
|
171
|
+
const pkgJsonPath = Object.keys(files).find((p)=>p === 'package/package.json' || p.indexOf('/package.json') === p.length - 13);
|
|
172
|
+
if (!pkgJsonPath || !files[pkgJsonPath]) {
|
|
173
|
+
throw new Error('package.json not found in tarball');
|
|
174
|
+
}
|
|
175
|
+
return JSON.parse(files[pkgJsonPath].toString('utf8'));
|
|
176
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/npm/npm-needs-publish/src/comparators/file-content.ts"],"sourcesContent":["/**\n * File content comparison for package tarballs\n *\n * Compares files between local and registry tarballs:\n * 1. Fast path: Compare tarball hashes\n * 2. If different: Extract and compare file-by-file\n * 3. Special handling for package.json (semantic comparison elsewhere)\n */\n\nimport crypto from 'crypto';\nimport Module from 'module';\nimport { Readable } from 'stream';\nimport { pipeline } from 'stream/promises';\nimport zlib from 'zlib';\nimport type { FileChange, FileComparison } from '../types.ts';\n\nconst _require = typeof require === 'undefined' ? Module.createRequire(import.meta.url) : require;\n\n// Lazy load tar\nlet _tar: typeof import('tar') | null = null;\n\nfunction getTar(): typeof import('tar') {\n if (!_tar) {\n _tar = _require('tar');\n }\n return _tar;\n}\n\n/**\n * Compare package files from two tarballs\n *\n * @param localTarball - Local package tarball as Buffer\n * @param registryTarball - Registry package tarball as Buffer\n * @returns File comparison result\n */\nexport async function comparePackageFiles(localTarball: Buffer, registryTarball: Buffer): Promise<FileComparison> {\n // Fast path: identical tarballs\n const localHash = hashBuffer(localTarball);\n const registryHash = hashBuffer(registryTarball);\n\n if (localHash === registryHash) {\n return {\n identical: true,\n fileChanges: [],\n packageJsonOnly: false,\n };\n }\n\n // Extract both tarballs to memory\n const localFiles = await extractTarball(localTarball);\n const registryFiles = await extractTarball(registryTarball);\n\n const changes: FileChange[] = [];\n\n // Build combined set of all paths\n const allPaths: Record<string, boolean> = {};\n const localKeys = Object.keys(localFiles);\n for (let i = 0; i < localKeys.length; i++) {\n allPaths[localKeys[i]] = true;\n }\n const registryKeys = Object.keys(registryFiles);\n for (let i = 0; i < registryKeys.length; i++) {\n allPaths[registryKeys[i]] = true;\n }\n\n let onlyPackageJsonDiffers = true;\n\n const pathKeys = Object.keys(allPaths);\n for (let i = 0; i < pathKeys.length; i++) {\n const filePath = pathKeys[i];\n const isPackageJson = filePath === 'package/package.json' || filePath.indexOf('/package.json') === filePath.length - 13;\n const localContent = localFiles[filePath];\n const registryContent = registryFiles[filePath];\n\n if (!registryContent) {\n // File added\n changes.push({ path: filePath, action: 'added' });\n if (!isPackageJson) onlyPackageJsonDiffers = false;\n } else if (!localContent) {\n // File removed\n changes.push({ path: filePath, action: 'removed' });\n if (!isPackageJson) onlyPackageJsonDiffers = false;\n } else if (!buffersEqual(localContent, registryContent)) {\n // File modified\n changes.push({ path: filePath, action: 'modified' });\n if (!isPackageJson) onlyPackageJsonDiffers = false;\n }\n }\n\n return {\n identical: changes.length === 0,\n fileChanges: changes,\n packageJsonOnly: onlyPackageJsonDiffers && changes.length > 0,\n };\n}\n\n/**\n * Extract tarball contents to memory\n *\n * @param tarball - Tarball as Buffer (gzipped)\n * @returns Map of file paths to content buffers\n */\nasync function extractTarball(tarball: Buffer): Promise<Record<string, Buffer>> {\n const files: Record<string, Buffer> = {};\n const tar = getTar();\n\n // Create a parser that collects file contents\n const parser = new tar.Parser({\n onReadEntry: (entry) => {\n if (entry.type === 'File') {\n const chunks: Buffer[] = [];\n\n entry.on('data', (chunk: Buffer) => {\n chunks.push(chunk);\n });\n\n entry.on('end', () => {\n files[entry.path] = Buffer.concat(chunks);\n });\n } else {\n // Drain non-file entries (directories, etc.)\n entry.resume();\n }\n },\n });\n\n // Process the tarball\n await pipeline(Readable.from(tarball), zlib.createGunzip(), parser);\n\n return files;\n}\n\n/**\n * Hash a buffer using SHA-512\n */\nexport function hashBuffer(buffer: Buffer): string {\n return crypto.createHash('sha512').update(buffer).digest('base64');\n}\n\n/**\n * Compare two buffers for equality\n */\nfunction buffersEqual(a: Buffer, b: Buffer): boolean {\n if (a.length !== b.length) return false;\n return crypto.timingSafeEqual(a, b);\n}\n\n/**\n * Get a summary of file changes\n */\nexport function getFileChangeSummary(changes: FileChange[]): string {\n if (changes.length === 0) {\n return 'No file changes';\n }\n\n const added = changes.filter((c) => c.action === 'added');\n const removed = changes.filter((c) => c.action === 'removed');\n const modified = changes.filter((c) => c.action === 'modified');\n\n const parts: string[] = [];\n\n if (added.length > 0) {\n parts.push(`${added.length} added`);\n }\n if (removed.length > 0) {\n parts.push(`${removed.length} removed`);\n }\n if (modified.length > 0) {\n parts.push(`${modified.length} modified`);\n }\n\n return `Files: ${parts.join(', ')} (${changes.length} total)`;\n}\n\n/**\n * Check if changes are only in package.json\n */\nexport function isOnlyPackageJsonChange(changes: FileChange[]): boolean {\n if (changes.length === 0) return false;\n\n for (let i = 0; i < changes.length; i++) {\n const path = changes[i].path;\n if (path !== 'package/package.json' && path.indexOf('/package.json') !== path.length - 13) {\n return false;\n }\n }\n return true;\n}\n"],"names":["crypto","Module","Readable","pipeline","zlib","_require","require","createRequire","url","_tar","getTar","comparePackageFiles","localTarball","registryTarball","localHash","hashBuffer","registryHash","identical","fileChanges","packageJsonOnly","localFiles","extractTarball","registryFiles","changes","allPaths","localKeys","Object","keys","i","length","registryKeys","onlyPackageJsonDiffers","pathKeys","filePath","isPackageJson","indexOf","localContent","registryContent","push","path","action","buffersEqual","tarball","files","tar","parser","Parser","onReadEntry","entry","type","chunks","on","chunk","Buffer","concat","resume","from","createGunzip","buffer","createHash","update","digest","a","b","timingSafeEqual","getFileChangeSummary","added","filter","c","removed","modified","parts","join","isOnlyPackageJsonChange"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/npm/npm-needs-publish/src/comparators/file-content.ts"],"sourcesContent":["/**\n * File content comparison for package tarballs\n *\n * Compares files between local and registry tarballs:\n * 1. Fast path: Compare tarball hashes\n * 2. If different: Extract and compare file-by-file\n * 3. Special handling for package.json (semantic comparison elsewhere)\n */\n\nimport crypto from 'crypto';\nimport Module from 'module';\nimport { pipeline as pipelineCb, Readable } from 'stream';\nimport { promisify } from 'util';\nimport zlib from 'zlib';\n\nconst pipeline = promisify(pipelineCb);\n\nimport type { FileChange, FileComparison } from '../types.ts';\n\nconst _require = typeof require === 'undefined' ? Module.createRequire(import.meta.url) : require;\n\n// Lazy load tar\nlet _tar: typeof import('tar') | null = null;\n\nfunction getTar(): typeof import('tar') {\n if (!_tar) {\n _tar = _require('tar');\n }\n return _tar;\n}\n\n/**\n * Compare package files from two tarballs\n *\n * @param localTarball - Local package tarball as Buffer\n * @param registryTarball - Registry package tarball as Buffer\n * @returns File comparison result\n */\nexport async function comparePackageFiles(localTarball: Buffer, registryTarball: Buffer): Promise<FileComparison> {\n // Fast path: identical tarballs\n const localHash = hashBuffer(localTarball);\n const registryHash = hashBuffer(registryTarball);\n\n if (localHash === registryHash) {\n return {\n identical: true,\n fileChanges: [],\n packageJsonOnly: false,\n };\n }\n\n // Extract both tarballs to memory\n const localFiles = await extractTarball(localTarball);\n const registryFiles = await extractTarball(registryTarball);\n\n const changes: FileChange[] = [];\n\n // Build combined set of all paths\n const allPaths: Record<string, boolean> = {};\n const localKeys = Object.keys(localFiles);\n for (let i = 0; i < localKeys.length; i++) {\n allPaths[localKeys[i]] = true;\n }\n const registryKeys = Object.keys(registryFiles);\n for (let i = 0; i < registryKeys.length; i++) {\n allPaths[registryKeys[i]] = true;\n }\n\n let onlyPackageJsonDiffers = true;\n\n const pathKeys = Object.keys(allPaths);\n for (let i = 0; i < pathKeys.length; i++) {\n const filePath = pathKeys[i];\n const isPackageJson = filePath === 'package/package.json' || filePath.indexOf('/package.json') === filePath.length - 13;\n const localContent = localFiles[filePath];\n const registryContent = registryFiles[filePath];\n\n if (!registryContent) {\n // File added\n changes.push({ path: filePath, action: 'added' });\n if (!isPackageJson) onlyPackageJsonDiffers = false;\n } else if (!localContent) {\n // File removed\n changes.push({ path: filePath, action: 'removed' });\n if (!isPackageJson) onlyPackageJsonDiffers = false;\n } else if (!buffersEqual(localContent, registryContent)) {\n // File modified\n changes.push({ path: filePath, action: 'modified' });\n if (!isPackageJson) onlyPackageJsonDiffers = false;\n }\n }\n\n return {\n identical: changes.length === 0,\n fileChanges: changes,\n packageJsonOnly: onlyPackageJsonDiffers && changes.length > 0,\n };\n}\n\n/**\n * Extract tarball contents to memory\n *\n * @param tarball - Tarball as Buffer (gzipped)\n * @returns Map of file paths to content buffers\n */\nasync function extractTarball(tarball: Buffer): Promise<Record<string, Buffer>> {\n const files: Record<string, Buffer> = {};\n const tar = getTar();\n\n // Create a parser that collects file contents\n const parser = new tar.Parser({\n onReadEntry: (entry) => {\n if (entry.type === 'File') {\n const chunks: Buffer[] = [];\n\n entry.on('data', (chunk: Buffer) => {\n chunks.push(chunk);\n });\n\n entry.on('end', () => {\n files[entry.path] = Buffer.concat(chunks);\n });\n } else {\n // Drain non-file entries (directories, etc.)\n entry.resume();\n }\n },\n });\n\n // Process the tarball\n await pipeline(Readable.from(tarball), zlib.createGunzip(), parser);\n\n return files;\n}\n\n/**\n * Hash a buffer using SHA-512\n */\nexport function hashBuffer(buffer: Buffer): string {\n return crypto.createHash('sha512').update(buffer).digest('base64');\n}\n\n/**\n * Compare two buffers for equality\n */\nfunction buffersEqual(a: Buffer, b: Buffer): boolean {\n if (a.length !== b.length) return false;\n return crypto.timingSafeEqual(a, b);\n}\n\n/**\n * Get a summary of file changes\n */\nexport function getFileChangeSummary(changes: FileChange[]): string {\n if (changes.length === 0) {\n return 'No file changes';\n }\n\n const added = changes.filter((c) => c.action === 'added');\n const removed = changes.filter((c) => c.action === 'removed');\n const modified = changes.filter((c) => c.action === 'modified');\n\n const parts: string[] = [];\n\n if (added.length > 0) {\n parts.push(`${added.length} added`);\n }\n if (removed.length > 0) {\n parts.push(`${removed.length} removed`);\n }\n if (modified.length > 0) {\n parts.push(`${modified.length} modified`);\n }\n\n return `Files: ${parts.join(', ')} (${changes.length} total)`;\n}\n\n/**\n * Check if changes are only in package.json\n */\nexport function isOnlyPackageJsonChange(changes: FileChange[]): boolean {\n if (changes.length === 0) return false;\n\n for (let i = 0; i < changes.length; i++) {\n const path = changes[i].path;\n if (path !== 'package/package.json' && path.indexOf('/package.json') !== path.length - 13) {\n return false;\n }\n }\n return true;\n}\n\n/**\n * Extract package.json from a tarball\n *\n * @param tarball - Tarball as Buffer (gzipped)\n * @returns Parsed package.json object\n */\nexport async function extractPackageJson(tarball: Buffer): Promise<unknown> {\n const files = await extractTarball(tarball);\n\n // Look for package.json in the tarball\n const pkgJsonPath = Object.keys(files).find((p) => p === 'package/package.json' || p.indexOf('/package.json') === p.length - 13);\n\n if (!pkgJsonPath || !files[pkgJsonPath]) {\n throw new Error('package.json not found in tarball');\n }\n\n return JSON.parse(files[pkgJsonPath].toString('utf8'));\n}\n"],"names":["crypto","Module","pipeline","pipelineCb","Readable","promisify","zlib","_require","require","createRequire","url","_tar","getTar","comparePackageFiles","localTarball","registryTarball","localHash","hashBuffer","registryHash","identical","fileChanges","packageJsonOnly","localFiles","extractTarball","registryFiles","changes","allPaths","localKeys","Object","keys","i","length","registryKeys","onlyPackageJsonDiffers","pathKeys","filePath","isPackageJson","indexOf","localContent","registryContent","push","path","action","buffersEqual","tarball","files","tar","parser","Parser","onReadEntry","entry","type","chunks","on","chunk","Buffer","concat","resume","from","createGunzip","buffer","createHash","update","digest","a","b","timingSafeEqual","getFileChangeSummary","added","filter","c","removed","modified","parts","join","isOnlyPackageJsonChange","extractPackageJson","pkgJsonPath","find","p","Error","JSON","parse","toString"],"mappings":"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"}
|
|
@@ -2,6 +2,6 @@
|
|
|
2
2
|
* Comparators - Core comparison logic for npm-needs-publish
|
|
3
3
|
*/
|
|
4
4
|
export { compareDependencies, getDependencyChangeSummary, hasSignificantDependencyChanges, } from './dependency.js';
|
|
5
|
-
export { comparePackageFiles, getFileChangeSummary, hashBuffer, isOnlyPackageJsonChange, } from './file-content.js';
|
|
5
|
+
export { comparePackageFiles, extractPackageJson, getFileChangeSummary, hashBuffer, isOnlyPackageJsonChange, } from './file-content.js';
|
|
6
6
|
export { comparePackageJson, isSignificantField, } from './package-json.js';
|
|
7
7
|
export { compareVersionSpecifiers, comparisonToSemanticChange, parseVersionSpecifier, type SemanticChangeOptions, } from './version-specifier.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Comparators - Core comparison logic for npm-needs-publish
|
|
3
3
|
*/ export { compareDependencies, getDependencyChangeSummary, hasSignificantDependencyChanges } from './dependency.js';
|
|
4
|
-
export { comparePackageFiles, getFileChangeSummary, hashBuffer, isOnlyPackageJsonChange } from './file-content.js';
|
|
4
|
+
export { comparePackageFiles, extractPackageJson, getFileChangeSummary, hashBuffer, isOnlyPackageJsonChange } from './file-content.js';
|
|
5
5
|
export { comparePackageJson, isSignificantField } from './package-json.js';
|
|
6
6
|
export { compareVersionSpecifiers, comparisonToSemanticChange, parseVersionSpecifier } from './version-specifier.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/npm/npm-needs-publish/src/comparators/index.ts"],"sourcesContent":["/**\n * Comparators - Core comparison logic for npm-needs-publish\n */\n\nexport {\n compareDependencies,\n getDependencyChangeSummary,\n hasSignificantDependencyChanges,\n} from './dependency.ts';\nexport {\n comparePackageFiles,\n getFileChangeSummary,\n hashBuffer,\n isOnlyPackageJsonChange,\n} from './file-content.ts';\n\nexport {\n comparePackageJson,\n isSignificantField,\n} from './package-json.ts';\nexport {\n compareVersionSpecifiers,\n comparisonToSemanticChange,\n parseVersionSpecifier,\n type SemanticChangeOptions,\n} from './version-specifier.ts';\n"],"names":["compareDependencies","getDependencyChangeSummary","hasSignificantDependencyChanges","comparePackageFiles","getFileChangeSummary","hashBuffer","isOnlyPackageJsonChange","comparePackageJson","isSignificantField","compareVersionSpecifiers","comparisonToSemanticChange","parseVersionSpecifier"],"mappings":"AAAA;;CAEC,GAED,SACEA,mBAAmB,EACnBC,0BAA0B,EAC1BC,+BAA+B,QAC1B,kBAAkB;AACzB,SACEC,mBAAmB,EACnBC,oBAAoB,EACpBC,UAAU,EACVC,uBAAuB,QAClB,oBAAoB;AAE3B,SACEC,kBAAkB,EAClBC,kBAAkB,QACb,oBAAoB;AAC3B,SACEC,wBAAwB,EACxBC,0BAA0B,EAC1BC,qBAAqB,QAEhB,yBAAyB"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/npm/npm-needs-publish/src/comparators/index.ts"],"sourcesContent":["/**\n * Comparators - Core comparison logic for npm-needs-publish\n */\n\nexport {\n compareDependencies,\n getDependencyChangeSummary,\n hasSignificantDependencyChanges,\n} from './dependency.ts';\nexport {\n comparePackageFiles,\n extractPackageJson,\n getFileChangeSummary,\n hashBuffer,\n isOnlyPackageJsonChange,\n} from './file-content.ts';\n\nexport {\n comparePackageJson,\n isSignificantField,\n} from './package-json.ts';\nexport {\n compareVersionSpecifiers,\n comparisonToSemanticChange,\n parseVersionSpecifier,\n type SemanticChangeOptions,\n} from './version-specifier.ts';\n"],"names":["compareDependencies","getDependencyChangeSummary","hasSignificantDependencyChanges","comparePackageFiles","extractPackageJson","getFileChangeSummary","hashBuffer","isOnlyPackageJsonChange","comparePackageJson","isSignificantField","compareVersionSpecifiers","comparisonToSemanticChange","parseVersionSpecifier"],"mappings":"AAAA;;CAEC,GAED,SACEA,mBAAmB,EACnBC,0BAA0B,EAC1BC,+BAA+B,QAC1B,kBAAkB;AACzB,SACEC,mBAAmB,EACnBC,kBAAkB,EAClBC,oBAAoB,EACpBC,UAAU,EACVC,uBAAuB,QAClB,oBAAoB;AAE3B,SACEC,kBAAkB,EAClBC,kBAAkB,QACb,oBAAoB;AAC3B,SACEC,wBAAwB,EACxBC,0BAA0B,EAC1BC,qBAAqB,QAEhB,yBAAyB"}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
* ```
|
|
19
19
|
*/
|
|
20
20
|
export { compareDependencies } from './comparators/dependency.js';
|
|
21
|
+
export { extractPackageJson } from './comparators/file-content.js';
|
|
21
22
|
export { comparePackageJson } from './comparators/package-json.js';
|
|
22
23
|
export { compareVersionSpecifiers, comparisonToSemanticChange, parseVersionSpecifier, type SemanticChangeOptions } from './comparators/version-specifier.js';
|
|
23
24
|
export { type NeedsPublishCallback, needsPublish, needsPublishCb } from './needs-publish.js';
|
package/dist/esm/index.js
CHANGED
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
* ```
|
|
19
19
|
*/ // Comparators
|
|
20
20
|
export { compareDependencies } from './comparators/dependency.js';
|
|
21
|
+
export { extractPackageJson } from './comparators/file-content.js';
|
|
21
22
|
export { comparePackageJson } from './comparators/package-json.js';
|
|
22
23
|
export { compareVersionSpecifiers, comparisonToSemanticChange, parseVersionSpecifier } from './comparators/version-specifier.js';
|
|
23
24
|
// Main API
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/npm/npm-needs-publish/src/index.ts"],"sourcesContent":["/**\n * npm-needs-publish\n *\n * Smart publish detection for npm packages - semantic package.json comparison\n * with semver-aware dependency analysis\n *\n * @example\n * ```typescript\n * import { needsPublish } from 'npm-needs-publish';\n *\n * const result = await needsPublish({ cwd: process.cwd() });\n * if (result.needsPublish) {\n * console.log('Publish needed:', result.reason);\n * // Proceed with npm publish\n * } else {\n * console.log('No publish needed:', result.reason);\n * }\n * ```\n */\n\n// Comparators\nexport { compareDependencies } from './comparators/dependency.ts';\nexport { comparePackageJson } from './comparators/package-json.ts';\nexport { compareVersionSpecifiers, comparisonToSemanticChange, parseVersionSpecifier, type SemanticChangeOptions } from './comparators/version-specifier.ts';\n// Main API\nexport { type NeedsPublishCallback, needsPublish, needsPublishCb } from './needs-publish.ts';\n\n// Types\nexport type {\n ChangeDetail,\n CompareOptions,\n CompareSpecifierOptions,\n DependencyChange,\n DependencyCompareOptions,\n DependencyComparison,\n FieldChange,\n FileChange,\n FileComparison,\n NeedsPublishOptions,\n NeedsPublishResult,\n PackageJson,\n PackageJsonComparison,\n ParsedVersionSpecifier,\n SemanticChange,\n SpecifierComparison,\n VersionSpecifierType,\n} from './types.ts';\n"],"names":["compareDependencies","comparePackageJson","compareVersionSpecifiers","comparisonToSemanticChange","parseVersionSpecifier","needsPublish","needsPublishCb"],"mappings":"AAAA;;;;;;;;;;;;;;;;;;CAkBC,GAED,cAAc;AACd,SAASA,mBAAmB,QAAQ,8BAA8B;AAClE,SAASC,kBAAkB,QAAQ,gCAAgC;AACnE,SAASC,wBAAwB,EAAEC,0BAA0B,EAAEC,qBAAqB,QAAoC,qCAAqC;AAC7J,WAAW;AACX,SAAoCC,YAAY,EAAEC,cAAc,QAAQ,qBAAqB"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/npm/npm-needs-publish/src/index.ts"],"sourcesContent":["/**\n * npm-needs-publish\n *\n * Smart publish detection for npm packages - semantic package.json comparison\n * with semver-aware dependency analysis\n *\n * @example\n * ```typescript\n * import { needsPublish } from 'npm-needs-publish';\n *\n * const result = await needsPublish({ cwd: process.cwd() });\n * if (result.needsPublish) {\n * console.log('Publish needed:', result.reason);\n * // Proceed with npm publish\n * } else {\n * console.log('No publish needed:', result.reason);\n * }\n * ```\n */\n\n// Comparators\nexport { compareDependencies } from './comparators/dependency.ts';\nexport { extractPackageJson } from './comparators/file-content.ts';\nexport { comparePackageJson } from './comparators/package-json.ts';\nexport { compareVersionSpecifiers, comparisonToSemanticChange, parseVersionSpecifier, type SemanticChangeOptions } from './comparators/version-specifier.ts';\n// Main API\nexport { type NeedsPublishCallback, needsPublish, needsPublishCb } from './needs-publish.ts';\n\n// Types\nexport type {\n ChangeDetail,\n CompareOptions,\n CompareSpecifierOptions,\n DependencyChange,\n DependencyCompareOptions,\n DependencyComparison,\n FieldChange,\n FileChange,\n FileComparison,\n NeedsPublishOptions,\n NeedsPublishResult,\n PackageJson,\n PackageJsonComparison,\n ParsedVersionSpecifier,\n SemanticChange,\n SpecifierComparison,\n VersionSpecifierType,\n} from './types.ts';\n"],"names":["compareDependencies","extractPackageJson","comparePackageJson","compareVersionSpecifiers","comparisonToSemanticChange","parseVersionSpecifier","needsPublish","needsPublishCb"],"mappings":"AAAA;;;;;;;;;;;;;;;;;;CAkBC,GAED,cAAc;AACd,SAASA,mBAAmB,QAAQ,8BAA8B;AAClE,SAASC,kBAAkB,QAAQ,gCAAgC;AACnE,SAASC,kBAAkB,QAAQ,gCAAgC;AACnE,SAASC,wBAAwB,EAAEC,0BAA0B,EAAEC,qBAAqB,QAAoC,qCAAqC;AAC7J,WAAW;AACX,SAAoCC,YAAY,EAAEC,cAAc,QAAQ,qBAAqB"}
|
|
@@ -15,8 +15,7 @@ import type { NeedsPublishOptions, NeedsPublishResult } from './types.js';
|
|
|
15
15
|
*/
|
|
16
16
|
export type NeedsPublishCallback = (error: Error | null, result?: NeedsPublishResult) => void;
|
|
17
17
|
/**
|
|
18
|
-
* Callback-based needsPublish
|
|
19
|
-
* Uses worker for older Node versions, runs locally on Node 14+
|
|
18
|
+
* Callback-based needsPublish
|
|
20
19
|
*/
|
|
21
20
|
export declare function needsPublishCb(options: NeedsPublishOptions, callback: NeedsPublishCallback): void;
|
|
22
21
|
/**
|
|
@@ -11,19 +11,9 @@
|
|
|
11
11
|
*/ import fs from 'fs';
|
|
12
12
|
import Module from 'module';
|
|
13
13
|
import path from 'path';
|
|
14
|
-
import { wrapWorker } from 'tsds-lib';
|
|
15
|
-
import url from 'url';
|
|
16
14
|
import { stringStartsWith } from './compat.js';
|
|
17
|
-
// Version check for worker pattern - use worker for Node < 14
|
|
18
|
-
const major = +process.versions.node.split('.')[0];
|
|
19
|
-
const version = major > 14 ? 'local' : 'stable';
|
|
20
15
|
const _require = typeof require === 'undefined' ? Module.createRequire(import.meta.url) : require;
|
|
21
|
-
|
|
22
|
-
const dist = path.join(__dirname, '..');
|
|
23
|
-
const workerWrapper = wrapWorker(path.join(dist, 'cjs', 'needs-publish.js'));
|
|
24
|
-
/**
|
|
25
|
-
* Worker function that runs on Node 14+
|
|
26
|
-
*/ function worker(options, callback) {
|
|
16
|
+
function needsPublishImpl(options, callback) {
|
|
27
17
|
const cwd = options.cwd || process.cwd();
|
|
28
18
|
// Load local package.json
|
|
29
19
|
const localPkg = options.package || JSON.parse(fs.readFileSync(path.join(cwd, 'package.json'), 'utf8'));
|
|
@@ -43,7 +33,7 @@ const workerWrapper = wrapWorker(path.join(dist, 'cjs', 'needs-publish.js'));
|
|
|
43
33
|
const { promisify } = _require('util');
|
|
44
34
|
const execFileAsync = promisify(execFile);
|
|
45
35
|
// Dynamic import for comparators (they use modern features)
|
|
46
|
-
const { comparePackageFiles, comparePackageJson, hashBuffer } = await import('./comparators/index.js');
|
|
36
|
+
const { comparePackageFiles, comparePackageJson, extractPackageJson, hashBuffer } = await import('./comparators/index.js');
|
|
47
37
|
// Get registry URL for scoped packages
|
|
48
38
|
let registry = options.registry;
|
|
49
39
|
if (!registry) {
|
|
@@ -188,7 +178,11 @@ const workerWrapper = wrapWorker(path.join(dist, 'cjs', 'needs-publish.js'));
|
|
|
188
178
|
}
|
|
189
179
|
// Step 6: If only package.json differs, do semantic comparison
|
|
190
180
|
if (fileComparison.packageJsonOnly && !options.packageJsonOnly) {
|
|
191
|
-
|
|
181
|
+
// Extract package.json from both tarballs for accurate comparison
|
|
182
|
+
// (packument metadata is missing fields like 'files')
|
|
183
|
+
const localTarballPkg = await extractPackageJson(localTarball);
|
|
184
|
+
const registryTarballPkg = await extractPackageJson(registryTarball);
|
|
185
|
+
const pkgJsonComparison = comparePackageJson(localTarballPkg, registryTarballPkg, {
|
|
192
186
|
includeOptionalDeps: options.includeOptionalDeps,
|
|
193
187
|
additionalSignificantFields: options.additionalSignificantFields,
|
|
194
188
|
ignoreFields: options.ignoreFields,
|
|
@@ -245,10 +239,9 @@ const workerWrapper = wrapWorker(path.join(dist, 'cjs', 'needs-publish.js'));
|
|
|
245
239
|
})().catch(callback);
|
|
246
240
|
}
|
|
247
241
|
/**
|
|
248
|
-
* Callback-based needsPublish
|
|
249
|
-
* Uses worker for older Node versions, runs locally on Node 14+
|
|
242
|
+
* Callback-based needsPublish
|
|
250
243
|
*/ export function needsPublishCb(options, callback) {
|
|
251
|
-
|
|
244
|
+
needsPublishImpl(options, callback);
|
|
252
245
|
}
|
|
253
246
|
/**
|
|
254
247
|
* Determine if a package needs to be published to npm.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/npm/npm-needs-publish/src/needs-publish.ts"],"sourcesContent":["/**\n * Main orchestration logic for npm-needs-publish\n *\n * Algorithm:\n * 1. Fetch registry packument → if E404, return needsPublish=true (first publish)\n * 2. Version check → if different, return needsPublish=true (intentional bump)\n * 3. Fast hash check → if identical, return needsPublish=false (no changes)\n * 4. Extract both tarballs, compare file-by-file (excluding package.json)\n * 5. If non-package.json files differ → return needsPublish=true\n * 6. If only package.json differs → do semantic comparison\n */\n\nimport fs from 'fs';\nimport Module from 'module';\nimport path from 'path';\nimport { wrapWorker } from 'tsds-lib';\nimport url from 'url';\nimport { stringStartsWith } from './compat.ts';\nimport type { ChangeDetail, NeedsPublishOptions, NeedsPublishResult, PackageJson } from './types.ts';\n\n// Version check for worker pattern - use worker for Node < 14\nconst major = +process.versions.node.split('.')[0];\nconst version = major > 14 ? 'local' : 'stable';\nconst _require = typeof require === 'undefined' ? Module.createRequire(import.meta.url) : require;\nconst __dirname = path.dirname(typeof __filename === 'undefined' ? url.fileURLToPath(import.meta.url) : __filename);\nconst dist = path.join(__dirname, '..');\nconst workerWrapper = wrapWorker(path.join(dist, 'cjs', 'needs-publish.js'));\n\n/**\n * Callback type for needsPublish\n */\nexport type NeedsPublishCallback = (error: Error | null, result?: NeedsPublishResult) => void;\n\n/**\n * Worker function that runs on Node 14+\n */\nfunction worker(options: NeedsPublishOptions, callback: NeedsPublishCallback): undefined {\n const cwd = options.cwd || process.cwd();\n\n // Load local package.json\n const localPkg: PackageJson = options.package || JSON.parse(fs.readFileSync(path.join(cwd, 'package.json'), 'utf8'));\n\n // Skip private packages\n if (localPkg.private) {\n callback(null, {\n needsPublish: false,\n reason: 'Package is private',\n });\n return;\n }\n\n (async () => {\n const pacote = _require('pacote');\n const Arborist = _require('@npmcli/arborist');\n const npa = _require('npm-package-arg');\n const { execFile } = _require('child_process');\n const { promisify } = _require('util');\n const execFileAsync = promisify(execFile);\n\n // Dynamic import for comparators (they use modern features)\n const { comparePackageFiles, comparePackageJson, hashBuffer } = await import('./comparators/index.ts');\n\n // Get registry URL for scoped packages\n let registry: string | undefined = options.registry;\n if (!registry) {\n const scope = stringStartsWith(localPkg.name, '@') ? localPkg.name.split('/')[0] : undefined;\n if (scope) {\n try {\n const { stdout } = await execFileAsync('npm', ['config', 'get', `${scope}:registry`]);\n registry = stdout.trim();\n if (registry === 'undefined') registry = undefined;\n } catch {\n // Fallback to default registry\n }\n }\n }\n\n // Step 1: Try to fetch registry packument\n let registryPkg: PackageJson;\n let registryTarball: Buffer;\n\n try {\n const packument = await pacote.packument(localPkg.name, {\n Arborist,\n ...(registry && { registry }),\n });\n\n const latestVersion = packument['dist-tags']?.latest;\n if (!latestVersion) {\n callback(null, {\n needsPublish: true,\n reason: 'No latest version found in registry (first publish)',\n changes: [{ type: 'first-publish', significance: 'critical' }],\n });\n return;\n }\n\n registryPkg = packument.versions[latestVersion] as unknown as PackageJson;\n\n // Step 2: Version comparison (fast path)\n if (localPkg.version !== latestVersion) {\n callback(null, {\n needsPublish: true,\n reason: `Version differs (local: ${localPkg.version}, registry: ${latestVersion})`,\n changes: [\n {\n type: 'version',\n field: 'version',\n oldValue: latestVersion,\n newValue: localPkg.version,\n significance: 'critical',\n },\n ],\n });\n return;\n }\n\n // Fetch registry tarball for comparison\n const tarballUrl = registryPkg.dist?.tarball;\n if (!tarballUrl) {\n callback(null, {\n needsPublish: true,\n reason: 'Registry package has no tarball URL',\n changes: [{ type: 'first-publish', significance: 'critical' }],\n });\n return;\n }\n\n registryTarball = await pacote.tarball(tarballUrl, {\n Arborist,\n integrity: registryPkg.dist?.integrity,\n });\n } catch (err: unknown) {\n const error = err as { code?: string; message?: string };\n // Package not found in registry (first publish)\n if (error.code === 'E404') {\n callback(null, {\n needsPublish: true,\n reason: 'Package not found in registry (first publish)',\n changes: [{ type: 'first-publish', significance: 'critical' }],\n });\n return;\n }\n // Unknown error - assume changed to be safe\n callback(null, {\n needsPublish: true,\n reason: `Error checking registry: ${error.message || 'Unknown error'}`,\n });\n return;\n }\n\n // Step 3: Pack local package\n let localTarball: Buffer;\n try {\n const spec = npa(cwd);\n const manifest = await pacote.manifest(spec, { Arborist });\n localTarball = await pacote.tarball(manifest._resolved, {\n Arborist,\n integrity: manifest._integrity,\n });\n } catch (err: unknown) {\n const error = err as { message?: string };\n callback(null, {\n needsPublish: true,\n reason: `Error packing local package: ${error.message || 'Unknown error'}`,\n });\n return;\n }\n\n // Step 4: Fast hash comparison\n const localHash = hashBuffer(localTarball);\n const registryHash = hashBuffer(registryTarball);\n\n if (localHash === registryHash) {\n callback(null, {\n needsPublish: false,\n reason: `No changes detected (hash: ${localHash.substring(0, 16)}...)`,\n });\n return;\n }\n\n // Step 5: File-by-file comparison\n const fileComparison = await comparePackageFiles(localTarball, registryTarball);\n\n if (fileComparison.identical) {\n // Hash mismatch but files identical - likely tarball metadata difference\n callback(null, {\n needsPublish: false,\n reason: 'Files identical (tarball metadata differs)',\n });\n return;\n }\n\n // Step 6: If only package.json differs, do semantic comparison\n if (fileComparison.packageJsonOnly && !options.packageJsonOnly) {\n const pkgJsonComparison = comparePackageJson(localPkg, registryPkg, {\n includeOptionalDeps: options.includeOptionalDeps,\n additionalSignificantFields: options.additionalSignificantFields,\n ignoreFields: options.ignoreFields,\n treatNarrowingAsEquivalent: options.treatNarrowingAsEquivalent,\n });\n\n if (!pkgJsonComparison.hasSignificantChanges) {\n callback(null, {\n needsPublish: false,\n reason: 'Package.json changes are not significant for consumers',\n changes: pkgJsonComparison.fieldChanges.map((fc) => ({\n type: 'field' as const,\n field: fc.field,\n oldValue: fc.oldValue,\n newValue: fc.newValue,\n significance: 'informational' as const,\n })),\n });\n return;\n }\n\n // Build changes list\n const changes: ChangeDetail[] = [\n ...pkgJsonComparison.fieldChanges.map((fc) => ({\n type: 'field' as const,\n field: fc.field,\n oldValue: fc.oldValue,\n newValue: fc.newValue,\n significance: fc.significance,\n })),\n ...pkgJsonComparison.dependencyChanges\n .filter((dc) => dc.semanticChange !== 'equivalent' && dc.semanticChange !== 'none')\n .map((dc) => ({\n type: 'dependency' as const,\n field: `${dc.type}.${dc.name}`,\n oldValue: dc.oldSpec,\n newValue: dc.newSpec,\n significance: 'significant' as const,\n })),\n ];\n\n callback(null, {\n needsPublish: true,\n reason: pkgJsonComparison.summary,\n changes,\n });\n return;\n }\n\n // Step 7: Other files changed\n callback(null, {\n needsPublish: true,\n reason: `Code changes detected (${fileComparison.fileChanges.length} files changed)`,\n changes: fileComparison.fileChanges.map((fc) => ({\n type: 'file' as const,\n field: fc.path,\n significance: 'significant' as const,\n })),\n });\n })().catch(callback);\n}\n\n/**\n * Callback-based needsPublish - works on Node 0.8+\n * Uses worker for older Node versions, runs locally on Node 14+\n */\nexport function needsPublishCb(options: NeedsPublishOptions, callback: NeedsPublishCallback): void {\n version !== 'local' ? workerWrapper(version, options, callback) : worker(options, callback);\n}\n\n/**\n * Determine if a package needs to be published to npm.\n *\n * @example\n * ```ts\n * import { needsPublish } from 'npm-needs-publish';\n *\n * const result = await needsPublish({ cwd: process.cwd() });\n * if (result.needsPublish) {\n * console.log('Publish needed:', result.reason);\n * }\n * ```\n */\nexport function needsPublish(options: NeedsPublishOptions = {}): Promise<NeedsPublishResult> {\n return new Promise((resolve, reject) => {\n needsPublishCb(options, (error, result) => {\n if (error) reject(error);\n else if (result) resolve(result);\n else reject(new Error('No result returned'));\n });\n });\n}\n"],"names":["fs","Module","path","wrapWorker","url","stringStartsWith","major","process","versions","node","split","version","_require","require","createRequire","__dirname","dirname","__filename","fileURLToPath","dist","join","workerWrapper","worker","options","callback","cwd","localPkg","package","JSON","parse","readFileSync","private","needsPublish","reason","pacote","Arborist","npa","execFile","promisify","execFileAsync","comparePackageFiles","comparePackageJson","hashBuffer","registry","scope","name","undefined","stdout","trim","registryPkg","registryTarball","packument","latestVersion","latest","changes","type","significance","field","oldValue","newValue","tarballUrl","tarball","integrity","err","error","code","message","localTarball","spec","manifest","_resolved","_integrity","localHash","registryHash","substring","fileComparison","identical","packageJsonOnly","pkgJsonComparison","includeOptionalDeps","additionalSignificantFields","ignoreFields","treatNarrowingAsEquivalent","hasSignificantChanges","fieldChanges","map","fc","dependencyChanges","filter","dc","semanticChange","oldSpec","newSpec","summary","fileChanges","length","catch","needsPublishCb","Promise","resolve","reject","result","Error"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["/Users/kevin/Dev/OpenSource/npm/npm-needs-publish/src/needs-publish.ts"],"sourcesContent":["/**\n * Main orchestration logic for npm-needs-publish\n *\n * Algorithm:\n * 1. Fetch registry packument → if E404, return needsPublish=true (first publish)\n * 2. Version check → if different, return needsPublish=true (intentional bump)\n * 3. Fast hash check → if identical, return needsPublish=false (no changes)\n * 4. Extract both tarballs, compare file-by-file (excluding package.json)\n * 5. If non-package.json files differ → return needsPublish=true\n * 6. If only package.json differs → do semantic comparison\n */\n\nimport fs from 'fs';\nimport Module from 'module';\nimport path from 'path';\nimport { stringStartsWith } from './compat.ts';\nimport type { ChangeDetail, NeedsPublishOptions, NeedsPublishResult, PackageJson } from './types.ts';\n\nconst _require = typeof require === 'undefined' ? Module.createRequire(import.meta.url) : require;\n\n/**\n * Callback type for needsPublish\n */\nexport type NeedsPublishCallback = (error: Error | null, result?: NeedsPublishResult) => void;\n\nfunction needsPublishImpl(options: NeedsPublishOptions, callback: NeedsPublishCallback): undefined {\n const cwd = options.cwd || process.cwd();\n\n // Load local package.json\n const localPkg: PackageJson = options.package || JSON.parse(fs.readFileSync(path.join(cwd, 'package.json'), 'utf8'));\n\n // Skip private packages\n if (localPkg.private) {\n callback(null, {\n needsPublish: false,\n reason: 'Package is private',\n });\n return;\n }\n\n (async () => {\n const pacote = _require('pacote');\n const Arborist = _require('@npmcli/arborist');\n const npa = _require('npm-package-arg');\n const { execFile } = _require('child_process');\n const { promisify } = _require('util');\n const execFileAsync = promisify(execFile);\n\n // Dynamic import for comparators (they use modern features)\n const { comparePackageFiles, comparePackageJson, extractPackageJson, hashBuffer } = await import('./comparators/index.ts');\n\n // Get registry URL for scoped packages\n let registry: string | undefined = options.registry;\n if (!registry) {\n const scope = stringStartsWith(localPkg.name, '@') ? localPkg.name.split('/')[0] : undefined;\n if (scope) {\n try {\n const { stdout } = await execFileAsync('npm', ['config', 'get', `${scope}:registry`]);\n registry = stdout.trim();\n if (registry === 'undefined') registry = undefined;\n } catch {\n // Fallback to default registry\n }\n }\n }\n\n // Step 1: Try to fetch registry packument\n let registryPkg: PackageJson;\n let registryTarball: Buffer;\n\n try {\n const packument = await pacote.packument(localPkg.name, {\n Arborist,\n ...(registry && { registry }),\n });\n\n const latestVersion = packument['dist-tags']?.latest;\n if (!latestVersion) {\n callback(null, {\n needsPublish: true,\n reason: 'No latest version found in registry (first publish)',\n changes: [{ type: 'first-publish', significance: 'critical' }],\n });\n return;\n }\n\n registryPkg = packument.versions[latestVersion] as unknown as PackageJson;\n\n // Step 2: Version comparison (fast path)\n if (localPkg.version !== latestVersion) {\n callback(null, {\n needsPublish: true,\n reason: `Version differs (local: ${localPkg.version}, registry: ${latestVersion})`,\n changes: [\n {\n type: 'version',\n field: 'version',\n oldValue: latestVersion,\n newValue: localPkg.version,\n significance: 'critical',\n },\n ],\n });\n return;\n }\n\n // Fetch registry tarball for comparison\n const tarballUrl = registryPkg.dist?.tarball;\n if (!tarballUrl) {\n callback(null, {\n needsPublish: true,\n reason: 'Registry package has no tarball URL',\n changes: [{ type: 'first-publish', significance: 'critical' }],\n });\n return;\n }\n\n registryTarball = await pacote.tarball(tarballUrl, {\n Arborist,\n integrity: registryPkg.dist?.integrity,\n });\n } catch (err: unknown) {\n const error = err as { code?: string; message?: string };\n // Package not found in registry (first publish)\n if (error.code === 'E404') {\n callback(null, {\n needsPublish: true,\n reason: 'Package not found in registry (first publish)',\n changes: [{ type: 'first-publish', significance: 'critical' }],\n });\n return;\n }\n // Unknown error - assume changed to be safe\n callback(null, {\n needsPublish: true,\n reason: `Error checking registry: ${error.message || 'Unknown error'}`,\n });\n return;\n }\n\n // Step 3: Pack local package\n let localTarball: Buffer;\n try {\n const spec = npa(cwd);\n const manifest = await pacote.manifest(spec, { Arborist });\n localTarball = await pacote.tarball(manifest._resolved, {\n Arborist,\n integrity: manifest._integrity,\n });\n } catch (err: unknown) {\n const error = err as { message?: string };\n callback(null, {\n needsPublish: true,\n reason: `Error packing local package: ${error.message || 'Unknown error'}`,\n });\n return;\n }\n\n // Step 4: Fast hash comparison\n const localHash = hashBuffer(localTarball);\n const registryHash = hashBuffer(registryTarball);\n\n if (localHash === registryHash) {\n callback(null, {\n needsPublish: false,\n reason: `No changes detected (hash: ${localHash.substring(0, 16)}...)`,\n });\n return;\n }\n\n // Step 5: File-by-file comparison\n const fileComparison = await comparePackageFiles(localTarball, registryTarball);\n\n if (fileComparison.identical) {\n // Hash mismatch but files identical - likely tarball metadata difference\n callback(null, {\n needsPublish: false,\n reason: 'Files identical (tarball metadata differs)',\n });\n return;\n }\n\n // Step 6: If only package.json differs, do semantic comparison\n if (fileComparison.packageJsonOnly && !options.packageJsonOnly) {\n // Extract package.json from both tarballs for accurate comparison\n // (packument metadata is missing fields like 'files')\n const localTarballPkg = (await extractPackageJson(localTarball)) as PackageJson;\n const registryTarballPkg = (await extractPackageJson(registryTarball)) as PackageJson;\n\n const pkgJsonComparison = comparePackageJson(localTarballPkg, registryTarballPkg, {\n includeOptionalDeps: options.includeOptionalDeps,\n additionalSignificantFields: options.additionalSignificantFields,\n ignoreFields: options.ignoreFields,\n treatNarrowingAsEquivalent: options.treatNarrowingAsEquivalent,\n });\n\n if (!pkgJsonComparison.hasSignificantChanges) {\n callback(null, {\n needsPublish: false,\n reason: 'Package.json changes are not significant for consumers',\n changes: pkgJsonComparison.fieldChanges.map((fc) => ({\n type: 'field' as const,\n field: fc.field,\n oldValue: fc.oldValue,\n newValue: fc.newValue,\n significance: 'informational' as const,\n })),\n });\n return;\n }\n\n // Build changes list\n const changes: ChangeDetail[] = [\n ...pkgJsonComparison.fieldChanges.map((fc) => ({\n type: 'field' as const,\n field: fc.field,\n oldValue: fc.oldValue,\n newValue: fc.newValue,\n significance: fc.significance,\n })),\n ...pkgJsonComparison.dependencyChanges\n .filter((dc) => dc.semanticChange !== 'equivalent' && dc.semanticChange !== 'none')\n .map((dc) => ({\n type: 'dependency' as const,\n field: `${dc.type}.${dc.name}`,\n oldValue: dc.oldSpec,\n newValue: dc.newSpec,\n significance: 'significant' as const,\n })),\n ];\n\n callback(null, {\n needsPublish: true,\n reason: pkgJsonComparison.summary,\n changes,\n });\n return;\n }\n\n // Step 7: Other files changed\n callback(null, {\n needsPublish: true,\n reason: `Code changes detected (${fileComparison.fileChanges.length} files changed)`,\n changes: fileComparison.fileChanges.map((fc) => ({\n type: 'file' as const,\n field: fc.path,\n significance: 'significant' as const,\n })),\n });\n })().catch(callback);\n}\n\n/**\n * Callback-based needsPublish\n */\nexport function needsPublishCb(options: NeedsPublishOptions, callback: NeedsPublishCallback): void {\n needsPublishImpl(options, callback);\n}\n\n/**\n * Determine if a package needs to be published to npm.\n *\n * @example\n * ```ts\n * import { needsPublish } from 'npm-needs-publish';\n *\n * const result = await needsPublish({ cwd: process.cwd() });\n * if (result.needsPublish) {\n * console.log('Publish needed:', result.reason);\n * }\n * ```\n */\nexport function needsPublish(options: NeedsPublishOptions = {}): Promise<NeedsPublishResult> {\n return new Promise((resolve, reject) => {\n needsPublishCb(options, (error, result) => {\n if (error) reject(error);\n else if (result) resolve(result);\n else reject(new Error('No result returned'));\n });\n });\n}\n"],"names":["fs","Module","path","stringStartsWith","_require","require","createRequire","url","needsPublishImpl","options","callback","cwd","process","localPkg","package","JSON","parse","readFileSync","join","private","needsPublish","reason","pacote","Arborist","npa","execFile","promisify","execFileAsync","comparePackageFiles","comparePackageJson","extractPackageJson","hashBuffer","registry","scope","name","split","undefined","stdout","trim","registryPkg","registryTarball","packument","latestVersion","latest","changes","type","significance","versions","version","field","oldValue","newValue","tarballUrl","dist","tarball","integrity","err","error","code","message","localTarball","spec","manifest","_resolved","_integrity","localHash","registryHash","substring","fileComparison","identical","packageJsonOnly","localTarballPkg","registryTarballPkg","pkgJsonComparison","includeOptionalDeps","additionalSignificantFields","ignoreFields","treatNarrowingAsEquivalent","hasSignificantChanges","fieldChanges","map","fc","dependencyChanges","filter","dc","semanticChange","oldSpec","newSpec","summary","fileChanges","length","catch","needsPublishCb","Promise","resolve","reject","result","Error"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "npm-needs-publish",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Smart publish detection for npm packages - semantic package.json comparison with semver-aware dependency analysis",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"npm",
|
|
@@ -55,34 +55,33 @@
|
|
|
55
55
|
"version": "tsds version"
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
|
-
"@npmcli/arborist": "
|
|
59
|
-
"fs-copy-compat": "
|
|
60
|
-
"fs-remove-compat": "
|
|
61
|
-
"mkdirp-classic": "
|
|
62
|
-
"npm-package-arg": "
|
|
63
|
-
"pacote": "
|
|
64
|
-
"semver": "
|
|
65
|
-
"tar": "
|
|
66
|
-
"temp-suffix": "
|
|
67
|
-
"tsds-lib": "*"
|
|
58
|
+
"@npmcli/arborist": "^7.5.4",
|
|
59
|
+
"fs-copy-compat": "^0.1.3",
|
|
60
|
+
"fs-remove-compat": "^0.2.1",
|
|
61
|
+
"mkdirp-classic": "^0.5.3",
|
|
62
|
+
"npm-package-arg": "^13.0.2",
|
|
63
|
+
"pacote": "^17.0.7",
|
|
64
|
+
"semver": "^7.7.3",
|
|
65
|
+
"tar": "^7.5.2",
|
|
66
|
+
"temp-suffix": "^1.0.8"
|
|
68
67
|
},
|
|
69
68
|
"devDependencies": {
|
|
70
|
-
"@types/mocha": "
|
|
71
|
-
"@types/node": "
|
|
69
|
+
"@types/mocha": "^10.0.10",
|
|
70
|
+
"@types/node": "^24.10.1",
|
|
72
71
|
"@types/pacote": "^11.1.8",
|
|
73
|
-
"@types/semver": "
|
|
74
|
-
"@types/tar": "
|
|
75
|
-
"module-link-unlink": "
|
|
76
|
-
"node-version-use": "
|
|
77
|
-
"os-shim": "
|
|
78
|
-
"queue-cb": "
|
|
79
|
-
"resolve": "
|
|
80
|
-
"short-hash": "
|
|
81
|
-
"ts-dev-stack": "
|
|
82
|
-
"tsds-config": "
|
|
83
|
-
"tsds-lib-test": "
|
|
72
|
+
"@types/semver": "^7.7.1",
|
|
73
|
+
"@types/tar": "^6.1.13",
|
|
74
|
+
"module-link-unlink": "^1.0.9",
|
|
75
|
+
"node-version-use": "^1.9.7",
|
|
76
|
+
"os-shim": "^0.1.3",
|
|
77
|
+
"queue-cb": "^1.6.1",
|
|
78
|
+
"resolve": "^1.22.11",
|
|
79
|
+
"short-hash": "^1.0.0",
|
|
80
|
+
"ts-dev-stack": "^1.21.2",
|
|
81
|
+
"tsds-config": "^0.2.0",
|
|
82
|
+
"tsds-lib-test": "^1.19.4"
|
|
84
83
|
},
|
|
85
84
|
"engines": {
|
|
86
|
-
"node": ">=16"
|
|
85
|
+
"node": ">=16.14.0"
|
|
87
86
|
}
|
|
88
87
|
}
|