2023-11-02 05:55:51 +08:00
|
|
|
/**
|
|
|
|
* External dependencies.
|
|
|
|
*/
|
|
|
|
const fs = require( 'fs' );
|
|
|
|
const path = require( 'path' );
|
|
|
|
|
|
|
|
// A cache for package files so that we don't keep loading them unnecessarily.
|
|
|
|
const packageFileCache = {};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Loads a package file or pull it from the cache.
|
|
|
|
*
|
|
|
|
* @param {string} packagePath The path to the package directory.
|
|
|
|
* @return {Object} The package file.
|
|
|
|
*/
|
|
|
|
function loadPackageFile( packagePath ) {
|
2023-11-30 03:18:42 +08:00
|
|
|
// Resolve the absolute path for consistency when loading and updating.
|
|
|
|
packagePath = path.resolve( __dirname, packagePath );
|
|
|
|
|
2023-11-02 05:55:51 +08:00
|
|
|
if ( packageFileCache[ packagePath ] ) {
|
|
|
|
return packageFileCache[ packagePath ];
|
|
|
|
}
|
|
|
|
|
|
|
|
const packageFile = JSON.parse(
|
|
|
|
fs.readFileSync( path.join( packagePath, 'package.json' ), 'utf8' )
|
|
|
|
);
|
|
|
|
|
|
|
|
packageFileCache[ packagePath ] = packageFile;
|
|
|
|
return packageFile;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Updates a package file on disk and in the cache.
|
|
|
|
*
|
|
|
|
* @param {string} packagePath The path to the package file to update.
|
|
|
|
* @param {Object} packageFile The new package file contents.
|
|
|
|
*/
|
|
|
|
function updatePackageFile( packagePath, packageFile ) {
|
2023-11-30 03:18:42 +08:00
|
|
|
// Resolve the absolute path for consistency when loading and updating.
|
|
|
|
packagePath = path.resolve( __dirname, packagePath );
|
2023-11-02 05:55:51 +08:00
|
|
|
packageFileCache[ packagePath ] = packageFile;
|
|
|
|
|
|
|
|
fs.writeFileSync(
|
|
|
|
path.join( packagePath, 'package.json' ),
|
2023-12-06 06:24:32 +08:00
|
|
|
// Make sure to keep the newline at the end of the file.
|
|
|
|
JSON.stringify( packageFile, null, '\t' ) + "\n",
|
2023-11-02 05:55:51 +08:00
|
|
|
'utf8'
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2025-02-05 17:28:11 +08:00
|
|
|
* Populated config object based on declared and resolved dependencies.
|
2023-11-02 05:55:51 +08:00
|
|
|
*
|
2025-02-05 17:28:11 +08:00
|
|
|
* @param {string} packageName Package name.
|
|
|
|
* @param {string} packagePath Package path.
|
|
|
|
* @param {Object} declaredDependencies Declared dependencies from package-file.
|
|
|
|
* @param {Object} resolvedDependencies Resolved dependencies from lock-file.
|
|
|
|
* @param {Object} config Dependency output path configuration.
|
|
|
|
* @param {Object} context The hook context object.
|
|
|
|
* @param {Function.<string>} context.log Logs a message to the console.
|
2023-11-02 05:55:51 +08:00
|
|
|
*
|
2025-02-05 17:28:11 +08:00
|
|
|
* @return void
|
2023-11-02 05:55:51 +08:00
|
|
|
*/
|
2025-02-05 17:28:11 +08:00
|
|
|
function updateConfig( packageName, packagePath, declaredDependencies, resolvedDependencies, config, context ) {
|
|
|
|
for ( const [ key, value ] of Object.entries( declaredDependencies ) ) {
|
|
|
|
if ( value.startsWith( 'workspace:' ) ) {
|
|
|
|
const normalizedPath = path.join( packagePath, resolvedDependencies[key].replace( 'link:', '' ) );
|
|
|
|
context.log( `[wireit][${ packageName }] Inspecting workspace dependency: ${ key } (${ normalizedPath })` );
|
|
|
|
|
|
|
|
// Actualize output storage with the identified entries.
|
2025-02-05 22:54:01 +08:00
|
|
|
const dependencyFile = loadPackageFile( normalizedPath );
|
2025-02-05 17:28:11 +08:00
|
|
|
if ( dependencyFile.files ) {
|
|
|
|
for ( const entry in dependencyFile.files ) {
|
|
|
|
const entryValue = dependencyFile.files[entry];
|
|
|
|
let normalizedValue;
|
|
|
|
if ( entryValue.startsWith( '!' ) ) {
|
|
|
|
normalizedValue = '!' + path.join( 'node_modules', key, entryValue.substring( 1 ) );
|
|
|
|
} else {
|
|
|
|
normalizedValue = path.join( 'node_modules', key, entryValue );
|
|
|
|
}
|
|
|
|
config.files.push( normalizedValue );
|
|
|
|
|
|
|
|
context.log( `[wireit][${ packageName }] - ${ normalizedValue }` );
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
context.log( `[wireit][${ packageName }] ---` );
|
|
|
|
}
|
2023-11-02 05:55:51 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2025-02-05 17:28:11 +08:00
|
|
|
* This hook allows for the mutation of the lockfile before it is serialized.
|
2023-11-02 05:55:51 +08:00
|
|
|
*
|
2025-02-05 17:28:11 +08:00
|
|
|
* @param {Object} lockfile The lock file that was produced by PNPM.
|
|
|
|
* @param {string} lockfile.lockfileVersion The version of the lock file spec.
|
|
|
|
* @param {Object.<string, Object>} lockfile.importers The packages in the workspace that are included in the lock file, keyed by the relative path to the package.
|
|
|
|
* @param {Object} context The hook context object.
|
|
|
|
* @param {Function.<string>} context.log Logs a message to the console.
|
2023-11-02 05:55:51 +08:00
|
|
|
*
|
2025-02-05 17:28:11 +08:00
|
|
|
* @return {Object} lockfile The updated lockfile.
|
2023-11-02 05:55:51 +08:00
|
|
|
*/
|
2025-02-05 17:28:11 +08:00
|
|
|
function afterAllResolved( lockfile, context ) {
|
2023-11-02 05:55:51 +08:00
|
|
|
context.log( '[wireit] Updating Dependency Lists' );
|
|
|
|
|
2025-02-05 17:28:11 +08:00
|
|
|
for ( const packagePath in lockfile.importers ) {
|
2023-11-02 05:55:51 +08:00
|
|
|
const packageFile = loadPackageFile( packagePath );
|
2025-02-05 17:28:11 +08:00
|
|
|
if ( packageFile.wireit ) {
|
|
|
|
context.log( `[wireit][${ packageFile.name }] Verifying 'wireit.dependencyOutputs'` );
|
|
|
|
|
|
|
|
// Initialize outputs storage and hash it's original state.
|
|
|
|
const config = {
|
|
|
|
allowUsuallyExcludedPaths: true, // This is needed so we can reference files in `node_modules`.
|
|
|
|
files: [ "package.json" ], // The files list will include globs for dependency files that we should fingerprint.
|
|
|
|
};
|
|
|
|
const originalConfigState = JSON.stringify( config );
|
|
|
|
|
|
|
|
// Walk through workspace-located dependencies and provision.
|
|
|
|
updateConfig(
|
|
|
|
packageFile.name,
|
|
|
|
packagePath,
|
|
|
|
{
|
|
|
|
...( packageFile.dependencies || {} ),
|
|
|
|
...( packageFile.devDependencies || {} ),
|
|
|
|
},
|
|
|
|
{
|
|
|
|
...( lockfile.importers[ packagePath ].dependencies || {} ),
|
|
|
|
...( lockfile.importers[ packagePath ].devDependencies || {} ),
|
|
|
|
},
|
|
|
|
config,
|
|
|
|
context
|
|
|
|
);
|
2023-11-02 05:55:51 +08:00
|
|
|
|
2025-02-05 17:28:11 +08:00
|
|
|
// Verify config state and update manifest on mismatch.
|
|
|
|
let updated = false;
|
|
|
|
const newConfigState = JSON.stringify( config );
|
|
|
|
if ( newConfigState !== originalConfigState ) {
|
|
|
|
const loadedConfigState = JSON.stringify( packageFile.wireit?.dependencyOutputs || {} );
|
|
|
|
if ( newConfigState !== loadedConfigState ) {
|
|
|
|
context.log( `[wireit][${ packageFile.name }] Conclusion: outdated, updating 'wireit.dependencyOutputs'` );
|
|
|
|
|
|
|
|
packageFile.wireit.dependencyOutputs = config;
|
|
|
|
updatePackageFile( packagePath, packageFile );
|
|
|
|
updated = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( ! updated ) {
|
|
|
|
context.log( `[wireit][${ packageFile.name }] Conclusion: up to date` );
|
2023-12-12 08:21:35 +08:00
|
|
|
}
|
2023-11-02 05:55:51 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
context.log( '[wireit] Done' );
|
|
|
|
|
|
|
|
return lockfile;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Note: The hook function names are important. They are used by PNPM when determining what functions to call.
|
|
|
|
module.exports = {
|
|
|
|
hooks: {
|
|
|
|
afterAllResolved,
|
|
|
|
},
|
|
|
|
};
|