Skip to content

Commit

Permalink
feat: PnP package resolution support (#273)
Browse files Browse the repository at this point in the history
* feat: PnP package resolution support

Resolves #272

* docs: add changelog entry

* feat: package resolution using Yarn 2.x .pnp.js

Per discussion in #272

* fix: exclude fake stylelint from jest haste map

* refactor: use more robust pnp package path check

* test: update yarn e2e snapshots
  • Loading branch information
adalinesimonian committed Nov 3, 2021
1 parent 7bde14e commit 65a6a06
Show file tree
Hide file tree
Showing 33 changed files with 23,176 additions and 85 deletions.
2 changes: 2 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
node_modules
dist
coverage
.pnp.*
.yarn
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,7 @@ coverage
/.vscode-test/**
/test/**/*.css
/package.json
.pnp.*
.yarn
# Unignore config files like .prettierrc.js, because they're ignored by default
!.*rc.js
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)

## [Unreleased]

### Added

- If Stylelint is installed in a workspace using [Yarn](https://yarnpkg.com/) with [Plug-n-Play](https://yarnpkg.com/features/pnp), it can now be resolved without the need for Yarn's [editor SDKs](https://yarnpkg.com/getting-started/editor-sdks). ([#273](https://github.com/stylelint/vscode-stylelint/issues/273)).

## [1.0.3](https://github.com/stylelint/vscode-stylelint/compare/v1.0.2...v1.0.3) (2021-10-27)

### Fixed
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`findPackageRoot should throw when encountering a file system error other than ENOENT or ENOTDIR 1`] = `"EACCES: permission denied, open 'foo/bar/baz'"`;
exports[`findPackageRoot with custom root file should throw when encountering a file system error other than ENOENT or ENOTDIR 1`] = `"EACCES: permission denied, open 'foo/bar/baz'"`;

