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

fix(node-resolve): handle "package.json" being in path #927

Merged
merged 5 commits into from Jul 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions .eslintignore
Expand Up @@ -4,3 +4,6 @@
**/test/**/output
packages/commonjs/test/fixtures
packages/typescript/test/fixtures/syntax-error

# temporary workaround for eslint bug where package.json is a directory
packages/node-resolve/test/fixtures/package-json-in-path
5 changes: 4 additions & 1 deletion .github/workflows/node-windows.yml
Expand Up @@ -27,6 +27,9 @@ jobs:
- name: Checkout Commit
uses: actions/checkout@v1

- name: Checkout Master
run: git branch -f master origin/master

- name: Setup Node
uses: actions/setup-node@v1
with:
Expand All @@ -39,4 +42,4 @@ jobs:
run: pnpm install --ignore-scripts

- name: run tests
run: pnpm ci:test --filter ...[${{ github.sha }}]
run: pnpm ci:test --filter "...[origin/master]"
5 changes: 4 additions & 1 deletion .github/workflows/validate.yml
Expand Up @@ -30,6 +30,9 @@ jobs:
with:
node-version: ${{ matrix.node }}

- name: Checkout Master
run: git branch -f master origin/master

- name: Install pnpm
run: npm install pnpm -g

Expand All @@ -56,4 +59,4 @@ jobs:
run: pnpm lint:js

- name: Run Tests
run: pnpm ci:coverage --filter ...[${{ github.sha }}]
run: pnpm ci:coverage --filter "...[origin/master]"
7 changes: 4 additions & 3 deletions packages/node-resolve/src/fs.js
Expand Up @@ -7,10 +7,11 @@ export const readFile = promisify(fs.readFile);
export const realpath = promisify(fs.realpath);
export { realpathSync } from 'fs';
export const stat = promisify(fs.stat);
export async function exists(filePath) {

export async function fileExists(filePath) {
try {
await access(filePath);
return true;
const res = await stat(filePath);
return res.isFile();
} catch {
return false;
}
Expand Down
8 changes: 4 additions & 4 deletions packages/node-resolve/src/index.js
Expand Up @@ -6,7 +6,7 @@ import deepMerge from 'deepmerge';
import isModule from 'is-module';

import { isDirCached, isFileCached, readCachedFile } from './cache';
import { exists, readFile, realpath } from './fs';
import { fileExists, readFile, realpath } from './fs';
import resolveImportSpecifiers from './resolveImportSpecifiers';
import { getMainFields, getPackageName, normalizeInput } from './util';
import handleDeprecatedOptions from './deprecated-options';
Expand Down Expand Up @@ -207,8 +207,8 @@ export function nodeResolve(opts = {}) {
}

if (hasPackageEntry && !preserveSymlinks) {
const fileExists = await exists(location);
if (fileExists) {
const exists = await fileExists(location);
if (exists) {
location = await realpath(location);
}
}
Expand All @@ -228,7 +228,7 @@ export function nodeResolve(opts = {}) {
}
}

if (options.modulesOnly && (await exists(location))) {
if (options.modulesOnly && (await fileExists(location))) {
const code = await readFile(location, 'utf-8');
if (isModule(code)) {
return {
Expand Down
3 changes: 1 addition & 2 deletions packages/node-resolve/src/package/utils.js
@@ -1,9 +1,8 @@
/* eslint-disable no-await-in-loop */
import path from 'path';
import fs from 'fs';
import { promisify } from 'util';

const fileExists = promisify(fs.exists);
import { fileExists } from '../fs';

function isModuleDir(current, moduleDirs) {
return moduleDirs.some((dir) => current.endsWith(dir));
Expand Down
13 changes: 7 additions & 6 deletions packages/node-resolve/src/resolveImportSpecifiers.js
Expand Up @@ -2,10 +2,12 @@ import fs from 'fs';
import { promisify } from 'util';
import { fileURLToPath, pathToFileURL } from 'url';

import { dirname } from 'path';

import resolve from 'resolve';

import { getPackageInfo, getPackageName } from './util';
import { exists, realpath } from './fs';
import { fileExists, realpath } from './fs';
import { isDirCached, isFileCached, readCachedFile } from './cache';
import resolvePackageExports from './package/resolvePackageExports';
import resolvePackageImports from './package/resolvePackageImports';
Expand All @@ -26,7 +28,7 @@ async function getPackageJson(importer, pkgName, resolveOptions, moduleDirectori
try {
const pkgJsonPath = await resolveImportPath(`${pkgName}/package.json`, resolveOptions);
const pkgJson = JSON.parse(await readFile(pkgJsonPath, 'utf-8'));
return { pkgJsonPath, pkgJson };
return { pkgJsonPath, pkgJson, pkgPath: dirname(pkgJsonPath) };
} catch (_) {
return null;
}
Expand Down Expand Up @@ -114,12 +116,11 @@ async function resolveId({
const result = await getPackageJson(importer, pkgName, resolveOptions, moduleDirectories);

if (result && result.pkgJson.exports) {
const { pkgJson, pkgJsonPath } = result;
const { pkgJson, pkgJsonPath, pkgPath } = result;
try {
const subpath =
pkgName === importSpecifier ? '.' : `.${importSpecifier.substring(pkgName.length)}`;
const pkgDr = pkgJsonPath.replace('package.json', '');
const pkgURL = pathToFileURL(pkgDr);
const pkgURL = pathToFileURL(`${pkgPath}/`);

const context = {
importer,
Expand Down Expand Up @@ -157,7 +158,7 @@ async function resolveId({
}

if (!preserveSymlinks) {
if (await exists(location)) {
if (await fileExists(location)) {
location = await realpath(location);
}
}
Expand Down
@@ -0,0 +1,3 @@
import { main } from "dependency/dist/something.js";

export default main();

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions packages/node-resolve/test/test.js
Expand Up @@ -124,6 +124,20 @@ test('supports JS extensions in TS when referring to TS imports', async (t) => {
t.is(module.exports, 'It works!');
});

test('handles package.json being a directory earlier in the path', async (t) => {
const bundle = await rollup({
input: 'package-json-in-path/package.json/main.js',
onwarn: () => t.fail('No warnings were expected'),
plugins: [
nodeResolve({
extensions: ['.js']
})
]
});
const { module } = await testBundle(t, bundle);
t.is(module.exports, 'It works!');
});

test('ignores IDs with null character', async (t) => {
const result = await nodeResolve().resolveId('\0someid', 'test.js');
t.is(result, null);
Expand Down
@@ -1,6 +1,7 @@
import Animal from '.';

import { makeRandomName } from '../core/utilities';

import Animal from '.';

export interface Dog extends Animal {
name: string;
Expand Down