Skip to content

Commit

Permalink
feat: add create functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
wraithgar committed Jun 21, 2023
1 parent c3d11c2 commit 4775bf3
Show file tree
Hide file tree
Showing 5 changed files with 261 additions and 155 deletions.
26 changes: 19 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,36 +58,48 @@ Creates a new empty instance of `PackageJson`.

---

### `async PackageJson.load(path)`
### `async PackageJson.create(path)`

Loads the `package.json` at the given path.
Creates an empty `package.json` at the given path. If one already exists
it will be overwritten.

---

### `async PackageJson.load(path, opts = {})`

Loads a `package.json` at the given path.

- `opts`: `Object` can contain:
- `create`: `Boolean` if true, a new package.json will be created if
one does not already exist. Will not clobber ane existing
package.json that can not be parsed.

### Example:

Loads contents of the `package.json` file located at `./`:
Loads contents of a `package.json` file located at `./`:

```js
const PackageJson = require('@npmcli/package-json')
const pkgJson = new PackageJson()
await pkgJson.load('./')
```

Throws an error in case the `package.json` file is missing or has invalid
Throws an error in case a `package.json` file is missing or has invalid
contents.

---

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

Convenience static method that returns a new instance and loads the contents of
the `package.json` file from that location.
a `package.json` file from that location.

- `path`: `String` that points to the folder from where to read the
`package.json` from

### Example:

Loads contents of the `package.json` file located at `./`:
Loads contents of a `package.json` file located at `./`:

```js
const PackageJson = require('@npmcli/package-json')
Expand Down Expand Up @@ -124,7 +136,7 @@ Convenience static that calls `load` before calling `prepare`

### `PackageJson.update(content)`

Updates the contents of the `package.json` with the `content` provided.
Updates the contents of a `package.json` with the `content` provided.

- `content`: `Object` containing the properties to be updated/replaced in the
`package.json` file.
Expand Down
46 changes: 37 additions & 9 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,33 @@ class PackageJson {
'binRefs',
])

// default behavior, loads a package.json at given path and JSON parses
static async load (path) {
// create a new empty package.json, so we can save at the given path even
// though we didn't start from a parsed file
static async create (path, opts = {}) {
const p = new PackageJson()
return p.load(path)
await p.create(path)
if (opts.data) {
return p.update(opts.data)
}
return p
}

// Loads a package.json at given path and JSON parses
static async load (path, opts = {}) {
const p = new PackageJson()
// Avoid try/catch if we aren't going to create
if (!opts.create) {
return p.load(path)
}

try {
return await p.load(path)
} catch (err) {
if (!err.message.startsWith('Could not read package.json')) {
throw err
}
return await p.create(path)
}
}

// read-package-json compatible behavior
Expand Down Expand Up @@ -159,10 +182,18 @@ class PackageJson {
return undefined
}

create (path) {
this.#path = path
this.#manifest = {}
return this
}

// This should be the ONLY way to set content in the manifest
update (content) {
if (!this.content) {
throw new Error('Can not update without existing data')
throw new Error('Can not update without content. Please `load` or `create`')
}

for (const step of knownSteps) {
this.#manifest = step({ content, originalContent: this.content })
}
Expand All @@ -186,11 +217,8 @@ class PackageJson {
[Symbol.for('newline')]: newline,
} = this.content

// These can only be undefined if we didn't parse JSON, which we currently don't support.
// const format = indent === undefined ? ' ' : indent
// const eol = newline === undefined ? '\n' : newline
const format = indent
const eol = newline
const format = indent === undefined ? ' ' : indent
const eol = newline === undefined ? '\n' : newline
const fileContent = `${
JSON.stringify(this.content, null, format)
}\n`
Expand Down
2 changes: 1 addition & 1 deletion lib/normalize.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const git = require('@npmcli/git')

const normalize = async (pkg, { strict, steps, root }) => {
if (!pkg.content) {
throw new Error('Can not normalize without existing data')
throw new Error('Can not normalize without content')
}
const data = pkg.content
const scripts = data.scripts || {}
Expand Down
38 changes: 24 additions & 14 deletions tap-snapshots/test/index.js.test.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,41 @@
* Make sure to inspect the output below. Do not ignore changes!
*/
'use strict'
exports[`test/index.js TAP custom formatting > should save back custom format to package.json 1`] = `
{"name":"foo","version":"1.0.1","description":"Lorem ipsum dolor"}
exports[`test/index.js TAP create with data > should save package.json with name 1`] = `
{
"name": "create-test"
}
`

exports[`test/index.js TAP invalid package.json data > should save updated content to package.json and ignore invalid data 1`] = `
this! is! not! json!
exports[`test/index.js TAP create without data > should save empty package.json 1`] = `
{}
`

exports[`test/index.js TAP read, update content and write > should properly save contennt to a package.json 1`] = `
{
"name": "foo",
"version": "1.0.1",
"description": "Lorem ipsum dolor"
}
exports[`test/index.js TAP load create:true empty dir > should save empty package.json 1`] = `
{}
`

exports[`test/index.js TAP load create:true existing parseable package.json > package.json should match existing 1`] = `
{"name":"test-package"}
`

exports[`test/index.js TAP start new package.json, update and write > should properly save contentn to a package.json 1`] = `
exports[`test/index.js TAP load custom formatting > should save back custom format to package.json 1`] = `
{"name":"foo","version":"1.0.1","description":"Lorem ipsum dolor"}
`

exports[`test/index.js TAP load read, update content and write > should properly save contennt to a package.json 1`] = `
{
"name": "foo"
"name": "foo",
"version": "1.0.1",
"description": "Lorem ipsum dolor"
}
`

exports[`test/index.js TAP update long package.json > should only update the defined property 1`] = `
exports[`test/index.js TAP load update long package.json > should only update the defined property 1`] = `
{
"version": "7.18.1",
"name": "npm",
Expand Down Expand Up @@ -274,7 +284,7 @@ exports[`test/index.js TAP update long package.json > should only update the def
`

exports[`test/index.js TAP update long package.json > should properly write updated pacakge.json contents 1`] = `
exports[`test/index.js TAP load update long package.json > should properly write updated pacakge.json contents 1`] = `
{
"version": "7.18.1",
"name": "npm",
Expand Down
Loading

0 comments on commit 4775bf3

Please sign in to comment.