exports[`findPackageRoot with defaults should throw when encountering a file system error other than ENOENT or ENOTDIR 1`] = `"EACCES: permission denied, open 'foo/bar/baz'"`;
237 changes: 171 additions & 66 deletions src/utils/packages/__tests__/find-package-root.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,102 +7,207 @@ const mockedFS = /** @type {tests.mocks.FSPromisesModule} */ (require('fs/promis
const findPackageRoot = require('../find-package-root').findPackageRoot;

describe('findPackageRoot', () => {
it('should resolve the package directory when package.json is present', async () => {
mockedFS.__mockFileSystem({
foo: {
bar: {
'package.json': '{}',
baz: {},
describe('with defaults', () => {
it('should resolve the package directory when package.json is present', async () => {
mockedFS.__mockFileSystem({
foo: {
bar: {
'package.json': '{}',
baz: {},
},
},
},
});

expect(await findPackageRoot('foo/bar/baz')).toBe('foo/bar');
});

expect(await findPackageRoot('foo/bar/baz')).toBe('foo/bar');
});
it('should resolve the package directory when the starting path points to a file', async () => {
mockedFS.__mockFileSystem({
foo: {
bar: {
'package.json': '{}',
baz: '',
},
},
});

it('should resolve the package directory when starting with a file path', async () => {
mockedFS.__mockFileSystem({
foo: {
bar: {
'package.json': '{}',
baz: '',
expect(await findPackageRoot('foo/bar/baz')).toBe('foo/bar');
});

it('should resolve the package directory when starting with a file path on a platform that throws ENOTDIR', async () => {
mockedFS.__mockFileSystem({
foo: {
bar: {
'package.json': '{}',
baz: createError('ENOTDIR', 'foo/bar/baz', -20, 'stat'),
},
},
},
});

expect(await findPackageRoot('foo/bar/baz')).toBe('foo/bar');
});

expect(await findPackageRoot('foo/bar/baz')).toBe('foo/bar');
});
it("should not resolve when package.json isn't in the tree", async () => {
mockedFS.__mockFileSystem({
foo: {
bar: {
baz: {},
},
},
});

it('should resolve the package directory when starting with a file path on a platform that throws ENOTDIR', async () => {
mockedFS.__mockFileSystem({
foo: {
bar: {
expect(await findPackageRoot('foo/bar/baz')).toBeUndefined();
});

it('should not resolve folders with a directory named package.json', async () => {
mockedFS.__mockFileSystem({
foo: {
'package.json': '{}',
baz: createError('ENOTDIR', 'foo/bar/baz', -20, 'stat'),
bar: {
'package.json': {},
baz: {},
},
},
},
});
});

expect(await findPackageRoot('foo/bar/baz')).toBe('foo/bar');
});
expect(await findPackageRoot('foo/bar/baz')).toBe('foo');

mockedFS.__mockFileSystem({
foo: {
'package.json': {},
bar: {
baz: {},
},
},
});

expect(await findPackageRoot('foo/bar/baz')).toBeUndefined();

it("should not resolve when package.json isn't in the tree", async () => {
mockedFS.__mockFileSystem({
foo: {
bar: {
baz: {},
mockedFS.__mockFileSystem({
'package.json': {},
foo: {
bar: {
baz: {},
},
},
},
});

expect(await findPackageRoot('foo/bar/baz')).toBeUndefined();
});

expect(await findPackageRoot('foo/bar/baz')).toBeUndefined();
it('should throw when encountering a file system error other than ENOENT or ENOTDIR', async () => {
mockedFS.__mockFileSystem({
foo: {
bar: {
baz: createError('EACCES', 'foo/bar/baz', -13, 'stat'),
},
},
});

await expect(findPackageRoot('foo/bar/baz')).rejects.toThrowErrorMatchingSnapshot();
});
});

it('should not resolve folders with a directory named package.json', async () => {
mockedFS.__mockFileSystem({
foo: {
'package.json': '{}',
bar: {
'package.json': {},
baz: {},
describe('with custom root file', () => {
it('should resolve the package directory when the root file is present', async () => {
mockedFS.__mockFileSystem({
foo: {
bar: {
'yarn.lock': '',
baz: {},
},
},
},
});
});

expect(await findPackageRoot('foo/bar/baz')).toBe('foo');
expect(await findPackageRoot('foo/bar/baz', 'yarn.lock')).toBe('foo/bar');
});

mockedFS.__mockFileSystem({
foo: {
'package.json': {},
bar: {
baz: {},
it('should resolve the package directory when the starting path points to a file', async () => {
mockedFS.__mockFileSystem({
foo: {
bar: {
'yarn.lock': '',
baz: '',
},
},
},
});

expect(await findPackageRoot('foo/bar/baz', 'yarn.lock')).toBe('foo/bar');
});

expect(await findPackageRoot('foo/bar/baz')).toBeUndefined();
it('should resolve the package directory when starting with a file path on a platform that throws ENOTDIR', async () => {
mockedFS.__mockFileSystem({
foo: {
bar: {
'yarn.lock': '{}',
baz: createError('ENOTDIR', 'foo/bar/baz', -20, 'stat'),
},
},
});

mockedFS.__mockFileSystem({
'package.json': {},
foo: {
bar: {
baz: {},
expect(await findPackageRoot('foo/bar/baz', 'yarn.lock')).toBe('foo/bar');
});

it("should not resolve when the root file isn't in the tree", async () => {
mockedFS.__mockFileSystem({
foo: {
bar: {
baz: {},
},
},
},
});

expect(await findPackageRoot('foo/bar/baz', 'yarn.lock')).toBeUndefined();
});

expect(await findPackageRoot('foo/bar/baz')).toBeUndefined();
});
it('should not resolve folders with a directory with the same name as the root file', async () => {
mockedFS.__mockFileSystem({
foo: {
'yarn.lock': '',
bar: {
'yarn.lock': {},
baz: {},
},
},
});

expect(await findPackageRoot('foo/bar/baz', 'yarn.lock')).toBe('foo');

mockedFS.__mockFileSystem({
foo: {
'yarn.lock': {},
bar: {
baz: {},
},
},
});

it('should throw when encountering a file system error other than ENOENT or ENOTDIR', async () => {
mockedFS.__mockFileSystem({
foo: {
bar: {
baz: createError('EACCES', 'foo/bar/baz', -13, 'stat'),
expect(await findPackageRoot('foo/bar/baz', 'yarn.lock')).toBeUndefined();

mockedFS.__mockFileSystem({
'yarn.lock': {},
foo: {
bar: {
baz: {},
},
},
},
});

expect(await findPackageRoot('foo/bar/baz', 'yarn.lock')).toBeUndefined();
});

await expect(findPackageRoot('foo/bar/baz')).rejects.toThrowErrorMatchingSnapshot();
it('should throw when encountering a file system error other than ENOENT or ENOTDIR', async () => {
mockedFS.__mockFileSystem({
foo: {
bar: {
baz: createError('EACCES', 'foo/bar/baz', -13, 'stat'),
},
},
});

await expect(
findPackageRoot('foo/bar/baz', 'yarn.lock'),
).rejects.toThrowErrorMatchingSnapshot();
});
});
});

0 comments on commit 65a6a06

Please sign in to comment.