@s2j/global-npm 2.1.1 → 2.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  # 📦 Global npm Package Setup
2
2
 
3
3
  Node.js の **グローバル npm パッケージ管理** を `package.json` で一元化する CLI です。
4
- macOS / Windows 11で同じ `global-npm` フローを使えます。
4
+ macOS、Windows 11で同じ `global-npm` フローを使えます。
5
5
 
6
6
  GitHub: [stein2nd/global-npm-setup](https://github.com/stein2nd/global-npm-setup)
7
7
 
@@ -29,13 +29,13 @@ global-npm install
29
29
  |--------|------|------|
30
30
  | Upstream 正本 | `@s2j/global-npm` 同梱 `package.json` | 公式 `dependencies` 一覧 |
31
31
  | ユーザー overlay | `$SETUP_DIR/user-deps.json` | 追加分、ピン留め |
32
- | 実効 package.json | `$SETUP_DIR/package.json` | ncu / install が読む実効マニフェスト |
32
+ | 実効 package.json | `$SETUP_DIR/package.json` | ncu、install が読む実効マニフェスト |
33
33
 
34
34
  **setup ディレクトリ (`$SETUP_DIR`) のデフォルト**
35
35
 
36
36
  | OS | パス |
37
37
  |----|------|
38
- | macOS / Linux | `~/.config/global-npm` |
38
+ | macOS、Linux | `~/.config/global-npm` |
39
39
  | Windows 11 | `%APPDATA%\global-npm` |
40
40
 
41
41
  `GLOBAL_NPM_SETUP_DIR` 環境変数で上書きできます。詳細は [docs/layout.md](./docs/layout.md) をご覧ください。
@@ -78,6 +78,7 @@ Node.js v18以上 (LTS 推奨) が未導入の場合は、先にインストー
78
78
 
79
79
  ```sh
80
80
  npm install -g @s2j/global-npm # CLI 本体の導入 (これは一度だけ)
81
+ global-npm check # 同梱 ncu で動作 (PATH に ncu 不要)
81
82
  global-npm add @s2j/docs-linter@^1.0.16 # 任意: ユーザー追加分
82
83
  global-npm install # 実効 package.json の dependencies を global install
83
84
  ```
@@ -130,7 +131,7 @@ flowchart LR
130
131
  ```
131
132
 
132
133
  * **check:** sync 後に ncu で更新候補を表示。ncu 自体は range を書き換えない。
133
- * **update:** 実効 package.json の `dependencies` / `devDependencies` の range を更新。
134
+ * **update:** 実効 package.json の `dependencies`、`devDependencies` の range を更新。
134
135
  * **install:** 実効 package.json の **dependencies** のみ global install。
135
136
 
136
137
  ## 開発用 scripts
@@ -158,7 +159,7 @@ npm run ncu:update
158
159
  |--------|------|
159
160
  | setup = package root | setup = `~/.config/global-npm`。Windows は `%APPDATA%\global-npm` |
160
161
  | 同梱 `package.json` を直接 ncu | 実効 package.json を ncu |
161
- | 3サブコマンド | 5サブコマンド (`sync` / `add` 追加) |
162
+ | 3サブコマンド | 5サブコマンド (`sync`、`add` 追加) |
162
163
 
163
164
  移行手順は、下記のとおりです。
164
165
 
@@ -6,6 +6,7 @@ const path = require('path');
6
6
  const { toGlobalInstallSpec } = require('../lib/install-spec.cjs');
7
7
  const { ensureSetupDir, readDependencies, readUserDeps, writeJson } = require('../lib/pkg-io.cjs');
8
8
  const { resolveSetupContext } = require('../lib/paths.cjs');
9
+ const { resolveNcuInvocation } = require('../lib/resolve-ncu.cjs');
9
10
  const { parseAddSpec, resolveDefaultRange } = require('../lib/resolve-range.cjs');
10
11
  const { formatReport, syncManifest } = require('../lib/sync-manifest.cjs');
11
12
 
@@ -25,10 +26,10 @@ function usage() {
25
26
  process.exit(1);
26
27
  }
27
28
 
28
- function run(command, args) {
29
+ function run(command, args, { useShell = shell } = {}) {
29
30
  const result = spawnSync(command, args, {
30
31
  stdio: 'inherit',
31
- shell,
32
+ shell: useShell,
32
33
  });
33
34
 
34
35
  if (result.error) {
@@ -39,6 +40,11 @@ function run(command, args) {
39
40
  process.exit(result.status ?? 1);
40
41
  }
41
42
 
43
+ function runNcu(args) {
44
+ const { command, prefixArgs, useShell } = resolveNcuInvocation(packageRoot);
45
+ run(command, [...prefixArgs, ...args], { useShell });
46
+ }
47
+
42
48
  function prepare() {
43
49
  ensureSetupDir(ctx);
44
50
  return syncManifest(ctx);
@@ -102,19 +108,19 @@ const restArgs = process.argv.slice(3);
102
108
  switch (subcommand) {
103
109
  case 'check':
104
110
  prepare();
105
- run('ncu', ['-g', '--format', 'time', '--packageFile', pkgPath]);
111
+ runNcu(['-g', '--format', 'time', '--packageFile', pkgPath]);
106
112
  break;
107
113
 
108
114
  case 'update':
109
115
  prepare();
110
- run('ncu', ['-g', '--format', 'time', '-u', '--packageFile', pkgPath]);
116
+ runNcu(['-g', '--format', 'time', '-u', '--packageFile', pkgPath]);
111
117
  break;
112
118
 
113
119
  case 'install': {
114
120
  prepare();
115
121
  const dependencies = readDependencies(pkgPath);
116
122
  const specs = Object.entries(dependencies).map(([name, versionRange]) =>
117
- toGlobalInstallSpec(name, versionRange),
123
+ toGlobalInstallSpec(name, versionRange, { pinVersion: true }),
118
124
  );
119
125
 
120
126
  if (specs.length === 0) {
@@ -1,13 +1,48 @@
1
1
  'use strict';
2
2
 
3
- function toGlobalInstallSpec(name, versionRange) {
3
+ const { spawnSync } = require('child_process');
4
+
5
+ const shell = process.platform === 'win32';
6
+
7
+ function resolvePinnedVersion(name, versionRange, { spawn = spawnSync } = {}) {
8
+ const trimmed = typeof versionRange === 'string' ? versionRange.trim() : '';
9
+ if (!trimmed) {
10
+ return undefined;
11
+ }
12
+
13
+ const result = spawn('npm', ['view', `${name}@${trimmed}`, 'version', '--json'], {
14
+ encoding: 'utf8',
15
+ shell,
16
+ });
17
+
18
+ if (result.status !== 0) {
19
+ return trimmed;
20
+ }
21
+
22
+ try {
23
+ const parsed = JSON.parse(result.stdout.trim());
24
+ if (typeof parsed === 'string' && parsed) {
25
+ return parsed;
26
+ }
27
+ } catch {
28
+ // fall through to range fallback
29
+ }
30
+
31
+ return trimmed;
32
+ }
33
+
34
+ function toGlobalInstallSpec(name, versionRange, { pinVersion = false, spawn = spawnSync } = {}) {
4
35
  if (typeof versionRange === 'string' && versionRange.trim() !== '') {
5
- return `${name}@${versionRange}`;
36
+ const target = pinVersion
37
+ ? resolvePinnedVersion(name, versionRange, { spawn })
38
+ : versionRange.trim();
39
+ return `${name}@${target}`;
6
40
  }
7
41
 
8
42
  return name;
9
43
  }
10
44
 
11
45
  module.exports = {
46
+ resolvePinnedVersion,
12
47
  toGlobalInstallSpec,
13
48
  };
@@ -0,0 +1,62 @@
1
+ 'use strict';
2
+
3
+ const { existsSync } = require('fs');
4
+ const path = require('path');
5
+
6
+ function bundledNcuCliPath(packageRoot) {
7
+ const nestedCli = path.join(
8
+ packageRoot,
9
+ 'node_modules',
10
+ 'npm-check-updates',
11
+ 'build',
12
+ 'cli.js',
13
+ );
14
+ if (existsSync(nestedCli)) {
15
+ return nestedCli;
16
+ }
17
+
18
+ try {
19
+ const pkgJson = require.resolve('npm-check-updates/package.json', {
20
+ paths: [packageRoot],
21
+ });
22
+ const cliJs = path.join(path.dirname(pkgJson), 'build', 'cli.js');
23
+ if (existsSync(cliJs)) {
24
+ return cliJs;
25
+ }
26
+ } catch {
27
+ // fall through to .bin / PATH
28
+ }
29
+
30
+ return undefined;
31
+ }
32
+
33
+ function resolveNcuInvocation(packageRoot) {
34
+ const cliJs = bundledNcuCliPath(packageRoot);
35
+ if (cliJs) {
36
+ return {
37
+ command: process.execPath,
38
+ prefixArgs: [cliJs],
39
+ useShell: false,
40
+ };
41
+ }
42
+
43
+ const binName = process.platform === 'win32' ? 'ncu.cmd' : 'ncu';
44
+ const localBin = path.join(packageRoot, 'node_modules', '.bin', binName);
45
+ if (existsSync(localBin)) {
46
+ return {
47
+ command: localBin,
48
+ prefixArgs: [],
49
+ useShell: process.platform === 'win32',
50
+ };
51
+ }
52
+
53
+ return {
54
+ command: 'ncu',
55
+ prefixArgs: [],
56
+ useShell: process.platform === 'win32',
57
+ };
58
+ }
59
+
60
+ module.exports = {
61
+ resolveNcuInvocation,
62
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@s2j/global-npm",
3
- "version": "2.1.1",
3
+ "version": "2.1.3",
4
4
  "description": "Manage globally installed npm packages via package.json with ncu.",
5
5
  "author": "Koutarou ISHIKAWA <stein2nd@gmail.com>",
6
6
  "type": "commonjs",
@@ -56,7 +56,7 @@
56
56
  "typescript": "^5.9.3"
57
57
  },
58
58
  "dependencies": {
59
- "@s2j/global-npm": "^2.1.0",
59
+ "@s2j/global-npm": "^2.1.2",
60
60
  "corepack": "^0.35.0",
61
61
  "editorconfig-cli": "^1.0.0",
62
62
  "envinfo": "^7.21.0",