@jsenv/package-publish 1.7.5 → 1.10.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/package-publish",
3
- "version": "1.7.5",
3
+ "version": "1.10.0",
4
4
  "description": "Publish package to one or many registry.",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -17,33 +17,26 @@
17
17
  "node": ">=16.13.0"
18
18
  },
19
19
  "publishConfig": {
20
- "access": "public",
21
- "registry": "https://registry.npmjs.org"
20
+ "access": "public"
22
21
  },
23
22
  "type": "module",
24
23
  "exports": {
25
24
  ".": {
26
- "import": "./main.js"
25
+ "import": "./src/main.js"
27
26
  },
28
27
  "./*": "./*"
29
28
  },
30
- "main": "./main.js",
29
+ "main": "./src/main.js",
31
30
  "files": [
32
- "/src/",
33
- "/main.js"
31
+ "/src/"
34
32
  ],
35
33
  "scripts": {
36
- "eslint": "npx eslint . --ext=.js,.mjs",
37
- "test": "node --experimental-json-modules ./script/test/test.mjs",
38
- "test-with-coverage": "npm run test -- --coverage",
39
- "prettier": "prettier --write ."
34
+ "test": "node --experimental-json-modules ./scripts/test.mjs"
40
35
  },
41
36
  "dependencies": {
42
- "@jsenv/filesystem": "4.0.0",
43
- "@jsenv/urls": "1.1.0",
44
- "@jsenv/logger": "4.0.1",
45
- "node-fetch": "2.6.7",
46
- "@jsenv/log": "1.6.3",
47
- "semver": "7.3.5"
37
+ "@jsenv/fetch": "1.1.3",
38
+ "@jsenv/filesystem": "4.1.0",
39
+ "@jsenv/log": "3.0.0",
40
+ "semver": "7.3.7"
48
41
  }
49
- }
42
+ }
@@ -2,7 +2,7 @@
2
2
  // https://github.com/npm/registry-issue-archive/issues/34
3
3
  // https://stackoverflow.com/questions/53212849/querying-information-about-specific-version-of-scoped-npm-package
4
4
 
5
- import nodeFetch from "node-fetch"
5
+ import { fetchUrl } from "@jsenv/fetch"
6
6
 
