Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deps updates #6458

Merged
merged 11 commits into from
May 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions DEPENDENCIES.md
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,8 @@ graph LR;
npmcli-mock-registry-->npmcli-template-oss["@npmcli/template-oss"];
npmcli-mock-registry-->pacote;
npmcli-package-json-->json-parse-even-better-errors;
npmcli-package-json-->normalize-package-data;
npmcli-package-json-->npm-normalize-package-bin;
npmcli-run-script-->npmcli-node-gyp["@npmcli/node-gyp"];
npmcli-run-script-->npmcli-promise-spawn["@npmcli/promise-spawn"];
npmcli-run-script-->read-package-json-fast;
Expand Down Expand Up @@ -694,7 +696,10 @@ graph LR;
npmcli-mock-registry-->tap;
npmcli-move-file-->mkdirp;
npmcli-move-file-->rimraf;
npmcli-package-json-->glob;
npmcli-package-json-->json-parse-even-better-errors;
npmcli-package-json-->normalize-package-data;
npmcli-package-json-->npm-normalize-package-bin;
npmcli-promise-spawn-->which;
npmcli-query-->postcss-selector-parser;
npmcli-run-script-->node-gyp;
Expand Down Expand Up @@ -784,6 +789,7 @@ graph LR;
tar-->minizlib;
tar-->mkdirp;
tar-->yallist;
tuf-js-->debug;
tuf-js-->make-fetch-happen;
tuf-js-->tufjs-models["@tufjs/models"];
tufjs-models-->minimatch;
Expand Down Expand Up @@ -817,6 +823,6 @@ packages higher up the chain.
- pacote, libnpmhook, libnpmorg, libnpmsearch, libnpmteam, npm-profile
- npm-registry-fetch, libnpmversion
- @npmcli/git, make-fetch-happen, @npmcli/config, init-package-json
- @npmcli/installed-package-contents, @npmcli/map-workspaces, cacache, npm-pick-manifest, @npmcli/run-script, read-package-json, promzard
- @npmcli/docs, @npmcli/fs, npm-bundled, read-package-json-fast, unique-filename, npm-install-checks, npm-package-arg, npm-packlist, normalize-package-data, @npmcli/package-json, bin-links, nopt, npmlog, parse-conflict-json, read
- @npmcli/installed-package-contents, @npmcli/map-workspaces, cacache, npm-pick-manifest, @npmcli/run-script, read-package-json, @npmcli/package-json, promzard
- @npmcli/docs, @npmcli/fs, npm-bundled, read-package-json-fast, unique-filename, npm-install-checks, npm-package-arg, npm-packlist, normalize-package-data, bin-links, nopt, npmlog, parse-conflict-json, read
- @npmcli/eslint-config, @npmcli/template-oss, ignore-walk, semver, npm-normalize-package-bin, @npmcli/name-from-folder, json-parse-even-better-errors, fs-minipass, ssri, unique-slug, @npmcli/promise-spawn, hosted-git-info, proc-log, validate-npm-package-name, @npmcli/node-gyp, minipass-fetch, @npmcli/query, cmd-shim, read-cmd-shim, write-file-atomic, abbrev, are-we-there-yet, gauge, minify-registry-metadata, ini, @npmcli/disparity-colors, mute-stream, npm-audit-report, npm-user-validate
157 changes: 130 additions & 27 deletions node_modules/@npmcli/package-json/lib/index.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,12 @@
const fs = require('fs')
const promisify = require('util').promisify
const readFile = promisify(fs.readFile)
const writeFile = promisify(fs.writeFile)
const { readFile, writeFile } = require('fs/promises')
const { resolve } = require('path')
const updateDeps = require('./update-dependencies.js')
const updateScripts = require('./update-scripts.js')
const updateWorkspaces = require('./update-workspaces.js')
const normalize = require('./normalize.js')

const parseJSON = require('json-parse-even-better-errors')

const _filename = Symbol('filename')
const _manifest = Symbol('manifest')
const _readFileContent = Symbol('readFileContent')

