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

Add parcel-link and parcel-unlink dev CLIs #8618

Merged
merged 61 commits into from
Nov 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
1cb67df
Link script
mischnic Aug 23, 2022
ba311de
Lint
mischnic Aug 23, 2022
2d2a040
Scaffold atlassian-parcel-link package
lettertwo Oct 5, 2022
f1abc6b
Make link and unlink executable
lettertwo Oct 5, 2022
cfbd3d5
Move binaries from src/ to bin/
lettertwo Oct 6, 2022
bfcdadd
Parse args and scaffold logging
lettertwo Oct 6, 2022
29066d0
Factor in original link implementation
lettertwo Oct 6, 2022
ed88188
Extract mapAtlassianPackageAliases util
lettertwo Oct 11, 2022
87fc3fb
Use log, not console.log
lettertwo Oct 11, 2022
7dc338d
Implement unlink
lettertwo Oct 11, 2022
b59ea01
Export link and unlink from module
lettertwo Oct 11, 2022
35acbfa
Allow configuration of the packageRoot for linking
lettertwo Oct 27, 2022
caf2182
Force install after unlink
lettertwo Oct 27, 2022
e888f2f
Parametrize the namespace and node_modules globs
lettertwo Nov 8, 2022
fbd0ac4
Improve namespaced config rewrites
lettertwo Nov 8, 2022
b98d2e9
Add namespace and nodeModulesGlobs options
lettertwo Nov 9, 2022
11a95b6
Remove references to atlassian from parcel-link
lettertwo Nov 9, 2022
df7b7cb
Update README
lettertwo Nov 9, 2022
8fb6335
Fix multi option parsing
lettertwo Nov 17, 2022
d38502b
Fix unlink arguments
lettertwo Dec 8, 2022
c0bfea7
Unify CLI and create submcommands
lettertwo Dec 13, 2022
24fab60
Lint/nits
lettertwo Dec 13, 2022
d479a38
Extract ParcelLinkConfig
lettertwo Dec 13, 2022
6190315
Extract command to factory
lettertwo Dec 14, 2022
f327589
Interface with @parcel/fs
lettertwo Dec 14, 2022
5d3cf66
Fix default command
lettertwo Dec 14, 2022
0ed0e63
Make command configurable
lettertwo Dec 14, 2022
b9dd405
[WIP] tests
lettertwo Dec 15, 2022
ecf2c0a
Throw instead of exit
lettertwo Dec 16, 2022
2fbae2b
Improve app root detection
lettertwo Dec 16, 2022
e865380
toJSON not toJson
lettertwo Dec 16, 2022
9f2f6c6
Validate fs operations before performing them
lettertwo Dec 16, 2022
16823a2
Add createFS test util
lettertwo Dec 16, 2022
328d0d7
Improve logged messages
lettertwo Dec 16, 2022
532db00
Naming nit
lettertwo Dec 16, 2022
640d32d
Add descriptive error messages
lettertwo Dec 21, 2022
9e99a6b
Rename parcel-link util to utils
lettertwo Dec 22, 2022
6db7152
Lint
lettertwo Dec 22, 2022
c624564
Use globSync from @parcel/utils
lettertwo Dec 23, 2022
f37f967
Use `withFileTypes` readdir option
lettertwo Dec 23, 2022
fe12b7b
Use CopyOnWriteToMemoryFS in tests
lettertwo Dec 23, 2022
c5a5023
Use OverlayFS in tests
lettertwo Aug 15, 2023
d059736
Reverse direction of symlink message
lettertwo Dec 23, 2022
ee89a69
Add tests for link with default and common options
lettertwo Dec 23, 2022
41e4ad0
Add tests, fixes for linking with a custom namespace
lettertwo Dec 23, 2022
015fc92
Add tests, fixes for custom node_modules globs
lettertwo Dec 23, 2022
1356e3e
Remove old unlink options
lettertwo Dec 24, 2022
42590a8
Fix link --dry-run
lettertwo Jan 4, 2023
40a3dcc
Add unlink tests
lettertwo Jan 4, 2023
4fa793b
Use fsFixture in parcel-link tests
lettertwo Jan 10, 2023
ad2e0c0
Fix missing bin link for namespaced links
lettertwo Jan 20, 2023
6d0782e
Update version
lettertwo Feb 25, 2023
89e1e76
lint
lettertwo Feb 25, 2023
8adda2a
Fix package versions
lettertwo Jul 10, 2023
59f6762
Fix parcel-link tests
lettertwo Jul 10, 2023
00a598f
Extract link and unlink commands
lettertwo Jul 11, 2023
bb0cf6f
Update @babel/core dep
lettertwo Oct 5, 2023
f93d2a2
Update readme
lettertwo Oct 5, 2023
bd84525
Fix parcel-link tests
lettertwo Oct 6, 2023
7e75d92
skip tests failing on windows
lettertwo Nov 2, 2023
dc1d820
Fix package versions
lettertwo Nov 2, 2023
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
555 changes: 555 additions & 0 deletions packages/core/integration-tests/test/parcel-link.js

