重新生成丢失的包锁.从node_modules. Json文件



我的项目的原始开发人员没有提交package-lock.json文件,只提交了package.json文件。当我做npm install时,我创建了我自己的package-lock.json文件,但那是5年前的事了,我当时没有意识到我需要将文件检入Git,因为我愚蠢地认为原始开发人员知道他们在做什么。

现在我们有了第二个开发人员,而且我需要添加一个新包。这两件事都要求我有"原始的"。package-lock.json文件。

是否有一种方法可以使用npm从我的node_modules目录的内容重建package-lock.json文件,这是现在唯一的真相来源?我查看了各种答案,并尝试了一些npm命令,例如npm i --package-lock-only,但这给了我一个今天创建的文件,而不是基于我的node_modules目录的文件。

所以,没有找到答案,我花了两天时间编写了一些PHP代码来为我完成这项工作。代码是不完整的,例如,它假设唯一的生产模块将是angularangular-ui-router,因为我不需要任何更复杂的项目。但是,创建package-lock.json文件的精确副本已经足够好了,因为它不能解析找不到的包的版本。

代码是为了工作而写的,不一定要容易理解,所以它可能有点不透明。

使用:

<?php
$package_lock = new PackageLock();
// or
$package_lock = new PackageLock('path/to/packages');

代码:

<?php
class PackageLock {
protected const MY_PACKAGE = 'my-package';
protected const MY_VERSION = '0.0.0';
//
protected const FILE_NAME = 'package-lock-recreated.json';
protected const NODE_MODULES = 'node_modules';
//
protected array $modules = [];
protected array $packages = [
'name' => PackageLock::MY_PACKAGE,
'version' => PackageLock::MY_VERSION,
'lockfileVersion' => 1,
'requires' => true,
];
protected string $dir;
public function __construct(string $dir = '.') {
$this->dir = $dir;
$this->packages['dependencies'] = $this->parse();
file_put_contents(PackageLock::FILE_NAME, preg_replace('/^( +)1/m', '$1', json_encode($this->packages, JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT)));
}
protected function parse(array $priors = []): array {
$nm = PackageLock::NODE_MODULES;
$requests = $priors;
array_unshift($requests, '');
$current_priors = $requests;
$current_priors[] = '';
$main_path = $this->dir . implode("/{$nm}/", $current_priors);
$dir_pattern = $main_path . '*';
$dirs = glob($dir_pattern);
$current_dir = dirname($dir_pattern, 2);
$dependencies = [];
foreach ($dirs as $dir) {
$module_name = basename($dir);
if (in_array($module_name, ['angular-moment-picker', 'json-loader', 'moment-timezone'])) {
continue;
}
$this->modules[$dir] = json_decode(file_get_contents("{$dir}/package.json"));
}
foreach ($this->modules as $dir => $module) {
if (strpos($dir, $main_path) !== 0) {
continue;
}
$module_name = basename($dir);
$dependencies[$module_name] = [
'version' => $module->version,
'resolved' => $module->_resolved,
'integrity' => $module->_integrity,
];
if (!$this->is_prod($module_name)) {
$dependencies[$module_name]['dev'] = true;
}
if ($this->is_optional($main_path . $module_name)) {
$dependencies[$module_name]['optional'] = true;
}
if (!empty($module->dependencies) && (array)$module->dependencies) {
$dependencies[$module_name]['requires'] = $module->dependencies;
}
if (is_dir("{$current_dir}/{$nm}/{$module_name}/{$nm}")) {
$dependencies[$module_name]['dependencies'] = $this->parse_dependencies($priors, $module_name);
}
}
return $dependencies;
}
protected function is_prod($module_name): bool {
return in_array($module_name, ['angular', 'angular-ui-router']);
}
protected function parse_dependencies(array $priors, string $module_name): array {
$priors[] = $module_name;
return $this->parse($priors);
}
protected function is_optional($key): bool {
$module_name = basename($key);
$is_optional = false;
if (!array_key_exists($key, $this->modules)) {
var_dump("Key does not exist: {$key}");
}
if ($this->modules[$key]) {
foreach ($this->modules[$key]->_requiredBy as $parent_module_path) {
if (in_array($parent_module_path, ['/', '#USER', '#DEV:/'])) {
break;
}
$parent_module_path = $this->module_to_file_path($parent_module_path);
if (array_key_exists($parent_module_path, $this->modules)) {
$is_optional = $this->check_optional($parent_module_path, $module_name);
}
else {
$file_name = "{$parent_module_path}/package.json";
if (!file_exists($file_name)) {
$is_optional = true;
}
else {
$this->modules[$parent_module_path] = json_decode(file_get_contents($file_name));
$is_optional = $this->check_optional($parent_module_path, $module_name);
unset($this->modules[$parent_module_path]);
}
}
if (!$is_optional) {
break;
}
}
}
return $is_optional;
}
protected function module_to_file_path($module_path): string {
return $this->dir . str_replace('/', '/' . PackageLock::NODE_MODULES . '/', $module_path);
}
protected function check_optional(string $parent_module_path, $module_name): bool {
if (
!empty($this->modules[$parent_module_path]->optionalDependencies)
&& property_exists($this->modules[$parent_module_path]->optionalDependencies, $module_name)
) {
$is_optional = true;
}
else {
$is_optional = $this->is_optional($parent_module_path);
}
return $is_optional;
}
}