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

module: resolve self-references #29327

Closed
wants to merge 1 commit into from
Closed

Conversation

jkrems
Copy link
Contributor

@jkrems jkrems commented Aug 26, 2019

See nodejs/modules#306

  1. Precondition: request isn't a relative path and wasn't resolved successfully using the existing algorithm.
  2. Find the closest package.json (the "package scope"), bail if none can be found.
  3. Check if request matches the name field of package.json.
  4. Resolve request against the package as if requiring from the outside.
  • Document logic in resolution docs.
  • Agree on prefix (package.json#name) to be used.
  • Implement ESM support.
  • Add to ESM resolution spec.
  • Add a flag for this feature.
  • Switch to looking for package.json#name, check node_modules first.
  • Create issue for tracking follow-up items to decide before unflagging. Unflagging self reference specifiers modules#403
  • Update commit message to match PR title, removing the reference to the exact API.

The unflagging issue should cover:

  1. A potential opt-in signal for packages that wish to use self-reference.
  2. Revisiting the order, especially if there is an opt-in signal.
  3. Getting final agreement on the sigil. This may happen as part of the unflagging PR.
Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • documentation is changed or added
  • commit message follows commit guidelines

@jkrems jkrems added the esm Issues and PRs related to the ECMAScript Modules implementation. label Aug 26, 2019
@jkrems jkrems added this to In progress in Support "exports" in package.json via automation Aug 26, 2019
@MylesBorins
Copy link
Member

I have to dig up the PR for introducing a scope / namespace... but ~ could potentially be a scope e.g. ~:some-module

@jkrems
Copy link
Contributor Author

jkrems commented Aug 26, 2019

@MylesBorins Unfortunately basically anything but \0 is a valid Unix directory name. So namespaces etc. won't remove the need for making it resolve last for backwards compat. But it could help make it more obvious that it's "special"!

@MylesBorins
Copy link
Member

MylesBorins commented Aug 26, 2019 via email

@GeoffreyBooth
Copy link
Member

This dovetails with the concept of package scope we’re introducing in ESM, as ~ would always refer to the root of the current package scope. It feels like there should be opportunities there for sharing code.

Of course I assume you plan on making this work in ESM too; we should make sure it doesn’t conflict with potentially eventually supporting browser import maps, if they have any plans for ~.

@GeoffreyBooth
Copy link
Member

It isn’t a valid path on Windows though. With it being a tier 1 platform do
we have to worry about breaking it?

Isn’t it the opposite? On Windows we know that ~ isn’t referring to a file path, so we could skip those checks.

@jkrems
Copy link
Contributor Author

jkrems commented Aug 26, 2019

It isn't a valid path on Windows though. With it being a tier 1 platform do we have to worry about breaking it?

We may have to check that trying to stat on Windows won’t throw (so we actually get to our logic). The specifier not working as-is across platforms would be a good thing because it reduces the risk that somebody used it already for other purposes.

@ljharb
Copy link
Member

ljharb commented Aug 27, 2019

cc @nodejs/modules

@mscdex mscdex added the wip Issues and PRs that are still a work in progress. label Aug 27, 2019
@bmeck
Copy link
Member

bmeck commented Aug 27, 2019

~ is a valid path on all general FS these days, see wikipedia for actual characters allowed in files.

On *nix:

date > '~' ; cat < '~'

Or on win32:

date > '~' ; type < '~'

However, the fact that it is valid doesn't necessarily mean it is portable. Lack of portability in particular on the myriad of package registries means that it is probably safe I would think, a quick search of require on gzemnid shows usage that we could comb through, but a cursory glance looks to be people altering resolution already.

gzemnid naive findings
ModuleBinder-0.0.1.tgz/tests/constructorinjection_test.js:9:var ConstructorInjection = require('~/'),
adfc-t30-paten-map-0.3.6.tgz/lib/index.js:22:"use strict";var e=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};exports.__esModule=!0,require("~/index.css"),require("~/node_modules/leaflet/dist/leaflet.css");var r=require("leaflet"),a=e(require("./layer/osm-layer")),t=e(require("./layer/soz-einrichtung")),l=new r.Map("map");l.setView(new r.LatLng(53.55,9.98),9),l.addLayer(a.default),l.addLayer(t.default);var u={OpenStreetMap:a.default},i={"Soziale Einrichtungen":t.default};r.control.layers(u,i).addTo(l);
astroman-1.3.0.tgz/lib/commands/create/react-native/__tests__/reduxAction.js:44:  const saveASTtoFile = require('~/utils/js/saveASTtoFile')
astroman-1.3.0.tgz/lib/commands/plug/react-native/utils/__tests__/wireUp.js:74:  const appendImport = require('~/utils/js/appendImport')
astroman-1.3.0.tgz/lib/commands/plug/react-native/utils/__tests__/wireUp.js:84:  const appendReducer = require('~/utils/js/appendReducer')
astroman-1.3.0.tgz/lib/commands/plug/react-native/utils/__tests__/wireUp.js:92:  const appendImport = require('~/utils/js/appendImport')
astroman-1.3.0.tgz/lib/commands/plug/react-native/utils/__tests__/wireUp.js:102:  const appendLogic = require('~/utils/js/appendLogic')
babel-plugin-root-require-1.3.0.tgz/test/does-not-transform.js:55:  const code = 'require("~foo");'
babel-plugin-root-require-1.3.0.tgz/test/does-not-transform.js:83:  const code = 'const require = () => {};\nrequire("~/foo");'
babel-plugin-root-require-1.3.0.tgz/test/fixtures/a/req-a.js:1:module.exports = require('~/a')
babel-plugin-root-require-1.3.0.tgz/test/fixtures/c/index.js:1:module.exports = require('~/' + 'c')
babel-plugin-root-require-1.3.0.tgz/test/fixtures/d/index.js:2:module.exports = require('~/' + myVar + '/d')
babel-plugin-root-require-1.3.0.tgz/test/fixtures/e/index.js:2:module.exports = require('~/ne' + myVar + '/e')
babel-plugin-root-require-1.3.0.tgz/test/index.js:25:  const result = transform('require("~/a/b/c");', {
babel-plugin-root-require-1.3.0.tgz/test/index.js:34:  const result = transform('require("~/a/b/c");', {
babel-plugin-root-require-1.3.0.tgz/test/index.js:103:  const result = transform('require("~/foo");', {
babel-plugin-root-require-1.3.0.tgz/test/index.js:112:  const result = transform('require("~/foo");', {
babel-plugin-root-require-1.3.0.tgz/test/index.js:121:  const result = transform('require("~/foo");', {
babel-plugin-root-require-1.3.0.tgz/test/index.js:130:  const result = transform('require("~/foo");', {
babel-plugin-root-require-1.3.0.tgz/test/index.js:171:  const result = transform('require("~/q/w/e/r/t/y");', {
babel-plugin-root-require-1.3.0.tgz/test/index.js:191:    return require("~/a");
babel-plugin-root-require-1.3.0.tgz/test/index.js:204:  const result = transform('require("~/foo/" + bar);', {
babel-plugin-sfcc-modules-1.0.3.tgz/lib/index.js:46:        // require('~/cartridge/scripts/foo')
bael-cms-template-0.1.2.tgz/store/index.js:99:        const info = require('~/content/setup/info.json');
bael-cms-template-0.1.2.tgz/store/index.js:100:        const connect = require('~/content/setup/connect.json');
benben-frontend-generator-1.0.23.tgz/template/src/css.js:1:require('~/css/style.scss');
best-require-1.1.4.tgz/test/test.js:9:assert.strictEqual(require('~/test/bar/d1/a'), 1);
best-require-1.1.4.tgz/test/test.js:11:assert.strictEqual(require('~/test/bar/d2/b.js'), 2);
best-require-1.1.4.tgz/test/test.js:12:assert.strictEqual(require('~/test/foo/d3/c.js'), 3);
best-require-1.1.4.tgz/test/time-test.js:11:    require('~/test/bar/d1/a');
best-require-1.1.4.tgz/test/time-test.js:13:    require('~/test/bar/d2/b.js');
best-require-1.1.4.tgz/test/time-test.js:14:    require('~/test/foo/d3/c.js');
blockstack-react-scripts-1.0.4.tgz/template/src/components/Resources/index.js:11:          src: require('~/assets/images/dev-resources/blockstack.js-documentation.png'),
blockstack-react-scripts-1.0.4.tgz/template/src/components/Resources/index.js:15:          src: require('~/assets/images/dev-resources/blockstack-tutorials.png'),
blockstack-react-scripts-1.0.4.tgz/template/src/components/Resources/index.js:19:          src: require('~/assets/images/dev-resources/blockstack-meetups.png'),
blockstack-react-scripts-1.0.4.tgz/template/src/components/Resources/index.js:23:          src: require('~/assets/images/dev-resources/blockstack-github.png'),
blockstack-react-scripts-1.0.4.tgz/template/src/components/Resources/index.js:27:          src: require('~/assets/images/dev-resources/app.co.png'),
blockstack-react-scripts-1.0.4.tgz/template/src/components/Resources/index.js:31:          src: require('~/assets/images/dev-resources/blockstack-blog.png'),
contacts_client-0.0.1.tgz/lib/api.js:7:	this.client = units.require('~');
contacts_client-0.0.1.tgz/lib/client/api.js:21:	this.client = units.require('~');
contacts_client-0.0.1.tgz/lib/client/auth.js:7:	this.client = units.require('~');
contacts_client-0.0.1.tgz/lib/contract.js:22:	var client = units.require('~');
container-store-3.0.1.tgz/__tests__/Container.spec.js:1:const Container = require('~/Container')
ctail-1.5.6.tgz/lib/config.js:5:    config = require("~/.ctail.json");
dockular-0.0.1.tgz/tests/example-test.js:16:const login = require('~/util/login');
dorc-0.0.1.tgz/src/cmd.js:11:const pad = require('~/lib/pad')
dorc-0.0.1.tgz/src/cmd.js:12:const Help = require('~/lib/help')
dorc-0.0.1.tgz/src/cmd.js:16:const zipObjRest = R.curry(require('~/lib/zip-obj-rest'))
dorc-0.0.1.tgz/src/cmd.js:17:const parseArgs = require('~/lib/parse-args')
dorc-0.0.1.tgz/src/handler/down/cmd.js:4:const pickIfAnySpecified = require('~/lib/pick-if-any-specified')
dorc-0.0.1.tgz/src/handler/down/cmd.test.js:8:} = require('~/test')
dorc-0.0.1.tgz/src/handler/exec/cmd.js:4:const pickIfAnySpecified = require('~/lib/pick-if-any-specified')
dorc-0.0.1.tgz/src/handler/exec/cmd.test.js:8:} = require('~/test')
dorc-0.0.1.tgz/src/handler/follow/cmd.js:4:const pickIfAnySpecified = require('~/lib/pick-if-any-specified')
dorc-0.0.1.tgz/src/handler/follow/cmd.test.js:8:} = require('~/test')
dorc-0.0.1.tgz/src/handler/restart/cmd.js:4:const pickIfAnySpecified = require('~/lib/pick-if-any-specified')
dorc-0.0.1.tgz/src/handler/restart/cmd.test.js:8:} = require('~/test')
dorc-0.0.1.tgz/src/handler/restart/index.js:1:const down = require('~/handler/down')
dorc-0.0.1.tgz/src/handler/restart/index.js:2:const up = require('~/handler/up')
dorc-0.0.1.tgz/src/handler/rmi/cmd.js:4:const pickIfAnySpecified = require('~/lib/pick-if-any-specified')
dorc-0.0.1.tgz/src/handler/rmi/cmd.js:5:const needsBuild = require('~/lib/service/needs-build')
dorc-0.0.1.tgz/src/handler/rmi/cmd.test.js:8:} = require('~/test')
dorc-0.0.1.tgz/src/handler/rmi/index.js:2:const getTags = require('~/lib/service/get-tags')
dorc-0.0.1.tgz/src/handler/run/cmd.js:1:const sharedOptions = require('~/lib/shared-options')
dorc-0.0.1.tgz/src/handler/run/cmd.test.js:3:const docker = require('~/lib/docker-api')
dorc-0.0.1.tgz/src/handler/run/cmd.test.js:12:} = require('~/test')
dorc-0.0.1.tgz/src/handler/run/command.js:3:const zipObjRest = R.curry(require('~/lib/zip-obj-rest'))
dorc-0.0.1.tgz/src/handler/run/make-run-args.js:8:const moveProps = require('~/lib/move-props')
dorc-0.0.1.tgz/src/handler/run/make-run-args.js:9:const mergeProps = require('~/lib/merge-props')
dorc-0.0.1.tgz/src/handler/run/make-run-args.js:10:const transformDockerOptions = require('~/lib/transform-docker-options')
dorc-0.0.1.tgz/src/handler/run/make-run-args.js:12:const getMainTag = require('~/lib/get-main-tag')
dorc-0.0.1.tgz/src/handler/run/parse.js:4:const keysMatching = require('~/lib/keys-matching')
dorc-0.0.1.tgz/src/handler/run/parse.js:5:const mapKeys = require('~/lib/map-keys')
dorc-0.0.1.tgz/src/handler/run/parse.js:6:const zipObjRest = R.curry(require('~/lib/zip-obj-rest'))
dorc-0.0.1.tgz/src/handler/run/parse.js:7:const prepOptionsForMinimist = require('~/lib/prep-options-for-minimist')
dorc-0.0.1.tgz/src/handler/up/cmd.js:3:const sharedOptions = require('~/lib/shared-options')
dorc-0.0.1.tgz/src/handler/up/cmd.js:4:const pickIfAnySpecified = require('~/lib/pick-if-any-specified')
dorc-0.0.1.tgz/src/handler/up/index.js:1:const build = require('~/handler/build')
dorc-0.0.1.tgz/src/handler/up/index.js:2:const run = require('~/handler/run')
dorc-0.0.1.tgz/src/handler/up/index.js:3:const follow = require('~/handler/follow')
dorc-0.0.1.tgz/src/handler/up/index.js:4:const needsBuild = require('~/lib/service/needs-build')
dorc-0.0.1.tgz/src/lib/get-config.js:12:const configSchema = require('~/schema/config')
dorc-0.0.1.tgz/src/lib/help.js:4:const prefixLines = curry(require('~/lib/prefix-lines'))
dorc-0.0.1.tgz/src/lib/help.js:5:const toArrayAssignKeys = curry(require('~/lib/to-array-assign-keys'))
dorc-0.0.1.tgz/src/lib/parse-args.test.js:3:const run = require('~/handler/run')
dorc-0.0.1.tgz/src/lib/parse-args.test.js:4:const options = require('~/options')
dorc-0.0.1.tgz/src/lib/parse-args.test.js:5:const commands = require('~/commands')
dorc-0.0.1.tgz/src/scripts/save-run-options.js:5:const getRunOptions = require('~/lib/get-docker-run-options')
easy-require-1.0.1.tgz/perf/local.js:11:  app.require('~/inc/absolute');
easy-require-1.0.1.tgz/perf/nestedDirectory.js:11:  app.require('~/inc', true);
easy-require-1.0.1.tgz/perf/temp.js:6:var test = app.require('~/inc', true);
easy-require-1.0.1.tgz/tests/test.js:8:var test_local_dir = _require('~/local', true);
easy-require-1.0.1.tgz/tests/test.js:9:var test_empty_dir = _require('~/empty_dir', true);
easy-require-1.0.1.tgz/tests/test.js:10:var test_nested_dir = _require('~/nested_dir', true);
easy-require-1.0.1.tgz/tests/test.js:11:var test_no_dir = _require('~/no_dir');
easy-require-1.0.1.tgz/tests/test.js:12:var test_local = _require('~/local');
electron-ts-ipc-1.0.1.tgz/lib/index.js:6:var sub_1 = __importDefault(require("~/sub"));
ember-fastboot-server-0.7.3.tgz/lib/ember-app.js:57:    return ctx.require('~fastboot/app-factory');
eos-framework-0.4.0.tgz/src/app/actions/__tests__/affiliateActions.spec.js:6:const dataProvider = require('~/app/providers/BaseDataProvider');
eos-framework-0.4.0.tgz/src/app/actions/__tests__/episodeListActions.spec.js:7:const dataProvider = require('~/app/providers/BaseDataProvider');
eos-framework-0.4.0.tgz/src/app/actions/__tests__/searchActions.spec.js:6:const dataProvider = require('~/app/providers/BaseDataProvider');
eos-framework-0.4.0.tgz/src/app/helpers/headers.js:5:const getNSProcessEnvVar = require('~/app/helpers/environment').setNamespace();
eslint-plugin-no-require-self-ref-1.0.3.tgz/test.js:27:      code: 'require("~/hello")',
ethical-server-middleware-react-redux-0.0.6.tgz/test/specs/index.js:39:        .then(() => setTimeout(() => window.require('~'), 0))
ethical-utility-require-browser-0.0.1.tgz/test/specs/index.js:42:        expect(global.window.require('~/test/files/dist/a.js'))
ethical-utility-require-browser-0.0.1.tgz/test/specs/index.js:95:            global.window.require('~/app.js')
express-api-starter-kit-1.0.0.tgz/src/__tests__/helper.js:17:  require('~/server'); // eslint-disable-line global-require
fastboot-2.0.1.tgz/src/ember-app.js:203:      return ctx.require('~fastboot/app-factory');
fastboot-ryanone-1.0.0-rc.2.tgz/src/ember-app.js:158:      return ctx.require('~fastboot/app-factory');
fengyu-cli-1.0.9.tgz/template/framework/core/ws-plugin.js:9:    this.src = require('~/src/assets/img/src/common/default_load.png')
fsbx-2.1.0-beta.4.tgz/src/tests/fixtures/cases/case1/index.js:1://require("~/sub/hello.js");
fsbx-2.1.0-beta.4.tgz/src/tests/fixtures/cases/case1/index.js:44:// require("~/sub/hello.js");
fsbx-2.1.0-beta.4.tgz/src/tests/fixtures/cases/case1/sub/hello.js:1:console.log(require("~/bar.js"));
fusebox-cli-1.3.135.tgz/test/dynamic_modules.js:30:            "hello.js": `module.exports = require("~/stuff/boo.js");`,
fusebox-cli-1.3.135.tgz/test/dynamic_modules.js:41:            "hello.js": `module.exports = require("~/stuff/boo");`,
fusebox-cli-1.3.135.tgz/test/dynamic_modules.js:79:            FuseBox.dynamic("hello/world.js", "module.exports = require('~/foo')")`,
fusebox-cli-1.3.135.tgz/test/dynamic_modules.js:92:            FuseBox.dynamic("hello/world.js", "module.exports = require('~/foo.js')")`,
fusebox-cli-1.3.135.tgz/test/dynamic_modules.js:105:            FuseBox.dynamic("hello/world.js", "module.exports = require('~/foo.js')")`,
fusebox-cli-1.3.135.tgz/test/dynamic_modules.js:119:            FuseBox.dynamic("hello/world.js", "module.exports = require('~/foo.js')")`,
fusebox-cli-1.3.135.tgz/test/fixtures/cases/case1/index.js:1://require("~/sub/hello.js");
fusebox-cli-1.3.135.tgz/test/fixtures/cases/case1/index.js:44:// require("~/sub/hello.js");
fusebox-cli-1.3.135.tgz/test/fixtures/cases/case1/sub/hello.js:1:console.log(require("~/bar.js"));
fusebox-cli-1.3.135.tgz/test/generic_require.js:56:            "foo/bar.js": "module.exports = require('~/foo/hello.js')",
fusebox-cli-1.3.135.tgz/test/generic_require.js:68:            "foo/bar.js": "module.exports = require('~/foo/hello.js')",
fusebox-cli-1.3.135.tgz/test/generic_require.js:104:            "foo/index.js": `module.exports = require("~/bar")`,
fusebox-cli-1.3.135.tgz/test/generic_require.js:116:            "foo/index.js": `module.exports = require("~/bar/index")`,
fusebox-cli-1.3.135.tgz/test/generic_require.js:128:            "foo/index.js": `module.exports = require("~/bar/index.js")`,
ganesh-api-1.0.2.tgz/lib/firestore/models/Category.js:7:var _Enum = require('~/models/Enum');
ganesh-api-1.0.2.tgz/lib/firestore/models/Meat.js:7:var _Enum = require('~/models/Enum');
ganesh-api-1.0.2.tgz/lib/firestore/models/NanAndRice.js:7:var _Enum = require('~/models/Enum');
ganesh-api-1.0.2.tgz/lib/firestore/models/OrderStatus.js:7:var _Enum = require('~/models/Enum');
ganesh-api-1.0.2.tgz/lib/firestore/models/Payment.js:7:var _Enum = require('~/models/Enum');
ganesh-api-1.0.2.tgz/lib/firestore/models/Store.js:7:var _Enum = require('~/models/Enum');
generator-furious-0.0.2.tgz/generators/app/templates/src/app/healthz/tests/index.test.js:1:const { createTestServer } = require('~infra/test');
generator-furious-0.0.2.tgz/generators/app/templates/src/index.js:1:const Configuration = require('~infra/configuration');
generator-furious-0.0.2.tgz/generators/app/templates/src/index.js:2:const { createServer } = require('~infra/fastify');
generator-furious-0.0.2.tgz/generators/app/templates/src/index.js:3:const Logger = require('~infra/logger');
generator-furious-0.0.2.tgz/generators/app/templates/src/infra/test/index.js:1:const Configuration = require('~infra/configuration');
generator-furious-0.0.2.tgz/generators/app/templates/src/infra/test/index.js:2:const { createServer } = require('~infra/fastify');
generator-furious-0.0.2.tgz/generators/app/templates/src/infra/test/index.js:3:const Logger = require('~infra/logger');
goman-0.0.4.tgz/src/g.js:20:  generatorConfig = require('~/.g/.g.config.json');
gpms_permission-0.0.1.tgz/playground/playground.js:2://const GPValidObject = require('~/development.api/gplib_validobject/dist/index');
gridsome-0.6.3.tgz/app/main.js:4:  main = require('~/main').default
grunt-init-react-0.1.8.tgz/root/src/app/pages/About.js:11:      readmeHtml = require('~/README.md');
hmls-2.2.0.tgz/bin/scaffold/routes/slash/index.js:8:      const page = require('~/pages/slash/index.marko')
hmls-2.2.0.tgz/index.js:12:const config = require('~/config')
hmls-2.2.0.tgz/test/index.js:7:const HMLS = require('~/index')
hook-require-path-1.1.0.tgz/test/install.manual-test.js:24:  const dir1ModuleA = require('~/module-a')
hook-require-path-1.1.0.tgz/test/install.manual-test.js:47:  const module = require('~/inner-require')
hook-require-path-1.1.0.tgz/test/install.manual-test.js:62:  const randomC = require('~/../random')
hook-require-path-1.1.0.tgz/test/install.manual-test.js:82:  const circle1 = require('~/circle1')
hook-require-path-1.1.0.tgz/test/install.manual-test.js:106:  const circle1 = require('~/circle1')
hook-require-path-1.1.0.tgz/test/install.manual-test.js:110:    const tmp = require('~/circle1')
hook-require-path-1.1.0.tgz/test/test-modules/dir2/circle2.js:2:module.exports.other = require('~/circle1')
ignite-matt-oakes-react-native-boilerplate-2.0.0.tgz/boilerplate/src/navigation/rootNavigationStack.js:9:    getScreen: () => require("~/src/screens/Welcome").default
ignite-matt-oakes-react-native-boilerplate-2.0.0.tgz/boilerplate/src/theme/images.js:4:  // logo: require("~/src/images/logo.png")
impacter-0.0.8.tgz/ig.js:37:        const assets = require('~/../assets/assets.json');
izi-3.1.0.tgz/fuzzy-time.js:6:} = require('~/i18n')
lsk-mobx-0.1.0.tgz/src/App/App.server.js:22:      ...require('~/modules/server').default(this),
lsk-mobx-0.1.0.tgz/src/Uapp/Uapp.js:29:      ...require('~/modules/uapp').default(this), // eslint-disable-line
lvx-cli-1.0.6.tgz/template/framework/core/lvx-plugin.js:9:  this.src = require('~/src/assets/img/src/common/default_load.png')
marko-starter-2.0.4.tgz/index.js:5:require('~/src');
marko-starter-2.0.4.tgz/index.js:24:const logging = require('~/src/logging');
marko-starter-2.0.4.tgz/index.js:25:const pluginManager = require('~/src/plugin-manager');
marko-starter-2.0.4.tgz/index.js:28:const _createProject = require('~/src/util/createProject');
marko-starter-2.0.4.tgz/index.js:29:const _runProjectTasks = require('~/src/util/runProjectTasks');
marko-starter-2.0.4.tgz/index.js:30:const _triggerProjectHook = require('~/src/util/triggerProjectHook');
marko-starter-2.0.4.tgz/index.js:125:          const _buildAllRoutes = require('~/src/util/buildAllRoutes');
marko-starter-2.0.4.tgz/src/models/BuildResult.js:15:    project: require('~/src/models/Project'),
marko-starter-2.0.4.tgz/src/models/Project.js:3:const Raw = require('~/src/models/Raw');
marko-starter-2.0.4.tgz/src/models/Project.js:4:const logging = require('~/src/logging');
marko-starter-2.0.4.tgz/src/models/Project.js:5:const routeHandlerUtil = require('~/src/route-handler-util');
marko-starter-2.0.4.tgz/src/models/Project.js:86:      default: require('~/src/util/isProduction')
marko-starter-2.0.4.tgz/src/plugin-manager.js:3:const logging = require('~/src/logging');
marko-starter-2.0.4.tgz/src/plugin-manager.js:4:const Project = require('~/src/models/Project');
marko-starter-2.0.4.tgz/src/plugin-manager.js:27:      Raw: require('~/src/models/Raw'),
marko-starter-2.0.4.tgz/src/util/buildAllRoutes.js:7:const BuildResult = require('~/src/models/BuildResult');
marko-starter-2.0.4.tgz/src/util/createProject.js:4:const logging = require('~/src/logging');
marko-starter-2.0.4.tgz/src/util/createProject.js:6:const ProjectSchema = require('~/src/models/Project');
marko-starter-2.0.4.tgz/src/util/createProject.js:81:    require('~/src/project-tasks/print-configuration')
marko-starter-2.0.4.tgz/src/util/triggerProjectHook.js:3:const pluginManager = require('~/src/plugin-manager');
meta-client-0.0.0-c32.tgz/lib/Space/Meta/Graphics/Model/Model.js:1:'use strict';Object.defineProperty(exports,'__esModule',{value:true});var _src=require('~/src');function _classCallCheck(instance,Constructor){if(!(instance instanceof Constructor)){throw new TypeError('Cannot call a class as a function')}}var Model=function Model(file){_classCallCheck(this,Model);return new _src.Meta({graphics:new _src.Graphics({model:file},true)})};exports.default=Model;
mongo-purge-1.0.1.tgz/index.js:4:const options = require('~/lib/cli')
mongo-purge-1.0.1.tgz/index.js:9:const log = require('~/lib/logger')
mongo-purge-1.0.1.tgz/lib/cli.js:4:const log = require('~/lib/logger')
mongo-purge-1.0.1.tgz/lib/cli.js:8:  .version(require('~/package.json').version)
nativescript-dev-webpack-0.24.0.tgz/load-application-css-angular.js:5:        global.registerModule("./app.css", () => require("~/app"));
nativescript-download-progress-1.1.0.tgz/android-worker.js:4:      global.require('~/../internal/ts_helpers.js');
nativescript-download-progress-1.1.0.tgz/android-worker.js:6:    global.require('~/vendor');
nativescript-tus-upload-1.0.5.tgz/android-worker.js:5:    global.require('~/../internal/ts_helpers.js');
nativescript-tus-upload-1.0.5.tgz/android-worker.js:7:  global.require('~/vendor');
ned-transpile-1.0.6.tgz/test/fixtures/root-import/bars/bar/bool.js:1:module.exports = require('~/result')
ned-transpile-1.0.6.tgz/test/fixtures/root-require/bars/bar/bool.js:1:module.exports = require('~/result')
ned-transpile-1.0.6.tgz/test/fixtures/root-require/foos/fool.js:1:module.exports = require('~/bars/bar/bool')
ned-transpile-1.0.6.tgz/test/fixtures/root-require/index.js:1:var x = require('~/')
ned-transpile-1.0.6.tgz/test/fixtures/root-require/index.js:2:var y = require('~')
ned-transpile-1.0.6.tgz/test/fixtures/root-require/index.js:3:module.exports = require('~/foos/fool')
nexus-repo-0.0.16.tgz/nexusRepoCli.js:4://var config = require('~/.nexusRepo.json')
nodecopter-0.0.2.tgz/nodecopter.js:50:            config = require('~/nodecopter.json')
nuxt-feathers-vuex-0.0.7.tgz/lib/templates/plugin.js:47:    let { store, hooks, options } = require('~/store/services/' + name)
nuxt-feathers-vuex-0.0.7.tgz/lib/templates/plugin.js:80:  allNames.includes('auth') ? require('~/store/services/auth').store : {}
nuxt-i18n-module-0.2.7.tgz/src/templates/plugin.js:33:    messages[lang] = require('~/assets/locale/' + lang + '.json')
nuxt.js-0.0.1.tgz/examples/i18n/plugins/i18n.js:13:      'en': require('~/locales/en.json'),
nuxt.js-0.0.1.tgz/examples/i18n/plugins/i18n.js:14:      'fr': require('~/locales/fr.json')
open_castings_components-1.0.1.tgz/lib/Buttons/stories/Button.js:17:var _ = require('~/');
open_castings_components-1.0.1.tgz/lib/Generic/stories/oc_editable_hoc.js:15:var _ = require('~/');
open_castings_components-1.0.1.tgz/lib/Generic/stories/oc_editable_hoc.js:17:var _load_mui_theme = require('~/.storybook/load_mui_theme');
open_castings_components-1.0.1.tgz/lib/Profile/stories/profile_basic_stats.js:9:var _ = require('~/');
open_castings_components-1.0.1.tgz/lib/Profile/stories/profile_basic_stats.js:11:var _load_mui_theme = require('~/.storybook/load_mui_theme');
open_castings_components-1.0.1.tgz/lib/Profile/stories/profile_edit_jobs.js:9:var _ = require('~/');
open_castings_components-1.0.1.tgz/lib/Profile/stories/profile_edit_jobs.js:11:var _load_mui_theme = require('~/.storybook/load_mui_theme');
open_castings_components-1.0.1.tgz/lib/Profile/stories/profile_education_training.js:9:var _ = require('~/');
open_castings_components-1.0.1.tgz/lib/Profile/stories/profile_education_training.js:11:var _load_mui_theme = require('~/.storybook/load_mui_theme');
open_castings_components-1.0.1.tgz/lib/Profile/stories/profile_education_training_item.js:9:var _ = require('~/');
open_castings_components-1.0.1.tgz/lib/Profile/stories/profile_education_training_item.js:11:var _load_mui_theme = require('~/.storybook/load_mui_theme');
open_castings_components-1.0.1.tgz/lib/Profile/stories/profile_image.js:9:var _ = require('~/');
open_castings_components-1.0.1.tgz/lib/Profile/stories/profile_jobs.js:9:var _ = require('~/');
open_castings_components-1.0.1.tgz/lib/Profile/stories/profile_jobs.js:11:var _load_mui_theme = require('~/.storybook/load_mui_theme');
open_castings_components-1.0.1.tgz/lib/Profile/stories/profile_overview.js:9:var _ = require('~/');
open_castings_components-1.0.1.tgz/lib/Profile/stories/profile_overview.js:11:var _load_mui_theme = require('~/.storybook/load_mui_theme');
open_castings_components-1.0.1.tgz/lib/Profile/stories/profile_skills.js:9:var _ = require('~/');
open_castings_components-1.0.1.tgz/lib/Profile/stories/profile_skills.js:11:var _load_mui_theme = require('~/.storybook/load_mui_theme');
open_castings_components-1.0.1.tgz/lib/Profile/stories/profile_title.js:9:var _ = require('~/');
open_castings_components-1.0.1.tgz/lib/Profile/stories/profile_title.js:11:var _load_mui_theme = require('~/.storybook/load_mui_theme');
open_castings_components-1.0.1.tgz/lib/Social/stories/facebook_followers.js:9:var _ = require('~/');
open_castings_components-1.0.1.tgz/lib/Social/stories/twitter_followers.js:9:var _ = require('~/');
oyod-0.1.1.tgz/server/test/apis/pv.test.js:4:var router = require('~/server/apis/pv/pv.api')
oyod-0.1.1.tgz/server/test/apis/pv.test.js:5:var PV = require('~/server/apis/pv/pv.model')
oyod-0.1.1.tgz/server/test/apis/pv.test.js:6:var db = require('~/server/lib/db-driver')
oyod-0.1.1.tgz/server/test/integration/basic-app-installation.test.js:6:var User = require('~/server/models/user')
oyod-0.1.1.tgz/server/test/integration/basic-app-installation.test.js:7:var AccessToken = require('~/server/models/access-token')
oyod-0.1.1.tgz/server/test/integration/basic-app-installation.test.js:8:var appRouter = require('~/server/index.js')
oyod-0.1.1.tgz/server/test/routes/oauth.test.js:6:var User = require('~/server/models/user')
oyod-0.1.1.tgz/server/test/routes/oauth.test.js:7:var appRouter = require('~/server/index.js')
panela-0.2.0.tgz/lib/builder.js:16:const { isFunction } = onepath.require('~/util');
panela-0.2.0.tgz/lib/core.js:24:const logger = onepath.require('~/logger');
panela-0.2.0.tgz/lib/core.js:25:const { isFunction, isArray, isObject } = onepath.require('~/util');
panela-0.2.0.tgz/lib/database.js:15:const util = onepath.require('~/util');
panela-0.2.0.tgz/lib/endpoint.js:12:const Core = onepath.require('~/core');
panela-0.2.0.tgz/lib/endpoint.js:13:const { isString, isFunction, slice } = onepath.require('~/util');
panela-0.2.0.tgz/lib/engine.js:15:const util = onepath.require('~/util');
panela-0.2.0.tgz/lib/host.js:15:const Middleware = onepath.require('~/middleware');
panela-0.2.0.tgz/lib/host.js:16:const NginxConfig = onepath.require('~/nginxc');
panela-0.2.0.tgz/lib/host.js:17:const Route = onepath.require('~/route');
panela-0.2.0.tgz/lib/host.js:18:const { isString, slice } = onepath.require('~/util');
panela-0.2.0.tgz/lib/hosts.js:24:const { isString } = onepath.require('~/util');
panela-0.2.0.tgz/lib/middleware.js:14:const Endpoint = onepath.require('~/endpoint');
panela-0.2.0.tgz/lib/middleware.js:15:const { isString, slice } = onepath.require('~/util');
panela-0.2.0.tgz/lib/nginxc.js:22:const { isString } = onepath.require('~/util');
panela-0.2.0.tgz/lib/panela.js:16:const Builder = onepath.require('~/builder');
panela-0.2.0.tgz/lib/panela.js:17:const Core = onepath.require('~/core');
panela-0.2.0.tgz/lib/panela.js:18:const Database = onepath.require('~/database');
panela-0.2.0.tgz/lib/panela.js:19:const Engine = onepath.require('~/engine');
panela-0.2.0.tgz/lib/panela.js:20:const Host = onepath.require('~/host');
panela-0.2.0.tgz/lib/panela.js:21:const Route = onepath.require('~/route');
panela-0.2.0.tgz/lib/panela.js:22:const hosts = onepath.require('~/hosts');
panela-0.2.0.tgz/lib/panela.js:23:const logger = onepath.require('~/logger');
panela-0.2.0.tgz/lib/panela.js:24:const NginxConfig = onepath.require('~/nginxc');
panela-0.2.0.tgz/lib/panela.js:25:const { isObject, isString, isFunction } = onepath.require('~/util');
panela-0.2.0.tgz/lib/route.js:14:const Endpoint = onepath.require('~/endpoint');
panela-0.2.0.tgz/lib/route.js:15:const { isString, slice } = onepath.require('~/util');
playland-2.1.1.tgz/src/components/App.js:10:const Home = () => 
plex-vr-0.9.0.tgz/lib/api/index.js:21:var _request = require('~api/request');
plex-vr-0.9.0.tgz/lib/api/index.js:23:var _headers = require('~api/headers');
plex-vr-0.9.0.tgz/lib/api/request.js:8:var _xml2json = require('~util/xml2json');
postjss-0.1.0.tgz/src/webpack/tests/report-loader.spec.js:8:  const loader = require('~/webpack/report-loader').default
prism-cli-0.3.1.tgz/prism.js:11:        ansi_mapping = require('~/.prismrc');
pult-cli-0.5.0.tgz/base-template/test/server/index_test.js:4:var routes = require('~/server/index')
quasar-application-0.0.4.tgz/lib/templates/entry.js:29:require('~/css/<%= asset %>')
rachnerd-test-plugin-0.0.34.tgz/test/utils.spec.js:23:        let fileContent = 'Some text or code require("~/someLib"); plus some other stuff';
rachnerd-test-plugin-0.0.34.tgz/test/utils.spec.js:28:        let fileContent = 'Some text or code require("~/someLib"); plus some other stuff';
rachnerd-test-plugin-0.0.34.tgz/test/utils.spec.js:36:        let expectedOutput = 'require("~/some/directory/deep/lib");';
rachnerd-test-plugin-0.0.34.tgz/test/utils.spec.js:42:        let expectedOutput = 'require("~/some/directory/deep/child/lib");';
rachnerd-test-plugin-0.0.34.tgz/test/utils.spec.js:48:        let expectedOutput = 'require("~/some/directory/lib");';
rachnerd-test-plugin-0.0.34.tgz/test/utils.spec.js:54:        let expectedOutput = 'require("~/some/directory/deep/lib"); require("~/some/directory/deep/lib");';
rachnerd-test-plugin-0.0.34.tgz/test/utils.spec.js:70:                require("~/some/directory/deep/lib");
rachnerd-test-plugin-0.0.34.tgz/test/utils.spec.js:71:                require("~/some/directory/otherdirectory/lib");
rachnerd-test-plugin-0.0.34.tgz/test/utils.spec.js:72:                require("~/some/directory/lib");
rachnerd-test-plugin-0.0.34.tgz/test/utils.spec.js:87:                require("~/some/directory/lib-dir/lib.lib_lib/lib");
rachnerd-test-plugin-0.0.34.tgz/test/utils.spec.js:88:                require("~/some/directory/deep/lib-dir/lib.lib_lib/lib");
react-native-template-allmax-1.3.0.tgz/src/global/strings.js:11:    privateStrings = require('~/localization/ru-RU').strings;
react-native-template-allmax-1.3.0.tgz/src/global/strings.js:14:    privateStrings = require('~/localization/en-US').strings;
react-native-template-csorlandi-advanced-1.0.1.tgz/src/pages/main/index.js:40:      source={require('~/images/rocketseat_logo.png')}
react-native-template-csorlandi-basic-2.0.3.tgz/src/pages/Main/index.js:40:      source={require('~/images/rocketseat_logo.png')}
react-native-template-feature-based-basic-0.2.0.tgz/src/themes/images.js:4:	//logo: require('~/assets/images/react.png'),
react-native-template-feature-based-redux-0.4.0.tgz/src/store/ducks/index.js:5:	// product: require('~/common/state/product/ProductDuck').reducer,
react-native-template-feature-based-redux-0.4.0.tgz/src/store/ducks/index.js:6:	// user: require('~/user/state/UserDuck').reducer,
react-native-template-feature-based-redux-0.4.0.tgz/src/themes/images.js:4:	//logo: require('~/assets/images/react.png'),
react-native-template-scalable-0.3.0.tgz/src/themes/Images.js:4:  //logo: require('~/assets/images/lego.png'),
react-native-template-scalable-redux-0.4.0.tgz/src/store/Ducks.js:5:	// product: require('~/common/state/product/ProductDuck').reducer,
react-native-template-scalable-redux-0.4.0.tgz/src/store/Ducks.js:6:	// user: require('~/user/state/UserDuck').reducer,
react-native-template-scalable-redux-0.4.0.tgz/src/themes/Images.js:4:  //logo: require('~/assets/images/lego.png'),
reacteum-1.2.1.tgz/src/store/index.js:19:const history = isBrowser ? require('~/store/history') : null;
reaction-build-1.0.0-rc.104.tgz/lib/server.js:58:  var app = require('~/../web/server').default.app;
reaction-build-1.0.0-rc.104.tgz/lib/storiesOf/StorybookView/index.js:47:      var rootStyle = require('~/../web/styles/root.scss?root=./web/styles/');
require-app-root-1.0.0-a.tgz/test/main.js:16:		t.ok(require("~/library/a.js"), "a");
require-app-root-1.0.0-a.tgz/test/main.js:17:		t.ok(require("~/b.js"), "b");
requiro-1.8.0.tgz/test/fixtures/package_root/a/1.js:2:module.exports = require("~/b");
requiroify-1.2.1.tgz/test.js:6:var content = "require('~/dummy')";
root_require-0.0.0.tgz/test/index.js:6:  t.equal(require('~/a'), 123, 'prefix refers to project root')
root_require-0.0.0.tgz/test/index.js:7:  t.equal(require('~/a.js'), 123, 'file extension does not break things')
root_require-0.0.0.tgz/test/index.js:11:    require('~/a')
root_require-0.0.0.tgz/test/index.js:18:  t.equal(require('~/test/a'), 123, 'setRoot() uses package.json to determine root by default')
root_require-0.0.0.tgz/test/index.js:21:  t.equal(require('~/a'), 123, 'setRoot changes the root')
root_require-0.0.0.tgz/test/index.js:28:    require('~/a')
salesforce-storelocator-1.0.5.tgz/store_locator/cartridge/controllers/Stores.js:19:var dsStyles        = require('~/cartridge/scripts/modules/util/Styles.ds');
slack-rx-event-1.0.0.tgz/examples/eventRouter/index.js:4:const slackRx = require('~/index.js')
slack-rx-event-1.0.0.tgz/test/index.spec.js:5:const slackRx = require('~/index.js')
start-deepsweet-react-component-preset-0.0.6.tgz/lib/webpack/demo/index.js:11:var _demo = require('~/demo/');
start-deepsweet-react-component-preset-0.0.6.tgz/lib/webpack/demo/index.js:29:    renderDemo(require('~/demo/').default);
start-deepsweet-react-components-monorepo-preset-0.0.14.tgz/lib/webpack/demo/index.js:11:var _demo = require('~/demo/');
start-deepsweet-react-components-monorepo-preset-0.0.14.tgz/lib/webpack/demo/index.js:29:    renderDemo(require('~/demo/').default);
steal-conditional-1.1.3.tgz/test/relative-conditions/main.js:1:var foo = require("~/polyfill#?./some/deep/folder/dont-load-it");
steal-conditional-1.1.3.tgz/test/relative-conditions/main.js:2:var bar = require("~/some/deep/#{./some/deep/folder/which}");
steal-conditional-1.1.3.tgz/test/relative-conditions/main.js:11:require("~/some/deep/folder/test");
steal-conditional-1.1.3.tgz/test/relative-conditions/some/deep/folder/test.js:1:var dotdotSlashX3 = require("~/some/deep/#{../../../some/deep/folder/which}");
steal-conditional-1.1.3.tgz/test/relative-conditions/some/deep/folder/test.js:2:var dotdotSlashX3AndExport = require("~/some/deep/#{../../../some/deep/folder/which.foo}");
steal-npm-1.0.11.tgz/test/import_test.js:302:	var app = "var foobar = require('~/foo/foobar');" +
steal-npm-1.0.11.tgz/test/import_test.js:303:						"var barfoo = require('~/./bar/barfoo');" +
steal-npm-1.0.11.tgz/test/import_test.js:336:	var app = "var foobar = require('~/foo/foobar');" +
szuprefix_crm-0.1.0.tgz/src/router/index.js:11:            component: require('~/views/index.vue')
szuprefix_crm-0.1.0.tgz/src/store/index.js:6:require('~/configs/axios')
tarantul-0.8.148.tgz/lib/server/app/api/registration.js:13:        return require('~/user/main').default;
tarantul-0.8.148.tgz/lib/server/app/game.js:81:            result.push([key, require('~/user/main').default.create(user)]);
tns-core-modules-5.4.1.tgz/profiling/profiling.js:132:    var appConfig = require("~/package.json");
tns-core-modules-5.4.1.tgz/ui/styling/style-scope.js:24:    var appConfig = require("~/package.json");
tns-i18n-0.0.10.tgz/index.js:9:  var defaults = require('~/i18n/' + defaultLang);
tns-i18n-0.0.10.tgz/index.js:12:    strings = require('~/i18n/' + lang);
tns-i18n-deep-0.0.13.tgz/index.js:8:  var defaults = require("~/i18n/" + defaultLang);
tns-i18n-deep-0.0.13.tgz/index.js:11:    strings = require("~/i18n/" + lang);
toolkit-ui-0.12.1.tgz/src/plugins/i18n.js:20:      'en': require('~/locales/en.json'),
toolkit-ui-0.12.1.tgz/src/plugins/i18n.js:21:      'fr': require('~/locales/fr.json')
universal-alias-loader-1.2.2.tgz/tests/alias-resolve.spec.js:84:    .toEqual(`require('~/pages/home/story.js')`)
valid8r-0.0.5.tgz/__test__/Validator.spec.js:1:const Validator = require('~/Validator')
vcf-rntemplate-0.0.1.tgz/src/pages/Home/index.js:19:    
vues-0.5.20.tgz/lib/__tests__/server.js:52:        require("~/test.css")
zhiwang-cli-1.0.1.tgz/framework/core/lvx-plugin.js:9:  this.src = require('~/src/assets/img/src/common/default_load.png')
That comes out to 92 modules in the public registry using this pattern.
ModuleBinder
adfc-t30-paten-map
astroman
babel-plugin-root-require
babel-plugin-sfcc-modules
bael-cms-template
benben-frontend-generator
best-require
blockstack-react-scripts
contacts_client
container-store
ctail
dockular
dorc
easy-require
electron-ts-ipc
ember-fastboot-server
eos-framework
eslint-plugin-no-require-self-ref
ethical-server-middleware-react-redux
ethical-utility-require-browser
express-api-starter-kit
fastboot
fastboot-ryanone-1.0.0
fengyu-cli
fsbx-2.1.0
fusebox-cli
ganesh-api
generator-furious
goman
gpms_permission
gridsome
grunt-init-react
hmls
hook-require-path
ignite-matt-oakes-react-native-boilerplate
impacter
izi
lsk-mobx
lvx-cli
marko-starter
meta-client-0.0.0
mongo-purge
nativescript-dev-webpack
nativescript-download-progress
nativescript-tus-upload
ned-transpile
nexus-repo
nodecopter
nuxt-feathers-vuex
nuxt-i18n-module
nuxt.js
open_castings_components
oyod
panela
playland
plex-vr
postjss
prism-cli
pult-cli
quasar-application
rachnerd-test-plugin
react-native-template-allmax
react-native-template-csorlandi-advanced
react-native-template-csorlandi-basic
react-native-template-feature-based-basic
react-native-template-feature-based-redux
react-native-template-scalable
react-native-template-scalable-redux
reacteum
reaction-build-1.0.0
require-app-root-1.0.0
requiro
requiroify
root_require
salesforce-storelocator
slack-rx-event
start-deepsweet-react-component-preset
start-deepsweet-react-components-monorepo-preset
steal-conditional
steal-npm
szuprefix_crm
tarantul
tns-core-modules
tns-i18n
tns-i18n-deep
toolkit-ui
universal-alias-loader
valid8r
vcf-rntemplate
vues
zhiwang-cli

From github it is harder to perform the search since ~ is stubbed out. 92 isn't terrible to audit by hand to see what is going on but a fair number of these seem to actually be using require dynamically with expressions or import which is harder to grep for. A small look into these, it looks like most are expecting ~ to be at some concept of a "root" but the root differs from application root vs package root. I think identifying packages that are mutating resolution to ensure we don't break them might be prudent. Packages not found naively sometimes are sizable enough to make me think a more thorough search is necessary babel-plugin-root-import.

Copy link
Member

@devsnek devsnek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if this isn't pointing to os.homedir() i don't think tilde should be used. Just too surprising/confusing.

Support "exports" in package.json automation moved this from In progress to Review in progress Aug 27, 2019
@Fishrock123
Copy link
Member

Would it be more reasonable to add a separate api for this rather than relying on figuring out a new specifier?

@ljharb
Copy link
Member

ljharb commented Aug 27, 2019

@Fishrock123 that would be much more confusing and complex for the massive ecosystem that handles resolution; and it wouldn’t work as nicely with ESM. It’s far cleaner to do it via specifier imo.

@ljharb
Copy link
Member

ljharb commented Aug 27, 2019

@devsnek tilde is the most commonly used alias in my experience (babel/webpack/TS) for this exact feature, package root. Do you have an alternative suggestion?

@devsnek
Copy link
Member

devsnek commented Aug 27, 2019

# and & come to mind. Anything that isn't already widely used with a different meaning.

@jkrems
Copy link
Contributor Author

jkrems commented Aug 27, 2019

Since # is now the official symbol for "private" in Javascript, using it for "public interface" would be really confusing I think. ~ as a shorthand for "the current package" is following the ecosystem precedent but other symbols would be possible. For example @ or ^ or even a more complex prefix like <pkg> would be possible alternatives.

@MylesBorins
Copy link
Member

Wouldn't the namespace approach make it different enough from home directory?

@jkrems
Copy link
Contributor Author

jkrems commented Aug 27, 2019

@MylesBorins Ah, gotcha. Right, if the issue is "~/ could be confused with the home directory", then we may be able to compromise on ~: even though the main may look weird (just ~:?). Or is the idea that we'd require a package name in addition to ~:, so ~:@foo/bar and checking against the name in package.json?

@devsnek
Copy link
Member

devsnek commented Aug 27, 2019

My issue with the tilde is more of the fact that it's the first character in the string, which for the last 30 years has meant "expand to $HOME" in unix, and however long powershell has existed. If we're trying to make paths less confusing, I don't think using tilde at the start is the best approach.

Perhaps :~ or @~?

@Fishrock123
Copy link
Member

Fishrock123 commented Aug 27, 2019

My 2c is over at nodejs/modules#306 (comment)

I feel like if it is necessary Node.js can add some separate API for this, but if it for some reason needs to be within import statements then I strongly feel this should go to TC39, not us. (Although we may be able to make a recommendation.)

@ljharb
Copy link
Member

ljharb commented Aug 27, 2019

Requiring the package name defeats one of the benefits of having the alias, which is “not repeating the package name”.

@ljharb
Copy link
Member

ljharb commented Aug 27, 2019

@Fishrock123 TC39 is irrelevant here; there’s no concept of a “package” and the spec intentionally avoids imposing any restrictions on specifier contents.

@MylesBorins
Copy link
Member

my idea would be that ~: would refer to the root of the package so you could do

~:named-export

@ljharb
Copy link
Member

ljharb commented Aug 27, 2019

by "named-export" you mean, any specifier that's reachable from the package root, filtered through exports?

@devongovett
Copy link
Contributor

devongovett commented Aug 27, 2019

FWIW, Parcel and other tools already implement tilde resolution as it is being proposed here. https://parceljs.org/module_resolution.html

I don't think anyone would expect ~ to resolve to the home directory in the context of module resolution since this has never been true in node. It would also be pretty weird if it did resolve to the home dir since the resolution would change depending on the system it runs on, and thus would be non-portable.

@GeoffreyBooth
Copy link
Member

I don’t think anyone would expect ~ to resolve to the home directory in the context of module resolution since this has never been true in node.

I agree with this. Non-portable code is uncommon, and we shouldn’t assume that that’s the default or the user expectation. The only use case I can think of is the Node equivalent of shell scripts, but even those would probably usually use relative references.

I think there’s an advantage to reusing the ~ symbol, as users are already familiar with it meaning “home.” In the Node context, per this proposal, “home” would just mean the root of the package/project. I think that’s what most users would expect, as evidenced by https://github.com/entwicklerstube/babel-plugin-root-import.

@devsnek
Copy link
Member

devsnek commented Aug 27, 2019

Userland code can do whatever it wants, people opt into it. We don't plan to let this be overridden and I know at least three people I've talked to who would want avoid using tilde as an expansion.

@nodejs-github-bot
Copy link
Collaborator

@jkrems
Copy link
Contributor Author

jkrems commented Oct 24, 2019

Landed in 71bcd05

@jkrems jkrems closed this Oct 24, 2019
Support "exports" in package.json automation moved this from Reviewer approved to Done Oct 24, 2019
jkrems added a commit that referenced this pull request Oct 24, 2019
Adds the ability to `import` or `require` a package from within its
own source code. This allows tests and examples to be written using
the package name, making them easier to reuse by consumers of the
package.

Assuming the `name` field in `package.json` is set to `my-pkg`, its
test could use `require('my-pkg')` or `import 'my-pkg'` even if
there's no `node_modules/my-pkg` while testing the package itself.

An important difference between this and relative specifiers like
`require('../')` is that self-references use the public interface
of the package as defined in the `exports` field while relative
specifiers don't.

This behavior is guarded by a new experimental flag
(`--experimental-resolve-self`).

PR-URL: #29327
Reviewed-By: Guy Bedford <guybedford@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Copy link
Member

@MylesBorins MylesBorins left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Post land RSLGTM

@jkrems jkrems deleted the tilde-self branch October 25, 2019 15:46
4. LOAD_NODE_MODULES(X, dirname(Y))
5. THROW "not found"
5. LOAD_NODE_MODULES(X, dirname(Y))
4. LOAD_SELF_REFERENCE(X, dirname(Y))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these entries misnumbered?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They are! Let me create a follow-up to fix that.

Copy link
Contributor Author

@jkrems jkrems Oct 25, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix in #30117

jkrems added a commit to jkrems/node that referenced this pull request Oct 25, 2019
targos pushed a commit that referenced this pull request Oct 28, 2019
Adds the ability to `import` or `require` a package from within its
own source code. This allows tests and examples to be written using
the package name, making them easier to reuse by consumers of the
package.

Assuming the `name` field in `package.json` is set to `my-pkg`, its
test could use `require('my-pkg')` or `import 'my-pkg'` even if
there's no `node_modules/my-pkg` while testing the package itself.

An important difference between this and relative specifiers like
`require('../')` is that self-references use the public interface
of the package as defined in the `exports` field while relative
specifiers don't.

This behavior is guarded by a new experimental flag
(`--experimental-resolve-self`).

PR-URL: #29327
Reviewed-By: Guy Bedford <guybedford@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
jkrems added a commit that referenced this pull request Oct 29, 2019
Refs: #29327

PR-URL: #30117
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
targos pushed a commit that referenced this pull request Nov 5, 2019
Refs: #29327

PR-URL: #30117
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
@targos targos mentioned this pull request Nov 5, 2019
targos pushed a commit that referenced this pull request Nov 8, 2019
Adds the ability to `import` or `require` a package from within its
own source code. This allows tests and examples to be written using
the package name, making them easier to reuse by consumers of the
package.

Assuming the `name` field in `package.json` is set to `my-pkg`, its
test could use `require('my-pkg')` or `import 'my-pkg'` even if
there's no `node_modules/my-pkg` while testing the package itself.

An important difference between this and relative specifiers like
`require('../')` is that self-references use the public interface
of the package as defined in the `exports` field while relative
specifiers don't.

This behavior is guarded by a new experimental flag
(`--experimental-resolve-self`).

PR-URL: #29327
Reviewed-By: Guy Bedford <guybedford@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
targos pushed a commit that referenced this pull request Nov 8, 2019
Refs: #29327

PR-URL: #30117
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
@targos targos added the semver-minor PRs that contain new features and should be released in the next minor version. label Nov 10, 2019
targos pushed a commit that referenced this pull request Jan 8, 2020
Adds the ability to `import` or `require` a package from within its
own source code. This allows tests and examples to be written using
the package name, making them easier to reuse by consumers of the
package.

Assuming the `name` field in `package.json` is set to `my-pkg`, its
test could use `require('my-pkg')` or `import 'my-pkg'` even if
there's no `node_modules/my-pkg` while testing the package itself.

An important difference between this and relative specifiers like
`require('../')` is that self-references use the public interface
of the package as defined in the `exports` field while relative
specifiers don't.

This behavior is guarded by a new experimental flag
(`--experimental-resolve-self`).

PR-URL: #29327
Reviewed-By: Guy Bedford <guybedford@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
targos pushed a commit that referenced this pull request Jan 8, 2020
Refs: #29327

PR-URL: #30117
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
targos pushed a commit that referenced this pull request Jan 8, 2020
Adds the ability to `import` or `require` a package from within its
own source code. This allows tests and examples to be written using
the package name, making them easier to reuse by consumers of the
package.

Assuming the `name` field in `package.json` is set to `my-pkg`, its
test could use `require('my-pkg')` or `import 'my-pkg'` even if
there's no `node_modules/my-pkg` while testing the package itself.

An important difference between this and relative specifiers like
`require('../')` is that self-references use the public interface
of the package as defined in the `exports` field while relative
specifiers don't.

This behavior is guarded by a new experimental flag
(`--experimental-resolve-self`).

PR-URL: #29327
Reviewed-By: Guy Bedford <guybedford@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
targos pushed a commit that referenced this pull request Jan 8, 2020
Refs: #29327

PR-URL: #30117
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
BethGriggs pushed a commit that referenced this pull request Feb 6, 2020
Adds the ability to `import` or `require` a package from within its
own source code. This allows tests and examples to be written using
the package name, making them easier to reuse by consumers of the
package.

Assuming the `name` field in `package.json` is set to `my-pkg`, its
test could use `require('my-pkg')` or `import 'my-pkg'` even if
there's no `node_modules/my-pkg` while testing the package itself.

An important difference between this and relative specifiers like
`require('../')` is that self-references use the public interface
of the package as defined in the `exports` field while relative
specifiers don't.

This behavior is guarded by a new experimental flag
(`--experimental-resolve-self`).

PR-URL: #29327
Reviewed-By: Guy Bedford <guybedford@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
BethGriggs pushed a commit that referenced this pull request Feb 6, 2020
Refs: #29327

PR-URL: #30117
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
@MylesBorins MylesBorins mentioned this pull request Feb 8, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
author ready PRs that have at least one approval, no pending requests for changes, and a CI started. esm Issues and PRs related to the ECMAScript Modules implementation. experimental Issues and PRs related to experimental features. module Issues and PRs related to the module subsystem. semver-minor PRs that contain new features and should be released in the next minor version.
Development

Successfully merging this pull request may close these issues.

None yet