mirror of
https://github.com/titanscouting/tra-analysis.git
synced 2024-12-30 18:59:10 +00:00
152 lines
5.5 KiB
Markdown
152 lines
5.5 KiB
Markdown
|
# `file:` specifiers
|
||
|
|
||
|
`specifier` refers to the value part of the `package.json`'s `dependencies`
|
||
|
object. This is a semver expression for registry dependencies and
|
||
|
URLs and URL-like strings for other types.
|
||
|
|
||
|
### Dependency Specifiers
|
||
|
|
||
|
* A `file:` specifier is either an absolute path (eg `/path/to/thing`, `d:\path\to\thing`):
|
||
|
* An absolute `file:///absolute/path` with any number of leading slashes
|
||
|
being treated as a single slash. That is, `file:/foo/bar` and
|
||
|
`file:///foo/bar` reference the same package.
|
||
|
* … or a relative path (eg `../path/to/thing`, `path\to\subdir`). Leading
|
||
|
slashes on a file specifier will be removed, that is 'file://../foo/bar`
|
||
|
references the same package as same as `file:../foo/bar`. The latter is
|
||
|
considered canonical.
|
||
|
* Attempting to install a specifier that has a windows drive letter will
|
||
|
produce an error on non-Windows systems.
|
||
|
* A valid `file:` specifier points is:
|
||
|
* a valid package file. That is, a `.tar`, `.tar.gz` or `.tgz` containing
|
||
|
`<dir>/package.json`.
|
||
|
* OR, a directory that contains a `package.json`
|
||
|
|
||
|
Relative specifiers are relative to the file they were found in, or, if
|
||
|
provided on the command line, the CWD that the command was run from.
|
||
|
|
||
|
An absolute specifier found in a `package.json` or `npm-shrinkwrap.json` is
|
||
|
probably an error as it's unlikely to be portable between computers and
|
||
|
should warn.
|
||
|
|
||
|
A specifier provided as a command line argument that is on a different drive
|
||
|
is an error. That is, `npm install file:d:/foo/bar` is an error if the
|
||
|
current drive is `c`. The point of this rule is that if we can't produce a
|
||
|
relative path then it's an error.
|
||
|
|
||
|
### Specifier Disambiguation
|
||
|
|
||
|
On the command line, plain paths are allowed. These paths can be ambiguous
|
||
|
as they could be a path, a plain package name or a github shortcut. This
|
||
|
ambiguity is resolved by checking to see if either a directory exists that
|
||
|
contains a `package.json`. If either is the case then the specifier is a
|
||
|
file specifier, otherwise it's a registry or github specifier.
|
||
|
|
||
|
### Specifier Matching
|
||
|
|
||
|
A specifier is considered to match a dependency on disk when the `realpath`
|
||
|
of the fully resolved specifier matches the `realpath` of the package on disk.
|
||
|
|
||
|
### Saving File Specifiers
|
||
|
|
||
|
When saving to both `package.json` and `npm-shrinkwrap.json` they will be
|
||
|
saved using the `file:../relative/path` form, and the relative path will be
|
||
|
relative to the project's root folder. This is particularly important to
|
||
|
note for the `npm-shrinkwrap.json` as it means the specifier there will
|
||
|
be different then the original `package.json` (where it was relative to that
|
||
|
`package.json`).
|
||
|
|
||
|
When shrinkwrapping file specifiers, the contents of the destination
|
||
|
package's `node_modules` WILL NOT be included in the shrinkwrap. If you want to lock
|
||
|
down the destination package's `node_modules` you should create a shrinkwrap for it
|
||
|
separately.
|
||
|
|
||
|
This is necessary to support the mono repo use case where many projects file
|
||
|
to the same package. If each project included its own `npm-shrinkwrap.json`
|
||
|
then they would each have their own distinct set of transitive dependencies
|
||
|
and they'd step on each other any time you ran an install in one or the other.
|
||
|
|
||
|
NOTE: This should not have an effect on shrinkwrapping of other sorts of
|
||
|
shrinkwrapped packages.
|
||
|
|
||
|
### Installation
|
||
|
|
||
|
#### File type specifiers pointing at tarballs
|
||
|
|
||
|
File-type specifiers pointing at a `.tgz` or `.tar.gz` or `.tar` file will
|
||
|
install it as a package file in the same way we would a remote tarball. The
|
||
|
checksum of the package file should be recorded so that we can check for updates.
|
||
|
|
||
|
#### File type specifers pointing at directories
|
||
|
|
||
|
File-type specifiers that point at directories will necessarily not do
|
||
|
anything for `fetch` and `extract` phases.
|
||
|
|
||
|
The symlink should be created during the `finalize` phase.
|
||
|
|
||
|
The `preinstall` for file-type specifiers MUST be run AFTER the
|
||
|
`finalize` phase as the symlink may be a relative path reaching outside the
|
||
|
current project root and a symlink that resolves in `.staging` won't resolve
|
||
|
in the package's final resting place.
|
||
|
|
||
|
If the module is inside the package root that we're running the install for then
|
||
|
dependencies of the linked package will be hoisted to the top level as usual.
|
||
|
|
||
|
If the module is outside the package root then dependencies will be installed inside
|
||
|
the linked module's `node_modules` folder.
|
||
|
|
||
|
### Removal
|
||
|
|
||
|
Removal should remove the symlink.
|
||
|
|
||
|
Removal MUST NOT remove the transitive dependencies IF they're installed in
|
||
|
the linked module's `node_modules` folder.
|
||
|
|
||
|
### Listing
|
||
|
|
||
|
In listings they should not include a version as the version is not
|
||
|
something `npm` is concerned about. This also makes them easily
|
||
|
distinguishable from symlinks of packages that have other dependency
|
||
|
specifiers.
|
||
|
|
||
|
If you had run:
|
||
|
|
||
|
```
|
||
|
npm install --save file:../a
|
||
|
```
|
||
|
|
||
|
And then run:
|
||
|
```
|
||
|
npm ls
|
||
|
```
|
||
|
|
||
|
You would see:
|
||
|
|
||
|
```
|
||
|
example-package@1.0.0 /path/to/example-package
|
||
|
└── a → file:../a
|
||
|
```
|
||
|
|
||
|
```
|
||
|
example-package@1.0.0 /path/to/example-package
|
||
|
+-- a -> file:../a
|
||
|
```
|
||
|
|
||
|
Of note here: No version is included as the relevant detail is WHERE the
|
||
|
package came from, not what version happened to be in that path.
|
||
|
|
||
|
### Outdated
|
||
|
|
||
|
Local specifiers should only show up in `npm outdated` if they're missing
|
||
|
and when they do, they should be reported as:
|
||
|
|
||
|
```
|
||
|
Package Current Wanted Latest Location
|
||
|
a MISSING LOCAL LOCAL example-package
|
||
|
```
|
||
|
|
||
|
### Updating
|
||
|
|
||
|
If a dependency with a local specifier is already installed then `npm
|
||
|
update` shouldn't do anything. If one is missing then it should be
|
||
|
installed as if you ran `npm install`.
|