@bobfrankston/npmglobalize 1.0.92 → 1.0.93
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/.claude/settings.local.json +3 -1
- package/lib.d.ts +3 -5
- package/lib.js +66 -36
- package/package.json +12 -2
package/lib.d.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* Current approach uses synchronous child_process calls for stability and simplicity.
|
|
10
10
|
* Consider library-based approach if async operations or cross-platform issues arise.
|
|
11
11
|
*/
|
|
12
|
+
import { NpmCommonConfig } from '@bobfrankston/userconfig';
|
|
12
13
|
/** Options for the globalize operation */
|
|
13
14
|
export interface GlobalizeOptions {
|
|
14
15
|
/** Bump type: patch (default), minor, major */
|
|
@@ -94,11 +95,8 @@ export interface WorkspaceResult {
|
|
|
94
95
|
}
|
|
95
96
|
/** Read and parse package.json from a directory */
|
|
96
97
|
export declare function readPackageJson(dir: string): any;
|
|
97
|
-
/** Global npm config from %USERPROFILE%\.userconfig\npm.json5 */
|
|
98
|
-
export
|
|
99
|
-
scope?: string;
|
|
100
|
-
npmVisibility?: 'private' | 'public';
|
|
101
|
-
}
|
|
98
|
+
/** Global npm config from %USERPROFILE%\.userconfig\npm.json5 — via @bobfrankston/userconfig */
|
|
99
|
+
export type UserNpmConfig = NpmCommonConfig;
|
|
102
100
|
/** Get the .userconfig directory path (%USERPROFILE%\.userconfig) */
|
|
103
101
|
export declare function getUserConfigDir(): string;
|
|
104
102
|
/** Read global npm config from %USERPROFILE%\.userconfig\npm.json5 */
|
package/lib.js
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
import fs from 'fs';
|
|
13
13
|
import path from 'path';
|
|
14
14
|
import { execSync, spawnSync } from 'child_process';
|
|
15
|
+
import { readConfig as readUserConfig, writeConfig as writeUserConfig, configDir } from '@bobfrankston/userconfig';
|
|
15
16
|
/** Wrapper for spawnSync that avoids DEP0190 (args + shell: true).
|
|
16
17
|
* When shell is true, joins cmd+args into a single command string. */
|
|
17
18
|
function spawnSafe(cmd, args, options = {}) {
|
|
@@ -90,43 +91,17 @@ export function readPackageJson(dir) {
|
|
|
90
91
|
}
|
|
91
92
|
/** Get the .userconfig directory path (%USERPROFILE%\.userconfig) */
|
|
92
93
|
export function getUserConfigDir() {
|
|
93
|
-
|
|
94
|
-
return path.join(userProfile, '.userconfig');
|
|
94
|
+
return configDir;
|
|
95
95
|
}
|
|
96
96
|
/** Read global npm config from %USERPROFILE%\.userconfig\npm.json5 */
|
|
97
97
|
export function readUserNpmConfig() {
|
|
98
|
-
|
|
99
|
-
if (!fs.existsSync(configPath)) {
|
|
100
|
-
return {};
|
|
101
|
-
}
|
|
102
|
-
try {
|
|
103
|
-
const content = fs.readFileSync(configPath, 'utf-8');
|
|
104
|
-
return JSON5.parse(content);
|
|
105
|
-
}
|
|
106
|
-
catch (error) {
|
|
107
|
-
console.warn(`Warning: Could not parse ${configPath}: ${error.message}`);
|
|
108
|
-
return {};
|
|
109
|
-
}
|
|
98
|
+
return readUserConfig();
|
|
110
99
|
}
|
|
111
100
|
/** Write global npm config to %USERPROFILE%\.userconfig\npm.json5 */
|
|
112
101
|
export function writeUserNpmConfig(config) {
|
|
113
|
-
const
|
|
114
|
-
if (!fs.existsSync(configDir)) {
|
|
115
|
-
fs.mkdirSync(configDir, { recursive: true });
|
|
116
|
-
}
|
|
117
|
-
const configPath = path.join(configDir, 'npm.json5');
|
|
118
|
-
// Read existing to merge
|
|
119
|
-
const existing = readUserNpmConfig();
|
|
102
|
+
const existing = readUserConfig();
|
|
120
103
|
const merged = { ...existing, ...config };
|
|
121
|
-
|
|
122
|
-
const entries = Object.entries(merged);
|
|
123
|
-
for (let i = 0; i < entries.length; i++) {
|
|
124
|
-
const [key, value] = entries[i];
|
|
125
|
-
const comma = i < entries.length - 1 ? ',' : '';
|
|
126
|
-
lines.push(` ${key}: ${JSON.stringify(value)}${comma}`);
|
|
127
|
-
}
|
|
128
|
-
lines.push('}');
|
|
129
|
-
fs.writeFileSync(configPath, lines.join('\n') + '\n', 'utf-8');
|
|
104
|
+
writeUserConfig(merged);
|
|
130
105
|
}
|
|
131
106
|
/** Read .globalize.json5 config file */
|
|
132
107
|
export function readConfig(dir) {
|
|
@@ -340,13 +315,36 @@ export function checkNpmAccess(packageName) {
|
|
|
340
315
|
return 'restricted'; // Default for scoped
|
|
341
316
|
}
|
|
342
317
|
else {
|
|
343
|
-
// Unscoped packages are always public if they exist
|
|
318
|
+
// Unscoped packages are always public if they exist — but only if we own them
|
|
344
319
|
const result = spawnSafe('npm', ['view', packageName, 'name'], {
|
|
345
320
|
encoding: 'utf-8',
|
|
346
321
|
stdio: 'pipe',
|
|
347
322
|
shell: true
|
|
348
323
|
});
|
|
349
324
|
if (result.status === 0 && result.stdout && result.stdout.trim()) {
|
|
325
|
+
// Package exists on npm — check if current user is a maintainer
|
|
326
|
+
const maintResult = spawnSafe('npm', ['view', packageName, 'maintainers', '--json'], {
|
|
327
|
+
encoding: 'utf-8',
|
|
328
|
+
stdio: 'pipe',
|
|
329
|
+
shell: true
|
|
330
|
+
});
|
|
331
|
+
if (maintResult.status === 0 && maintResult.stdout) {
|
|
332
|
+
const auth = checkNpmAuth();
|
|
333
|
+
if (auth.username) {
|
|
334
|
+
try {
|
|
335
|
+
const maintainers = JSON.parse(maintResult.stdout.trim());
|
|
336
|
+
const names = Array.isArray(maintainers)
|
|
337
|
+
? maintainers.map((m) => typeof m === 'string' ? m.replace(/ <.*/, '') : m.name)
|
|
338
|
+
: [];
|
|
339
|
+
if (!names.includes(auth.username)) {
|
|
340
|
+
return null; // Exists but we don't own it
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
catch {
|
|
344
|
+
// Parse failed — fall through to return public
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
350
348
|
return 'public';
|
|
351
349
|
}
|
|
352
350
|
return null;
|
|
@@ -2168,13 +2166,45 @@ export async function globalize(cwd, options = {}, configOptions = {}) {
|
|
|
2168
2166
|
console.log(colors.dim(` Use --npm public to make it public`));
|
|
2169
2167
|
}
|
|
2170
2168
|
else {
|
|
2171
|
-
|
|
2172
|
-
console.log(colors.yellow(` Unscoped packages cannot be private on npm.`));
|
|
2169
|
+
// Unscoped new package — prompt to add scope (same as explicit-private path)
|
|
2173
2170
|
const ucfg = readUserNpmConfig();
|
|
2174
2171
|
const auth2 = checkNpmAuth();
|
|
2175
|
-
const
|
|
2176
|
-
|
|
2177
|
-
|
|
2172
|
+
const defaultScope = ucfg.scope
|
|
2173
|
+
|| (auth2.username ? `@${auth2.username}` : undefined);
|
|
2174
|
+
const scopedExample = defaultScope ? `${defaultScope}/${pkg.name}` : `@scope/${pkg.name}`;
|
|
2175
|
+
console.log(colors.yellow(`WARNING: Package '${pkg.name}' is unscoped and will be PUBLIC.`));
|
|
2176
|
+
console.log(colors.yellow(` Unscoped packages cannot be private on npm.`));
|
|
2177
|
+
if (dryRun) {
|
|
2178
|
+
console.log(` [dry-run] Would prompt to add scope (e.g., ${scopedExample})`);
|
|
2179
|
+
}
|
|
2180
|
+
else {
|
|
2181
|
+
const addScope = await confirm(`Add scope to make it private (e.g., ${scopedExample})?`, true);
|
|
2182
|
+
if (addScope) {
|
|
2183
|
+
const scope = await promptText('Scope:', defaultScope);
|
|
2184
|
+
if (scope) {
|
|
2185
|
+
const normalizedScope = scope.startsWith('@') ? scope : `@${scope}`;
|
|
2186
|
+
const newName = `${normalizedScope}/${pkg.name}`;
|
|
2187
|
+
pkg.name = newName;
|
|
2188
|
+
writePackageJson(cwd, pkg);
|
|
2189
|
+
console.log(colors.green(`✓ Renamed package to ${newName}`));
|
|
2190
|
+
if (!ucfg.scope) {
|
|
2191
|
+
const saveScope = await confirm(`Save scope "${normalizedScope}" to global config (${getUserConfigDir()}\\npm.json5)?`, true);
|
|
2192
|
+
if (saveScope) {
|
|
2193
|
+
writeUserNpmConfig({ scope: normalizedScope });
|
|
2194
|
+
console.log(colors.green(`✓ Saved default scope to ${getUserConfigDir()}\\npm.json5`));
|
|
2195
|
+
}
|
|
2196
|
+
}
|
|
2197
|
+
}
|
|
2198
|
+
else {
|
|
2199
|
+
console.log(colors.yellow(` No scope provided. Continuing as public.`));
|
|
2200
|
+
console.log(colors.yellow(` Use --npm public to suppress this prompt.`));
|
|
2201
|
+
}
|
|
2202
|
+
}
|
|
2203
|
+
else {
|
|
2204
|
+
console.log(colors.yellow(` Continuing as public.`));
|
|
2205
|
+
console.log(colors.yellow(` Use --npm public to suppress this prompt.`));
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2178
2208
|
}
|
|
2179
2209
|
}
|
|
2180
2210
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bobfrankston/npmglobalize",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.93",
|
|
4
4
|
"description": "Transform file: dependencies to npm versions for publishing",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"author": "Bob Frankston",
|
|
23
23
|
"license": "MIT",
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@types/node": "^25.
|
|
25
|
+
"@types/node": "^25.3.0",
|
|
26
26
|
"@types/npm-package-arg": "^6.1.4",
|
|
27
27
|
"@types/pacote": "^11.1.8"
|
|
28
28
|
},
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"url": "https://github.com/BobFrankston/npmglobalize.git"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
+
"@bobfrankston/userconfig": "^1.0.3",
|
|
34
35
|
"@npmcli/package-json": "^7.0.4",
|
|
35
36
|
"json5": "^2.2.3",
|
|
36
37
|
"libnpmversion": "^8.0.3",
|
|
@@ -40,5 +41,14 @@
|
|
|
40
41
|
},
|
|
41
42
|
"publishConfig": {
|
|
42
43
|
"access": "public"
|
|
44
|
+
},
|
|
45
|
+
".dependencies": {
|
|
46
|
+
"@bobfrankston/userconfig": "file:../userconfig",
|
|
47
|
+
"@npmcli/package-json": "^7.0.4",
|
|
48
|
+
"json5": "^2.2.3",
|
|
49
|
+
"libnpmversion": "^8.0.3",
|
|
50
|
+
"npm-registry-fetch": "^19.1.1",
|
|
51
|
+
"pacote": "^21.0.4",
|
|
52
|
+
"simple-git": "^3.30.0"
|
|
43
53
|
}
|
|
44
54
|
}
|