Skip to content

Commit

Permalink
feat: add prepare function
Browse files Browse the repository at this point in the history
This implements most of the logic found in `read-package-json` with the
exception of parsing package comments from specific files.

It also shares all the normalization logic into one method, that
`normalize` and `prepare` then pick and choose which ones to use.

This will allow us to maintain the functionality that
`read-package-json` has of skipping certain steps, but doing so in a
more config-based way instead of passing in functions to run.

All the existing `read-package-json` tests were ported over, and new
ones added to get to 100% coverage.

For now the 'steps' will be undocumented.
  • Loading branch information
wraithgar committed May 15, 2023
1 parent 278b65f commit f32c0d9
Show file tree
Hide file tree
Showing 5 changed files with 900 additions and 55 deletions.
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,20 @@ Convenience static method like `load` but for calling `normalize`

---

---

### `async PackageJson.prepare()`

Like `load` but intended for reading package.json files before publish.

---

### **static** `async PackageJson.prepare(path)`

Convenience static method like `load` but for calling `prepare`

---

### `PackageJson.update(content)`

Updates the contents of the `package.json` with the `content` provided.
Expand Down
109 changes: 100 additions & 9 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,50 +23,107 @@ 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) {
return await new PackageJson(path).normalize()
static async normalize (path, opts) {
return await new PackageJson(path).normalize(opts)
}

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

constructor (path) {
this.#path = path
this.#filename = resolve(path, 'package.json')
}

async load () {
async load (parseIndex) {
let parseErr
try {
this.#readFileContent =
await readFile(this.#filename, 'utf8')
} catch (err) {
err.message = `Could not read package.json: ${err}`
throw 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) {
err.message = `Invalid package.json: ${err}`
throw err
}

return this
}

get content () {
return this.#manifest
}

get path () {
return this.#path
}

update (content) {
// validates both current manifest and content param
const invalidContent =
Expand Down Expand Up @@ -94,6 +151,9 @@ class PackageJson {
}

async save () {
if (this.#fromIndex) {
throw new Error('No package.json to save to')
}
const {
[Symbol.for('indent')]: indent,
[Symbol.for('newline')]: newline,
Expand All @@ -111,11 +171,42 @@ class PackageJson {
}
}

async normalize () {
async normalize (opts = {}) {
if (!opts.steps) {
opts.steps = this.constructor.normalizeSteps
}
await this.load()
await normalize(this)
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

0 comments on commit f32c0d9

Please sign in to comment.