Large diffs are not rendered by default.

72 changes: 72 additions & 0 deletions packages/dev/parcel-link/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# `parcel-link`

A CLI for linking a dev version of Parcel into a project.

## Installation

Clone and run `yarn`, then `cd packages/dev/parcel-link && yarn link`
to make the `parcel-link` binary globally available.

## Usage

In an Parcel project root:

```sh
$ parcel-link [options] [packageRoot]
```

### Specifying `packageRoot`

```sh
$ parcel-link /path/to/parcel/packages
```

By default, `parcel-link` will link to packages in the same
location where `parcel-link` is found. But it is common
to want to link other worktrees of Parcel, and it's not fun
to have to first re-link `parcel-link` to a new location.

For this reason, `parcel-link` accepts a `packageRoot` argument,
which specifies a path to a Parcel `packages` directory.
Links will then be made to packages in that location instead
of the default.

### Specifying a `namespace`

```sh
$ parcel-link --namespace @my-parcel-fork
```

When linking into a project that uses a fork of Parcel,
the published packages may have a different namespace from
Parcel, so `parcel-link` allows specifying a namespace.

If defined to someting other than `"@parcel"`,
`parcel-link` will do some extra work to adjust
namespaced packages to reference linked packages instead.

### Linking into a monorepo

```sh
$ parcel-link --node-modules-globs build-tools/*/node_modules build-tools/parcel/*/node_modules
```

In a monorepo, there may be multiple locations where
Parcel packages are installed. For this, `parcel-link`
allows specifying globs of locations where packages should be linked.

Note that specifying any value here will override the default of `node_modules`,
so if you want to preserve the default behavior, be sure to include `node_modules`
in the list of globs:

```sh
$ parcel-link -g build-tools/*/node_modules -g build-tools/parcel/*/node_modules -g node_modules
```

## Cleanup

To restore the project to its default Parcel install:

```sh
$ parcel-link unlink [options] [packageRoot]
```
20 changes: 20 additions & 0 deletions packages/dev/parcel-link/bin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#! /usr/bin/env node

// @flow strict-local
/* eslint-disable no-console */

'use strict';

// $FlowFixMe[untyped-import]
require('@parcel/babel-register');

let program = require('./src/cli').createProgram();

(async function main() {
try {
await program.parseAsync();
} catch (e) {
console.error(e);
process.exit(1);
}
})();
21 changes: 21 additions & 0 deletions packages/dev/parcel-link/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"name": "@parcel/link",
"description": "A CLI for linking a dev version of Parcel into a project",
"version": "2.10.2",
"private": true,
"bin": {
"parcel-link": "bin.js"
},
"scripts": {
"test": "cd ../../.. && yarn test:integration --grep @parcel/link"
},
"main": "src/index.js",
"dependencies": {
"@babel/core": "^7.22.11",
"@parcel/babel-register": "2.10.2",
"@parcel/fs": "2.10.2",
"@parcel/utils": "2.10.2",
"commander": "^7.0.0",
"nullthrows": "^1.1.1"
}
}
106 changes: 106 additions & 0 deletions packages/dev/parcel-link/src/ParcelLinkConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// @flow

import type {FileSystem} from '@parcel/fs';

import {globSync} from '@parcel/utils';

import assert from 'assert';
import nullthrows from 'nullthrows';
import path from 'path';

