@jsdevtools/npm-publish 3.1.0 → 4.0.0

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.
Files changed (67) hide show
  1. package/README.md +39 -25
  2. package/bin/npm-publish.js +17 -7
  3. package/lib/action/core.d.ts +1 -1
  4. package/lib/action/core.js +16 -25
  5. package/lib/action/core.js.map +1 -1
  6. package/lib/action/main.js +5 -32
  7. package/lib/action/main.js.map +1 -1
  8. package/lib/cli/index.js +7 -11
  9. package/lib/cli/index.js.map +1 -1
  10. package/lib/cli/parse-cli-arguments.js +3 -10
  11. package/lib/cli/parse-cli-arguments.js.map +1 -1
  12. package/lib/compare-and-publish/compare-and-publish.d.ts +1 -1
  13. package/lib/compare-and-publish/compare-and-publish.js +16 -18
  14. package/lib/compare-and-publish/compare-and-publish.js.map +1 -1
  15. package/lib/compare-and-publish/compare-versions.d.ts +1 -1
  16. package/lib/compare-and-publish/compare-versions.js +12 -19
  17. package/lib/compare-and-publish/compare-versions.js.map +1 -1
  18. package/lib/compare-and-publish/get-arguments.js +6 -8
  19. package/lib/compare-and-publish/get-arguments.js.map +1 -1
  20. package/lib/compare-and-publish/index.js +1 -17
  21. package/lib/compare-and-publish/index.js.map +1 -1
  22. package/lib/errors.js +22 -41
  23. package/lib/errors.js.map +1 -1
  24. package/lib/format-publish-result.d.ts +1 -1
  25. package/lib/format-publish-result.js +3 -10
  26. package/lib/format-publish-result.js.map +1 -1
  27. package/lib/index.d.ts +1 -1
  28. package/lib/index.js +4 -22
  29. package/lib/index.js.map +1 -1
  30. package/lib/normalize-options.d.ts +1 -1
  31. package/lib/normalize-options.js +18 -44
  32. package/lib/normalize-options.js.map +1 -1
  33. package/lib/npm/call-npm-cli.d.ts +1 -0
  34. package/lib/npm/call-npm-cli.js +15 -42
  35. package/lib/npm/call-npm-cli.js.map +1 -1
  36. package/lib/npm/index.js +2 -18
  37. package/lib/npm/index.js.map +1 -1
  38. package/lib/npm/use-npm-environment.d.ts +1 -1
  39. package/lib/npm/use-npm-environment.js +14 -22
  40. package/lib/npm/use-npm-environment.js.map +1 -1
  41. package/lib/npm-publish.js +10 -14
  42. package/lib/npm-publish.js.map +1 -1
  43. package/lib/options.js +4 -7
  44. package/lib/options.js.map +1 -1
  45. package/lib/read-manifest.js +27 -53
  46. package/lib/read-manifest.js.map +1 -1
  47. package/lib/results.d.ts +1 -1
  48. package/lib/results.js +2 -5
  49. package/lib/results.js.map +1 -1
  50. package/package.json +39 -42
  51. package/src/action/core.ts +7 -8
  52. package/src/action/main.ts +4 -4
  53. package/src/cli/index.ts +1 -1
  54. package/src/cli/parse-cli-arguments.ts +1 -0
  55. package/src/compare-and-publish/compare-and-publish.ts +12 -7
  56. package/src/compare-and-publish/compare-versions.ts +2 -2
  57. package/src/compare-and-publish/get-arguments.ts +4 -1
  58. package/src/errors.ts +1 -1
  59. package/src/format-publish-result.ts +1 -1
  60. package/src/index.ts +1 -1
  61. package/src/normalize-options.ts +13 -8
  62. package/src/npm/call-npm-cli.ts +14 -12
  63. package/src/npm/use-npm-environment.ts +11 -12
  64. package/src/npm-publish.ts +3 -3
  65. package/src/read-manifest.ts +16 -9
  66. package/src/results.ts +2 -1
  67. package/src/tar.d.ts +0 -3
@@ -1,17 +1,17 @@
1
1
  import os from "node:os";
2
2
 
3
3
  import * as errors from "./errors.js";
4
- import type { PackageManifest } from "./read-manifest.js";
5
4
  import {
5
+ type Access,
6
6
  ACCESS_PUBLIC,
7
7
  ACCESS_RESTRICTED,
8
- STRATEGY_UPGRADE,
9
- STRATEGY_ALL,
10
- type Access,
11
- type Strategy,
12
- type Options,
13
8
  type Logger,
9
+ type Options,
10
+ type Strategy,
11
+ STRATEGY_ALL,
12
+ STRATEGY_UPGRADE,
14
13
  } from "./options.js";
14
+ import type { PackageManifest } from "./read-manifest.js";
15
15
 
16
16
  const REGISTRY_NPM = "https://registry.npmjs.org/";
17
17
  export const TAG_LATEST = "latest";
@@ -97,8 +97,13 @@ const validateRegistry = (value: unknown): URL => {
97
97
  };
