Skip to content

Commit

Permalink
More copy-pasting from node's source code; add test coverage for read…
Browse files Browse the repository at this point in the history
…ing package.json exports field
  • Loading branch information
cspotcode committed Nov 29, 2020
1 parent eda6039 commit 492b4d4
Show file tree
Hide file tree
Showing 15 changed files with 49 additions and 24 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
node_modules/
/node_modules/
/tests/node_modules/
.nyc_output/
coverage/
.DS_Store
Expand Down
19 changes: 8 additions & 11 deletions dist-raw/node-cjs-loader-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
// Each function and variable below must have a comment linking to the source in node's github repo.

const path = require('path');
const {internalModuleReadJSON} = require('./node-internal-fs');
const packageJsonReader = require('./node-package-json-reader');
const {JSONParse} = require('./node-primordials');

module.exports.assertScriptCanLoadAsCJSImpl = assertScriptCanLoadAsCJSImpl;

// copied from Module._extensions['.js']
// https://github.com/nodejs/node/blob/2d5d77306f6dff9110c1f77fefab25f973415770/lib/internal/modules/cjs/loader.js#L1211-L1217
// https://github.com/nodejs/node/blob/v15.3.0/lib/internal/modules/cjs/loader.js#L1113-L1120
function assertScriptCanLoadAsCJSImpl(filename) {
const pkg = readPackageScope(filename);
// Function require shouldn't be used in ES modules.
Expand Down Expand Up @@ -41,31 +42,27 @@ function readPackageScope(checkPath) {
// Copied from https://github.com/nodejs/node/blob/2d5d77306f6dff9110c1f77fefab25f973415770/lib/internal/modules/cjs/loader.js#L249
const packageJsonCache = new Map();

// Copied from https://github.com/nodejs/node/blob/2d5d77306f6dff9110c1f77fefab25f973415770/lib/internal/modules/cjs/loader.js#L251-L283
// Copied from https://github.com/nodejs/node/blob/v15.3.0/lib/internal/modules/cjs/loader.js#L275-L304
function readPackage(requestPath) {
const jsonPath = path.resolve(requestPath, 'package.json');

const existing = packageJsonCache.get(jsonPath);
if (existing !== undefined) return existing;

const json = internalModuleReadJSON(path.toNamespacedPath(jsonPath));
const result = packageJsonReader.read(jsonPath);
const json = result.containsKeys === false ? '{}' : result.string;
if (json === undefined) {
packageJsonCache.set(jsonPath, false);
return false;
}

// TODO Related to `--experimental-policy`? Disabling for now
// if (manifest) {
// const jsonURL = pathToFileURL(jsonPath);
// manifest.assertIntegrity(jsonURL, json);
// }

try {
const parsed = JSON.parse(json);
const parsed = JSONParse(json);
const filtered = {
name: parsed.name,
main: parsed.main,
exports: parsed.exports,
imports: parsed.imports,
type: parsed.type
};
packageJsonCache.set(jsonPath, filtered);
Expand Down
12 changes: 9 additions & 3 deletions dist-raw/node-internal-fs.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
const fs = require('fs');

// In node's core, this is implemented in C
// https://github.com/nodejs/node/blob/e9f293750760d59243020d0376edf242c9a26b67/src/node_file.cc#L845-L939
// https://github.com/nodejs/node/blob/v15.3.0/src/node_file.cc#L891-L985
function internalModuleReadJSON(path) {
let string
try {
return fs.readFileSync(path, 'utf8')
string = fs.readFileSync(path, 'utf8')
} catch (e) {
if (e.code === 'ENOENT') return undefined
if (e.code === 'ENOENT') return []
throw e
}
// Node's implementation checks for the presence of relevant keys: main, name, type, exports, imports
// Node does this for performance to skip unnecessary parsing.
// This would slow us down and, based on our usage, we can skip it.
const containsKeys = true
return [string, containsKeys]
}

module.exports = {
Expand Down
2 changes: 1 addition & 1 deletion dist-raw/node-package-json-reader.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ const cache = new SafeMap();
let manifest;

/**
*
* @param {string} jsonPath
* @return {[string, boolean]}
*/
function read(jsonPath) {
if (cache.has(jsonPath)) {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"build-pack": "node ./scripts/build-pack.js",
"test-spec": "mocha dist/**/*.spec.js -R spec --bail",
"test-cov": "nyc mocha -- \"dist/**/*.spec.js\" -R spec --bail",
"test": "npm run build && npm run lint && npm run test-cov",
"test": "npm run build && npm run lint && npm run test-cov --",
"coverage-report": "nyc report --reporter=lcov",
"prepare": "npm run build-nopack"
},
Expand Down
8 changes: 4 additions & 4 deletions src/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -860,7 +860,7 @@ describe('ts-node', function () {
it('should compile and execute as ESM', (done) => {
exec(`${cmd} index.ts`, { cwd: join(__dirname, '../tests/esm') }, function (err, stdout) {
expect(err).to.equal(null)
expect(stdout).to.equal('foo bar baz biff\n')
expect(stdout).to.equal('foo bar baz biff libfoo\n')

return done()
})
Expand All @@ -883,15 +883,15 @@ describe('ts-node', function () {
it('via --experimental-specifier-resolution', (done) => {
exec(`${cmd} --experimental-specifier-resolution=node index.ts`, { cwd: join(__dirname, '../tests/esm-node-resolver') }, function (err, stdout) {
expect(err).to.equal(null)
expect(stdout).to.equal('foo bar baz biff\n')
expect(stdout).to.equal('foo bar baz biff libfoo\n')

return done()
})
})
it('via --es-module-specifier-resolution alias', (done) => {
exec(`${cmd} --experimental-modules --es-module-specifier-resolution=node index.ts`, { cwd: join(__dirname, '../tests/esm-node-resolver') }, function (err, stdout) {
expect(err).to.equal(null)
expect(stdout).to.equal('foo bar baz biff\n')
expect(stdout).to.equal('foo bar baz biff libfoo\n')

return done()
})
Expand All @@ -905,7 +905,7 @@ describe('ts-node', function () {
}
}, function (err, stdout) {
expect(err).to.equal(null)
expect(stdout).to.equal('foo bar baz biff\n')
expect(stdout).to.equal('foo bar baz biff libfoo\n')

return done()
})
Expand Down
3 changes: 2 additions & 1 deletion tests/esm-node-resolver/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import {foo} from './foo'
import {bar} from './bar'
import {baz} from './baz'
import {biff} from './biff'
import {libfoo} from 'libfoo'

if(typeof module !== 'undefined') throw new Error('module should not exist in ESM')

console.log(`${foo} ${bar} ${baz} ${biff}`)
console.log(`${foo} ${bar} ${baz} ${biff} ${libfoo}`)
1 change: 1 addition & 0 deletions tests/esm-node-resolver/node_modules/libfoo/entrypoint.js

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

2 changes: 2 additions & 0 deletions tests/esm-node-resolver/node_modules/libfoo/index.d.ts

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

6 changes: 6 additions & 0 deletions tests/esm-node-resolver/node_modules/libfoo/package.json

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

3 changes: 2 additions & 1 deletion tests/esm/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import {foo} from './foo.js'
import {bar} from './bar.js'
import {baz} from './baz.js'
import {biff} from './biff.js'
import {libfoo} from 'libfoo'

// Test import builtin modules
import {readFileSync} from 'fs';
if(typeof readFileSync !== 'function') throw new Error('failed to import builtin module')

if(typeof module !== 'undefined') throw new Error('module should not exist in ESM')

console.log(`${foo} ${bar} ${baz} ${biff}`)
console.log(`${foo} ${bar} ${baz} ${biff} ${libfoo}`)
1 change: 1 addition & 0 deletions tests/esm/node_modules/libfoo/entrypoint.js

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

2 changes: 2 additions & 0 deletions tests/esm/node_modules/libfoo/index.d.ts

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

6 changes: 6 additions & 0 deletions tests/esm/node_modules/libfoo/package.json

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

3 changes: 2 additions & 1 deletion tests/esm/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"compilerOptions": {
"module": "ESNext",
"allowJs": true,
"jsx": "react"
"jsx": "react",
"moduleResolution": "node"
}
}

0 comments on commit 492b4d4

Please sign in to comment.