const LOCK_FILE_NAMES = ['yarn.lock', 'package-lock.json', 'pnpm-lock.yaml'];
const SCM_FILE_NAMES = ['.git', '.hg'];

export class ParcelLinkConfig {
fs: FileSystem;
appRoot: string;
packageRoot: string;
namespace: string = '@parcel';
nodeModulesGlobs: string[] = ['node_modules'];
filename: string = '.parcel-link';

static load(
appRoot: string,
{fs, filename = '.parcel-link'}: {|fs: FileSystem, filename?: string|},
): ParcelLinkConfig {
let manifest = JSON.parse(
fs.readFileSync(path.join(appRoot, filename), 'utf8'),
);
return new ParcelLinkConfig({...manifest, fs});
}

constructor(options: {|
fs: FileSystem,
appRoot: string,
packageRoot: string,
namespace?: string,
nodeModulesGlobs?: string[],
filename?: string,
|}) {
this.fs = nullthrows(options.fs, 'fs is required');
this.appRoot = nullthrows(options.appRoot, 'appRoot is required');
this.packageRoot = nullthrows(
options.packageRoot,
'packageRoot is required',
);
this.namespace = options.namespace ?? this.namespace;
this.nodeModulesGlobs = options.nodeModulesGlobs ?? this.nodeModulesGlobs;
this.filename = options.filename ?? this.filename;
}

save(): Promise<void> {
return this.fs.writeFile(
path.join(this.appRoot, this.filename),
JSON.stringify(this, null, 2),
);
}

delete(): Promise<void> {
return this.fs.rimraf(path.join(this.appRoot, this.filename));
}

validateAppRoot() {
assert(
[...LOCK_FILE_NAMES, ...SCM_FILE_NAMES].some(filename =>
this.fs.existsSync(path.join(this.appRoot, filename)),
),
`Not a project root: '${this.appRoot}'`,
);
}

validatePackageRoot() {
assert(
this.fs.existsSync(path.join(this.packageRoot, 'core/core')),
`Not a package root: '${this.packageRoot}'`,
);
}

validate(): void {
this.validateAppRoot();
this.validatePackageRoot();
}

getNodeModulesPaths(): string[] {
return this.nodeModulesGlobs.reduce(
(matches, pattern) => [
...matches,
...globSync(pattern, this.fs, {cwd: this.appRoot, onlyFiles: false}),
],
[],
);
}

toJSON(): {|
appRoot: string,
packageRoot: string,
namespace: string,
nodeModulesGlobs: string[],
|} {
return {
appRoot: this.appRoot,
packageRoot: this.packageRoot,
namespace: this.namespace,
nodeModulesGlobs: this.nodeModulesGlobs,
};
}
}
25 changes: 25 additions & 0 deletions packages/dev/parcel-link/src/cli.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// @flow strict-local
/* eslint-disable no-console */

import type {LinkCommandOptions} from './link';
import type {UnlinkCommandOptions} from './unlink';

// $FlowFixMe[untyped-import]
import {version} from '../package.json';
import {createLinkCommand} from './link';
import {createUnlinkCommand} from './unlink';

import commander from 'commander';

export type ProgramOptions = {|...LinkCommandOptions, ...UnlinkCommandOptions|};

// $FlowFixMe[invalid-exported-annotation]
export function createProgram(opts?: ProgramOptions): commander.Command {
let {fs, log = console.log, link, unlink} = opts ?? {};
return new commander.Command()
.version(version, '-V, --version')
.description('A tool for linking a dev copy of Parcel into an app')
.addHelpText('after', `\nThe link command is the default command.`)
.addCommand(createLinkCommand({fs, log, link}), {isDefault: true})
.addCommand(createUnlinkCommand({fs, log, unlink}));
}
10 changes: 10 additions & 0 deletions packages/dev/parcel-link/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// @flow strict-local

export type {ProgramOptions} from './cli';
export type {LinkOptions} from './link';
export type {UnlinkOptions} from './unlink';

export {createProgram} from './cli';
export {link} from './link';
export {unlink} from './unlink';
export {ParcelLinkConfig} from './ParcelLinkConfig';
Loading
Loading