// a list of handy specialized helper functions that take
// care of special cases that are handled by the npm cli
const knownSteps = new Set([
Expand All @@ -29,42 +23,111 @@ const knownKeys = new Set([
])

class PackageJson {
static normalizeSteps = Object.freeze([
'_id',
'_attributes',
'bundledDependencies',
'bundleDependencies',
'optionalDedupe',
'scripts',
'funding',
'bin',
])

static prepareSteps = Object.freeze([
'_attributes',
'bundledDependencies',
'bundleDependencies',
'gypfile',
'serverjs',
'scriptpath',
'authors',
'readme',
'mans',
'binDir',
'gitHead',
'fillTypes',
'normalizeData',
'binRefs',
])

// default behavior, just loads and parses
static async load (path) {
return await new PackageJson(path).load()
}

// read-package-json compatible behavior
static async prepare (path, opts) {
return await new PackageJson(path).prepare(opts)
}

// read-package-json-fast compatible behavior
static async normalize (path, opts) {
return await new PackageJson(path).normalize(opts)
}

#filename
#path
#manifest = {}
#readFileContent = ''
#fromIndex = false

constructor (path) {
this[_filename] = resolve(path, 'package.json')
this[_manifest] = {}
this[_readFileContent] = ''
this.#path = path
this.#filename = resolve(path, 'package.json')
}

async load () {
async load (parseIndex) {
let parseErr
try {
this[_readFileContent] =
await readFile(this[_filename], 'utf8')
this.#readFileContent =
await readFile(this.#filename, 'utf8')
} catch (err) {
throw new Error('package.json not found')
err.message = `Could not read package.json: ${err}`
if (!parseIndex) {
throw err
}
parseErr = err
}

if (parseErr) {
const indexFile = resolve(this.#path, 'index.js')
let indexFileContent
try {
indexFileContent = await readFile(indexFile, 'utf8')
} catch (err) {
throw parseErr
}
try {
this.#manifest = fromComment(indexFileContent)
} catch (err) {
throw parseErr
}
this.#fromIndex = true
return this
}

try {
this[_manifest] =
parseJSON(this[_readFileContent])
this.#manifest = parseJSON(this.#readFileContent)
} catch (err) {
throw new Error(`Invalid package.json: ${err}`)
err.message = `Invalid package.json: ${err}`
throw err
}

return this
}

get content () {
return this[_manifest]
return this.#manifest
}

get path () {
return this.#path
}

update (content) {
// validates both current manifest and content param
const invalidContent =
typeof this[_manifest] !== 'object'
typeof this.#manifest !== 'object'
|| typeof content !== 'object'
if (invalidContent) {
throw Object.assign(
Expand All @@ -74,36 +137,76 @@ class PackageJson {
}

for (const step of knownSteps) {
this[_manifest] = step({ content, originalContent: this[_manifest] })
this.#manifest = step({ content, originalContent: this.#manifest })
}

// unknown properties will just be overwitten
for (const [key, value] of Object.entries(content)) {
if (!knownKeys.has(key)) {
this[_manifest][key] = value
this.#manifest[key] = value
}
}

return this
}

async save () {
if (this.#fromIndex) {
throw new Error('No package.json to save to')
}
const {
[Symbol.for('indent')]: indent,
[Symbol.for('newline')]: newline,
} = this[_manifest]
} = this.#manifest

const format = indent === undefined ? ' ' : indent
const eol = newline === undefined ? '\n' : newline
const fileContent = `${
JSON.stringify(this[_manifest], null, format)
JSON.stringify(this.#manifest, null, format)
}\n`
.replace(/\n/g, eol)

if (fileContent.trim() !== this[_readFileContent].trim()) {
return await writeFile(this[_filename], fileContent)
if (fileContent.trim() !== this.#readFileContent.trim()) {
return await writeFile(this.#filename, fileContent)
}
}

async normalize (opts = {}) {
if (!opts.steps) {
opts.steps = this.constructor.normalizeSteps
}
await this.load()
await normalize(this, opts)
return this
}

async prepare (opts = {}) {
if (!opts.steps) {
opts.steps = this.constructor.prepareSteps
}
await this.load(true)
await normalize(this, opts)
return this
}
}

// /**package { "name": "foo", "version": "1.2.3", ... } **/
function fromComment (data) {
data = data.split(/^\/\*\*package(?:\s|$)/m)

if (data.length < 2) {
throw new Error('File has no package in comments')
}
data = data[1]
data = data.split(/\*\*\/$/m)

if (data.length < 2) {
throw new Error('File has no package in comments')
}
data = data[0]
data = data.replace(/^\s*\*/mg, '')

return parseJSON(data)
}

module.exports = PackageJson
Loading