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

devEngines proposal #27

Merged
merged 1 commit into from
Oct 8, 2024
Merged
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
122 changes: 122 additions & 0 deletions devengines-field-proposal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# Proposal: `package.json` `devEngines` Field

This is a specification a `package.json` field to define the runtime and package manager for _developing_ a project or package (_not_ consuming/installing it as a dependency in another project). The field is named `devEngines` and is a new top-level field defined with this schema:

```typescript
interface DevEngines {
os?: DevEngineDependency | DevEngineDependency[];
cpu?: DevEngineDependency | DevEngineDependency[];
libc?: DevEngineDependency | DevEngineDependency[];
runtime?: DevEngineDependency | DevEngineDependency[];
packageManager?: DevEngineDependency | DevEngineDependency[];
}

interface DevEngineDependency {
name: string;
version?: string;
onFail?: 'ignore' | 'warn' | 'error' | 'download';
}
```

The `os`, `cpu`, `libc`, `runtime`, and `packageManager` sub-fields could either be an object or an array of objects, if the user wants to define multiple acceptable OSes, CPUs, C compilers, runtimes or package managers. The first acceptable option would be used, and `onFail` would be triggered for the last defined option if none validate. If unspecified, `onFail` defaults to `error` for the non-array notation; or it defaults to `error` for the last element in the array and `ignore` for all prior elements, for the array notation. Validation would check the name and version ranges.

The `name` field would be a string, corresponding to different sources depending on the parent field:

- `os`: [NPM docs for `engines.os`](https://docs.npmjs.com/cli/v10/configuring-npm/package-json#os).
- `cpu`: [NPM docs for `engines.cpu`](https://docs.npmjs.com/cli/v10/configuring-npm/package-json#cpu).
- `libc`: `glibc` or `musl`; see [NPM docs for `config.libc`](https://docs.npmjs.com/cli/v10/using-npm/config#libc).
- `runtime`: [WinterCG Runtime Keys](https://runtime-keys.proposal.wintercg.org/).
- `packageManager` . . . I don’t know, we could define the list as part of the spec, or perhaps it would need to correspond to an npm registry package name. Suggestions welcome.

The `version` field syntax would match that defined for [`engines.node`](https://docs.npmjs.com/cli/v10/configuring-npm/package-json#engines), so something like `">= 16.0.0 < 22"` or `">= 20"`. If unspecified, any version matches.

The `onFail` field defines what should happen if validation fails:

- `ignore`: nothing.
- `warn`: print something and continue.
- `error`: print something and exit.
- `download`: remediate the validation failure by downloading the requested tool/version.

In the event of `onFail: 'download'`, it would be the responsibility of the tool to determine what and how to download, perhaps by looking in the tool’s associated lockfile for a specific version and integrity hash. It could also be supported on a case-by-case basis, like perhaps Yarn and pnpm could support downloading a satisfactory version while npm would error.

## Examples

### Typical example

```json
"devEngines": {
"runtime": {
"name": "node",
"version": ">= 20.0.0",
"onFail": "error"
},
"packageManager": {
"name": "yarn",
"version": "3.2.3",
"onFail": "download"
}
}
```

### “Uses every possible field” example:

```json
"devEngines": {
"os": {
"name": "darwin",
"version": ">= 23.0.0"
},
"cpu": [
{
"name": "arm"
}, {
"name": "x86"
}
],
"libc": {
"name": "glibc"
},
"runtime": [
{
"name": "bun",
"version": ">= 1.0.0",
"onFail": "ignore"
},
{
"name": "node",
"version": ">= 20.0.0",
"onFail": "error"
},
],
"packageManager": [
{
"name": "bun",
"version": ">= 1.0.0",
"onFail": "ignore"
},
{
"name": "yarn",
"version": "3.2.3",
"onFail": "download"
}
]
}
```

## Future Expansions

Some potential future expansions of this spec that have been discussed are:

- `runtime` and `packageManager` might take shorthand string values defining the desired name or name with version/version range.

## References

- Inspiration: https://github.com/nodejs/node/issues/51888#issuecomment-1967102442

- Initial discussion: https://github.com/openjs-foundation/package-metadata-interoperability-collab-space/issues/15

## Implementations

- https://github.com/npm/npm-install-checks/pull/116

- https://github.com/npm/cli/pull/7766