98
98
 
99
99
  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
+ }
102
107
  }
103
108
 
104
109
  throw new errors.InvalidTagError(value);
@@ -36,9 +36,11 @@ export const VIEW = "view";
36
36
  export const PUBLISH = "publish";
37
37
 
38
38
  export const E404 = "E404";
39
+ export const E409 = "E409";
39
40
  export const EPUBLISHCONFLICT = "EPUBLISHCONFLICT";
40
41
 
41
- const NPM = os.platform() === "win32" ? "npm.cmd" : "npm";
42
+ const IS_WINDOWS = os.platform() === "win32";
43
+ const NPM = IS_WINDOWS ? "npm.cmd" : "npm";
42
44
  const JSON_MATCH_RE = /(\{[\s\S]*\})/mu;
43
45
 
44
46
  const baseArguments = (options: NpmCliOptions) =>
@@ -68,15 +70,14 @@ export async function callNpmCli<CommandT extends string>(
68
70
  let error;
69
71
 
70
72
  if (exitCode === 0) {
71
- successData = parseJson<SuccessData<CommandT>>(stdout);
73
+ successData = parseJson(stdout) as SuccessData<CommandT> | undefined;
72
74
  } else {
73
- const errorPayload = parseJson<{ error?: { code?: unknown } }>(
74
- stdout,
75
- stderr
76
- );
75
+ const errorPayload = parseJson(stdout, stderr) as
76
+ | { error?: { code?: unknown } }
77
+ | undefined;
77
78
 
78
- if (errorPayload?.error?.code) {
79
- errorCode = String(errorPayload.error.code).toUpperCase();
79
+ if (typeof errorPayload?.error?.code === "string") {
80
+ errorCode = errorPayload.error.code.toUpperCase();
80
81
  }
81
82
 
82
83
  error = new errors.NpmCallError(command, exitCode, stderr);
@@ -106,10 +107,11 @@ async function execNpm(
106
107
 
107
108
  const npm = childProcess.spawn(NPM, commandArguments, {
108
109
  env: { ...process.env, ...environment },
110
+ shell: IS_WINDOWS,
109
111
  });
110
112
 
111
- npm.stdout.on("data", (data) => (stdout += data));
112
- npm.stderr.on("data", (data) => (stderr += data));
113
+ npm.stdout.on("data", (data: string) => (stdout += data));
114
+ npm.stderr.on("data", (data: string) => (stderr += data));
113
115
  npm.on("close", (code) => {
114
116
  logger?.debug?.(`Received stdout: ${stdout}`);
115
117
  logger?.debug?.(`Received stderr: ${stderr}`);
@@ -132,13 +134,13 @@ async function execNpm(
132
134
  * @param values CLI outputs to check
133
135
  * @returns Parsed JSON, if able to parse.
134
136
  */
135
- function parseJson<TParsed>(...values: string[]): TParsed | undefined {
137
+ function parseJson(...values: string[]): unknown {
136
138
  for (const value of values) {
137
139
  const jsonValue = JSON_MATCH_RE.exec(value)?.[1];
138
140
 
139
141
  if (jsonValue) {
140
142
  try {
141
- return JSON.parse(jsonValue) as TParsed;
143
+ return JSON.parse(jsonValue);
142
144
  } catch {
143
145
  return undefined;
144
146
  }
@@ -2,8 +2,8 @@ import fs from "node:fs/promises";
2
2
  import os from "node:os";
3
3
  import path from "node:path";
4
4
 
5
- import type { PackageManifest } from "../read-manifest.js";
6
5
  import type { NormalizedOptions } from "../normalize-options.js";
6
+ import type { PackageManifest } from "../read-manifest.js";
7
7
 
8
8
  export type NpmCliEnvironment = Record<string, string>;
9
9
 
@@ -29,22 +29,21 @@ export async function useNpmEnvironment<TReturn>(
29
29
  task: NpmCliTask<TReturn>
30
30
  ): Promise<TReturn> {
31
31
  const { registry, token, logger, temporaryDirectory } = options;
32
- const npmrcDirectory = await fs.mkdtemp(
33
- path.join(temporaryDirectory, "npm-publish-")
34
- );
35
- const npmrc = path.join(npmrcDirectory, ".npmrc");
36
- const environment = {
37
- NODE_AUTH_TOKEN: token,
38
- npm_config_userconfig: npmrc,
39
- };
40
-
32
+ const { host, origin, pathname } = registry;
33
+ const pathnameWithSlash = pathname.endsWith("/") ? pathname : `${pathname}/`;
41
34
  const config = [
42
35
  "; created by jsdevtools/npm-publish",
43
- `//${registry.host}/:_authToken=\${NODE_AUTH_TOKEN}`,
44
- `registry=${registry.href}`,
36
+ `//${host}${pathnameWithSlash}:_authToken=\${NODE_AUTH_TOKEN}`,
37
+ `registry=${origin}${pathnameWithSlash}`,
45
38
  "",
46
39
  ].join(os.EOL);
47
40
 
41
+ const npmrcDirectory = await fs.mkdtemp(
42
+ path.join(temporaryDirectory, "npm-publish-")
43
+ );
44
+ const npmrc = path.join(npmrcDirectory, ".npmrc");
45
+ const environment = { NODE_AUTH_TOKEN: token, npm_config_userconfig: npmrc };
46
+
48
47
  await fs.writeFile(npmrc, config, "utf8");
49
48
 
50
49
  logger?.debug?.(`Temporary .npmrc created at ${npmrc}\n${config}`);
@@ -1,9 +1,9 @@
1
- import { readManifest } from "./read-manifest.js";
2
- import { normalizeOptions } from "./normalize-options.js";
3
- import { useNpmEnvironment } from "./npm/index.js";
4
1
  import { compareAndPublish } from "./compare-and-publish/index.js";
5
2
  import { formatPublishResult } from "./format-publish-result.js";
3
+ import { normalizeOptions } from "./normalize-options.js";
4
+ import { useNpmEnvironment } from "./npm/index.js";
6
5
  import type { Options } from "./options.js";
6
+ import { readManifest } from "./read-manifest.js";
7
7
  import type { Results } from "./results.js";
8
8
 
9
9
  /**
@@ -1,8 +1,11 @@
1
1
  import fs from "node:fs/promises";
2
2
  import path from "node:path";
3
+
3
4
  import semverValid from "semver/functions/valid.js";
4
- import tarList from "tar/lib/list.js";
5
5
  import type { ReadEntry } from "tar";
6
+ import { list as tarList } from "tar/list";
7
+ import validatePackageName from "validate-npm-package-name";
8
+
6
9
  import * as errors from "./errors.js";
7
10
 
8
11
  /** A package manifest (package.json) and associated details. */
@@ -39,10 +42,14 @@ const isTarball = (file: unknown): file is string => {
39
42
  return typeof file === "string" && path.extname(file) === TARBALL_EXTNAME;
40
43
  };
41
44
 
42
- const validateVersion = (version: unknown): string | undefined => {
45
+ const normalizeVersion = (version: unknown): string | undefined => {
43
46
  return semverValid(version as string) ?? undefined;
44
47
  };
45
48
 
49
+ const validateName = (name: unknown): name is string => {
50
+ return validatePackageName(name as string).validForNewPackages;
51
+ };
52
+
46
53
  const readPackageJson = async (...pathSegments: string[]): Promise<string> => {
47
54
  const file = path.resolve(...pathSegments);
48
55
 
@@ -55,14 +62,14 @@ const readPackageJson = async (...pathSegments: string[]): Promise<string> => {
55
62
 
56
63
  const readTarballPackageJson = async (file: string): Promise<string> => {
57
64
  const data: Buffer[] = [];
58
- const onentry = (entry: ReadEntry) => {
65
+ const onReadEntry = (entry: ReadEntry) => {
59
66
  if (entry.path === "package/package.json") {
60
67
  entry.on("data", (chunk) => data.push(chunk));
61
68
  }
62
69
  };
63
70
 
64
71
  try {
65
- await tarList({ file, onentry });
72
+ await tarList({ file, onReadEntry });
66
73
 
67
74
  if (data.length === 0) {
68
75
  throw new Error("package.json not found inside archive");
@@ -109,19 +116,19 @@ export async function readManifest(
109
116
 
110
117
  try {
111
118
  manifestJson = JSON.parse(manifestContents) as Record<string, unknown>;
112
- name = manifestJson["name"];
113
- version = validateVersion(manifestJson["version"]);
114
- publishConfig = manifestJson["publishConfig"] ?? {};
119
+ name = manifestJson.name;
120
+ version = normalizeVersion(manifestJson.version);
121
+ publishConfig = manifestJson.publishConfig ?? {};
115
122
  } catch (error) {
116
123
  throw new errors.PackageJsonParseError(packageSpec, error);
117
124
  }
118
125
 
119
- if (typeof name !== "string" || name.length === 0) {
126
+ if (!validateName(name)) {
120
127
  throw new errors.InvalidPackageNameError(name);
121
128
  }
122
129
 
123
130
  if (typeof version !== "string") {
124
- throw new errors.InvalidPackageVersionError(manifestJson["version"]);
131
+ throw new errors.InvalidPackageVersionError(manifestJson.version);
125
132
  }
126
133
 
127
134
  if (
package/src/results.ts CHANGED
@@ -1,6 +1,7 @@
1
- import type { Access, Strategy } from "./options.js";
2
1
  import type { ReleaseType as SemverReleaseType } from "semver";
3
2
 
3
+ import type { Access, Strategy } from "./options.js";
4
+
4
5
  /** Release type */
5
6
  export type ReleaseType = SemverReleaseType | typeof INITIAL | typeof DIFFERENT;
6
7
 
package/src/tar.d.ts DELETED
@@ -1,3 +0,0 @@
1
- declare module "tar/lib/list.js" {
2
- export { list as default } from "tar";
3
- }