Skip to content

Commit f45e793

Browse files
authoredJun 1, 2024
fix(windows): allow spawning npm cli on windows (#199)
Fixes #198
1 parent c292f92 commit f45e793

9 files changed

+171
-24
lines changed
 

‎dist/main.js

+106-10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎dist/main.js.map

+4-4
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package-lock.json

+28-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
"@types/command-line-args": "^5.2.1",
5757
"@types/node": "^20.10.3",
5858
"@types/tar": "^6.1.6",
59+
"@types/validate-npm-package-name": "^4.0.2",
5960
"@typescript-eslint/eslint-plugin": "^7.2.0",
6061
"@typescript-eslint/parser": "^7.2.0",
6162
"@vitest/coverage-istanbul": "^1.0.1",
@@ -81,6 +82,7 @@
8182
"@types/semver": "^7.5.2",
8283
"command-line-args": "5.2.1",
8384
"semver": "7.6.0",
84-
"tar": "6.2.1"
85+
"tar": "6.2.1",
86+
"validate-npm-package-name": "^5.0.1"
8587
}
8688
}

‎src/__tests__/normalize-options.test.ts

+11-1
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ describe("normalizeOptions", () => {
134134
});
135135
});
136136

137-
it("should validate tag value", () => {
137+
it("should validate tag type", () => {
138138
expect(() => {
139139
subject.normalizeOptions(manifest, {
140140
token: "abc123",
@@ -144,6 +144,16 @@ describe("normalizeOptions", () => {
144144
}).toThrow(errors.InvalidTagError);
145145
});
146146

147+
it("should validate tag value", () => {
148+
expect(() => {
149+
subject.normalizeOptions(manifest, {
150+
token: "abc123",
151+
// tag must not require contain characters encoded by encodeUriComponent
152+
tag: "fresh&clean",
153+
});
154+
}).toThrow(errors.InvalidTagError);
155+
});
156+
147157
it("should validate access value", () => {
148158
expect(() => {
149159
subject.normalizeOptions(manifest, {

‎src/errors.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export class PackageJsonParseError extends SyntaxError {
6262

6363
export class InvalidPackageNameError extends TypeError {
6464
public constructor(value: unknown) {
65-
super(`Package name must be a string, got "${String(value)}"`);
65+
super(`Package name is not valid, got "${String(value)}"`);
6666
this.name = "InvalidPackageNameError";
6767
}
6868
}

‎src/normalize-options.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,13 @@ const validateRegistry = (value: unknown): URL => {
9797
};
9898

9999
const validateTag = (value: unknown): string => {
100-
if (typeof value === "string" && value.length > 0) {
101-
return value;
100+
if (typeof value === "string") {
101+
const trimmedValue = value.trim();
102+
const encodedValue = encodeURIComponent(trimmedValue);
103+
104+
if (trimmedValue.length > 0 && trimmedValue === encodedValue) {
105+
return value;
106+
}
102107
}
103108

104109
throw new errors.InvalidTagError(value);

‎src/npm/call-npm-cli.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ export const PUBLISH = "publish";
3838
export const E404 = "E404";
3939
export const EPUBLISHCONFLICT = "EPUBLISHCONFLICT";
4040

41-
const NPM = os.platform() === "win32" ? "npm.cmd" : "npm";
41+
const IS_WINDOWS = os.platform() === "win32";
42+
const NPM = IS_WINDOWS ? "npm.cmd" : "npm";
4243
const JSON_MATCH_RE = /(\{[\s\S]*\})/mu;
4344

4445
const baseArguments = (options: NpmCliOptions) =>
@@ -106,6 +107,7 @@ async function execNpm(
106107

107108
const npm = childProcess.spawn(NPM, commandArguments, {
108109
env: { ...process.env, ...environment },
110+
shell: IS_WINDOWS,
109111
});
110112

111113
npm.stdout.on("data", (data: string) => (stdout += data));

‎src/read-manifest.ts

+8-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import fs from "node:fs/promises";
22
import path from "node:path";
3+
import validatePackageName from "validate-npm-package-name";
34
import semverValid from "semver/functions/valid.js";
45
import tarList from "tar/lib/list.js";
56
import type { ReadEntry } from "tar";
@@ -39,10 +40,14 @@ const isTarball = (file: unknown): file is string => {
3940
return typeof file === "string" && path.extname(file) === TARBALL_EXTNAME;
4041
};
4142

42-
const validateVersion = (version: unknown): string | undefined => {
43+
const normalizeVersion = (version: unknown): string | undefined => {
4344
return semverValid(version as string) ?? undefined;
4445
};
4546

47+
const validateName = (name: unknown): name is string => {
48+
return validatePackageName(name as string).validForNewPackages;
49+
};
50+
4651
const readPackageJson = async (...pathSegments: string[]): Promise<string> => {
4752
const file = path.resolve(...pathSegments);
4853

@@ -110,13 +115,13 @@ export async function readManifest(
110115
try {
111116
manifestJson = JSON.parse(manifestContents) as Record<string, unknown>;
112117
name = manifestJson["name"];
113-
version = validateVersion(manifestJson["version"]);
118+
version = normalizeVersion(manifestJson["version"]);
114119
publishConfig = manifestJson["publishConfig"] ?? {};
115120
} catch (error) {
116121
throw new errors.PackageJsonParseError(packageSpec, error);
117122
}
118123

119-
if (typeof name !== "string" || name.length === 0) {
124+
if (!validateName(name)) {
120125
throw new errors.InvalidPackageNameError(name);
121126
}
122127

0 commit comments

Comments
 (0)
Failed to load comments.