7
7
  export const fetchLatestInRegistry = async ({
8
8
  registryUrl,
@@ -10,7 +10,7 @@ export const fetchLatestInRegistry = async ({
10
10
  token,
11
11
  }) => {
12
12
  const requestUrl = `${registryUrl}/${packageName}`
13
- const response = await nodeFetch(requestUrl, {
13
+ const response = await fetchUrl(requestUrl, {
14
14
  method: "GET",
15
15
  headers: {
16
16
  // "user-agent": "jsenv",
@@ -1,7 +1,8 @@
1
+ import { fileURLToPath } from "node:url"
2
+ import { readFileSync, writeFileSync } from "node:fs"
1
3
  import { exec } from "node:child_process"
2
- import { readFile, writeFile, removeEntry } from "@jsenv/filesystem"
3
- import { resolveUrl, urlToFileSystemPath } from "@jsenv/urls"
4
- import { UNICODE } from "@jsenv/log"
4
+ import { createTaskLog } from "@jsenv/log"
5
+ import { removeEntry } from "@jsenv/filesystem"
5
6
 
6
7
  import { setNpmConfig } from "./setNpmConfig.js"
7
8
 
@@ -13,156 +14,152 @@ export const publish = async ({
13
14
  registryUrl,
14
15
  token,
15
16
  }) => {
16
- const getResult = async () => {
17
- try {
18
- const promises = []
19
- const previousValue = process.env.NODE_AUTH_TOKEN
20
- const restoreProcessEnv = () => {
21
- process.env.NODE_AUTH_TOKEN = previousValue
22
- }
23
- process.env.NODE_AUTH_TOKEN = token
24
- const rootPackageFileUrl = resolveUrl("./package.json", rootDirectoryUrl)
25
- const rootPackageString = await readFile(rootPackageFileUrl)
26
- const restorePackageFile = () =>
27
- writeFile(rootPackageFileUrl, rootPackageString)
28
- const packageObject = JSON.parse(rootPackageString)
17
+ const publishTask = createTaskLog(`publish ${packageSlug} on ${registryUrl}`)
18
+ try {
19
+ // process.env.NODE_AUTH_TOKEN
20
+ const previousValue = process.env.NODE_AUTH_TOKEN
21
+ const restoreProcessEnv = () => {
22
+ process.env.NODE_AUTH_TOKEN = previousValue
23
+ }
24
+ process.env.NODE_AUTH_TOKEN = token
25
+ // updating package.json to publish on the correct registry
26
+ let restorePackageFile = () => {}
27
+ const rootPackageFileUrl = new URL("./package.json", rootDirectoryUrl)
28
+ const rootPackageFileContent = readFileSync(rootPackageFileUrl)
29
+ const packageObject = JSON.parse(String(rootPackageFileContent))
30
+ const { publishConfig } = packageObject
31
+ const registerUrlFromPackage = publishConfig
32
+ ? publishConfig.registry || "https://registry.npmjs.org"
33
+ : "https://registry.npmjs.org"
34
+ if (registryUrl !== registerUrlFromPackage) {
35
+ restorePackageFile = () =>
36
+ writeFileSync(rootPackageFileUrl, rootPackageFileContent)
29
37
  packageObject.publishConfig = packageObject.publishConfig || {}
30
38
  packageObject.publishConfig.registry = registryUrl
31
- promises.push(
32
- writeFile(
33
- rootPackageFileUrl,
34
- JSON.stringify(packageObject, null, " "),
35
- ),
39
+ writeFileSync(
40
+ rootPackageFileUrl,
41
+ JSON.stringify(packageObject, null, " "),
36
42
  )
37
- const npmConfigFileUrl = resolveUrl("./.npmrc", rootDirectoryUrl)
38
- let restoreNpmConfigFile
39
- let projectNpmConfigString
40
- try {
41
- projectNpmConfigString = await readFile(npmConfigFileUrl)
42
- restoreNpmConfigFile = () =>
43
- writeFile(npmConfigFileUrl, projectNpmConfigString)
44
- } catch (e) {
45
- if (e.code === "ENOENT") {
46
- restoreNpmConfigFile = () => removeEntry(npmConfigFileUrl)
47
- projectNpmConfigString = ""
48
- } else {
49
- throw e
50
- }
43
+ }
44
+ // updating .npmrc to add the token
45
+ const npmConfigFileUrl = new URL("./.npmrc", rootDirectoryUrl)
46
+ let restoreNpmConfigFile
47
+ let npmConfigFileContent
48
+ try {
49
+ npmConfigFileContent = String(readFileSync(npmConfigFileUrl))
50
+ restoreNpmConfigFile = () =>
51
+ writeFileSync(npmConfigFileUrl, npmConfigFileContent)
52
+ } catch (e) {
53
+ if (e.code === "ENOENT") {
54
+ restoreNpmConfigFile = () => removeEntry(npmConfigFileUrl)
55
+ npmConfigFileContent = ""
56
+ } else {
57
+ throw e
51
58
  }
52
- promises.push(
53
- writeFile(
54
- npmConfigFileUrl,
55
- setNpmConfig(projectNpmConfigString, {
56
- [computeRegistryTokenKey(registryUrl)]: token,
57
- [computeRegistryKey(packageObject.name)]: registryUrl,
58
- }),
59
- ),
60
- )
61
- await Promise.all(promises)
62
- try {
63
- return await new Promise((resolve, reject) => {
64
- const command = exec(
65
- "npm publish --no-workspaces",
66
- {
67
- cwd: urlToFileSystemPath(rootDirectoryUrl),
68
- stdio: "silent",
69
- },
70
- (error) => {
71
- if (error) {
72
- // publish conflict generally occurs because servers
73
- // returns 200 after npm publish
74
- // but returns previous version if asked immediatly
75
- // after for the last published version.
59
+ }
60
+ writeFileSync(
61
+ npmConfigFileUrl,
62
+ setNpmConfig(npmConfigFileContent, {
63
+ [computeRegistryTokenKey(registryUrl)]: token,
64
+ [computeRegistryKey(packageObject.name)]: registryUrl,
65
+ }),
66
+ )
67
+ try {
68
+ const reason = await new Promise((resolve, reject) => {
69
+ const command = exec(
70
+ "npm publish --no-workspaces",
71
+ {
72
+ cwd: fileURLToPath(rootDirectoryUrl),
73
+ stdio: "silent",
74
+ },
75
+ (error) => {
76
+ if (error) {
77
+ // publish conflict generally occurs because servers
78
+ // returns 200 after npm publish
79
+ // but returns previous version if asked immediatly
80
+ // after for the last published version.
76
81
 
77
- // TODO: ideally we should catch 404 error returned from npm
78
- // it happens it the token is not allowed to publish
79
- // a repository. And when we detect this we display a more useful message
80
- // suggesting the token rights are insufficient to publish the package
82
+ // TODO: ideally we should catch 404 error returned from npm
83
+ // it happens it the token is not allowed to publish
84
+ // a repository. And when we detect this we display a more useful message
85
+ // suggesting the token rights are insufficient to publish the package
81
86
 
82
- // npm publish conclit
83
- if (error.message.includes("EPUBLISHCONFLICT")) {
84
- resolve({
85
- success: true,
86
- reason: "already-published",
87
- })
88
- } else if (
89
- error.message.includes("Cannot publish over existing version")
90
- ) {
91
- resolve({
92
- success: true,
93
- reason: "already-published",
94
- })
95
- } else if (
96
- error.message.includes(
97
- "You cannot publish over the previously published versions",
98
- )
99
- ) {
100
- resolve({
101
- success: true,
102
- reason: "already-published",
103
- })
104
- }
105
- // github publish conflict
106
- else if (
107
- error.message.includes(
108
- "ambiguous package version in package.json",
109
- )
110
- ) {
111
- resolve({
112
- success: true,
113
- reason: "already-published",
114
- })
115
- } else {
116
- reject(error)
117
- }
118
- } else {
87
+ // npm publish conclit
88
+ if (error.message.includes("EPUBLISHCONFLICT")) {
89
+ resolve({
90
+ success: true,
91
+ reason: "already-published",
92
+ })
93
+ } else if (
94
+ error.message.includes("Cannot publish over existing version")
95
+ ) {
96
+ resolve({
97
+ success: true,
98
+ reason: "already-published",
99
+ })
100
+ } else if (
101
+ error.message.includes(
102
+ "You cannot publish over the previously published versions",
103
+ )
104
+ ) {
119
105
  resolve({
120
106
  success: true,
121
- reason: "published",
107
+ reason: "already-published",
122
108
  })
123
109
  }
124
- },
125
- )
126
- if (logNpmPublishOutput) {
127
- command.stdout.on("data", (data) => {
128
- logger.debug(data)
129
- })
130
- command.stderr.on("data", (data) => {
131
- // debug because this output is part of
132
- // the error message generated by a failing npm publish
133
- logger.debug(data)
134
- })
135
- }
136
- })
137
- } finally {
138
- await Promise.all([
139
- restoreProcessEnv(),
140
- restorePackageFile(),
141
- restoreNpmConfigFile(),
142
- ])
110
+ // github publish conflict
111
+ else if (
112
+ error.message.includes(
113
+ "ambiguous package version in package.json",
114
+ )
115
+ ) {
116
+ resolve({
117
+ success: true,
118
+ reason: "already-published",
119
+ })
120
+ } else {
121
+ reject(error)
122
+ }
123
+ } else {
124
+ resolve({
125
+ success: true,
126
+ reason: "published",
127
+ })
128
+ }
129
+ },
130
+ )
131
+ if (logNpmPublishOutput) {
132
+ command.stdout.on("data", (data) => {
133
+ logger.debug(data)
134
+ })
135
+ command.stderr.on("data", (data) => {
136
+ // debug because this output is part of
137
+ // the error message generated by a failing npm publish
138
+ logger.debug(data)
139
+ })
140
+ }
141
+ })
142
+ if (reason === "already-published") {
143
+ publishTask.setRightText(`(already published)`)
143
144
  }
144
- } catch (e) {
145
+ publishTask.done()
145
146
  return {
146
- success: false,
147
- reason: e,
147
+ success: true,
148
+ reason,
148
149
  }
150
+ } finally {
151
+ restoreProcessEnv()
152
+ restorePackageFile()
153
+ restoreNpmConfigFile()
149
154
  }
150
- }
151
- const { success, reason } = await getResult()
152
- if (success) {
153
- if (reason === "already-published") {
154
- logger.info(
155
- `${UNICODE.INFO} ${packageSlug} was already published on ${registryUrl}`,
156
- )
157
- } else {
158
- logger.info(`${UNICODE.OK} ${packageSlug} published on ${registryUrl}`)
155
+ } catch (e) {
156
+ publishTask.fail()
157
+ console.error(e.stack)
158
+ return {
159
+ success: false,
160
+ reason: e,
159
161
  }
160
- } else {
161
- logger.error(`${UNICODE.FAILURE} error when publishing ${packageSlug} in ${registryUrl}
162
- --- error stack ---
163
- ${reason.stack}`)
164
162
  }
165
- return { success, reason }
166
163
  }
167
164
 
168
165
  const computeRegistryTokenKey = (registryUrl) => {
@@ -1,20 +1,20 @@
1
- import { resolveUrl, urlToFileSystemPath } from "@jsenv/urls"
2
- import { readFile } from "@jsenv/filesystem"
1
+ import { fileURLToPath } from "node:url"
2
+ import { readFileSync } from "node:fs"
3
3
 
4
- export const readProjectPackage = async ({ rootDirectoryUrl }) => {
5
- const packageFileUrl = resolveUrl("./package.json", rootDirectoryUrl)
6
- let packageObject
4
+ export const readProjectPackage = ({ rootDirectoryUrl }) => {
5
+ const packageFileUrlObject = new URL("./package.json", rootDirectoryUrl)
6
+ let packageInProject
7
7
  try {
8
- const packageString = await readFile(packageFileUrl, { as: "string" })
8
+ const packageString = String(readFileSync(packageFileUrlObject))
9
9
  try {
10
- packageObject = JSON.parse(packageString)
10
+ packageInProject = JSON.parse(packageString)
11
11
  } catch (e) {
12
12
  if (e.name === "SyntaxError") {
13
13
  throw new Error(`syntax error while parsing project package.json
14
14
  --- syntax error stack ---
15
15
  ${e.stack}
16
16
  --- package.json path ---
17
- ${urlToFileSystemPath(packageFileUrl)}`)
17
+ ${fileURLToPath(packageFileUrlObject)}`)
18
18
  }
19
19
  throw e
20
20
  }
@@ -23,10 +23,10 @@ ${urlToFileSystemPath(packageFileUrl)}`)
23
23
  throw new Error(
24
24
  `cannot find project package.json
25
25
  --- package.json path ---
26
- ${urlToFileSystemPath(packageFileUrl)}`,
26
+ ${fileURLToPath(packageFileUrlObject)}`,
27
27
  )
28
28
  }
29
29
  throw e
30
30
  }
31
- return packageObject
31
+ return packageInProject
32
32
  }
@@ -5,4 +5,4 @@
5
5
  * discover codebase progressively
6
6
  */
7
7
 
8
- export { publishPackage } from "./src/publishPackage.js"
8
+ export { publishPackage } from "./publishPackage.js"
@@ -1,5 +1,5 @@
1
1
  import { assertAndNormalizeDirectoryUrl } from "@jsenv/filesystem"
2
- import { createLogger } from "@jsenv/logger"
2
+ import { createLogger } from "@jsenv/log"
3
3
 
4
4
  import { fetchLatestInRegistry } from "./internal/fetchLatestInRegistry.js"
5
5
  import { publish } from "./internal/publish.js"
@@ -32,9 +32,7 @@ export const publishPackage = async ({
32
32
  assertRegistriesConfig(registriesConfig)
33
33
 
34
34
  logger.debug(`reading project package.json`)
35
- const packageInProject = await readProjectPackage({
36
- rootDirectoryUrl,
37
- })
35
+ const packageInProject = readProjectPackage({ rootDirectoryUrl })
38
36
 
39
37
  const { name: packageName, version: packageVersion } = packageInProject
40
38
  logger.info(`${packageName}@${packageVersion} found in package.json`)