├── .editorconfig ├── .eslintrc ├── .github ├── .well-known │ └── funding-manifest-urls ├── FUNDING.yml ├── INCIDENT_RESPONSE_PROCESS.md ├── THREAT_MODEL.md └── workflows │ ├── executable.yml │ ├── node-aught.yml │ ├── node-pretest.yml │ ├── node-tens.yml │ ├── node-twenties.yml │ ├── rebase.yml │ └── require-allow-edits.yml ├── .gitignore ├── .npmrc ├── LICENSE ├── SECURITY.md ├── appveyor.yml ├── async.js ├── bin └── resolve ├── example ├── async.js └── sync.js ├── index.js ├── index.mjs ├── lib ├── async.js ├── caller.js ├── homedir.js ├── node-modules-paths.js ├── normalize-options.js └── sync.js ├── package.json ├── readme.markdown ├── sync.js └── test ├── dotdot.js ├── dotdot ├── abc │ └── index.js └── index.js ├── faulty_basedir.js ├── filter.js ├── filter_sync.js ├── home_paths.js ├── home_paths_sync.js ├── mock.js ├── mock_sync.js ├── module_dir.js ├── module_dir ├── xmodules │ └── aaa │ │ └── index.js ├── ymodules │ └── aaa │ │ └── index.js └── zmodules │ └── bbb │ ├── main.js │ └── package.json ├── node-modules-paths.js ├── node_path.js ├── node_path ├── x │ ├── aaa │ │ └── index.js │ └── ccc │ │ └── index.js └── y │ ├── bbb │ └── index.js │ └── ccc │ └── index.js ├── nonstring.js ├── pathfilter.js ├── pathfilter └── deep_ref │ ├── main.js │ └── node_modules │ └── deep │ ├── alt.js │ ├── deeper │ └── ref.js │ ├── package.json │ └── ref.js ├── pathfilter_sync.js ├── precedence.js ├── precedence ├── aaa.js ├── aaa │ ├── index.js │ └── main.js ├── bbb.js └── bbb │ └── main.js ├── resolver.js ├── resolver ├── bar │ └── node_modules │ │ └── foo │ │ └── index.js ├── baz │ ├── doom.js │ ├── package.json │ └── quux.js ├── biz │ └── node_modules │ │ ├── garply │ │ ├── lib │ │ │ └── index.js │ │ └── package.json │ │ ├── grux │ │ └── index.js │ │ └── tiv │ │ └── index.js ├── browser_field │ ├── a.js │ ├── b.js │ └── package.json ├── cup.coffee ├── dot_main │ ├── index.js │ └── package.json ├── dot_slash_main │ ├── index.js │ └── package.json ├── empty_main │ ├── index.js │ └── package.json ├── false_main │ ├── index.js │ └── package.json ├── foo.js ├── incorrect_main │ ├── index.js │ └── package.json ├── invalid_main │ └── package.json ├── malformed_package_json │ ├── index.js │ └── package.json ├── missing_index │ └── package.json ├── missing_main │ ├── index.js │ └── package.json ├── mug.coffee ├── mug.js ├── multirepo │ ├── .npmrc │ ├── lerna.json │ ├── package.json │ └── packages │ │ ├── package-a │ │ ├── index.js │ │ └── package.json │ │ └── package-b │ │ ├── index.js │ │ └── package.json ├── nested_symlinks │ ├── common │ │ └── node_modules │ │ │ └── buffer │ │ │ ├── index.js │ │ │ └── package.json │ └── mylib │ │ ├── async.js │ │ ├── node_modules │ │ ├── buffer │ │ └── resolve │ │ ├── package.json │ │ └── sync.js ├── null_main │ ├── index.js │ └── package.json ├── other_path │ ├── lib │ │ └── other-lib.js │ └── root.js ├── punycode │ └── node_modules │ │ └── punycode │ │ └── index.js ├── quux │ └── foo │ │ └── index.js ├── same_names │ ├── foo.js │ └── foo │ │ └── index.js ├── symlinked │ ├── .gitignore │ ├── _ │ │ ├── .gitignore │ │ ├── node_modules │ │ │ ├── foo.js │ │ │ └── package │ │ └── symlink_target │ │ │ └── .gitkeep │ └── package │ │ ├── bar.js │ │ └── package.json └── without_basedir │ ├── main.js │ └── node_modules │ └── mymodule.js ├── resolver_sync.js ├── shadowed_core.js ├── shadowed_core ├── .gitignore └── node_modules │ └── util │ └── index.js ├── subdirs.js ├── subdirs └── node_modules │ └── a │ ├── b │ └── c │ │ └── x.json │ └── package.json ├── symlinks.js └── symlinks ├── dest └── node_modules │ └── mod-a └── source └── node_modules └── mod-a ├── index.js └── package.json /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | max_line_length = 200 11 | 12 | [*.js] 13 | block_comment_start = /* 14 | block_comment = * 15 | block_comment_end = */ 16 | 17 | [*.yml] 18 | indent_size = 1 19 | 20 | [package.json] 21 | indent_style = tab 22 | 23 | [CHANGELOG.md] 24 | indent_style = space 25 | indent_size = 2 26 | 27 | [{*.json,Makefile}] 28 | max_line_length = unset 29 | 30 | [test/{dotdot,resolver,module_dir,multirepo,node_path,pathfilter,precedence}/**/*] 31 | indent_style = unset 32 | indent_size = unset 33 | max_line_length = unset 34 | insert_final_newline = unset 35 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | 4 | "extends": "@ljharb", 5 | 6 | "ignorePatterns": [ 7 | "test/resolver/malformed_package_json/package.json", 8 | "test/list-exports/**", 9 | ], 10 | 11 | "rules": { 12 | "indent": [2, 4], 13 | "strict": 0, 14 | "complexity": 0, 15 | "consistent-return": 0, 16 | "curly": 0, 17 | "dot-notation": [2, { "allowKeywords": true }], 18 | "func-name-matching": 0, 19 | "func-style": 0, 20 | "global-require": 1, 21 | "id-length": [2, { "min": 1, "max": 40 }], 22 | "max-lines": [2, 350], 23 | "max-lines-per-function": 1, 24 | "max-nested-callbacks": 0, 25 | "max-params": 0, 26 | "max-statements-per-line": [2, { "max": 2 }], 27 | "max-statements": 0, 28 | "no-magic-numbers": 0, 29 | "no-shadow": 0, 30 | "no-use-before-define": 0, 31 | "sort-keys": 0, 32 | }, 33 | "overrides": [ 34 | { 35 | "files": "bin/**", 36 | "rules": { 37 | "no-process-exit": "off", 38 | }, 39 | }, 40 | { 41 | "files": "example/**", 42 | "rules": { 43 | "no-console": 0, 44 | }, 45 | }, 46 | { 47 | "files": "test/resolver/nested_symlinks/mylib/*.js", 48 | "rules": { 49 | "no-throw-literal": 0, 50 | }, 51 | }, 52 | { 53 | "files": "test/**", 54 | "parserOptions": { 55 | "ecmaVersion": 5, 56 | "allowReserved": false, 57 | }, 58 | "rules": { 59 | "dot-notation": [2, { "allowPattern": "throws" }], 60 | "max-lines": 0, 61 | "max-lines-per-function": 0, 62 | "no-unused-vars": [2, { "vars": "all", "args": "none" }], 63 | }, 64 | }, 65 | ], 66 | } 67 | -------------------------------------------------------------------------------- /.github/.well-known/funding-manifest-urls: -------------------------------------------------------------------------------- 1 | https://github.com/ljharb/.github/blob/HEAD/funding.json 2 | https://github.com/ljharb/.github/blob/main/funding.json 3 | https://github.com/browserify/resolve 4 | https://github.com/sponsors/ljharb 5 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [ljharb] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: npm/resolve 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.github/INCIDENT_RESPONSE_PROCESS.md: -------------------------------------------------------------------------------- 1 | # Incident Response Process for **resolve** 2 | 3 | ## Reporting a Vulnerability 4 | 5 | We take the security of **resolve** very seriously. If you believe you’ve found a security vulnerability, please inform us responsibly through coordinated disclosure. 6 | 7 | ### How to Report 8 | 9 | > **Do not** report security vulnerabilities through public GitHub issues, discussions, or social media. 10 | 11 | Instead, please use one of these secure channels: 12 | 13 | 1. **GitHub Security Advisories** 14 | Use the **Report a vulnerability** button in the Security tab of the [browserify/resolve repository](https://github.com/browserify/resolve). 15 | 16 | 2. **Email** 17 | Follow the posted [Security Policy](https://github.com/browserify/resolve/security/policy). 18 | 19 | ### What to Include 20 | 21 | **Required Information:** 22 | - Brief description of the vulnerability type 23 | - Affected version(s) and components 24 | - Steps to reproduce the issue 25 | - Impact assessment (what an attacker could achieve) 26 | - Confirm the issue is not present in test files (in other words, only via the official entry points in `exports`) 27 | 28 | **Helpful Additional Details:** 29 | - Full paths of affected source files 30 | - Specific commit or branch where the issue exists 31 | - Required configuration to reproduce 32 | - Proof-of-concept code (if available) 33 | - Suggested mitigation or fix 34 | 35 | ## Our Response Process 36 | 37 | **Timeline Commitments:** 38 | - **Initial acknowledgment**: Within 24 hours 39 | - **Detailed response**: Within 3 business days 40 | - **Status updates**: Every 7 days until resolved 41 | - **Resolution target**: 90 days for most issues 42 | 43 | **What We’ll Do:** 44 | 1. Acknowledge your report and assign a tracking ID 45 | 2. Assess the vulnerability and determine severity 46 | 3. Develop and test a fix 47 | 4. Coordinate disclosure timeline with you 48 | 5. Release a security update and publish an advisory and CVE 49 | 6. Credit you in our security advisory (if desired) 50 | 51 | ## Disclosure Policy 52 | 53 | - **Coordinated disclosure**: We’ll work with you on timing 54 | - **Typical timeline**: 90 days from report to public disclosure 55 | - **Early disclosure**: If actively exploited 56 | - **Delayed disclosure**: For complex issues 57 | 58 | ## Scope 59 | 60 | **In Scope:** 61 | - **resolve** package (all supported versions) 62 | - Official examples and documentation 63 | - Core resolution APIs 64 | - Dependencies with direct security implications 65 | 66 | **Out of Scope:** 67 | - Third-party wrappers or extensions 68 | - Bundler-specific integrations 69 | - Social engineering or physical attacks 70 | - Theoretical vulnerabilities without practical exploitation 71 | - Issues in non-production files 72 | 73 | ## Security Measures 74 | 75 | **Our Commitments:** 76 | - Regular vulnerability scanning via `npm audit` 77 | - Automated security checks in CI/CD (GitHub Actions) 78 | - Secure coding practices and mandatory code review 79 | - Prompt patch releases for critical issues 80 | 81 | **User Responsibilities:** 82 | - Keep **resolve** updated 83 | - Monitor dependency vulnerabilities 84 | - Follow secure configuration guidelines for module resolution 85 | 86 | ## Legal Safe Harbor 87 | 88 | **We will NOT:** 89 | - Initiate legal action 90 | - Contact law enforcement 91 | - Suspend or terminate your access 92 | 93 | **You must:** 94 | - Only test against your own installations 95 | - Not access, modify, or delete user data 96 | - Not degrade service availability 97 | - Not publicly disclose before coordinated disclosure 98 | - Act in good faith 99 | 100 | ## Recognition 101 | 102 | - **Advisory Credits**: Credit in GitHub Security Advisories (unless anonymous) 103 | 104 | ## Security Updates 105 | 106 | **Stay Informed:** 107 | - Subscribe to npm updates for **resolve** 108 | - Enable GitHub Security Advisory notifications 109 | 110 | **Update Process:** 111 | - Patch releases (e.g., 1.22.10 → 1.22.11) 112 | - Out-of-band releases for critical issues 113 | - Advisories via GitHub Security Advisories 114 | 115 | ## Contact Information 116 | 117 | - **Security reports**: Security tab of [browserify/resolve](https://github.com/browserify/resolve/security) 118 | - **General inquiries**: GitHub Discussions or Issues 119 | 120 | -------------------------------------------------------------------------------- /.github/THREAT_MODEL.md: -------------------------------------------------------------------------------- 1 | ## Threat Model for resolve (module path resolution library) 2 | 3 | ### 1. Library Overview 4 | 5 | - **Library Name:** resolve 6 | - **Brief Description:** Implements Node.js `require.resolve()` algorithm for synchronous and asynchronous file path resolution. Used to locate modules and files in Node.js projects. 7 | - **Key Public APIs/Functions:** `resolve.sync()` / `resolve/sync`, `resolve()` / `resolve/async` 8 | 9 | ### 2. Define Scope 10 | 11 | This threat model focuses on the core path resolution algorithm, including filesystem interaction, option handling, and cache management. 12 | 13 | ### 3. Conceptual System Diagram 14 | 15 | ``` 16 | Caller Application → resolve(id, options) → Resolution Algorithm → File System 17 | │ 18 | └→ Options Handling 19 | └→ Cache System 20 | ``` 21 | 22 | **Trust Boundaries:** 23 | - **Input module IDs:** May come from untrusted sources (user input, configuration) 24 | - **Filesystem access:** The library interacts with the filesystem to resolve paths 25 | - **Options:** Provided by the caller 26 | - **Cache:** Used to improve performance, but could be a vector for tampering or information disclosure if not handled securely 27 | 28 | ### 4. Identify Assets 29 | 30 | - **Integrity of resolution output:** Ensure correct and safe file path matching. 31 | - **Confidentiality of configuration:** Prevent sensitive path information from being leaked. 32 | - **Availability/performance for host application:** Prevent crashes or resource exhaustion. 33 | - **Security of host application:** Prevent path traversal or unintended filesystem access. 34 | - **Reputation of library:** Maintain trust by avoiding supply chain attacks and vulnerabilities[1][3][4]. 35 | 36 | ### 5. Identify Threats 37 | 38 | | Component / API / Interaction | S | T | R | I | D | E | 39 | |-----------------------------------------------------|----|----|----|----|----|----| 40 | | Public API Call (`resolve/async`, `resolve/sync`) | ✓ | ✓ | – | ✓ | – | – | 41 | | Filesystem Access | – | ✓ | – | ✓ | ✓ | – | 42 | | Options Handling | ✓ | ✓ | – | ✓ | – | – | 43 | | Cache System | – | ✓ | – | ✓ | – | – | 44 | 45 | **Key Threats:** 46 | - **Spoofing:** Malicious module IDs mimicking legitimate packages, or spoofing configuration options[1]. 47 | - **Tampering:** Caller-provided paths altering resolution order, or cache tampering leading to incorrect results[1][4]. 48 | - **Information Disclosure:** Error messages revealing filesystem structure or sensitive paths[1]. 49 | - **Denial of Service:** Recursive or excessive resolution exhausting filesystem handles or causing application crashes[1]. 50 | - **Path Traversal:** Malicious input allowing access to files outside the intended directory[4]. 51 | 52 | ### 6. Mitigation/Countermeasures 53 | 54 | | Threat Identified | Proposed Mitigation | 55 | |--------------------------------------------|---------------------| 56 | | Spoofing (malicious module IDs/config) | Sanitize input IDs; validate against known patterns; restrict `basedir` to app-controlled paths[1][4]. | 57 | | Tampering (path traversal, cache) | Validate input IDs for directory escapes; secure cache reads/writes; restrict cache to trusted sources[1][4]. | 58 | | Information Disclosure (error messages) | Generic "not found" errors without internal paths; avoid exposing sensitive configuration in errors[1]. | 59 | | Denial of Service (resource exhaustion) | Limit recursive resolution depth; implement timeout; monitor for excessive filesystem operations[1]. | 60 | 61 | ### 7. Risk Ranking 62 | 63 | - **High:** Path traversal via malicious IDs (if not properly mitigated) 64 | - **Medium:** Cache tampering or spoofing (if cache is not secured) 65 | - **Low:** Information disclosure in errors (if error handling is generic) 66 | 67 | ### 8. Next Steps & Review 68 | 69 | 1. **Implement input sanitization for module IDs and configuration.** 70 | 2. **Add resolution depth limiting and timeout.** 71 | 3. **Audit cache handling for race conditions and tampering.** 72 | 4. **Regularly review dependencies for vulnerabilities.** 73 | 5. **Keep documentation and threat model up to date.** 74 | 6. **Monitor for new threats as the ecosystem and library evolve[1][3].** 75 | -------------------------------------------------------------------------------- /.github/workflows/executable.yml: -------------------------------------------------------------------------------- 1 | name: resolve executable 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | _: 7 | name: cli 8 | 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: actions/checkout@v4 13 | - uses: ljharb/actions/node/install@main 14 | - run: "[ $(./bin/resolve fs) = 'fs' ]" 15 | name: run inside the package with a direct path 16 | - run: "npm link && [ $(resolve fs) = 'fs' ] && npm uninstall -g resolve" 17 | name: run linked as a global in the PATH 18 | - run: "[ $(npx resolve fs) = 'fs' ]" 19 | name: run via npx 20 | -------------------------------------------------------------------------------- /.github/workflows/node-aught.yml: -------------------------------------------------------------------------------- 1 | name: 'Tests: node.js < 10' 2 | 3 | on: [pull_request, push] 4 | 5 | jobs: 6 | tests: 7 | uses: ljharb/actions/.github/workflows/node.yml@main 8 | with: 9 | range: '< 10' 10 | type: minors 11 | command: npm run tests-only 12 | 13 | node: 14 | name: 'node < 10' 15 | needs: [tests] 16 | runs-on: ubuntu-latest 17 | steps: 18 | - run: true 19 | -------------------------------------------------------------------------------- /.github/workflows/node-pretest.yml: -------------------------------------------------------------------------------- 1 | name: 'Tests: pretest/posttest' 2 | 3 | on: [pull_request, push] 4 | 5 | jobs: 6 | tests: 7 | uses: ljharb/actions/.github/workflows/pretest.yml@main 8 | -------------------------------------------------------------------------------- /.github/workflows/node-tens.yml: -------------------------------------------------------------------------------- 1 | name: 'Tests: node.js 10 - 20' 2 | 3 | on: [pull_request, push] 4 | 5 | permissions: 6 | contents: read 7 | 8 | jobs: 9 | tests: 10 | uses: ljharb/actions/.github/workflows/node.yml@main 11 | with: 12 | range: '>= 10 < 20' 13 | type: minors 14 | command: npm run tests-only 15 | 16 | node: 17 | name: 'node 10 - 20' 18 | needs: [tests] 19 | runs-on: ubuntu-latest 20 | steps: 21 | - run: true 22 | -------------------------------------------------------------------------------- /.github/workflows/node-twenties.yml: -------------------------------------------------------------------------------- 1 | name: 'Tests: node.js >= 20' 2 | 3 | on: [pull_request, push] 4 | 5 | permissions: 6 | contents: read 7 | 8 | jobs: 9 | tests: 10 | uses: ljharb/actions/.github/workflows/node.yml@main 11 | with: 12 | range: '>= 20' 13 | type: minors 14 | command: npm run tests-only 15 | 16 | node: 17 | name: 'node >= 20' 18 | needs: [tests] 19 | runs-on: ubuntu-latest 20 | steps: 21 | - run: true 22 | -------------------------------------------------------------------------------- /.github/workflows/rebase.yml: -------------------------------------------------------------------------------- 1 | name: Automatic Rebase 2 | 3 | on: [pull_request_target] 4 | 5 | jobs: 6 | _: 7 | uses: ljharb/actions/.github/workflows/rebase.yml@main 8 | secrets: 9 | token: ${{ secrets.GITHUB_TOKEN }} 10 | -------------------------------------------------------------------------------- /.github/workflows/require-allow-edits.yml: -------------------------------------------------------------------------------- 1 | name: Require “Allow Edits” 2 | 3 | on: [pull_request_target] 4 | 5 | jobs: 6 | _: 7 | name: "Require “Allow Edits”" 8 | 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: ljharb/require-allow-edits@main 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # gitignore 2 | node_modules 3 | **/node_modules 4 | 5 | coverage/ 6 | .nyc_output/ 7 | 8 | # Only apps should have lockfiles 9 | npm-shrinkwrap.json 10 | package-lock.json 11 | yarn.lock 12 | 13 | # symlinked file used in tests 14 | test/resolver/symlinked/_/node_modules/package 15 | 16 | .npmignore 17 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2012 James Halliday 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security 2 | 3 | Please file a private vulnerability via GitHub, email [@ljharb](https://github.com/ljharb), or see https://tidelift.com/security if you have a potential security vulnerability to report. 4 | 5 | ## Incident Response 6 | 7 | See our [Incident Response Process](.github/INCIDENT_RESPONSE_PROCESS.md). 8 | 9 | ## Threat Model 10 | 11 | See [THREAT_MODEL.md](./THREAT_MODEL.md). 12 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | version: 1.0.{build} 2 | skip_branch_with_pr: true 3 | build: off 4 | 5 | environment: 6 | matrix: 7 | #- nodejs_version: "17" 8 | - nodejs_version: "16" 9 | - nodejs_version: "15" 10 | - nodejs_version: "14" 11 | - nodejs_version: "13" 12 | - nodejs_version: "12" 13 | - nodejs_version: "11" 14 | - nodejs_version: "10" 15 | - nodejs_version: "9" 16 | - nodejs_version: "8" 17 | - nodejs_version: "7" 18 | - nodejs_version: "6" 19 | - nodejs_version: "5" 20 | - nodejs_version: "4" 21 | - nodejs_version: "3" 22 | - nodejs_version: "2" 23 | - nodejs_version: "1" 24 | - nodejs_version: "0.12" 25 | - nodejs_version: "0.10" 26 | - nodejs_version: "0.8" 27 | - nodejs_version: "0.6" 28 | matrix: 29 | # fast_finish: true 30 | allow_failures: 31 | - nodejs_version: "0.8" 32 | # platform: x86 # x64 has started failing on the registry side, around early November 2020 33 | - nodejs_version: "0.6" 34 | 35 | platform: 36 | - x86 37 | - x64 38 | 39 | # Install scripts. (runs after repo cloning) 40 | install: 41 | # Fix symlinks in working copy (see https://github.com/appveyor/ci/issues/650#issuecomment-186592582) / https://github.com/charleskorn/batect/commit/d08986802ec43086902958c4ee7e57ff3e71dbef 42 | - git config core.symlinks true 43 | - git reset --hard 44 | # Get the latest stable version of Node.js or io.js 45 | - ps: if ($env:nodejs_version -ne '0.6') { Install-Product node $env:nodejs_version $env:platform } 46 | - ps: Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version) $env:platform 47 | - IF %nodejs_version% EQU 0.6 npm config set strict-ssl false && npm -g install npm@1.3 48 | - IF %nodejs_version% EQU 0.8 npm config set strict-ssl false && npm -g install npm@1.4.28 && npm install -g npm@4.5 49 | - IF %nodejs_version% EQU 1 npm -g install npm@2.9 50 | - IF %nodejs_version% EQU 2 npm -g install npm@4 51 | - IF %nodejs_version% EQU 3 npm -g install npm@4 52 | - IF %nodejs_version% EQU 4 npm -g install npm@5.3 53 | - IF %nodejs_version% EQU 5 npm -g install npm@5.3 54 | - IF %nodejs_version% EQU 6 npm -g install npm@6.9 55 | - IF %nodejs_version% EQU 7 npm -g install npm@6 56 | - IF %nodejs_version% EQU 8 npm -g install npm@6 57 | - IF %nodejs_version% EQU 9 npm -g install npm@6.9 58 | - IF %nodejs_version% EQU 10 npm -g install npm@7 59 | - IF %nodejs_version% EQU 11 npm -g install npm@7 60 | - IF %nodejs_version% EQU 12 npm -g install npm@7 61 | - IF %nodejs_version% EQU 13 npm -g install npm@7 62 | - IF %nodejs_version% EQU 14 npm -g install npm@7 63 | - IF %nodejs_version% EQU 15 npm -g install npm@7 64 | - IF %nodejs_version% EQU 16 npm -g install npm@7 65 | - set PATH=%APPDATA%\npm;%PATH% 66 | #- IF %nodejs_version% NEQ 0.6 AND %nodejs_version% NEQ 0.8 npm -g install npm 67 | # install modules 68 | - npm install 69 | 70 | # Post-install test scripts. 71 | test_script: 72 | # Output useful info for debugging. 73 | - node --version 74 | - npm --version 75 | # run tests 76 | - cd 77 | - npm run tests-only 78 | - 'subst X: ..' 79 | - 'cd /d X:\resolve' 80 | - cd 81 | - npm run tests-only 82 | -------------------------------------------------------------------------------- /async.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = require('./lib/async'); 4 | -------------------------------------------------------------------------------- /bin/resolve: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | 'use strict'; 4 | 5 | var path = require('path'); 6 | var fs = require('fs'); 7 | 8 | if ( 9 | String(process.env.npm_lifecycle_script).slice(0, 8) !== 'resolve ' 10 | && ( 11 | !process.argv 12 | || process.argv.length < 2 13 | || (process.argv[1] !== __filename && fs.statSync(process.argv[1]).ino !== fs.statSync(__filename).ino) 14 | || (process.env.npm_lifecycle_event !== 'npx' && process.env._ && fs.realpathSync(path.resolve(process.env._)) !== __filename) 15 | ) 16 | ) { 17 | console.error('Error: `resolve` must be run directly as an executable'); 18 | process.exit(1); 19 | } 20 | 21 | var supportsPreserveSymlinkFlag = require('supports-preserve-symlinks-flag'); 22 | 23 | var preserveSymlinks = false; 24 | for (var i = 2; i < process.argv.length; i += 1) { 25 | if (process.argv[i].slice(0, 2) === '--') { 26 | if (supportsPreserveSymlinkFlag && process.argv[i] === '--preserve-symlinks') { 27 | preserveSymlinks = true; 28 | } else if (process.argv[i].length > 2) { 29 | console.error('Unknown argument ' + process.argv[i].replace(/[=].*$/, '')); 30 | process.exit(2); 31 | } 32 | process.argv.splice(i, 1); 33 | i -= 1; 34 | if (process.argv[i] === '--') { break; } // eslint-disable-line no-restricted-syntax 35 | } 36 | } 37 | 38 | if (process.argv.length < 3) { 39 | console.error('Error: `resolve` expects a specifier'); 40 | process.exit(2); 41 | } 42 | 43 | var resolve = require('../'); 44 | 45 | var result = resolve.sync(process.argv[2], { 46 | basedir: process.cwd(), 47 | preserveSymlinks: preserveSymlinks 48 | }); 49 | 50 | console.log(result); 51 | -------------------------------------------------------------------------------- /example/async.js: -------------------------------------------------------------------------------- 1 | var resolve = require('../'); 2 | resolve('tap', { basedir: __dirname }, function (err, res) { 3 | if (err) console.error(err); 4 | else console.log(res); 5 | }); 6 | -------------------------------------------------------------------------------- /example/sync.js: -------------------------------------------------------------------------------- 1 | var resolve = require('../'); 2 | var res = resolve.sync('tap', { basedir: __dirname }); 3 | console.log(res); 4 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var async = require('./lib/async'); 2 | async.sync = require('./lib/sync'); 3 | 4 | module.exports = async; 5 | -------------------------------------------------------------------------------- /index.mjs: -------------------------------------------------------------------------------- 1 | import async from 'resolve/async'; 2 | import sync from 'resolve/sync'; 3 | 4 | export { async, sync }; 5 | -------------------------------------------------------------------------------- /lib/async.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var getHomedir = require('./homedir'); 3 | var path = require('path'); 4 | var caller = require('./caller'); 5 | var nodeModulesPaths = require('./node-modules-paths'); 6 | var normalizeOptions = require('./normalize-options'); 7 | var isCore = require('is-core-module'); 8 | 9 | var realpathFS = process.platform !== 'win32' && fs.realpath && typeof fs.realpath.native === 'function' ? fs.realpath.native : fs.realpath; 10 | 11 | var homedir = getHomedir(); 12 | var defaultPaths = function () { 13 | return [ 14 | path.join(homedir, '.node_modules'), 15 | path.join(homedir, '.node_libraries') 16 | ]; 17 | }; 18 | 19 | var defaultIsFile = function isFile(file, cb) { 20 | fs.stat(file, function (err, stat) { 21 | if (!err) { 22 | return cb(null, stat.isFile() || stat.isFIFO()); 23 | } 24 | if (err.code === 'ENOENT' || err.code === 'ENOTDIR') return cb(null, false); 25 | return cb(err); 26 | }); 27 | }; 28 | 29 | var defaultIsDir = function isDirectory(dir, cb) { 30 | fs.stat(dir, function (err, stat) { 31 | if (!err) { 32 | return cb(null, stat.isDirectory()); 33 | } 34 | if (err.code === 'ENOENT' || err.code === 'ENOTDIR') return cb(null, false); 35 | return cb(err); 36 | }); 37 | }; 38 | 39 | var defaultRealpath = function realpath(x, cb) { 40 | realpathFS(x, function (realpathErr, realPath) { 41 | if (realpathErr && realpathErr.code !== 'ENOENT') cb(realpathErr); 42 | else cb(null, realpathErr ? x : realPath); 43 | }); 44 | }; 45 | 46 | var maybeRealpath = function maybeRealpath(realpath, x, opts, cb) { 47 | if (!opts || !opts.preserveSymlinks) { 48 | realpath(x, cb); 49 | } else { 50 | cb(null, x); 51 | } 52 | }; 53 | 54 | var defaultReadPackage = function defaultReadPackage(readFile, pkgfile, cb) { 55 | readFile(pkgfile, function (readFileErr, body) { 56 | if (readFileErr) cb(readFileErr); 57 | else { 58 | try { 59 | var pkg = JSON.parse(body); 60 | cb(null, pkg); 61 | } catch (jsonErr) { 62 | cb(jsonErr); 63 | } 64 | } 65 | }); 66 | }; 67 | 68 | var getPackageCandidates = function getPackageCandidates(x, start, opts) { 69 | var dirs = nodeModulesPaths(start, opts, x); 70 | for (var i = 0; i < dirs.length; i++) { 71 | dirs[i] = path.join(dirs[i], x); 72 | } 73 | return dirs; 74 | }; 75 | 76 | module.exports = function resolve(x, options, callback) { 77 | var cb = callback; 78 | var opts = options; 79 | if (typeof options === 'function') { 80 | cb = opts; 81 | opts = {}; 82 | } 83 | if (typeof x !== 'string') { 84 | var err = new TypeError('Path must be a string.'); 85 | return process.nextTick(function () { 86 | cb(err); 87 | }); 88 | } 89 | 90 | opts = normalizeOptions(x, opts); 91 | 92 | var isFile = opts.isFile || defaultIsFile; 93 | var isDirectory = opts.isDirectory || defaultIsDir; 94 | var readFile = opts.readFile || fs.readFile; 95 | var realpath = opts.realpath || defaultRealpath; 96 | var readPackage = opts.readPackage || defaultReadPackage; 97 | if (opts.readFile && opts.readPackage) { 98 | var conflictErr = new TypeError('`readFile` and `readPackage` are mutually exclusive.'); 99 | return process.nextTick(function () { 100 | cb(conflictErr); 101 | }); 102 | } 103 | var packageIterator = opts.packageIterator; 104 | 105 | var extensions = opts.extensions || ['.js']; 106 | var includeCoreModules = opts.includeCoreModules !== false; 107 | var basedir = opts.basedir || path.dirname(caller()); 108 | var parent = opts.filename || basedir; 109 | 110 | opts.paths = opts.paths || defaultPaths(); 111 | 112 | // ensure that `basedir` is an absolute path at this point, resolving against the process' current working directory 113 | var absoluteStart = path.resolve(basedir); 114 | 115 | maybeRealpath( 116 | realpath, 117 | absoluteStart, 118 | opts, 119 | function (err, realStart) { 120 | if (err) cb(err); 121 | else validateBasedir(realStart); 122 | } 123 | ); 124 | 125 | function validateBasedir(basedir) { 126 | if (opts.basedir) { 127 | var dirError = new TypeError('Provided basedir "' + basedir + '" is not a directory' + (opts.preserveSymlinks ? '' : ', or a symlink to a directory')); 128 | dirError.code = 'INVALID_BASEDIR'; 129 | isDirectory(basedir, function (err, result) { 130 | if (err) return cb(err); 131 | if (!result) { return cb(dirError); } 132 | validBasedir(basedir); 133 | }); 134 | } else { 135 | validBasedir(basedir); 136 | } 137 | } 138 | 139 | var res; 140 | function validBasedir(basedir) { 141 | if ((/^(?:\.\.?(?:\/|$)|\/|([A-Za-z]:)?[/\\])/).test(x)) { 142 | res = path.resolve(basedir, x); 143 | if (x === '.' || x === '..' || x.slice(-1) === '/') res += '/'; 144 | if ((/\/$/).test(x) && res === basedir) { 145 | loadAsDirectory(res, opts.package, onfile); 146 | } else loadAsFile(res, opts.package, onfile); 147 | } else if (includeCoreModules && isCore(x)) { 148 | return cb(null, x); 149 | } else loadNodeModules(x, basedir, function (err, n, pkg) { 150 | if (err) cb(err); 151 | else if (n) { 152 | return maybeRealpath(realpath, n, opts, function (err, realN) { 153 | if (err) { 154 | cb(err); 155 | } else { 156 | cb(null, realN, pkg); 157 | } 158 | }); 159 | } else { 160 | var moduleError = new Error("Cannot find module '" + x + "' from '" + parent + "'"); 161 | moduleError.code = 'MODULE_NOT_FOUND'; 162 | cb(moduleError); 163 | } 164 | }); 165 | } 166 | 167 | function onfile(err, m, pkg) { 168 | if (err) cb(err); 169 | else if (m) cb(null, m, pkg); 170 | else loadAsDirectory(res, function (err, d, pkg) { 171 | if (err) cb(err); 172 | else if (d) { 173 | maybeRealpath(realpath, d, opts, function (err, realD) { 174 | if (err) { 175 | cb(err); 176 | } else { 177 | cb(null, realD, pkg); 178 | } 179 | }); 180 | } else { 181 | var moduleError = new Error("Cannot find module '" + x + "' from '" + parent + "'"); 182 | moduleError.code = 'MODULE_NOT_FOUND'; 183 | cb(moduleError); 184 | } 185 | }); 186 | } 187 | 188 | function loadAsFile(x, thePackage, callback) { 189 | var loadAsFilePackage = thePackage; 190 | var cb = callback; 191 | if (typeof loadAsFilePackage === 'function') { 192 | cb = loadAsFilePackage; 193 | loadAsFilePackage = undefined; 194 | } 195 | 196 | var exts = [''].concat(extensions); 197 | load(exts, x, loadAsFilePackage); 198 | 199 | function load(exts, x, loadPackage) { 200 | if (exts.length === 0) return cb(null, undefined, loadPackage); 201 | var file = x + exts[0]; 202 | 203 | var pkg = loadPackage; 204 | if (pkg) onpkg(null, pkg); 205 | else loadpkg(path.dirname(file), onpkg); 206 | 207 | function onpkg(err, pkg_, dir) { 208 | pkg = pkg_; 209 | if (err) return cb(err); 210 | if (dir && pkg && opts.pathFilter) { 211 | var rfile = path.relative(dir, file); 212 | var rel = rfile.slice(0, rfile.length - exts[0].length); 213 | var r = opts.pathFilter(pkg, x, rel); 214 | if (r) return load( 215 | [''].concat(extensions.slice()), 216 | path.resolve(dir, r), 217 | pkg 218 | ); 219 | } 220 | isFile(file, onex); 221 | } 222 | function onex(err, ex) { 223 | if (err) return cb(err); 224 | if (ex) return cb(null, file, pkg); 225 | load(exts.slice(1), x, pkg); 226 | } 227 | } 228 | } 229 | 230 | function loadpkg(dir, cb) { 231 | if (dir === '' || dir === '/') return cb(null); 232 | if (process.platform === 'win32' && (/^\w:[/\\]*$/).test(dir)) { 233 | return cb(null); 234 | } 235 | if ((/[/\\]node_modules[/\\]*$/).test(dir)) return cb(null); 236 | 237 | maybeRealpath(realpath, dir, opts, function (unwrapErr, pkgdir) { 238 | if (unwrapErr) return loadpkg(path.dirname(dir), cb); 239 | var pkgfile = path.join(pkgdir, 'package.json'); 240 | isFile(pkgfile, function (err, ex) { 241 | // on err, ex is false 242 | if (!ex) return loadpkg(path.dirname(dir), cb); 243 | 244 | readPackage(readFile, pkgfile, function (err, pkgParam) { 245 | if (err && !(err instanceof SyntaxError)) cb(err); 246 | 247 | var pkg = pkgParam; 248 | 249 | if (pkg && opts.packageFilter) { 250 | pkg = opts.packageFilter(pkg, pkgfile, dir); 251 | } 252 | cb(null, pkg, dir); 253 | }); 254 | }); 255 | }); 256 | } 257 | 258 | function loadAsDirectory(x, loadAsDirectoryPackage, callback) { 259 | var cb = callback; 260 | var fpkg = loadAsDirectoryPackage; 261 | if (typeof fpkg === 'function') { 262 | cb = fpkg; 263 | fpkg = opts.package; 264 | } 265 | 266 | maybeRealpath(realpath, x, opts, function (unwrapErr, pkgdir) { 267 | if (unwrapErr) return loadAsDirectory(path.dirname(x), fpkg, cb); 268 | var pkgfile = path.join(pkgdir, 'package.json'); 269 | isFile(pkgfile, function (err, ex) { 270 | if (err) return cb(err); 271 | if (!ex) return loadAsFile(path.join(x, 'index'), fpkg, cb); 272 | 273 | readPackage(readFile, pkgfile, function (err, pkgParam) { 274 | if (err) return cb(err); 275 | 276 | var pkg = pkgParam; 277 | 278 | if (pkg && opts.packageFilter) { 279 | pkg = opts.packageFilter(pkg, pkgfile, pkgdir); 280 | } 281 | 282 | if (pkg && pkg.main) { 283 | if (typeof pkg.main !== 'string') { 284 | var mainError = new TypeError('package “' + pkg.name + '” `main` must be a string'); 285 | mainError.code = 'INVALID_PACKAGE_MAIN'; 286 | return cb(mainError); 287 | } 288 | if (pkg.main === '.' || pkg.main === './') { 289 | pkg.main = 'index'; 290 | } 291 | loadAsFile(path.resolve(x, pkg.main), pkg, function (err, m, pkg) { 292 | if (err) return cb(err); 293 | if (m) return cb(null, m, pkg); 294 | if (!pkg) return loadAsFile(path.join(x, 'index'), pkg, cb); 295 | 296 | var dir = path.resolve(x, pkg.main); 297 | loadAsDirectory(dir, pkg, function (err, n, pkg) { 298 | if (err) return cb(err); 299 | if (n) return cb(null, n, pkg); 300 | loadAsFile(path.join(x, 'index'), pkg, function (err, m, pkg) { 301 | if (err) return cb(err); 302 | if (m) return cb(null, m, pkg); 303 | var incorrectMainError = new Error("Cannot find module '" + path.resolve(x, pkg.main) + "'. Please verify that the package.json has a valid \"main\" entry"); 304 | incorrectMainError.code = 'INCORRECT_PACKAGE_MAIN'; 305 | return cb(incorrectMainError); 306 | }); 307 | }); 308 | }); 309 | return; 310 | } 311 | 312 | loadAsFile(path.join(x, '/index'), pkg, cb); 313 | }); 314 | }); 315 | }); 316 | } 317 | 318 | function processDirs(cb, dirs) { 319 | if (dirs.length === 0) return cb(null, undefined); 320 | var dir = dirs[0]; 321 | 322 | isDirectory(path.dirname(dir), isdir); 323 | 324 | function isdir(err, isdir) { 325 | if (err) return cb(err); 326 | if (!isdir) return processDirs(cb, dirs.slice(1)); 327 | loadAsFile(dir, opts.package, onfile); 328 | } 329 | 330 | function onfile(err, m, pkg) { 331 | if (err) return cb(err); 332 | if (m) return cb(null, m, pkg); 333 | loadAsDirectory(dir, opts.package, ondir); 334 | } 335 | 336 | function ondir(err, n, pkg) { 337 | if (err) return cb(err); 338 | if (n) return cb(null, n, pkg); 339 | processDirs(cb, dirs.slice(1)); 340 | } 341 | } 342 | function loadNodeModules(x, start, cb) { 343 | var thunk = function () { return getPackageCandidates(x, start, opts); }; 344 | processDirs( 345 | cb, 346 | packageIterator ? packageIterator(x, start, thunk, opts) : thunk() 347 | ); 348 | } 349 | }; 350 | -------------------------------------------------------------------------------- /lib/caller.js: -------------------------------------------------------------------------------- 1 | module.exports = function () { 2 | // see https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi 3 | var origPrepareStackTrace = Error.prepareStackTrace; 4 | Error.prepareStackTrace = function (_, stack) { return stack; }; 5 | var stack = (new Error()).stack; 6 | Error.prepareStackTrace = origPrepareStackTrace; 7 | return stack[2].getFileName(); 8 | }; 9 | -------------------------------------------------------------------------------- /lib/homedir.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var os = require('os'); 4 | 5 | // adapted from https://github.com/sindresorhus/os-homedir/blob/11e089f4754db38bb535e5a8416320c4446e8cfd/index.js 6 | 7 | module.exports = os.homedir || function homedir() { 8 | var home = process.env.HOME; 9 | var user = process.env.LOGNAME || process.env.USER || process.env.LNAME || process.env.USERNAME; 10 | 11 | if (process.platform === 'win32') { 12 | return process.env.USERPROFILE || process.env.HOMEDRIVE + process.env.HOMEPATH || home || null; 13 | } 14 | 15 | if (process.platform === 'darwin') { 16 | return home || (user ? '/Users/' + user : null); 17 | } 18 | 19 | if (process.platform === 'linux') { 20 | return home || (process.getuid() === 0 ? '/root' : (user ? '/home/' + user : null)); // eslint-disable-line no-extra-parens 21 | } 22 | 23 | return home || null; 24 | }; 25 | -------------------------------------------------------------------------------- /lib/node-modules-paths.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var parse = path.parse || require('path-parse'); // eslint-disable-line global-require 3 | 4 | var getNodeModulesDirs = function getNodeModulesDirs(absoluteStart, modules) { 5 | var prefix = '/'; 6 | if ((/^([A-Za-z]:)/).test(absoluteStart)) { 7 | prefix = ''; 8 | } else if ((/^\\\\/).test(absoluteStart)) { 9 | prefix = '\\\\'; 10 | } 11 | 12 | var paths = [absoluteStart]; 13 | var parsed = parse(absoluteStart); 14 | while (parsed.dir !== paths[paths.length - 1]) { 15 | paths.push(parsed.dir); 16 | parsed = parse(parsed.dir); 17 | } 18 | 19 | return paths.reduce(function (dirs, aPath) { 20 | return dirs.concat(modules.map(function (moduleDir) { 21 | return path.resolve(prefix, aPath, moduleDir); 22 | })); 23 | }, []); 24 | }; 25 | 26 | module.exports = function nodeModulesPaths(start, opts, request) { 27 | var modules = opts && opts.moduleDirectory 28 | ? [].concat(opts.moduleDirectory) 29 | : ['node_modules']; 30 | 31 | if (opts && typeof opts.paths === 'function') { 32 | return opts.paths( 33 | request, 34 | start, 35 | function () { return getNodeModulesDirs(start, modules); }, 36 | opts 37 | ); 38 | } 39 | 40 | var dirs = getNodeModulesDirs(start, modules); 41 | return opts && opts.paths ? dirs.concat(opts.paths) : dirs; 42 | }; 43 | -------------------------------------------------------------------------------- /lib/normalize-options.js: -------------------------------------------------------------------------------- 1 | module.exports = function (x, opts) { 2 | /** 3 | * This file is purposefully a passthrough. It's expected that third-party 4 | * environments will override it at runtime in order to inject special logic 5 | * into `resolve` (by manipulating the options). One such example is the PnP 6 | * code path in Yarn. 7 | */ 8 | 9 | return opts || {}; 10 | }; 11 | -------------------------------------------------------------------------------- /lib/sync.js: -------------------------------------------------------------------------------- 1 | var isCore = require('is-core-module'); 2 | var fs = require('fs'); 3 | var path = require('path'); 4 | var getHomedir = require('./homedir'); 5 | var caller = require('./caller'); 6 | var nodeModulesPaths = require('./node-modules-paths'); 7 | var normalizeOptions = require('./normalize-options'); 8 | 9 | var realpathFS = process.platform !== 'win32' && fs.realpathSync && typeof fs.realpathSync.native === 'function' ? fs.realpathSync.native : fs.realpathSync; 10 | 11 | var homedir = getHomedir(); 12 | var defaultPaths = function () { 13 | return [ 14 | path.join(homedir, '.node_modules'), 15 | path.join(homedir, '.node_libraries') 16 | ]; 17 | }; 18 | 19 | var defaultIsFile = function isFile(file) { 20 | try { 21 | var stat = fs.statSync(file, { throwIfNoEntry: false }); 22 | } catch (e) { 23 | if (e && (e.code === 'ENOENT' || e.code === 'ENOTDIR')) return false; 24 | throw e; 25 | } 26 | return !!stat && (stat.isFile() || stat.isFIFO()); 27 | }; 28 | 29 | var defaultIsDir = function isDirectory(dir) { 30 | try { 31 | var stat = fs.statSync(dir, { throwIfNoEntry: false }); 32 | } catch (e) { 33 | if (e && (e.code === 'ENOENT' || e.code === 'ENOTDIR')) return false; 34 | throw e; 35 | } 36 | return !!stat && stat.isDirectory(); 37 | }; 38 | 39 | var defaultRealpathSync = function realpathSync(x) { 40 | try { 41 | return realpathFS(x); 42 | } catch (realpathErr) { 43 | if (realpathErr.code !== 'ENOENT') { 44 | throw realpathErr; 45 | } 46 | } 47 | return x; 48 | }; 49 | 50 | var maybeRealpathSync = function maybeRealpathSync(realpathSync, x, opts) { 51 | if (!opts || !opts.preserveSymlinks) { 52 | return realpathSync(x); 53 | } 54 | return x; 55 | }; 56 | 57 | var defaultReadPackageSync = function defaultReadPackageSync(readFileSync, pkgfile) { 58 | return JSON.parse(readFileSync(pkgfile)); 59 | }; 60 | 61 | var getPackageCandidates = function getPackageCandidates(x, start, opts) { 62 | var dirs = nodeModulesPaths(start, opts, x); 63 | for (var i = 0; i < dirs.length; i++) { 64 | dirs[i] = path.join(dirs[i], x); 65 | } 66 | return dirs; 67 | }; 68 | 69 | module.exports = function resolveSync(x, options) { 70 | if (typeof x !== 'string') { 71 | throw new TypeError('Path must be a string.'); 72 | } 73 | var opts = normalizeOptions(x, options); 74 | 75 | var isFile = opts.isFile || defaultIsFile; 76 | var isDirectory = opts.isDirectory || defaultIsDir; 77 | var readFileSync = opts.readFileSync || fs.readFileSync; 78 | var realpathSync = opts.realpathSync || defaultRealpathSync; 79 | var readPackageSync = opts.readPackageSync || defaultReadPackageSync; 80 | if (opts.readFileSync && opts.readPackageSync) { 81 | throw new TypeError('`readFileSync` and `readPackageSync` are mutually exclusive.'); 82 | } 83 | var packageIterator = opts.packageIterator; 84 | 85 | var extensions = opts.extensions || ['.js']; 86 | var includeCoreModules = opts.includeCoreModules !== false; 87 | var basedir = opts.basedir || path.dirname(caller()); 88 | var parent = opts.filename || basedir; 89 | 90 | opts.paths = opts.paths || defaultPaths(); 91 | 92 | // ensure that `basedir` is an absolute path at this point, resolving against the process' current working directory 93 | var absoluteStart = maybeRealpathSync(realpathSync, path.resolve(basedir), opts); 94 | 95 | if (opts.basedir && !isDirectory(absoluteStart)) { 96 | var dirError = new TypeError('Provided basedir "' + opts.basedir + '" is not a directory' + (opts.preserveSymlinks ? '' : ', or a symlink to a directory')); 97 | dirError.code = 'INVALID_BASEDIR'; 98 | throw dirError; 99 | } 100 | 101 | if ((/^(?:\.\.?(?:\/|$)|\/|([A-Za-z]:)?[/\\])/).test(x)) { 102 | var res = path.resolve(absoluteStart, x); 103 | if (x === '.' || x === '..' || x.slice(-1) === '/') res += '/'; 104 | var m = loadAsFileSync(res) || loadAsDirectorySync(res); 105 | if (m) return maybeRealpathSync(realpathSync, m, opts); 106 | } else if (includeCoreModules && isCore(x)) { 107 | return x; 108 | } else { 109 | var n = loadNodeModulesSync(x, absoluteStart); 110 | if (n) return maybeRealpathSync(realpathSync, n, opts); 111 | } 112 | 113 | var err = new Error("Cannot find module '" + x + "' from '" + parent + "'"); 114 | err.code = 'MODULE_NOT_FOUND'; 115 | throw err; 116 | 117 | function loadAsFileSync(x) { 118 | var pkg = loadpkg(path.dirname(x)); 119 | 120 | if (pkg && pkg.dir && pkg.pkg && opts.pathFilter) { 121 | var rfile = path.relative(pkg.dir, x); 122 | var r = opts.pathFilter(pkg.pkg, x, rfile); 123 | if (r) { 124 | x = path.resolve(pkg.dir, r); // eslint-disable-line no-param-reassign 125 | } 126 | } 127 | 128 | if (isFile(x)) { 129 | return x; 130 | } 131 | 132 | for (var i = 0; i < extensions.length; i++) { 133 | var file = x + extensions[i]; 134 | if (isFile(file)) { 135 | return file; 136 | } 137 | } 138 | } 139 | 140 | function loadpkg(dir) { 141 | if (dir === '' || dir === '/') return; 142 | if (process.platform === 'win32' && (/^\w:[/\\]*$/).test(dir)) { 143 | return; 144 | } 145 | if ((/[/\\]node_modules[/\\]*$/).test(dir)) return; 146 | 147 | var pkgfile = path.join(isDirectory(dir) ? maybeRealpathSync(realpathSync, dir, opts) : dir, 'package.json'); 148 | 149 | if (!isFile(pkgfile)) { 150 | return loadpkg(path.dirname(dir)); 151 | } 152 | 153 | var pkg; 154 | try { 155 | pkg = readPackageSync(readFileSync, pkgfile); 156 | } catch (e) { 157 | if (!(e instanceof SyntaxError)) { 158 | throw e; 159 | } 160 | } 161 | 162 | if (pkg && opts.packageFilter) { 163 | pkg = opts.packageFilter(pkg, pkgfile, dir); 164 | } 165 | 166 | return { pkg: pkg, dir: dir }; 167 | } 168 | 169 | function loadAsDirectorySync(x) { 170 | var pkgfile = path.join(isDirectory(x) ? maybeRealpathSync(realpathSync, x, opts) : x, '/package.json'); 171 | if (isFile(pkgfile)) { 172 | try { 173 | var pkg = readPackageSync(readFileSync, pkgfile); 174 | } catch (e) {} 175 | 176 | if (pkg && opts.packageFilter) { 177 | pkg = opts.packageFilter(pkg, pkgfile, x); 178 | } 179 | 180 | if (pkg && pkg.main) { 181 | if (typeof pkg.main !== 'string') { 182 | var mainError = new TypeError('package “' + pkg.name + '” `main` must be a string'); 183 | mainError.code = 'INVALID_PACKAGE_MAIN'; 184 | throw mainError; 185 | } 186 | if (pkg.main === '.' || pkg.main === './') { 187 | pkg.main = 'index'; 188 | } 189 | try { 190 | var mainPath = path.resolve(x, pkg.main); 191 | var m = loadAsFileSync(mainPath); 192 | if (m) return m; 193 | var n = loadAsDirectorySync(mainPath); 194 | if (n) return n; 195 | var checkIndex = loadAsFileSync(path.resolve(x, 'index')); 196 | if (checkIndex) return checkIndex; 197 | } catch (e) { } 198 | var incorrectMainError = new Error("Cannot find module '" + path.resolve(x, pkg.main) + "'. Please verify that the package.json has a valid \"main\" entry"); 199 | incorrectMainError.code = 'INCORRECT_PACKAGE_MAIN'; 200 | throw incorrectMainError; 201 | } 202 | } 203 | 204 | return loadAsFileSync(path.join(x, '/index')); 205 | } 206 | 207 | function loadNodeModulesSync(x, start) { 208 | var thunk = function () { return getPackageCandidates(x, start, opts); }; 209 | var dirs = packageIterator ? packageIterator(x, start, thunk, opts) : thunk(); 210 | 211 | for (var i = 0; i < dirs.length; i++) { 212 | var dir = dirs[i]; 213 | if (isDirectory(path.dirname(dir))) { 214 | var m = loadAsFileSync(dir); 215 | if (m) return m; 216 | var n = loadAsDirectorySync(dir); 217 | if (n) return n; 218 | } 219 | } 220 | } 221 | }; 222 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "resolve", 3 | "description": "resolve like require.resolve() on behalf of files asynchronously and synchronously", 4 | "version": "2.0.0-next.5", 5 | "repository": { 6 | "type": "git", 7 | "url": "git://github.com/browserify/resolve.git" 8 | }, 9 | "bin": { 10 | "resolve": "./bin/resolve" 11 | }, 12 | "main": "index.js", 13 | "exports": { 14 | ".": [ 15 | { 16 | "import": "./index.mjs", 17 | "default": "./index.js" 18 | }, 19 | "./index.js" 20 | ], 21 | "./sync": "./lib/sync.js", 22 | "./async": "./lib/async.js", 23 | "./package.json": "./package.json" 24 | }, 25 | "keywords": [ 26 | "resolve", 27 | "require", 28 | "node", 29 | "module" 30 | ], 31 | "scripts": { 32 | "prepack": "npmignore --auto --commentLines=autogenerated", 33 | "prepublishOnly": "safe-publish-latest", 34 | "prepublish": "not-in-publish || npm run prepublishOnly", 35 | "prelint": "eclint check $(git ls-files | grep -Ev test/list-exports$ | xargs find 2> /dev/null | grep -vE 'node_modules|\\.git')", 36 | "lint": "eslint --ext=js,mjs --no-eslintrc -c .eslintrc . 'bin/**'", 37 | "pretests-only": "cd ./test/resolver/nested_symlinks && node mylib/sync && node mylib/async", 38 | "tests-only": "tape test/*.js", 39 | "pretest": "npm run lint", 40 | "test": "npm run --silent tests-only", 41 | "posttest": "npm run test:multirepo && npx npm@\">= 10.2\" audit --production", 42 | "test:multirepo": "cd ./test/resolver/multirepo && npm install && npm test" 43 | }, 44 | "license": "MIT", 45 | "author": { 46 | "name": "James Halliday", 47 | "email": "mail@substack.net", 48 | "url": "http://substack.net" 49 | }, 50 | "funding": { 51 | "url": "https://github.com/sponsors/ljharb" 52 | }, 53 | "dependencies": { 54 | "is-core-module": "^2.16.1", 55 | "path-parse": "^1.0.7", 56 | "supports-preserve-symlinks-flag": "^1.0.0" 57 | }, 58 | "devDependencies": { 59 | "@ljharb/eslint-config": "^21.1.1", 60 | "array.prototype.map": "^1.0.8", 61 | "copy-dir": "^1.3.0", 62 | "eclint": "^2.8.1", 63 | "eslint": "=8.8.0", 64 | "in-publish": "^2.0.1", 65 | "mkdirp": "^0.5.6", 66 | "mv": "^2.1.1", 67 | "npmignore": "^0.3.1", 68 | "object-keys": "^1.1.1", 69 | "rimraf": "^2.7.1", 70 | "safe-publish-latest": "^2.0.0", 71 | "tap": "^0.4.13", 72 | "tape": "^5.9.0", 73 | "tmp": "^0.0.31" 74 | }, 75 | "publishConfig": { 76 | "ignore": [ 77 | ".github/workflows", 78 | ".github/.well-known", 79 | "appveyor.yml", 80 | "test/resolver/malformed_package_json", 81 | "test/list-exports" 82 | ] 83 | }, 84 | "engines": { 85 | "node": ">= 0.4" 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /readme.markdown: -------------------------------------------------------------------------------- 1 | # resolve [![Version Badge][2]][1] 2 | 3 | implements the [node `require.resolve()` algorithm](https://nodejs.org/api/modules.html#modules_all_together) such that you can `require.resolve()` on behalf of a file asynchronously and synchronously 4 | 5 | [![github actions][actions-image]][actions-url] 6 | [![coverage][codecov-image]][codecov-url] 7 | [![dependency status][5]][6] 8 | [![dev dependency status][7]][8] 9 | [![License][license-image]][license-url] 10 | [![Downloads][downloads-image]][downloads-url] 11 | 12 | [![npm badge][11]][1] 13 | 14 | # example 15 | 16 | asynchronously resolve: 17 | 18 | ```js 19 | var resolve = require('resolve/async'); // or, require('resolve') 20 | resolve('tap', { basedir: __dirname }, function (err, res) { 21 | if (err) console.error(err); 22 | else console.log(res); 23 | }); 24 | ``` 25 | 26 | ``` 27 | $ node example/async.js 28 | /home/substack/projects/node-resolve/node_modules/tap/lib/main.js 29 | ``` 30 | 31 | synchronously resolve: 32 | 33 | ```js 34 | var resolve = require('resolve/sync'); // or, `require('resolve').sync 35 | var res = resolve('tap', { basedir: __dirname }); 36 | console.log(res); 37 | ``` 38 | 39 | ``` 40 | $ node example/sync.js 41 | /home/substack/projects/node-resolve/node_modules/tap/lib/main.js 42 | ``` 43 | 44 | # methods 45 | 46 | ```js 47 | var resolve = require('resolve'); 48 | var async = require('resolve/async'); 49 | var sync = require('resolve/sync'); 50 | ``` 51 | 52 | For both the synchronous and asynchronous methods, errors may have any of the following `err.code` values: 53 | 54 | - `MODULE_NOT_FOUND`: the given path string (`id`) could not be resolved to a module 55 | - `INVALID_BASEDIR`: the specified `opts.basedir` doesn't exist, or is not a directory 56 | - `INVALID_PACKAGE_MAIN`: a `package.json` was encountered with an invalid `main` property (eg. not a string) 57 | 58 | ## resolve(id, opts={}, cb) 59 | 60 | Asynchronously resolve the module path string `id` into `cb(err, res [, pkg])`, where `pkg` (if defined) is the data from `package.json`. 61 | 62 | options are: 63 | 64 | * opts.basedir - directory to begin resolving from 65 | 66 | * opts.package - `package.json` data applicable to the module being loaded 67 | 68 | * opts.extensions - array of file extensions to search in order 69 | 70 | * opts.includeCoreModules - set to `false` to exclude node core modules (e.g. `fs`) from the search 71 | 72 | * opts.readFile - how to read files asynchronously 73 | 74 | * opts.isFile - function to asynchronously test whether a file exists 75 | 76 | * opts.isDirectory - function to asynchronously test whether a file exists and is a directory 77 | 78 | * opts.realpath - function to asynchronously resolve a potential symlink to its real path 79 | 80 | * `opts.readPackage(readFile, pkgfile, cb)` - function to asynchronously read and parse a package.json file 81 | * readFile - the passed `opts.readFile` or `fs.readFile` if not specified 82 | * pkgfile - path to package.json 83 | * cb - callback. a SyntaxError error argument will be ignored, all other error arguments will be treated as an error. 84 | 85 | * `opts.packageFilter(pkg, pkgfile, dir)` - transform the parsed package.json contents before looking at the "main" field 86 | * pkg - package data 87 | * pkgfile - path to package.json 88 | * dir - directory that contains package.json 89 | 90 | * `opts.pathFilter(pkg, path, relativePath)` - transform a path within a package 91 | * pkg - package data 92 | * path - the path being resolved 93 | * relativePath - the path relative from the package.json location 94 | * returns - a relative path that will be joined from the package.json location 95 | 96 | * opts.paths - require.paths array to use if nothing is found on the normal `node_modules` recursive walk (probably don't use this) 97 | 98 | For advanced users, `paths` can also be a `opts.paths(request, start, opts)` function 99 | * request - the import specifier being resolved 100 | * start - lookup path 101 | * getNodeModulesDirs - a thunk (no-argument function) that returns the paths using standard `node_modules` resolution 102 | * opts - the resolution options 103 | 104 | * `opts.packageIterator(request, start, opts)` - return the list of candidate paths where the packages sources may be found (probably don't use this) 105 | * request - the import specifier being resolved 106 | * start - lookup path 107 | * getPackageCandidates - a thunk (no-argument function) that returns the paths using standard `node_modules` resolution 108 | * opts - the resolution options 109 | 110 | * opts.moduleDirectory - directory (or directories) in which to recursively look for modules. default: `"node_modules"` 111 | 112 | * opts.preserveSymlinks - if true, doesn't resolve `basedir` to real path before resolving. 113 | This is the way Node resolves dependencies when executed with the [--preserve-symlinks](https://nodejs.org/api/all.html#cli_preserve_symlinks) flag. 114 | 115 | default `opts` values: 116 | 117 | ```js 118 | { 119 | paths: [], 120 | basedir: __dirname, 121 | extensions: ['.js'], 122 | includeCoreModules: true, 123 | readFile: fs.readFile, 124 | isFile: function isFile(file, cb) { 125 | fs.stat(file, function (err, stat) { 126 | if (!err) { 127 | return cb(null, stat.isFile() || stat.isFIFO()); 128 | } 129 | if (err.code === 'ENOENT' || err.code === 'ENOTDIR') return cb(null, false); 130 | return cb(err); 131 | }); 132 | }, 133 | isDirectory: function isDirectory(dir, cb) { 134 | fs.stat(dir, function (err, stat) { 135 | if (!err) { 136 | return cb(null, stat.isDirectory()); 137 | } 138 | if (err.code === 'ENOENT' || err.code === 'ENOTDIR') return cb(null, false); 139 | return cb(err); 140 | }); 141 | }, 142 | realpath: function realpath(file, cb) { 143 | var realpath = typeof fs.realpath.native === 'function' ? fs.realpath.native : fs.realpath; 144 | realpath(file, function (realPathErr, realPath) { 145 | if (realPathErr && realPathErr.code !== 'ENOENT') cb(realPathErr); 146 | else cb(null, realPathErr ? file : realPath); 147 | }); 148 | }, 149 | readPackage: function defaultReadPackage(readFile, pkgfile, cb) { 150 | readFile(pkgfile, function (readFileErr, body) { 151 | if (readFileErr) cb(readFileErr); 152 | else { 153 | try { 154 | var pkg = JSON.parse(body); 155 | cb(null, pkg); 156 | } catch (jsonErr) { 157 | cb(jsonErr); 158 | } 159 | } 160 | }); 161 | }, 162 | moduleDirectory: 'node_modules', 163 | preserveSymlinks: false 164 | } 165 | ``` 166 | 167 | ## resolve.sync(id, opts) 168 | 169 | Synchronously resolve the module path string `id`, returning the result and 170 | throwing an error when `id` can't be resolved. 171 | 172 | options are: 173 | 174 | * opts.basedir - directory to begin resolving from 175 | 176 | * opts.extensions - array of file extensions to search in order 177 | 178 | * opts.includeCoreModules - set to `false` to exclude node core modules (e.g. `fs`) from the search 179 | 180 | * opts.readFileSync - how to read files synchronously 181 | 182 | * opts.isFile - function to synchronously test whether a file exists 183 | 184 | * opts.isDirectory - function to synchronously test whether a file exists and is a directory 185 | 186 | * opts.realpathSync - function to synchronously resolve a potential symlink to its real path 187 | 188 | * `opts.readPackageSync(readFileSync, pkgfile)` - function to synchronously read and parse a package.json file. a thrown SyntaxError will be ignored, all other exceptions will propagate. 189 | * readFileSync - the passed `opts.readFileSync` or `fs.readFileSync` if not specified 190 | * pkgfile - path to package.json 191 | 192 | * `opts.packageFilter(pkg, pkgfile, dir)` - transform the parsed package.json contents before looking at the "main" field 193 | * pkg - package data 194 | * pkgfile - path to package.json 195 | * dir - directory that contains package.json 196 | 197 | * `opts.pathFilter(pkg, path, relativePath)` - transform a path within a package 198 | * pkg - package data 199 | * path - the path being resolved 200 | * relativePath - the path relative from the package.json location 201 | * returns - a relative path that will be joined from the package.json location 202 | 203 | * opts.paths - require.paths array to use if nothing is found on the normal `node_modules` recursive walk (probably don't use this) 204 | 205 | For advanced users, `paths` can also be a `opts.paths(request, start, opts)` function 206 | * request - the import specifier being resolved 207 | * start - lookup path 208 | * getNodeModulesDirs - a thunk (no-argument function) that returns the paths using standard `node_modules` resolution 209 | * opts - the resolution options 210 | 211 | * `opts.packageIterator(request, start, opts)` - return the list of candidate paths where the packages sources may be found (probably don't use this) 212 | * request - the import specifier being resolved 213 | * start - lookup path 214 | * getPackageCandidates - a thunk (no-argument function) that returns the paths using standard `node_modules` resolution 215 | * opts - the resolution options 216 | 217 | * opts.moduleDirectory - directory (or directories) in which to recursively look for modules. default: `"node_modules"` 218 | 219 | * opts.preserveSymlinks - if true, doesn't resolve `basedir` to real path before resolving. 220 | This is the way Node resolves dependencies when executed with the [--preserve-symlinks](https://nodejs.org/api/all.html#cli_preserve_symlinks) flag. 221 | 222 | default `opts` values: 223 | 224 | ```js 225 | { 226 | paths: [], 227 | basedir: __dirname, 228 | extensions: ['.js'], 229 | includeCoreModules: true, 230 | readFileSync: fs.readFileSync, 231 | isFile: function isFile(file) { 232 | try { 233 | var stat = fs.statSync(file); 234 | } catch (e) { 235 | if (e && (e.code === 'ENOENT' || e.code === 'ENOTDIR')) return false; 236 | throw e; 237 | } 238 | return stat.isFile() || stat.isFIFO(); 239 | }, 240 | isDirectory: function isDirectory(dir) { 241 | try { 242 | var stat = fs.statSync(dir); 243 | } catch (e) { 244 | if (e && (e.code === 'ENOENT' || e.code === 'ENOTDIR')) return false; 245 | throw e; 246 | } 247 | return stat.isDirectory(); 248 | }, 249 | realpathSync: function realpathSync(file) { 250 | try { 251 | var realpath = typeof fs.realpathSync.native === 'function' ? fs.realpathSync.native : fs.realpathSync; 252 | return realpath(file); 253 | } catch (realPathErr) { 254 | if (realPathErr.code !== 'ENOENT') { 255 | throw realPathErr; 256 | } 257 | } 258 | return file; 259 | }, 260 | readPackageSync: function defaultReadPackageSync(readFileSync, pkgfile) { 261 | return JSON.parse(readFileSync(pkgfile)); 262 | }, 263 | moduleDirectory: 'node_modules', 264 | preserveSymlinks: false 265 | } 266 | ``` 267 | 268 | # install 269 | 270 | With [npm](https://npmjs.org) do: 271 | 272 | ```sh 273 | npm install resolve 274 | ``` 275 | 276 | # license 277 | 278 | MIT 279 | 280 | [1]: https://npmjs.org/package/resolve 281 | [2]: https://versionbadg.es/browserify/resolve.svg 282 | [5]: https://david-dm.org/browserify/resolve.svg 283 | [6]: https://david-dm.org/browserify/resolve 284 | [7]: https://david-dm.org/browserify/resolve/dev-status.svg 285 | [8]: https://david-dm.org/browserify/resolve#info=devDependencies 286 | [11]: https://nodei.co/npm/resolve.png?downloads=true&stars=true 287 | [license-image]: https://img.shields.io/npm/l/resolve.svg 288 | [license-url]: LICENSE 289 | [downloads-image]: https://img.shields.io/npm/dm/resolve.svg 290 | [downloads-url]: https://npm-stat.com/charts.html?package=resolve 291 | [codecov-image]: https://codecov.io/gh/browserify/resolve/branch/main/graphs/badge.svg 292 | [codecov-url]: https://app.codecov.io/gh/browserify/resolve/ 293 | [actions-image]: https://img.shields.io/endpoint?url=https://github-actions-badge-u3jn4tfpocch.runkit.sh/browserify/resolve 294 | [actions-url]: https://github.com/browserify/resolve/actions 295 | -------------------------------------------------------------------------------- /sync.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = require('./lib/sync'); 4 | -------------------------------------------------------------------------------- /test/dotdot.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var test = require('tape'); 3 | var resolve = require('../'); 4 | 5 | test('dotdot', function (t) { 6 | t.plan(4); 7 | var dir = path.join(__dirname, '/dotdot/abc'); 8 | 9 | resolve('..', { basedir: dir }, function (err, res, pkg) { 10 | t.ifError(err); 11 | t.equal(res, path.join(__dirname, 'dotdot/index.js')); 12 | }); 13 | 14 | resolve('.', { basedir: dir }, function (err, res, pkg) { 15 | t.ifError(err); 16 | t.equal(res, path.join(dir, 'index.js')); 17 | }); 18 | }); 19 | 20 | test('dotdot sync', function (t) { 21 | t.plan(2); 22 | var dir = path.join(__dirname, '/dotdot/abc'); 23 | 24 | var a = resolve.sync('..', { basedir: dir }); 25 | t.equal(a, path.join(__dirname, 'dotdot/index.js')); 26 | 27 | var b = resolve.sync('.', { basedir: dir }); 28 | t.equal(b, path.join(dir, 'index.js')); 29 | }); 30 | -------------------------------------------------------------------------------- /test/dotdot/abc/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/dotdot/abc/index.js -------------------------------------------------------------------------------- /test/dotdot/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/dotdot/index.js -------------------------------------------------------------------------------- /test/faulty_basedir.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var path = require('path'); 3 | var resolve = require('../'); 4 | 5 | test('faulty basedir must produce error in windows', { skip: process.platform !== 'win32' }, function (t) { 6 | t.plan(1); 7 | 8 | var resolverDir = 'C:\\a\\b\\c\\d'; 9 | 10 | resolve('tape/lib/test.js', { basedir: resolverDir }, function (err, res, pkg) { 11 | t.equal(!!err, true); 12 | }); 13 | }); 14 | 15 | test('non-existent basedir should not throw when preserveSymlinks is false', function (t) { 16 | t.plan(2); 17 | 18 | var opts = { 19 | basedir: path.join(path.sep, 'unreal', 'path', 'that', 'does', 'not', 'exist'), 20 | preserveSymlinks: false 21 | }; 22 | 23 | var module = './dotdot/abc'; 24 | 25 | resolve(module, opts, function (err, res) { 26 | t.equal(err.code, 'INVALID_BASEDIR'); 27 | t.equal(res, undefined); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /test/filter.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var test = require('tape'); 3 | var resolve = require('../'); 4 | 5 | test('filter', function (t) { 6 | t.plan(5); 7 | var dir = path.join(__dirname, 'resolver'); 8 | var packageFilterArgs; 9 | resolve('./baz', { 10 | basedir: dir, 11 | packageFilter: function (pkg, pkgfile, dir) { 12 | pkg.main = 'doom'; // eslint-disable-line no-param-reassign 13 | packageFilterArgs = [pkg, pkgfile, dir]; 14 | return pkg; 15 | } 16 | }, function (err, res, pkg) { 17 | if (err) t.fail(err); 18 | 19 | t.equal(res, path.join(dir, 'baz/doom.js'), 'changing the package "main" works'); 20 | 21 | var packageData = packageFilterArgs[0]; 22 | t.equal(pkg, packageData, 'first packageFilter argument is "pkg"'); 23 | t.equal(packageData.main, 'doom', 'package "main" was altered'); 24 | 25 | var packageFile = packageFilterArgs[1]; 26 | t.equal( 27 | packageFile, 28 | path.join(dir, 'baz/package.json'), 29 | 'second packageFilter argument is "pkgfile"' 30 | ); 31 | 32 | var packageFileDir = packageFilterArgs[2]; 33 | t.equal(packageFileDir, path.join(dir, 'baz'), 'third packageFilter argument is "dir"'); 34 | 35 | t.end(); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /test/filter_sync.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var test = require('tape'); 3 | var resolve = require('../'); 4 | 5 | test('filter', function (t) { 6 | var dir = path.join(__dirname, 'resolver'); 7 | var packageFilterArgs; 8 | var res = resolve.sync('./baz', { 9 | basedir: dir, 10 | packageFilter: function (pkg, pkgfile, dir) { 11 | pkg.main = 'doom'; // eslint-disable-line no-param-reassign 12 | packageFilterArgs = [pkg, pkgfile, dir]; 13 | return pkg; 14 | } 15 | }); 16 | 17 | t.equal(res, path.join(dir, 'baz/doom.js'), 'changing the package "main" works'); 18 | 19 | var packageData = packageFilterArgs[0]; 20 | t.equal(packageData.main, 'doom', 'package "main" was altered'); 21 | 22 | var packageFile = packageFilterArgs[1]; 23 | t.equal( 24 | packageFile, 25 | path.join(dir, 'baz/package.json'), 26 | 'second packageFilter argument is "pkgfile"' 27 | ); 28 | 29 | var packageDir = packageFilterArgs[2]; 30 | t.equal(packageDir, path.join(dir, 'baz'), 'third packageFilter argument is "dir"'); 31 | 32 | t.end(); 33 | }); 34 | -------------------------------------------------------------------------------- /test/home_paths.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var fs = require('fs'); 4 | var homedir = require('../lib/homedir'); 5 | var path = require('path'); 6 | 7 | var test = require('tape'); 8 | var mkdirp = require('mkdirp'); 9 | var rimraf = require('rimraf'); 10 | var mv = require('mv'); 11 | var copyDir = require('copy-dir'); 12 | var tmp = require('tmp'); 13 | 14 | var HOME = homedir(); 15 | 16 | var hnm = path.join(HOME, '.node_modules'); 17 | var hnl = path.join(HOME, '.node_libraries'); 18 | 19 | var resolve = require('../async'); 20 | 21 | function makeDir(t, dir, cb) { 22 | mkdirp(dir, function (err) { 23 | if (err) { 24 | cb(err); 25 | } else { 26 | t.teardown(function cleanup() { 27 | rimraf.sync(dir); 28 | }); 29 | cb(); 30 | } 31 | }); 32 | } 33 | 34 | function makeTempDir(t, dir, cb) { 35 | if (fs.existsSync(dir)) { 36 | var tmpResult = tmp.dirSync(); 37 | t.teardown(tmpResult.removeCallback); 38 | var backup = path.join(tmpResult.name, path.basename(dir)); 39 | mv(dir, backup, function (err) { 40 | if (err) { 41 | cb(err); 42 | } else { 43 | t.teardown(function () { 44 | mv(backup, dir, cb); 45 | }); 46 | makeDir(t, dir, cb); 47 | } 48 | }); 49 | } else { 50 | makeDir(t, dir, cb); 51 | } 52 | } 53 | 54 | test('homedir module paths', function (t) { 55 | t.plan(7); 56 | 57 | makeTempDir(t, hnm, function (err) { 58 | t.error(err, 'no error with HNM temp dir'); 59 | if (err) { 60 | return t.end(); 61 | } 62 | 63 | var bazHNMDir = path.join(hnm, 'baz'); 64 | var dotMainDir = path.join(hnm, 'dot_main'); 65 | copyDir.sync(path.join(__dirname, 'resolver/baz'), bazHNMDir); 66 | copyDir.sync(path.join(__dirname, 'resolver/dot_main'), dotMainDir); 67 | 68 | var bazPkg = { name: 'baz', main: 'quux.js' }; 69 | var dotMainPkg = { main: 'index' }; 70 | 71 | var bazHNMmain = path.join(bazHNMDir, 'quux.js'); 72 | t.equal(require.resolve('baz'), bazHNMmain, 'sanity check: require.resolve finds HNM `baz`'); 73 | var dotMainMain = path.join(dotMainDir, 'index.js'); 74 | t.equal(require.resolve('dot_main'), dotMainMain, 'sanity check: require.resolve finds `dot_main`'); 75 | 76 | makeTempDir(t, hnl, function (err) { 77 | t.error(err, 'no error with HNL temp dir'); 78 | if (err) { 79 | return t.end(); 80 | } 81 | var bazHNLDir = path.join(hnl, 'baz'); 82 | copyDir.sync(path.join(__dirname, 'resolver/baz'), bazHNLDir); 83 | 84 | var dotSlashMainDir = path.join(hnl, 'dot_slash_main'); 85 | var dotSlashMainMain = path.join(dotSlashMainDir, 'index.js'); 86 | var dotSlashMainPkg = { main: 'index' }; 87 | copyDir.sync(path.join(__dirname, 'resolver/dot_slash_main'), dotSlashMainDir); 88 | 89 | t.equal(require.resolve('baz'), bazHNMmain, 'sanity check: require.resolve finds HNM `baz`'); 90 | t.equal(require.resolve('dot_slash_main'), dotSlashMainMain, 'sanity check: require.resolve finds HNL `dot_slash_main`'); 91 | 92 | t.test('with temp dirs', function (st) { 93 | st.plan(3); 94 | 95 | st.test('just in `$HOME/.node_modules`', function (s2t) { 96 | s2t.plan(3); 97 | 98 | resolve('dot_main', function (err, res, pkg) { 99 | s2t.error(err, 'no error resolving `dot_main`'); 100 | s2t.equal(res, dotMainMain, '`dot_main` resolves in `$HOME/.node_modules`'); 101 | s2t.deepEqual(pkg, dotMainPkg); 102 | }); 103 | }); 104 | 105 | st.test('just in `$HOME/.node_libraries`', function (s2t) { 106 | s2t.plan(3); 107 | 108 | resolve('dot_slash_main', function (err, res, pkg) { 109 | s2t.error(err, 'no error resolving `dot_slash_main`'); 110 | s2t.equal(res, dotSlashMainMain, '`dot_slash_main` resolves in `$HOME/.node_libraries`'); 111 | s2t.deepEqual(pkg, dotSlashMainPkg); 112 | }); 113 | }); 114 | 115 | st.test('in `$HOME/.node_libraries` and `$HOME/.node_modules`', function (s2t) { 116 | s2t.plan(3); 117 | 118 | resolve('baz', function (err, res, pkg) { 119 | s2t.error(err, 'no error resolving `baz`'); 120 | s2t.equal(res, bazHNMmain, '`baz` resolves in `$HOME/.node_modules` when in both'); 121 | s2t.deepEqual(pkg, bazPkg); 122 | }); 123 | }); 124 | }); 125 | }); 126 | }); 127 | }); 128 | -------------------------------------------------------------------------------- /test/home_paths_sync.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var fs = require('fs'); 4 | var homedir = require('../lib/homedir'); 5 | var path = require('path'); 6 | 7 | var test = require('tape'); 8 | var mkdirp = require('mkdirp'); 9 | var rimraf = require('rimraf'); 10 | var mv = require('mv'); 11 | var copyDir = require('copy-dir'); 12 | var tmp = require('tmp'); 13 | 14 | var HOME = homedir(); 15 | 16 | var hnm = path.join(HOME, '.node_modules'); 17 | var hnl = path.join(HOME, '.node_libraries'); 18 | 19 | var resolve = require('../sync'); 20 | 21 | function makeDir(t, dir, cb) { 22 | mkdirp(dir, function (err) { 23 | if (err) { 24 | cb(err); 25 | } else { 26 | t.teardown(function cleanup() { 27 | rimraf.sync(dir); 28 | }); 29 | cb(); 30 | } 31 | }); 32 | } 33 | 34 | function makeTempDir(t, dir, cb) { 35 | if (fs.existsSync(dir)) { 36 | var tmpResult = tmp.dirSync(); 37 | t.teardown(tmpResult.removeCallback); 38 | var backup = path.join(tmpResult.name, path.basename(dir)); 39 | mv(dir, backup, function (err) { 40 | if (err) { 41 | cb(err); 42 | } else { 43 | t.teardown(function () { 44 | mv(backup, dir, cb); 45 | }); 46 | makeDir(t, dir, cb); 47 | } 48 | }); 49 | } else { 50 | makeDir(t, dir, cb); 51 | } 52 | } 53 | 54 | test('homedir module paths', function (t) { 55 | t.plan(7); 56 | 57 | makeTempDir(t, hnm, function (err) { 58 | t.error(err, 'no error with HNM temp dir'); 59 | if (err) { 60 | return t.end(); 61 | } 62 | 63 | var bazHNMDir = path.join(hnm, 'baz'); 64 | var dotMainDir = path.join(hnm, 'dot_main'); 65 | copyDir.sync(path.join(__dirname, 'resolver/baz'), bazHNMDir); 66 | copyDir.sync(path.join(__dirname, 'resolver/dot_main'), dotMainDir); 67 | 68 | var bazHNMmain = path.join(bazHNMDir, 'quux.js'); 69 | t.equal(require.resolve('baz'), bazHNMmain, 'sanity check: require.resolve finds HNM `baz`'); 70 | var dotMainMain = path.join(dotMainDir, 'index.js'); 71 | t.equal(require.resolve('dot_main'), dotMainMain, 'sanity check: require.resolve finds `dot_main`'); 72 | 73 | makeTempDir(t, hnl, function (err) { 74 | t.error(err, 'no error with HNL temp dir'); 75 | if (err) { 76 | return t.end(); 77 | } 78 | var bazHNLDir = path.join(hnl, 'baz'); 79 | copyDir.sync(path.join(__dirname, 'resolver/baz'), bazHNLDir); 80 | 81 | var dotSlashMainDir = path.join(hnl, 'dot_slash_main'); 82 | var dotSlashMainMain = path.join(dotSlashMainDir, 'index.js'); 83 | copyDir.sync(path.join(__dirname, 'resolver/dot_slash_main'), dotSlashMainDir); 84 | 85 | t.equal(require.resolve('baz'), bazHNMmain, 'sanity check: require.resolve finds HNM `baz`'); 86 | t.equal(require.resolve('dot_slash_main'), dotSlashMainMain, 'sanity check: require.resolve finds HNL `dot_slash_main`'); 87 | 88 | t.test('with temp dirs', function (st) { 89 | st.plan(3); 90 | 91 | st.test('just in `$HOME/.node_modules`', function (s2t) { 92 | s2t.plan(1); 93 | 94 | var res = resolve('dot_main'); 95 | s2t.equal(res, dotMainMain, '`dot_main` resolves in `$HOME/.node_modules`'); 96 | }); 97 | 98 | st.test('just in `$HOME/.node_libraries`', function (s2t) { 99 | s2t.plan(1); 100 | 101 | var res = resolve('dot_slash_main'); 102 | s2t.equal(res, dotSlashMainMain, '`dot_slash_main` resolves in `$HOME/.node_libraries`'); 103 | }); 104 | 105 | st.test('in `$HOME/.node_libraries` and `$HOME/.node_modules`', function (s2t) { 106 | s2t.plan(1); 107 | 108 | var res = resolve('baz'); 109 | s2t.equal(res, bazHNMmain, '`baz` resolves in `$HOME/.node_modules` when in both'); 110 | }); 111 | }); 112 | }); 113 | }); 114 | }); 115 | -------------------------------------------------------------------------------- /test/mock.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var test = require('tape'); 3 | var resolve = require('../'); 4 | 5 | test('mock', function (t) { 6 | t.plan(8); 7 | 8 | var files = {}; 9 | files[path.resolve('/foo/bar/baz.js')] = 'beep'; 10 | 11 | var dirs = {}; 12 | dirs[path.resolve('/foo/bar')] = true; 13 | 14 | function opts(basedir) { 15 | return { 16 | basedir: path.resolve(basedir), 17 | isFile: function (file, cb) { 18 | cb(null, Object.prototype.hasOwnProperty.call(files, path.resolve(file))); 19 | }, 20 | isDirectory: function (dir, cb) { 21 | cb(null, !!dirs[path.resolve(dir)]); 22 | }, 23 | readFile: function (file, cb) { 24 | cb(null, files[path.resolve(file)]); 25 | }, 26 | realpath: function (file, cb) { 27 | cb(null, file); 28 | } 29 | }; 30 | } 31 | 32 | resolve('./baz', opts('/foo/bar'), function (err, res, pkg) { 33 | if (err) return t.fail(err); 34 | t.equal(res, path.resolve('/foo/bar/baz.js')); 35 | t.equal(pkg, undefined); 36 | }); 37 | 38 | resolve('./baz.js', opts('/foo/bar'), function (err, res, pkg) { 39 | if (err) return t.fail(err); 40 | t.equal(res, path.resolve('/foo/bar/baz.js')); 41 | t.equal(pkg, undefined); 42 | }); 43 | 44 | resolve('baz', opts('/foo/bar'), function (err, res) { 45 | t.equal(err.message, "Cannot find module 'baz' from '" + path.resolve('/foo/bar') + "'"); 46 | t.equal(err.code, 'MODULE_NOT_FOUND'); 47 | }); 48 | 49 | resolve('../baz', opts('/foo/bar'), function (err, res) { 50 | t.equal(err.message, "Cannot find module '../baz' from '" + path.resolve('/foo/bar') + "'"); 51 | t.equal(err.code, 'MODULE_NOT_FOUND'); 52 | }); 53 | }); 54 | 55 | test('mock from package', function (t) { 56 | t.plan(8); 57 | 58 | var files = {}; 59 | files[path.resolve('/foo/bar/baz.js')] = 'beep'; 60 | 61 | var dirs = {}; 62 | dirs[path.resolve('/foo/bar')] = true; 63 | 64 | function opts(basedir) { 65 | return { 66 | basedir: path.resolve(basedir), 67 | isFile: function (file, cb) { 68 | cb(null, Object.prototype.hasOwnProperty.call(files, file)); 69 | }, 70 | isDirectory: function (dir, cb) { 71 | cb(null, !!dirs[path.resolve(dir)]); 72 | }, 73 | 'package': { main: 'bar' }, 74 | readFile: function (file, cb) { 75 | cb(null, files[file]); 76 | }, 77 | realpath: function (file, cb) { 78 | cb(null, file); 79 | } 80 | }; 81 | } 82 | 83 | resolve('./baz', opts('/foo/bar'), function (err, res, pkg) { 84 | if (err) return t.fail(err); 85 | t.equal(res, path.resolve('/foo/bar/baz.js')); 86 | t.equal(pkg && pkg.main, 'bar'); 87 | }); 88 | 89 | resolve('./baz.js', opts('/foo/bar'), function (err, res, pkg) { 90 | if (err) return t.fail(err); 91 | t.equal(res, path.resolve('/foo/bar/baz.js')); 92 | t.equal(pkg && pkg.main, 'bar'); 93 | }); 94 | 95 | resolve('baz', opts('/foo/bar'), function (err, res) { 96 | t.equal(err.message, "Cannot find module 'baz' from '" + path.resolve('/foo/bar') + "'"); 97 | t.equal(err.code, 'MODULE_NOT_FOUND'); 98 | }); 99 | 100 | resolve('../baz', opts('/foo/bar'), function (err, res) { 101 | t.equal(err.message, "Cannot find module '../baz' from '" + path.resolve('/foo/bar') + "'"); 102 | t.equal(err.code, 'MODULE_NOT_FOUND'); 103 | }); 104 | }); 105 | 106 | test('mock package', function (t) { 107 | t.plan(2); 108 | 109 | var files = {}; 110 | files[path.resolve('/foo/node_modules/bar/baz.js')] = 'beep'; 111 | files[path.resolve('/foo/node_modules/bar/package.json')] = JSON.stringify({ 112 | main: './baz.js' 113 | }); 114 | 115 | var dirs = {}; 116 | dirs[path.resolve('/foo')] = true; 117 | dirs[path.resolve('/foo/node_modules')] = true; 118 | 119 | function opts(basedir) { 120 | return { 121 | basedir: path.resolve(basedir), 122 | isFile: function (file, cb) { 123 | cb(null, Object.prototype.hasOwnProperty.call(files, path.resolve(file))); 124 | }, 125 | isDirectory: function (dir, cb) { 126 | cb(null, !!dirs[path.resolve(dir)]); 127 | }, 128 | readFile: function (file, cb) { 129 | cb(null, files[path.resolve(file)]); 130 | }, 131 | realpath: function (file, cb) { 132 | cb(null, file); 133 | } 134 | }; 135 | } 136 | 137 | resolve('bar', opts('/foo'), function (err, res, pkg) { 138 | if (err) return t.fail(err); 139 | t.equal(res, path.resolve('/foo/node_modules/bar/baz.js')); 140 | t.equal(pkg && pkg.main, './baz.js'); 141 | }); 142 | }); 143 | 144 | test('mock package from package', function (t) { 145 | t.plan(2); 146 | 147 | var files = {}; 148 | files[path.resolve('/foo/node_modules/bar/baz.js')] = 'beep'; 149 | files[path.resolve('/foo/node_modules/bar/package.json')] = JSON.stringify({ 150 | main: './baz.js' 151 | }); 152 | 153 | var dirs = {}; 154 | dirs[path.resolve('/foo')] = true; 155 | dirs[path.resolve('/foo/node_modules')] = true; 156 | 157 | function opts(basedir) { 158 | return { 159 | basedir: path.resolve(basedir), 160 | isFile: function (file, cb) { 161 | cb(null, Object.prototype.hasOwnProperty.call(files, path.resolve(file))); 162 | }, 163 | isDirectory: function (dir, cb) { 164 | cb(null, !!dirs[path.resolve(dir)]); 165 | }, 166 | 'package': { main: 'bar' }, 167 | readFile: function (file, cb) { 168 | cb(null, files[path.resolve(file)]); 169 | }, 170 | realpath: function (file, cb) { 171 | cb(null, file); 172 | } 173 | }; 174 | } 175 | 176 | resolve('bar', opts('/foo'), function (err, res, pkg) { 177 | if (err) return t.fail(err); 178 | t.equal(res, path.resolve('/foo/node_modules/bar/baz.js')); 179 | t.equal(pkg && pkg.main, './baz.js'); 180 | }); 181 | }); 182 | 183 | test('symlinked', function (t) { 184 | t.plan(4); 185 | 186 | var files = {}; 187 | files[path.resolve('/foo/bar/baz.js')] = 'beep'; 188 | files[path.resolve('/foo/bar/symlinked/baz.js')] = 'beep'; 189 | 190 | var dirs = {}; 191 | dirs[path.resolve('/foo/bar')] = true; 192 | dirs[path.resolve('/foo/bar/symlinked')] = true; 193 | 194 | function opts(basedir) { 195 | return { 196 | preserveSymlinks: false, 197 | basedir: path.resolve(basedir), 198 | isFile: function (file, cb) { 199 | cb(null, Object.prototype.hasOwnProperty.call(files, path.resolve(file))); 200 | }, 201 | isDirectory: function (dir, cb) { 202 | cb(null, !!dirs[path.resolve(dir)]); 203 | }, 204 | readFile: function (file, cb) { 205 | cb(null, files[path.resolve(file)]); 206 | }, 207 | realpath: function (file, cb) { 208 | var resolved = path.resolve(file); 209 | 210 | if (resolved.indexOf('symlinked') >= 0) { 211 | cb(null, resolved); 212 | return; 213 | } 214 | 215 | var ext = path.extname(resolved); 216 | 217 | if (ext) { 218 | var dir = path.dirname(resolved); 219 | var base = path.basename(resolved); 220 | cb(null, path.join(dir, 'symlinked', base)); 221 | } else { 222 | cb(null, path.join(resolved, 'symlinked')); 223 | } 224 | } 225 | }; 226 | } 227 | 228 | resolve('./baz', opts('/foo/bar'), function (err, res, pkg) { 229 | if (err) return t.fail(err); 230 | t.equal(res, path.resolve('/foo/bar/symlinked/baz.js')); 231 | t.equal(pkg, undefined); 232 | }); 233 | 234 | resolve('./baz.js', opts('/foo/bar'), function (err, res, pkg) { 235 | if (err) return t.fail(err); 236 | t.equal(res, path.resolve('/foo/bar/symlinked/baz.js')); 237 | t.equal(pkg, undefined); 238 | }); 239 | }); 240 | 241 | test('readPackage', function (t) { 242 | t.plan(3); 243 | 244 | var files = {}; 245 | files[path.resolve('/foo/node_modules/bar/something-else.js')] = 'beep'; 246 | files[path.resolve('/foo/node_modules/bar/package.json')] = JSON.stringify({ 247 | main: './baz.js' 248 | }); 249 | files[path.resolve('/foo/node_modules/bar/baz.js')] = 'boop'; 250 | 251 | var dirs = {}; 252 | dirs[path.resolve('/foo')] = true; 253 | dirs[path.resolve('/foo/node_modules')] = true; 254 | 255 | function opts(basedir) { 256 | return { 257 | basedir: path.resolve(basedir), 258 | isFile: function (file, cb) { 259 | cb(null, Object.prototype.hasOwnProperty.call(files, path.resolve(file))); 260 | }, 261 | isDirectory: function (dir, cb) { 262 | cb(null, !!dirs[path.resolve(dir)]); 263 | }, 264 | 'package': { main: 'bar' }, 265 | readFile: function (file, cb) { 266 | cb(null, files[path.resolve(file)]); 267 | }, 268 | realpath: function (file, cb) { 269 | cb(null, file); 270 | } 271 | }; 272 | } 273 | 274 | t.test('with readFile', function (st) { 275 | st.plan(3); 276 | 277 | resolve('bar', opts('/foo'), function (err, res, pkg) { 278 | st.error(err); 279 | st.equal(res, path.resolve('/foo/node_modules/bar/baz.js')); 280 | st.equal(pkg && pkg.main, './baz.js'); 281 | }); 282 | }); 283 | 284 | var readPackage = function (readFile, file, cb) { 285 | var barPackage = path.join('bar', 'package.json'); 286 | if (file.slice(-barPackage.length) === barPackage) { 287 | cb(null, { main: './something-else.js' }); 288 | } else { 289 | cb(null, JSON.parse(files[path.resolve(file)])); 290 | } 291 | }; 292 | 293 | t.test('with readPackage', function (st) { 294 | st.plan(3); 295 | 296 | var options = opts('/foo'); 297 | delete options.readFile; 298 | options.readPackage = readPackage; 299 | resolve('bar', options, function (err, res, pkg) { 300 | st.error(err); 301 | st.equal(res, path.resolve('/foo/node_modules/bar/something-else.js')); 302 | st.equal(pkg && pkg.main, './something-else.js'); 303 | }); 304 | }); 305 | 306 | t.test('with readFile and readPackage', function (st) { 307 | st.plan(1); 308 | 309 | var options = opts('/foo'); 310 | options.readPackage = readPackage; 311 | resolve('bar', options, function (err) { 312 | st.throws(function () { throw err; }, TypeError, 'errors when both readFile and readPackage are provided'); 313 | }); 314 | }); 315 | }); 316 | -------------------------------------------------------------------------------- /test/mock_sync.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var test = require('tape'); 3 | var resolve = require('../'); 4 | 5 | test('mock', function (t) { 6 | t.plan(4); 7 | 8 | var files = {}; 9 | files[path.resolve('/foo/bar/baz.js')] = 'beep'; 10 | 11 | var dirs = {}; 12 | dirs[path.resolve('/foo/bar')] = true; 13 | dirs[path.resolve('/foo/node_modules')] = true; 14 | 15 | function opts(basedir) { 16 | return { 17 | basedir: path.resolve(basedir), 18 | isFile: function (file) { 19 | return Object.prototype.hasOwnProperty.call(files, path.resolve(file)); 20 | }, 21 | isDirectory: function (dir) { 22 | return !!dirs[path.resolve(dir)]; 23 | }, 24 | readFileSync: function (file) { 25 | return files[path.resolve(file)]; 26 | }, 27 | realpathSync: function (file) { 28 | return file; 29 | } 30 | }; 31 | } 32 | 33 | t.equal( 34 | resolve.sync('./baz', opts('/foo/bar')), 35 | path.resolve('/foo/bar/baz.js') 36 | ); 37 | 38 | t.equal( 39 | resolve.sync('./baz.js', opts('/foo/bar')), 40 | path.resolve('/foo/bar/baz.js') 41 | ); 42 | 43 | t.throws(function () { 44 | resolve.sync('baz', opts('/foo/bar')); 45 | }); 46 | 47 | t.throws(function () { 48 | resolve.sync('../baz', opts('/foo/bar')); 49 | }); 50 | }); 51 | 52 | test('mock package', function (t) { 53 | t.plan(1); 54 | 55 | var files = {}; 56 | files[path.resolve('/foo/node_modules/bar/baz.js')] = 'beep'; 57 | files[path.resolve('/foo/node_modules/bar/package.json')] = JSON.stringify({ 58 | main: './baz.js' 59 | }); 60 | 61 | var dirs = {}; 62 | dirs[path.resolve('/foo')] = true; 63 | dirs[path.resolve('/foo/node_modules')] = true; 64 | 65 | function opts(basedir) { 66 | return { 67 | basedir: path.resolve(basedir), 68 | isFile: function (file) { 69 | return Object.prototype.hasOwnProperty.call(files, path.resolve(file)); 70 | }, 71 | isDirectory: function (dir) { 72 | return !!dirs[path.resolve(dir)]; 73 | }, 74 | readFileSync: function (file) { 75 | return files[path.resolve(file)]; 76 | }, 77 | realpathSync: function (file) { 78 | return file; 79 | } 80 | }; 81 | } 82 | 83 | t.equal( 84 | resolve.sync('bar', opts('/foo')), 85 | path.resolve('/foo/node_modules/bar/baz.js') 86 | ); 87 | }); 88 | 89 | test('symlinked', function (t) { 90 | t.plan(2); 91 | 92 | var files = {}; 93 | files[path.resolve('/foo/bar/baz.js')] = 'beep'; 94 | files[path.resolve('/foo/bar/symlinked/baz.js')] = 'beep'; 95 | 96 | var dirs = {}; 97 | dirs[path.resolve('/foo/bar')] = true; 98 | dirs[path.resolve('/foo/bar/symlinked')] = true; 99 | 100 | function opts(basedir) { 101 | return { 102 | preserveSymlinks: false, 103 | basedir: path.resolve(basedir), 104 | isFile: function (file) { 105 | return Object.prototype.hasOwnProperty.call(files, path.resolve(file)); 106 | }, 107 | isDirectory: function (dir) { 108 | return !!dirs[path.resolve(dir)]; 109 | }, 110 | readFileSync: function (file) { 111 | return files[path.resolve(file)]; 112 | }, 113 | realpathSync: function (file) { 114 | var resolved = path.resolve(file); 115 | 116 | if (resolved.indexOf('symlinked') >= 0) { 117 | return resolved; 118 | } 119 | 120 | var ext = path.extname(resolved); 121 | 122 | if (ext) { 123 | var dir = path.dirname(resolved); 124 | var base = path.basename(resolved); 125 | return path.join(dir, 'symlinked', base); 126 | } 127 | return path.join(resolved, 'symlinked'); 128 | } 129 | }; 130 | } 131 | 132 | t.equal( 133 | resolve.sync('./baz', opts('/foo/bar')), 134 | path.resolve('/foo/bar/symlinked/baz.js') 135 | ); 136 | 137 | t.equal( 138 | resolve.sync('./baz.js', opts('/foo/bar')), 139 | path.resolve('/foo/bar/symlinked/baz.js') 140 | ); 141 | }); 142 | 143 | test('readPackageSync', function (t) { 144 | t.plan(3); 145 | 146 | var files = {}; 147 | files[path.resolve('/foo/node_modules/bar/something-else.js')] = 'beep'; 148 | files[path.resolve('/foo/node_modules/bar/package.json')] = JSON.stringify({ 149 | main: './baz.js' 150 | }); 151 | files[path.resolve('/foo/node_modules/bar/baz.js')] = 'boop'; 152 | 153 | var dirs = {}; 154 | dirs[path.resolve('/foo')] = true; 155 | dirs[path.resolve('/foo/node_modules')] = true; 156 | 157 | function opts(basedir, useReadPackage) { 158 | return { 159 | basedir: path.resolve(basedir), 160 | isFile: function (file) { 161 | return Object.prototype.hasOwnProperty.call(files, path.resolve(file)); 162 | }, 163 | isDirectory: function (dir) { 164 | return !!dirs[path.resolve(dir)]; 165 | }, 166 | readFileSync: useReadPackage ? null : function (file) { 167 | return files[path.resolve(file)]; 168 | }, 169 | realpathSync: function (file) { 170 | return file; 171 | } 172 | }; 173 | } 174 | t.test('with readFile', function (st) { 175 | st.plan(1); 176 | 177 | st.equal( 178 | resolve.sync('bar', opts('/foo')), 179 | path.resolve('/foo/node_modules/bar/baz.js') 180 | ); 181 | }); 182 | 183 | var readPackageSync = function (readFileSync, file) { 184 | if (file.indexOf(path.join('bar', 'package.json')) >= 0) { 185 | return { main: './something-else.js' }; 186 | } 187 | return JSON.parse(files[path.resolve(file)]); 188 | }; 189 | 190 | t.test('with readPackage', function (st) { 191 | st.plan(1); 192 | 193 | var options = opts('/foo'); 194 | delete options.readFileSync; 195 | options.readPackageSync = readPackageSync; 196 | 197 | st.equal( 198 | resolve.sync('bar', options), 199 | path.resolve('/foo/node_modules/bar/something-else.js') 200 | ); 201 | }); 202 | 203 | t.test('with readFile and readPackage', function (st) { 204 | st.plan(1); 205 | 206 | var options = opts('/foo'); 207 | options.readPackageSync = readPackageSync; 208 | st.throws( 209 | function () { resolve.sync('bar', options); }, 210 | TypeError, 211 | 'errors when both readFile and readPackage are provided' 212 | ); 213 | }); 214 | }); 215 | 216 | -------------------------------------------------------------------------------- /test/module_dir.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var test = require('tape'); 3 | var resolve = require('../'); 4 | 5 | test('moduleDirectory strings', function (t) { 6 | t.plan(4); 7 | var dir = path.join(__dirname, 'module_dir'); 8 | var xopts = { 9 | basedir: dir, 10 | moduleDirectory: 'xmodules' 11 | }; 12 | resolve('aaa', xopts, function (err, res, pkg) { 13 | t.ifError(err); 14 | t.equal(res, path.join(dir, '/xmodules/aaa/index.js')); 15 | }); 16 | 17 | var yopts = { 18 | basedir: dir, 19 | moduleDirectory: 'ymodules' 20 | }; 21 | resolve('aaa', yopts, function (err, res, pkg) { 22 | t.ifError(err); 23 | t.equal(res, path.join(dir, '/ymodules/aaa/index.js')); 24 | }); 25 | }); 26 | 27 | test('moduleDirectory array', function (t) { 28 | t.plan(6); 29 | var dir = path.join(__dirname, 'module_dir'); 30 | var aopts = { 31 | basedir: dir, 32 | moduleDirectory: ['xmodules', 'ymodules', 'zmodules'] 33 | }; 34 | resolve('aaa', aopts, function (err, res, pkg) { 35 | t.ifError(err); 36 | t.equal(res, path.join(dir, '/xmodules/aaa/index.js')); 37 | }); 38 | 39 | var bopts = { 40 | basedir: dir, 41 | moduleDirectory: ['zmodules', 'ymodules', 'xmodules'] 42 | }; 43 | resolve('aaa', bopts, function (err, res, pkg) { 44 | t.ifError(err); 45 | t.equal(res, path.join(dir, '/ymodules/aaa/index.js')); 46 | }); 47 | 48 | var copts = { 49 | basedir: dir, 50 | moduleDirectory: ['xmodules', 'ymodules', 'zmodules'] 51 | }; 52 | resolve('bbb', copts, function (err, res, pkg) { 53 | t.ifError(err); 54 | t.equal(res, path.join(dir, '/zmodules/bbb/main.js')); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /test/module_dir/xmodules/aaa/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/module_dir/xmodules/aaa/index.js -------------------------------------------------------------------------------- /test/module_dir/ymodules/aaa/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/module_dir/ymodules/aaa/index.js -------------------------------------------------------------------------------- /test/module_dir/zmodules/bbb/main.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/module_dir/zmodules/bbb/main.js -------------------------------------------------------------------------------- /test/module_dir/zmodules/bbb/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "main.js" 3 | } 4 | -------------------------------------------------------------------------------- /test/node-modules-paths.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var path = require('path'); 3 | var parse = path.parse || require('path-parse'); 4 | var keys = require('object-keys'); 5 | 6 | var nodeModulesPaths = require('../lib/node-modules-paths'); 7 | 8 | var verifyDirs = function verifyDirs(t, start, dirs, moduleDirectories, paths) { 9 | var moduleDirs = [].concat(moduleDirectories || 'node_modules'); 10 | if (paths) { 11 | for (var k = 0; k < paths.length; ++k) { 12 | moduleDirs.push(path.basename(paths[k])); 13 | } 14 | } 15 | 16 | var foundModuleDirs = {}; 17 | var uniqueDirs = {}; 18 | var parsedDirs = {}; 19 | for (var i = 0; i < dirs.length; ++i) { 20 | var parsed = parse(dirs[i]); 21 | if (!foundModuleDirs[parsed.base]) { foundModuleDirs[parsed.base] = 0; } 22 | foundModuleDirs[parsed.base] += 1; 23 | parsedDirs[parsed.dir] = true; 24 | uniqueDirs[dirs[i]] = true; 25 | } 26 | t.equal(keys(parsedDirs).length >= start.split(path.sep).length, true, 'there are >= dirs than "start" has'); 27 | var foundModuleDirNames = keys(foundModuleDirs); 28 | t.deepEqual(foundModuleDirNames, moduleDirs, 'all desired module dirs were found'); 29 | t.equal(keys(uniqueDirs).length, dirs.length, 'all dirs provided were unique'); 30 | 31 | var counts = {}; 32 | for (var j = 0; j < foundModuleDirNames.length; ++j) { 33 | counts[foundModuleDirs[j]] = true; 34 | } 35 | t.equal(keys(counts).length, 1, 'all found module directories had the same count'); 36 | }; 37 | 38 | test('node-modules-paths', function (t) { 39 | t.test('no options', function (t) { 40 | var start = path.join(__dirname, 'resolver'); 41 | var dirs = nodeModulesPaths(start); 42 | 43 | verifyDirs(t, start, dirs); 44 | 45 | t.end(); 46 | }); 47 | 48 | t.test('empty options', function (t) { 49 | var start = path.join(__dirname, 'resolver'); 50 | var dirs = nodeModulesPaths(start, {}); 51 | 52 | verifyDirs(t, start, dirs); 53 | 54 | t.end(); 55 | }); 56 | 57 | t.test('with paths=array option', function (t) { 58 | var start = path.join(__dirname, 'resolver'); 59 | var paths = ['a', 'b']; 60 | var dirs = nodeModulesPaths(start, { paths: paths }); 61 | 62 | verifyDirs(t, start, dirs, null, paths); 63 | 64 | t.end(); 65 | }); 66 | 67 | t.test('with paths=function option', function (t) { 68 | var paths = function paths(request, absoluteStart, getNodeModulesDirs, opts) { 69 | return getNodeModulesDirs().concat(path.join(absoluteStart, 'not node modules', request)); 70 | }; 71 | 72 | var start = path.join(__dirname, 'resolver'); 73 | var dirs = nodeModulesPaths(start, { paths: paths }, 'pkg'); 74 | 75 | verifyDirs(t, start, dirs, null, [path.join(start, 'not node modules', 'pkg')]); 76 | 77 | t.end(); 78 | }); 79 | 80 | t.test('with paths=function skipping node modules resolution', function (t) { 81 | var paths = function paths(request, absoluteStart, getNodeModulesDirs, opts) { 82 | return []; 83 | }; 84 | var start = path.join(__dirname, 'resolver'); 85 | var dirs = nodeModulesPaths(start, { paths: paths }); 86 | t.deepEqual(dirs, [], 'no node_modules was computed'); 87 | t.end(); 88 | }); 89 | 90 | t.test('with moduleDirectory option', function (t) { 91 | var start = path.join(__dirname, 'resolver'); 92 | var moduleDirectory = 'not node modules'; 93 | var dirs = nodeModulesPaths(start, { moduleDirectory: moduleDirectory }); 94 | 95 | verifyDirs(t, start, dirs, moduleDirectory); 96 | 97 | t.end(); 98 | }); 99 | 100 | t.test('with 1 moduleDirectory and paths options', function (t) { 101 | var start = path.join(__dirname, 'resolver'); 102 | var paths = ['a', 'b']; 103 | var moduleDirectory = 'not node modules'; 104 | var dirs = nodeModulesPaths(start, { paths: paths, moduleDirectory: moduleDirectory }); 105 | 106 | verifyDirs(t, start, dirs, moduleDirectory, paths); 107 | 108 | t.end(); 109 | }); 110 | 111 | t.test('with 1+ moduleDirectory and paths options', function (t) { 112 | var start = path.join(__dirname, 'resolver'); 113 | var paths = ['a', 'b']; 114 | var moduleDirectories = ['not node modules', 'other modules']; 115 | var dirs = nodeModulesPaths(start, { paths: paths, moduleDirectory: moduleDirectories }); 116 | 117 | verifyDirs(t, start, dirs, moduleDirectories, paths); 118 | 119 | t.end(); 120 | }); 121 | 122 | t.test('combine paths correctly on Windows', function (t) { 123 | var start = 'C:\\Users\\username\\myProject\\src'; 124 | var paths = []; 125 | var moduleDirectories = ['node_modules', start]; 126 | var dirs = nodeModulesPaths(start, { paths: paths, moduleDirectory: moduleDirectories }); 127 | 128 | t.equal(dirs.indexOf(path.resolve(start)) > -1, true, 'should contain start dir'); 129 | 130 | t.end(); 131 | }); 132 | 133 | t.test('combine paths correctly on non-Windows', { skip: process.platform === 'win32' }, function (t) { 134 | var start = '/Users/username/git/myProject/src'; 135 | var paths = []; 136 | var moduleDirectories = ['node_modules', '/Users/username/git/myProject/src']; 137 | var dirs = nodeModulesPaths(start, { paths: paths, moduleDirectory: moduleDirectories }); 138 | 139 | t.equal(dirs.indexOf(path.resolve(start)) > -1, true, 'should contain start dir'); 140 | 141 | t.end(); 142 | }); 143 | }); 144 | -------------------------------------------------------------------------------- /test/node_path.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var path = require('path'); 3 | var test = require('tape'); 4 | var resolve = require('../'); 5 | 6 | test('$NODE_PATH', function (t) { 7 | t.plan(8); 8 | 9 | var isDir = function (dir, cb) { 10 | if (dir === '/node_path' || dir === 'node_path/x') { 11 | return cb(null, true); 12 | } 13 | fs.stat(dir, function (err, stat) { 14 | if (!err) { 15 | return cb(null, stat.isDirectory()); 16 | } 17 | if (err.code === 'ENOENT' || err.code === 'ENOTDIR') return cb(null, false); 18 | return cb(err); 19 | }); 20 | }; 21 | 22 | resolve('aaa', { 23 | paths: [ 24 | path.join(__dirname, '/node_path/x'), 25 | path.join(__dirname, '/node_path/y') 26 | ], 27 | basedir: __dirname, 28 | isDirectory: isDir 29 | }, function (err, res) { 30 | t.error(err); 31 | t.equal(res, path.join(__dirname, '/node_path/x/aaa/index.js'), 'aaa resolves'); 32 | }); 33 | 34 | resolve('bbb', { 35 | paths: [ 36 | path.join(__dirname, '/node_path/x'), 37 | path.join(__dirname, '/node_path/y') 38 | ], 39 | basedir: __dirname, 40 | isDirectory: isDir 41 | }, function (err, res) { 42 | t.error(err); 43 | t.equal(res, path.join(__dirname, '/node_path/y/bbb/index.js'), 'bbb resolves'); 44 | }); 45 | 46 | resolve('ccc', { 47 | paths: [ 48 | path.join(__dirname, '/node_path/x'), 49 | path.join(__dirname, '/node_path/y') 50 | ], 51 | basedir: __dirname, 52 | isDirectory: isDir 53 | }, function (err, res) { 54 | t.error(err); 55 | t.equal(res, path.join(__dirname, '/node_path/x/ccc/index.js'), 'ccc resolves'); 56 | }); 57 | 58 | // ensure that relative paths still resolve against the regular `node_modules` correctly 59 | resolve('tap', { 60 | paths: [ 61 | 'node_path' 62 | ], 63 | basedir: path.join(__dirname, 'node_path/x'), 64 | isDirectory: isDir 65 | }, function (err, res) { 66 | var root = require('tap/package.json').main; // eslint-disable-line global-require 67 | t.error(err); 68 | t.equal(res.replace('/node_modules/.vlt/··tap@0.4.13/', '/'), path.resolve(__dirname, '..', 'node_modules/tap', root), 'tap resolves'); 69 | }); 70 | }); 71 | -------------------------------------------------------------------------------- /test/node_path/x/aaa/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/node_path/x/aaa/index.js -------------------------------------------------------------------------------- /test/node_path/x/ccc/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/node_path/x/ccc/index.js -------------------------------------------------------------------------------- /test/node_path/y/bbb/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/node_path/y/bbb/index.js -------------------------------------------------------------------------------- /test/node_path/y/ccc/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/node_path/y/ccc/index.js -------------------------------------------------------------------------------- /test/nonstring.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var resolve = require('../'); 3 | 4 | test('nonstring', function (t) { 5 | t.plan(1); 6 | resolve(555, function (err, res, pkg) { 7 | t.ok(err); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /test/pathfilter.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var test = require('tape'); 3 | var resolve = require('../'); 4 | 5 | var resolverDir = path.join(__dirname, '/pathfilter/deep_ref'); 6 | 7 | var pathFilterFactory = function (t) { 8 | return function (pkg, x, remainder) { 9 | t.equal(pkg.version, '1.2.3'); 10 | t.equal(x, path.join(resolverDir, 'node_modules/deep/ref')); 11 | t.equal(remainder, 'ref'); 12 | return 'alt'; 13 | }; 14 | }; 15 | 16 | test('#62: deep module references and the pathFilter', function (t) { 17 | t.test('deep/ref.js', function (st) { 18 | st.plan(3); 19 | 20 | resolve('deep/ref', { basedir: resolverDir }, function (err, res, pkg) { 21 | if (err) st.fail(err); 22 | 23 | st.equal(pkg.version, '1.2.3'); 24 | st.equal(res, path.join(resolverDir, 'node_modules/deep/ref.js')); 25 | }); 26 | 27 | var res = resolve.sync('deep/ref', { basedir: resolverDir }); 28 | st.equal(res, path.join(resolverDir, 'node_modules/deep/ref.js')); 29 | }); 30 | 31 | t.test('deep/deeper/ref', function (st) { 32 | st.plan(4); 33 | 34 | resolve( 35 | 'deep/deeper/ref', 36 | { basedir: resolverDir }, 37 | function (err, res, pkg) { 38 | if (err) t.fail(err); 39 | st.notEqual(pkg, undefined); 40 | st.equal(pkg.version, '1.2.3'); 41 | st.equal(res, path.join(resolverDir, 'node_modules/deep/deeper/ref.js')); 42 | } 43 | ); 44 | 45 | var res = resolve.sync( 46 | 'deep/deeper/ref', 47 | { basedir: resolverDir } 48 | ); 49 | st.equal(res, path.join(resolverDir, 'node_modules/deep/deeper/ref.js')); 50 | }); 51 | 52 | t.test('deep/ref alt', function (st) { 53 | st.plan(8); 54 | 55 | var pathFilter = pathFilterFactory(st); 56 | 57 | var res = resolve.sync( 58 | 'deep/ref', 59 | { basedir: resolverDir, pathFilter: pathFilter } 60 | ); 61 | st.equal(res, path.join(resolverDir, 'node_modules/deep/alt.js')); 62 | 63 | resolve( 64 | 'deep/ref', 65 | { basedir: resolverDir, pathFilter: pathFilter }, 66 | function (err, res, pkg) { 67 | if (err) st.fail(err); 68 | st.equal(res, path.join(resolverDir, 'node_modules/deep/alt.js')); 69 | st.end(); 70 | } 71 | ); 72 | }); 73 | 74 | t.end(); 75 | }); 76 | -------------------------------------------------------------------------------- /test/pathfilter/deep_ref/main.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/pathfilter/deep_ref/main.js -------------------------------------------------------------------------------- /test/pathfilter/deep_ref/node_modules/deep/alt.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/pathfilter/deep_ref/node_modules/deep/alt.js -------------------------------------------------------------------------------- /test/pathfilter/deep_ref/node_modules/deep/deeper/ref.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/pathfilter/deep_ref/node_modules/deep/deeper/ref.js -------------------------------------------------------------------------------- /test/pathfilter/deep_ref/node_modules/deep/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "deep", 3 | "version": "1.2.3" 4 | } 5 | -------------------------------------------------------------------------------- /test/pathfilter/deep_ref/node_modules/deep/ref.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/pathfilter/deep_ref/node_modules/deep/ref.js -------------------------------------------------------------------------------- /test/pathfilter_sync.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var path = require('path'); 3 | var resolve = require('../'); 4 | 5 | test('synchronous pathfilter', function (t) { 6 | var res; 7 | var resolverDir = __dirname + '/pathfilter/deep_ref'; 8 | var pathFilter = function (pkg, x, remainder) { 9 | t.equal(pkg.version, '1.2.3'); 10 | t.equal(x, path.join(resolverDir, 'node_modules', 'deep', 'ref')); 11 | t.equal(remainder, 'ref'); 12 | return 'alt'; 13 | }; 14 | 15 | res = resolve.sync('deep/ref', { basedir: resolverDir }); 16 | t.equal(res, path.join(resolverDir, 'node_modules', 'deep', 'ref.js')); 17 | 18 | res = resolve.sync('deep/deeper/ref', { basedir: resolverDir }); 19 | t.equal(res, path.join(resolverDir, 'node_modules', 'deep', 'deeper', 'ref.js')); 20 | 21 | res = resolve.sync('deep/ref', { basedir: resolverDir, pathFilter: pathFilter }); 22 | t.equal(res, path.join(resolverDir, 'node_modules', 'deep', 'alt.js')); 23 | t.end(); 24 | }); 25 | -------------------------------------------------------------------------------- /test/precedence.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var test = require('tape'); 3 | var resolve = require('../'); 4 | 5 | test('precedence', function (t) { 6 | t.plan(3); 7 | var dir = path.join(__dirname, 'precedence/aaa'); 8 | 9 | resolve('./', { basedir: dir }, function (err, res, pkg) { 10 | t.ifError(err); 11 | t.equal(res, path.join(dir, 'index.js')); 12 | t.equal(pkg.name, 'resolve'); 13 | }); 14 | }); 15 | 16 | test('./ should not load ${dir}.js', function (t) { // eslint-disable-line no-template-curly-in-string 17 | t.plan(1); 18 | var dir = path.join(__dirname, 'precedence/bbb'); 19 | 20 | resolve('./', { basedir: dir }, function (err, res, pkg) { 21 | t.ok(err); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test/precedence/aaa.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/precedence/aaa.js -------------------------------------------------------------------------------- /test/precedence/aaa/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/precedence/aaa/index.js -------------------------------------------------------------------------------- /test/precedence/aaa/main.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/precedence/aaa/main.js -------------------------------------------------------------------------------- /test/precedence/bbb.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/precedence/bbb.js -------------------------------------------------------------------------------- /test/precedence/bbb/main.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/precedence/bbb/main.js -------------------------------------------------------------------------------- /test/resolver.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var fs = require('fs'); 3 | var test = require('tape'); 4 | var resolve = require('../'); 5 | var async = require('../async'); 6 | 7 | test('`./async` entry point', function (t) { 8 | t.equal(resolve, async, '`./async` entry point is the same as `main`'); 9 | t.end(); 10 | }); 11 | 12 | test('async foo', function (t) { 13 | t.plan(12); 14 | var dir = path.join(__dirname, 'resolver'); 15 | 16 | resolve('./foo', { basedir: dir }, function (err, res, pkg) { 17 | if (err) t.fail(err); 18 | t.equal(res, path.join(dir, 'foo.js')); 19 | t.equal(pkg && pkg.name, 'resolve'); 20 | }); 21 | 22 | resolve('./foo.js', { basedir: dir }, function (err, res, pkg) { 23 | if (err) t.fail(err); 24 | t.equal(res, path.join(dir, 'foo.js')); 25 | t.equal(pkg && pkg.name, 'resolve'); 26 | }); 27 | 28 | resolve('./foo', { basedir: dir, 'package': { main: 'resolver' } }, function (err, res, pkg) { 29 | if (err) t.fail(err); 30 | t.equal(res, path.join(dir, 'foo.js')); 31 | t.equal(pkg && pkg.main, 'resolver'); 32 | }); 33 | 34 | resolve('./foo.js', { basedir: dir, 'package': { main: 'resolver' } }, function (err, res, pkg) { 35 | if (err) t.fail(err); 36 | t.equal(res, path.join(dir, 'foo.js')); 37 | t.equal(pkg.main, 'resolver'); 38 | }); 39 | 40 | resolve('./foo', { basedir: dir, filename: path.join(dir, 'baz.js') }, function (err, res) { 41 | if (err) t.fail(err); 42 | t.equal(res, path.join(dir, 'foo.js')); 43 | }); 44 | 45 | resolve('foo', { basedir: dir }, function (err) { 46 | t.equal(err.message, "Cannot find module 'foo' from '" + path.resolve(dir) + "'"); 47 | t.equal(err.code, 'MODULE_NOT_FOUND'); 48 | }); 49 | 50 | // Test that filename is reported as the "from" value when passed. 51 | resolve('foo', { basedir: dir, filename: path.join(dir, 'baz.js') }, function (err) { 52 | t.equal(err.message, "Cannot find module 'foo' from '" + path.join(dir, 'baz.js') + "'"); 53 | }); 54 | }); 55 | 56 | test('bar', function (t) { 57 | t.plan(6); 58 | var dir = path.join(__dirname, 'resolver'); 59 | 60 | resolve('foo', { basedir: dir + '/bar' }, function (err, res, pkg) { 61 | if (err) t.fail(err); 62 | t.equal(res, path.join(dir, 'bar/node_modules/foo/index.js')); 63 | t.equal(pkg, undefined); 64 | }); 65 | 66 | resolve('foo', { basedir: dir + '/bar' }, function (err, res, pkg) { 67 | if (err) t.fail(err); 68 | t.equal(res, path.join(dir, 'bar/node_modules/foo/index.js')); 69 | t.equal(pkg, undefined); 70 | }); 71 | 72 | resolve('foo', { basedir: dir + '/bar', 'package': { main: 'bar' } }, function (err, res, pkg) { 73 | if (err) t.fail(err); 74 | t.equal(res, path.join(dir, 'bar/node_modules/foo/index.js')); 75 | t.equal(pkg.main, 'bar'); 76 | }); 77 | }); 78 | 79 | test('baz', function (t) { 80 | t.plan(4); 81 | var dir = path.join(__dirname, 'resolver'); 82 | 83 | resolve('./baz', { basedir: dir }, function (err, res, pkg) { 84 | if (err) t.fail(err); 85 | t.equal(res, path.join(dir, 'baz/quux.js')); 86 | t.equal(pkg.main, 'quux.js'); 87 | }); 88 | 89 | resolve('./baz', { basedir: dir, 'package': { main: 'resolver' } }, function (err, res, pkg) { 90 | if (err) t.fail(err); 91 | t.equal(res, path.join(dir, 'baz/quux.js')); 92 | t.equal(pkg.main, 'quux.js'); 93 | }); 94 | }); 95 | 96 | test('biz', function (t) { 97 | t.plan(24); 98 | var dir = path.join(__dirname, 'resolver/biz/node_modules'); 99 | 100 | resolve('./grux', { basedir: dir }, function (err, res, pkg) { 101 | if (err) t.fail(err); 102 | t.equal(res, path.join(dir, 'grux/index.js')); 103 | t.equal(pkg, undefined); 104 | }); 105 | 106 | resolve('./grux', { basedir: dir, 'package': { main: 'biz' } }, function (err, res, pkg) { 107 | if (err) t.fail(err); 108 | t.equal(res, path.join(dir, 'grux/index.js')); 109 | t.equal(pkg.main, 'biz'); 110 | }); 111 | 112 | resolve('./garply', { basedir: dir }, function (err, res, pkg) { 113 | if (err) t.fail(err); 114 | t.equal(res, path.join(dir, 'garply/lib/index.js')); 115 | t.equal(pkg.main, './lib'); 116 | }); 117 | 118 | resolve('./garply', { basedir: dir, 'package': { main: 'biz' } }, function (err, res, pkg) { 119 | if (err) t.fail(err); 120 | t.equal(res, path.join(dir, 'garply/lib/index.js')); 121 | t.equal(pkg.main, './lib'); 122 | }); 123 | 124 | resolve('tiv', { basedir: dir + '/grux' }, function (err, res, pkg) { 125 | if (err) t.fail(err); 126 | t.equal(res, path.join(dir, 'tiv/index.js')); 127 | t.equal(pkg, undefined); 128 | }); 129 | 130 | resolve('tiv', { basedir: dir + '/grux', 'package': { main: 'grux' } }, function (err, res, pkg) { 131 | if (err) t.fail(err); 132 | t.equal(res, path.join(dir, 'tiv/index.js')); 133 | t.equal(pkg.main, 'grux'); 134 | }); 135 | 136 | resolve('tiv', { basedir: dir + '/garply' }, function (err, res, pkg) { 137 | if (err) t.fail(err); 138 | t.equal(res, path.join(dir, 'tiv/index.js')); 139 | t.equal(pkg, undefined); 140 | }); 141 | 142 | resolve('tiv', { basedir: dir + '/garply', 'package': { main: './lib' } }, function (err, res, pkg) { 143 | if (err) t.fail(err); 144 | t.equal(res, path.join(dir, 'tiv/index.js')); 145 | t.equal(pkg.main, './lib'); 146 | }); 147 | 148 | resolve('grux', { basedir: dir + '/tiv' }, function (err, res, pkg) { 149 | if (err) t.fail(err); 150 | t.equal(res, path.join(dir, 'grux/index.js')); 151 | t.equal(pkg, undefined); 152 | }); 153 | 154 | resolve('grux', { basedir: dir + '/tiv', 'package': { main: 'tiv' } }, function (err, res, pkg) { 155 | if (err) t.fail(err); 156 | t.equal(res, path.join(dir, 'grux/index.js')); 157 | t.equal(pkg.main, 'tiv'); 158 | }); 159 | 160 | resolve('garply', { basedir: dir + '/tiv' }, function (err, res, pkg) { 161 | if (err) t.fail(err); 162 | t.equal(res, path.join(dir, 'garply/lib/index.js')); 163 | t.equal(pkg.main, './lib'); 164 | }); 165 | 166 | resolve('garply', { basedir: dir + '/tiv', 'package': { main: 'tiv' } }, function (err, res, pkg) { 167 | if (err) t.fail(err); 168 | t.equal(res, path.join(dir, 'garply/lib/index.js')); 169 | t.equal(pkg.main, './lib'); 170 | }); 171 | }); 172 | 173 | test('quux', function (t) { 174 | t.plan(2); 175 | var dir = path.join(__dirname, 'resolver/quux'); 176 | 177 | resolve('./foo', { basedir: dir, 'package': { main: 'quux' } }, function (err, res, pkg) { 178 | if (err) t.fail(err); 179 | t.equal(res, path.join(dir, 'foo/index.js')); 180 | t.equal(pkg.main, 'quux'); 181 | }); 182 | }); 183 | 184 | test('normalize', function (t) { 185 | t.plan(2); 186 | var dir = path.join(__dirname, 'resolver/biz/node_modules/grux'); 187 | 188 | resolve('../grux', { basedir: dir }, function (err, res, pkg) { 189 | if (err) t.fail(err); 190 | t.equal(res, path.join(dir, 'index.js')); 191 | t.equal(pkg, undefined); 192 | }); 193 | }); 194 | 195 | test('cup', function (t) { 196 | t.plan(5); 197 | var dir = path.join(__dirname, 'resolver'); 198 | 199 | resolve('./cup', { basedir: dir, extensions: ['.js', '.coffee'] }, function (err, res) { 200 | if (err) t.fail(err); 201 | t.equal(res, path.join(dir, 'cup.coffee')); 202 | }); 203 | 204 | resolve('./cup.coffee', { basedir: dir }, function (err, res) { 205 | if (err) t.fail(err); 206 | t.equal(res, path.join(dir, 'cup.coffee')); 207 | }); 208 | 209 | resolve('./cup', { basedir: dir, extensions: ['.js'] }, function (err, res) { 210 | t.equal(err.message, "Cannot find module './cup' from '" + path.resolve(dir) + "'"); 211 | t.equal(err.code, 'MODULE_NOT_FOUND'); 212 | }); 213 | 214 | // Test that filename is reported as the "from" value when passed. 215 | resolve('./cup', { basedir: dir, extensions: ['.js'], filename: path.join(dir, 'cupboard.js') }, function (err, res) { 216 | t.equal(err.message, "Cannot find module './cup' from '" + path.join(dir, 'cupboard.js') + "'"); 217 | }); 218 | }); 219 | 220 | test('mug', function (t) { 221 | t.plan(3); 222 | var dir = path.join(__dirname, 'resolver'); 223 | 224 | resolve('./mug', { basedir: dir }, function (err, res) { 225 | if (err) t.fail(err); 226 | t.equal(res, path.join(dir, 'mug.js')); 227 | }); 228 | 229 | resolve('./mug', { basedir: dir, extensions: ['.coffee', '.js'] }, function (err, res) { 230 | if (err) t.fail(err); 231 | t.equal(res, path.join(dir, '/mug.coffee')); 232 | }); 233 | 234 | resolve('./mug', { basedir: dir, extensions: ['.js', '.coffee'] }, function (err, res) { 235 | t.equal(res, path.join(dir, '/mug.js')); 236 | }); 237 | }); 238 | 239 | test('other path', function (t) { 240 | t.plan(6); 241 | var resolverDir = path.join(__dirname, 'resolver'); 242 | var dir = path.join(resolverDir, 'bar'); 243 | var otherDir = path.join(resolverDir, 'other_path'); 244 | 245 | resolve('root', { basedir: dir, paths: [otherDir] }, function (err, res) { 246 | if (err) t.fail(err); 247 | t.equal(res, path.join(resolverDir, 'other_path/root.js')); 248 | }); 249 | 250 | resolve('lib/other-lib', { basedir: dir, paths: [otherDir] }, function (err, res) { 251 | if (err) t.fail(err); 252 | t.equal(res, path.join(resolverDir, 'other_path/lib/other-lib.js')); 253 | }); 254 | 255 | resolve('root', { basedir: dir }, function (err, res) { 256 | t.equal(err.message, "Cannot find module 'root' from '" + path.resolve(dir) + "'"); 257 | t.equal(err.code, 'MODULE_NOT_FOUND'); 258 | }); 259 | 260 | resolve('zzz', { basedir: dir, paths: [otherDir] }, function (err, res) { 261 | t.equal(err.message, "Cannot find module 'zzz' from '" + path.resolve(dir) + "'"); 262 | t.equal(err.code, 'MODULE_NOT_FOUND'); 263 | }); 264 | }); 265 | 266 | test('path iterator', function (t) { 267 | t.plan(2); 268 | 269 | var resolverDir = path.join(__dirname, 'resolver'); 270 | 271 | var exactIterator = function (x, start, getPackageCandidates, opts) { 272 | return [path.join(resolverDir, x)]; 273 | }; 274 | 275 | resolve('baz', { packageIterator: exactIterator }, function (err, res, pkg) { 276 | if (err) t.fail(err); 277 | t.equal(res, path.join(resolverDir, 'baz/quux.js')); 278 | t.equal(pkg && pkg.name, 'baz'); 279 | }); 280 | }); 281 | 282 | test('empty main', function (t) { 283 | t.plan(1); 284 | 285 | var resolverDir = path.join(__dirname, 'resolver'); 286 | var dir = path.join(resolverDir, 'empty_main'); 287 | 288 | resolve('./empty_main', { basedir: resolverDir }, function (err, res, pkg) { 289 | if (err) t.fail(err); 290 | t.equal(res, path.join(dir, 'index.js')); 291 | }); 292 | }); 293 | 294 | test('incorrect main', function (t) { 295 | t.plan(1); 296 | 297 | var resolverDir = path.join(__dirname, 'resolver'); 298 | var dir = path.join(resolverDir, 'incorrect_main'); 299 | 300 | resolve('./incorrect_main', { basedir: resolverDir }, function (err, res, pkg) { 301 | if (err) t.fail(err); 302 | t.equal(res, path.join(dir, 'index.js')); 303 | }); 304 | }); 305 | 306 | test('missing index', function (t) { 307 | t.plan(2); 308 | 309 | var resolverDir = path.join(__dirname, 'resolver'); 310 | resolve('./missing_index', { basedir: resolverDir }, function (err, res, pkg) { 311 | t.ok(err instanceof Error); 312 | t.equal(err && err.code, 'INCORRECT_PACKAGE_MAIN', 'error has correct error code'); 313 | }); 314 | }); 315 | 316 | test('missing main', function (t) { 317 | t.plan(1); 318 | 319 | var resolverDir = path.join(__dirname, 'resolver'); 320 | var dir = path.join(resolverDir, 'missing_main'); 321 | 322 | resolve('./missing_main', { basedir: resolverDir }, function (err, res, pkg) { 323 | if (err) t.fail(err); 324 | t.equal(res, path.join(dir, 'index.js')); 325 | }); 326 | }); 327 | 328 | test('null main', function (t) { 329 | t.plan(1); 330 | 331 | var resolverDir = path.join(__dirname, 'resolver'); 332 | var dir = path.join(resolverDir, 'null_main'); 333 | 334 | resolve('./null_main', { basedir: resolverDir }, function (err, res, pkg) { 335 | if (err) t.fail(err); 336 | t.equal(res, path.join(dir, 'index.js')); 337 | }); 338 | }); 339 | 340 | test('main: false', function (t) { 341 | t.plan(2); 342 | 343 | var basedir = path.join(__dirname, 'resolver'); 344 | var dir = path.join(basedir, 'false_main'); 345 | resolve('./false_main', { basedir: basedir }, function (err, res, pkg) { 346 | if (err) t.fail(err); 347 | t.equal( 348 | res, 349 | path.join(dir, 'index.js'), 350 | '`"main": false`: resolves to `index.js`' 351 | ); 352 | t.deepEqual(pkg, { 353 | name: 'false_main', 354 | main: false 355 | }); 356 | }); 357 | }); 358 | 359 | test('without basedir', function (t) { 360 | t.plan(1); 361 | 362 | var dir = path.join(__dirname, 'resolver/without_basedir'); 363 | var tester = require(path.join(dir, 'main.js')); // eslint-disable-line global-require 364 | 365 | tester(t, function (err, res, pkg) { 366 | if (err) { 367 | t.fail(err); 368 | } else { 369 | t.equal(res, path.join(dir, 'node_modules/mymodule.js')); 370 | } 371 | }); 372 | }); 373 | 374 | test('#52 - incorrectly resolves module-paths like "./someFolder/" when there is a file of the same name', function (t) { 375 | t.plan(2); 376 | 377 | var dir = path.join(__dirname, 'resolver'); 378 | 379 | resolve('./foo', { basedir: path.join(dir, 'same_names') }, function (err, res, pkg) { 380 | if (err) t.fail(err); 381 | t.equal(res, path.join(dir, 'same_names/foo.js')); 382 | }); 383 | 384 | resolve('./foo/', { basedir: path.join(dir, 'same_names') }, function (err, res, pkg) { 385 | if (err) t.fail(err); 386 | t.equal(res, path.join(dir, 'same_names/foo/index.js')); 387 | }); 388 | }); 389 | 390 | test('#211 - incorrectly resolves module-paths like "." when from inside a folder with a sibling file of the same name', function (t) { 391 | t.plan(2); 392 | 393 | var dir = path.join(__dirname, 'resolver'); 394 | 395 | resolve('./', { basedir: path.join(dir, 'same_names/foo') }, function (err, res, pkg) { 396 | if (err) t.fail(err); 397 | t.equal(res, path.join(dir, 'same_names/foo/index.js')); 398 | }); 399 | 400 | resolve('.', { basedir: path.join(dir, 'same_names/foo') }, function (err, res, pkg) { 401 | if (err) t.fail(err); 402 | t.equal(res, path.join(dir, 'same_names/foo/index.js')); 403 | }); 404 | }); 405 | 406 | test('async: #121 - treating an existing file as a dir when no basedir', function (t) { 407 | var testFile = path.basename(__filename); 408 | 409 | t.test('sanity check', function (st) { 410 | st.plan(1); 411 | resolve('./' + testFile, function (err, res, pkg) { 412 | if (err) t.fail(err); 413 | st.equal(res, __filename, 'sanity check'); 414 | }); 415 | }); 416 | 417 | t.test('with a fake directory', function (st) { 418 | st.plan(4); 419 | 420 | resolve('./' + testFile + '/blah', function (err, res, pkg) { 421 | st.ok(err, 'there is an error'); 422 | st.notOk(res, 'no result'); 423 | 424 | st.equal(err && err.code, 'MODULE_NOT_FOUND', 'error code matches require.resolve'); 425 | st.equal( 426 | err && err.message, 427 | 'Cannot find module \'./' + testFile + '/blah\' from \'' + __dirname + '\'', 428 | 'can not find nonexistent module' 429 | ); 430 | st.end(); 431 | }); 432 | }); 433 | 434 | t.end(); 435 | }); 436 | 437 | test('async dot main', function (t) { 438 | var start = new Date(); 439 | t.plan(3); 440 | resolve('./resolver/dot_main', function (err, ret) { 441 | t.notOk(err); 442 | t.equal(ret, path.join(__dirname, 'resolver/dot_main/index.js')); 443 | t.ok(new Date() - start < 50, 'resolve.sync timedout'); 444 | t.end(); 445 | }); 446 | }); 447 | 448 | test('async dot slash main', function (t) { 449 | var start = new Date(); 450 | t.plan(3); 451 | resolve('./resolver/dot_slash_main', function (err, ret) { 452 | t.notOk(err); 453 | t.equal(ret, path.join(__dirname, 'resolver/dot_slash_main/index.js')); 454 | t.ok(new Date() - start < 50, 'resolve.sync timedout'); 455 | t.end(); 456 | }); 457 | }); 458 | 459 | test('not a directory', function (t) { 460 | t.plan(6); 461 | var path = './foo'; 462 | resolve(path, { basedir: __filename }, function (err, res, pkg) { 463 | t.ok(err, 'a non-directory errors'); 464 | t.equal(arguments.length, 1); 465 | t.equal(res, undefined); 466 | t.equal(pkg, undefined); 467 | 468 | t.equal(err && err.message, 'Provided basedir "' + __filename + '" is not a directory, or a symlink to a directory'); 469 | t.equal(err && err.code, 'INVALID_BASEDIR'); 470 | }); 471 | }); 472 | 473 | test('non-string "main" field in package.json', function (t) { 474 | t.plan(5); 475 | 476 | var dir = path.join(__dirname, 'resolver'); 477 | resolve('./invalid_main', { basedir: dir }, function (err, res, pkg) { 478 | t.ok(err, 'errors on non-string main'); 479 | t.equal(err.message, 'package “invalid_main” `main` must be a string'); 480 | t.equal(err.code, 'INVALID_PACKAGE_MAIN'); 481 | t.equal(res, undefined, 'res is undefined'); 482 | t.equal(pkg, undefined, 'pkg is undefined'); 483 | }); 484 | }); 485 | 486 | test('non-string "main" field in package.json', function (t) { 487 | t.plan(5); 488 | 489 | var dir = path.join(__dirname, 'resolver'); 490 | resolve('./invalid_main', { basedir: dir }, function (err, res, pkg) { 491 | t.ok(err, 'errors on non-string main'); 492 | t.equal(err.message, 'package “invalid_main” `main` must be a string'); 493 | t.equal(err.code, 'INVALID_PACKAGE_MAIN'); 494 | t.equal(res, undefined, 'res is undefined'); 495 | t.equal(pkg, undefined, 'pkg is undefined'); 496 | }); 497 | }); 498 | 499 | test('browser field in package.json', function (t) { 500 | t.plan(3); 501 | 502 | var dir = path.join(__dirname, 'resolver'); 503 | resolve( 504 | './browser_field', 505 | { 506 | basedir: dir, 507 | packageFilter: function packageFilter(pkg) { 508 | if (pkg.browser) { 509 | pkg.main = pkg.browser; // eslint-disable-line no-param-reassign 510 | delete pkg.browser; // eslint-disable-line no-param-reassign 511 | } 512 | return pkg; 513 | } 514 | }, 515 | function (err, res, pkg) { 516 | if (err) t.fail(err); 517 | t.equal(res, path.join(dir, 'browser_field', 'b.js')); 518 | t.equal(pkg && pkg.main, 'b'); 519 | t.equal(pkg && pkg.browser, undefined); 520 | } 521 | ); 522 | }); 523 | 524 | test('absolute paths', function (t) { 525 | t.plan(4); 526 | 527 | var extensionless = __filename.slice(0, -path.extname(__filename).length); 528 | 529 | resolve(__filename, function (err, res) { 530 | t.equal( 531 | res, 532 | __filename, 533 | 'absolute path to this file resolves' 534 | ); 535 | }); 536 | resolve(extensionless, function (err, res) { 537 | t.equal( 538 | res, 539 | __filename, 540 | 'extensionless absolute path to this file resolves' 541 | ); 542 | }); 543 | resolve(__filename, { basedir: process.cwd() }, function (err, res) { 544 | t.equal( 545 | res, 546 | __filename, 547 | 'absolute path to this file with a basedir resolves' 548 | ); 549 | }); 550 | resolve(extensionless, { basedir: process.cwd() }, function (err, res) { 551 | t.equal( 552 | res, 553 | __filename, 554 | 'extensionless absolute path to this file with a basedir resolves' 555 | ); 556 | }); 557 | }); 558 | 559 | var malformedDir = path.join(__dirname, 'resolver/malformed_package_json'); 560 | test('malformed package.json', { skip: !fs.existsSync(malformedDir) }, function (t) { 561 | /* eslint operator-linebreak: ["error", "before"], function-paren-newline: "off" */ 562 | t.plan( 563 | (3 * 3) // 3 sets of 3 assertions in the final callback 564 | + 2 // 1 readPackage call with malformed package.json 565 | ); 566 | 567 | var basedir = malformedDir; 568 | var expected = path.join(basedir, 'index.js'); 569 | 570 | resolve('./index.js', { basedir: basedir }, function (err, res, pkg) { 571 | t.error(err, 'no error'); 572 | t.equal(res, expected, 'malformed package.json is silently ignored'); 573 | t.equal(pkg, undefined, 'malformed package.json gives an undefined `pkg` argument'); 574 | }); 575 | 576 | resolve( 577 | './index.js', 578 | { 579 | basedir: basedir, 580 | packageFilter: function (pkg, pkgfile, dir) { 581 | t.fail('should not reach here'); 582 | } 583 | }, 584 | function (err, res, pkg) { 585 | t.error(err, 'with packageFilter: no error'); 586 | t.equal(res, expected, 'with packageFilter: malformed package.json is silently ignored'); 587 | t.equal(pkg, undefined, 'with packageFilter: malformed package.json gives an undefined `pkg` argument'); 588 | } 589 | ); 590 | 591 | resolve( 592 | './index.js', 593 | { 594 | basedir: basedir, 595 | readPackage: function (readFile, pkgfile, cb) { 596 | t.equal(pkgfile, path.join(basedir, 'package.json'), 'readPackageSync: `pkgfile` is package.json path'); 597 | readFile(pkgfile, function (err, result) { 598 | try { 599 | cb(null, JSON.parse(result)); 600 | } catch (e) { 601 | t.ok(e instanceof SyntaxError, 'readPackage: malformed package.json parses as a syntax error'); 602 | cb(e); 603 | } 604 | }); 605 | } 606 | }, 607 | function (err, res, pkg) { 608 | t.error(err, 'with readPackage: no error'); 609 | t.equal(res, expected, 'with readPackage: malformed package.json is silently ignored'); 610 | t.equal(pkg, undefined, 'with readPackage: malformed package.json gives an undefined `pkg` argument'); 611 | } 612 | ); 613 | }); 614 | -------------------------------------------------------------------------------- /test/resolver/bar/node_modules/foo/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/resolver/bar/node_modules/foo/index.js -------------------------------------------------------------------------------- /test/resolver/baz/doom.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/resolver/baz/doom.js -------------------------------------------------------------------------------- /test/resolver/baz/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "baz", 3 | "main": "quux.js" 4 | } 5 | -------------------------------------------------------------------------------- /test/resolver/baz/quux.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/resolver/baz/quux.js -------------------------------------------------------------------------------- /test/resolver/biz/node_modules/garply/lib/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/resolver/biz/node_modules/garply/lib/index.js -------------------------------------------------------------------------------- /test/resolver/biz/node_modules/garply/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main" : "./lib" 3 | } 4 | -------------------------------------------------------------------------------- /test/resolver/biz/node_modules/grux/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/resolver/biz/node_modules/grux/index.js -------------------------------------------------------------------------------- /test/resolver/biz/node_modules/tiv/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/resolver/biz/node_modules/tiv/index.js -------------------------------------------------------------------------------- /test/resolver/browser_field/a.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/resolver/browser_field/a.js -------------------------------------------------------------------------------- /test/resolver/browser_field/b.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/resolver/browser_field/b.js -------------------------------------------------------------------------------- /test/resolver/browser_field/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "browser_field", 3 | "main": "a", 4 | "browser": "b" 5 | } 6 | -------------------------------------------------------------------------------- /test/resolver/cup.coffee: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /test/resolver/dot_main/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/resolver/dot_main/index.js -------------------------------------------------------------------------------- /test/resolver/dot_main/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "." 3 | } 4 | -------------------------------------------------------------------------------- /test/resolver/dot_slash_main/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/resolver/dot_slash_main/index.js -------------------------------------------------------------------------------- /test/resolver/dot_slash_main/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "./" 3 | } 4 | -------------------------------------------------------------------------------- /test/resolver/empty_main/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/resolver/empty_main/index.js -------------------------------------------------------------------------------- /test/resolver/empty_main/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "" 3 | } -------------------------------------------------------------------------------- /test/resolver/false_main/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/resolver/false_main/index.js -------------------------------------------------------------------------------- /test/resolver/false_main/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "false_main", 3 | "main": false 4 | } 5 | -------------------------------------------------------------------------------- /test/resolver/foo.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/resolver/foo.js -------------------------------------------------------------------------------- /test/resolver/incorrect_main/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/resolver/incorrect_main/index.js -------------------------------------------------------------------------------- /test/resolver/incorrect_main/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "wrong.js" 3 | } 4 | -------------------------------------------------------------------------------- /test/resolver/invalid_main/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "invalid_main", 3 | "main": [ 4 | "why is this a thing", 5 | "srsly omg wtf" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /test/resolver/malformed_package_json/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/resolver/malformed_package_json/index.js -------------------------------------------------------------------------------- /test/resolver/malformed_package_json/package.json: -------------------------------------------------------------------------------- 1 | { 2 | -------------------------------------------------------------------------------- /test/resolver/missing_index/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "index.js" 3 | } -------------------------------------------------------------------------------- /test/resolver/missing_main/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/resolver/missing_main/index.js -------------------------------------------------------------------------------- /test/resolver/missing_main/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "notmain": "index.js" 3 | } -------------------------------------------------------------------------------- /test/resolver/mug.coffee: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/resolver/mug.coffee -------------------------------------------------------------------------------- /test/resolver/mug.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/resolver/mug.js -------------------------------------------------------------------------------- /test/resolver/multirepo/.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /test/resolver/multirepo/lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [ 3 | "packages/*" 4 | ], 5 | "version": "0.0.0" 6 | } 7 | -------------------------------------------------------------------------------- /test/resolver/multirepo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ljharb-monorepo-symlink-test", 3 | "private": true, 4 | "version": "0.0.0", 5 | "description": "", 6 | "main": "index.js", 7 | "scripts": { 8 | "postinstall": "lerna bootstrap", 9 | "test": "node packages/package-a" 10 | }, 11 | "author": "", 12 | "license": "MIT", 13 | "dependencies": { 14 | "jquery": "^3.3.1", 15 | "resolve": "../../../" 16 | }, 17 | "devDependencies": { 18 | "lerna": "^3.4.3" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/resolver/multirepo/packages/package-a/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var assert = require('assert'); 4 | var path = require('path'); 5 | var resolve = require('resolve'); 6 | 7 | var basedir = __dirname + '/node_modules/@my-scope/package-b'; 8 | 9 | var expected = path.join(__dirname, '../../node_modules/jquery/dist/jquery.js'); 10 | 11 | /* 12 | * preserveSymlinks === false 13 | * will search NPM package from 14 | * - packages/package-b/node_modules 15 | * - packages/node_modules 16 | * - node_modules 17 | */ 18 | assert.equal(resolve.sync('jquery', { basedir: basedir, preserveSymlinks: false }), expected); 19 | assert.equal(resolve.sync('../../node_modules/jquery', { basedir: basedir, preserveSymlinks: false }), expected); 20 | 21 | /* 22 | * preserveSymlinks === true 23 | * will search NPM package from 24 | * - packages/package-a/node_modules/@my-scope/packages/package-b/node_modules 25 | * - packages/package-a/node_modules/@my-scope/packages/node_modules 26 | * - packages/package-a/node_modules/@my-scope/node_modules 27 | * - packages/package-a/node_modules/node_modules 28 | * - packages/package-a/node_modules 29 | * - packages/node_modules 30 | * - node_modules 31 | */ 32 | assert.equal(resolve.sync('jquery', { basedir: basedir, preserveSymlinks: true }), expected); 33 | assert.equal(resolve.sync('../../../../../node_modules/jquery', { basedir: basedir, preserveSymlinks: true }), expected); 34 | 35 | console.log(' * all monorepo paths successfully resolved through symlinks'); 36 | -------------------------------------------------------------------------------- /test/resolver/multirepo/packages/package-a/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@my-scope/package-a", 3 | "version": "0.0.0", 4 | "private": true, 5 | "description": "", 6 | "license": "MIT", 7 | "main": "index.js", 8 | "scripts": { 9 | "test": "echo \"Error: run tests from root\" && exit 1" 10 | }, 11 | "dependencies": { 12 | "@my-scope/package-b": "^0.0.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/resolver/multirepo/packages/package-b/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/resolver/multirepo/packages/package-b/index.js -------------------------------------------------------------------------------- /test/resolver/multirepo/packages/package-b/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@my-scope/package-b", 3 | "private": true, 4 | "version": "0.0.0", 5 | "description": "", 6 | "license": "MIT", 7 | "main": "index.js", 8 | "scripts": { 9 | "test": "echo \"Error: run tests from root\" && exit 1" 10 | }, 11 | "dependencies": { 12 | "@my-scope/package-a": "^0.0.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/resolver/nested_symlinks/common/node_modules/buffer/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/resolver/nested_symlinks/common/node_modules/buffer/index.js -------------------------------------------------------------------------------- /test/resolver/nested_symlinks/common/node_modules/buffer/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "fake buffer shim", 3 | "main": "index.js", 4 | "name": "buffer", 5 | "version": "0.0.0", 6 | "private": true 7 | } 8 | -------------------------------------------------------------------------------- /test/resolver/nested_symlinks/mylib/async.js: -------------------------------------------------------------------------------- 1 | var a = require.resolve('buffer/').replace(process.cwd(), '$CWD'); 2 | var b; 3 | var c; 4 | 5 | var test = function test() { 6 | console.log(a, ': require.resolve, preserveSymlinks ' + (process.execArgv.indexOf('preserve-symlinks') > -1 ? 'true' : 'false')); 7 | console.log(b, ': preserveSymlinks true'); 8 | console.log(c, ': preserveSymlinks false'); 9 | 10 | if (a !== b && a !== c) { 11 | throw 'async: no match'; 12 | } 13 | console.log('async: success! a matched either b or c\n'); 14 | }; 15 | 16 | require('resolve')('buffer/', { preserveSymlinks: true }, function (err, result) { 17 | if (err) { throw err; } 18 | b = result.replace(process.cwd(), '$CWD'); 19 | if (b && c) { test(); } 20 | }); 21 | require('resolve')('buffer/', { preserveSymlinks: false }, function (err, result) { 22 | if (err) { throw err; } 23 | c = result.replace(process.cwd(), '$CWD'); 24 | if (b && c) { test(); } 25 | }); 26 | 27 | -------------------------------------------------------------------------------- /test/resolver/nested_symlinks/mylib/node_modules/buffer: -------------------------------------------------------------------------------- 1 | ../../common/node_modules/buffer -------------------------------------------------------------------------------- /test/resolver/nested_symlinks/mylib/node_modules/resolve: -------------------------------------------------------------------------------- 1 | ../../../../.. -------------------------------------------------------------------------------- /test/resolver/nested_symlinks/mylib/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mylib", 3 | "version": "0.0.0", 4 | "description": "", 5 | "private": true, 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "buffer": "*" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/resolver/nested_symlinks/mylib/sync.js: -------------------------------------------------------------------------------- 1 | var a = require.resolve('buffer/').replace(process.cwd(), '$CWD'); 2 | var b = require('resolve').sync('buffer/', { preserveSymlinks: true }).replace(process.cwd(), '$CWD'); 3 | var c = require('resolve').sync('buffer/', { preserveSymlinks: false }).replace(process.cwd(), '$CWD'); 4 | 5 | console.log(a, ': require.resolve, preserveSymlinks ' + (process.execArgv.indexOf('preserve-symlinks') > -1 ? 'true' : 'false')); 6 | console.log(b, ': preserveSymlinks true'); 7 | console.log(c, ': preserveSymlinks false'); 8 | 9 | if (a !== b && a !== c) { 10 | throw 'sync: no match'; 11 | } 12 | console.log('sync: success! a matched either b or c\n'); 13 | -------------------------------------------------------------------------------- /test/resolver/null_main/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/resolver/null_main/index.js -------------------------------------------------------------------------------- /test/resolver/null_main/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": null 3 | } -------------------------------------------------------------------------------- /test/resolver/other_path/lib/other-lib.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/resolver/other_path/lib/other-lib.js -------------------------------------------------------------------------------- /test/resolver/other_path/root.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/resolver/other_path/root.js -------------------------------------------------------------------------------- /test/resolver/punycode/node_modules/punycode/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/resolver/punycode/node_modules/punycode/index.js -------------------------------------------------------------------------------- /test/resolver/quux/foo/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/resolver/quux/foo/index.js -------------------------------------------------------------------------------- /test/resolver/same_names/foo.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/resolver/same_names/foo.js -------------------------------------------------------------------------------- /test/resolver/same_names/foo/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/resolver/same_names/foo/index.js -------------------------------------------------------------------------------- /test/resolver/symlinked/.gitignore: -------------------------------------------------------------------------------- 1 | symlink 2 | -------------------------------------------------------------------------------- /test/resolver/symlinked/_/.gitignore: -------------------------------------------------------------------------------- 1 | !node_modules 2 | -------------------------------------------------------------------------------- /test/resolver/symlinked/_/node_modules/foo.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/resolver/symlinked/_/node_modules/foo.js -------------------------------------------------------------------------------- /test/resolver/symlinked/_/node_modules/package: -------------------------------------------------------------------------------- 1 | ../../package -------------------------------------------------------------------------------- /test/resolver/symlinked/_/symlink_target/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/resolver/symlinked/_/symlink_target/.gitkeep -------------------------------------------------------------------------------- /test/resolver/symlinked/package/bar.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/resolver/symlinked/package/bar.js -------------------------------------------------------------------------------- /test/resolver/symlinked/package/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "bar.js" 3 | } -------------------------------------------------------------------------------- /test/resolver/without_basedir/main.js: -------------------------------------------------------------------------------- 1 | var resolve = require('../../../'); 2 | 3 | module.exports = function (t, cb) { 4 | resolve('mymodule', null, cb); 5 | }; 6 | -------------------------------------------------------------------------------- /test/resolver/without_basedir/node_modules/mymodule.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/resolver/without_basedir/node_modules/mymodule.js -------------------------------------------------------------------------------- /test/resolver_sync.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var fs = require('fs'); 3 | var test = require('tape'); 4 | 5 | var resolve = require('../'); 6 | var sync = require('../sync'); 7 | 8 | var requireResolveSupportsPaths = require.resolve.length > 1 9 | && !(/^v12\.[012]\./).test(process.version); // broken in v12.0-12.2, see https://github.com/nodejs/node/issues/27794 10 | 11 | var requireResolveDefaultPathsBroken = (/^v8\.9\.|^v9\.[01]\.0|^v9\.2\./).test(process.version); 12 | // broken in node v8.9.x, v9.0, v9.1, v9.2.x. see https://github.com/nodejs/node/pull/17113 13 | 14 | test('`./sync` entry point', function (t) { 15 | t.equal(resolve.sync, sync, '`./sync` entry point is the same as `.sync` on `main`'); 16 | t.end(); 17 | }); 18 | 19 | test('foo', function (t) { 20 | var dir = path.join(__dirname, 'resolver'); 21 | 22 | t.equal( 23 | resolve.sync('./foo', { basedir: dir }), 24 | path.join(dir, 'foo.js'), 25 | './foo' 26 | ); 27 | if (requireResolveSupportsPaths) { 28 | t.equal( 29 | resolve.sync('./foo', { basedir: dir }), 30 | require.resolve('./foo', { paths: [dir] }), 31 | './foo: resolve.sync === require.resolve' 32 | ); 33 | } 34 | 35 | t.equal( 36 | resolve.sync('./foo.js', { basedir: dir }), 37 | path.join(dir, 'foo.js'), 38 | './foo.js' 39 | ); 40 | if (requireResolveSupportsPaths) { 41 | t.equal( 42 | resolve.sync('./foo.js', { basedir: dir }), 43 | require.resolve('./foo.js', { paths: [dir] }), 44 | './foo.js: resolve.sync === require.resolve' 45 | ); 46 | } 47 | 48 | t.equal( 49 | resolve.sync('./foo.js', { basedir: dir, filename: path.join(dir, 'bar.js') }), 50 | path.join(dir, 'foo.js') 51 | ); 52 | 53 | t.throws(function () { 54 | resolve.sync('foo', { basedir: dir }); 55 | }); 56 | 57 | // Test that filename is reported as the "from" value when passed. 58 | t.throws( 59 | function () { 60 | resolve.sync('foo', { basedir: dir, filename: path.join(dir, 'bar.js') }); 61 | }, 62 | { 63 | name: 'Error', 64 | message: "Cannot find module 'foo' from '" + path.join(dir, 'bar.js') + "'" 65 | } 66 | ); 67 | 68 | t.end(); 69 | }); 70 | 71 | test('bar', function (t) { 72 | var dir = path.join(__dirname, 'resolver'); 73 | 74 | var basedir = path.join(dir, 'bar'); 75 | 76 | t.equal( 77 | resolve.sync('foo', { basedir: basedir }), 78 | path.join(dir, 'bar/node_modules/foo/index.js'), 79 | 'foo in bar' 80 | ); 81 | if (!requireResolveDefaultPathsBroken && requireResolveSupportsPaths) { 82 | t.equal( 83 | resolve.sync('foo', { basedir: basedir }), 84 | require.resolve('foo', { paths: [basedir] }), 85 | 'foo in bar: resolve.sync === require.resolve' 86 | ); 87 | } 88 | 89 | t.end(); 90 | }); 91 | 92 | test('baz', function (t) { 93 | var dir = path.join(__dirname, 'resolver'); 94 | 95 | t.equal( 96 | resolve.sync('./baz', { basedir: dir }), 97 | path.join(dir, 'baz/quux.js'), 98 | './baz' 99 | ); 100 | if (requireResolveSupportsPaths) { 101 | t.equal( 102 | resolve.sync('./baz', { basedir: dir }), 103 | require.resolve('./baz', { paths: [dir] }), 104 | './baz: resolve.sync === require.resolve' 105 | ); 106 | } 107 | 108 | t.end(); 109 | }); 110 | 111 | test('biz', function (t) { 112 | var dir = path.join(__dirname, 'resolver/biz/node_modules'); 113 | 114 | t.equal( 115 | resolve.sync('./grux', { basedir: dir }), 116 | path.join(dir, 'grux/index.js') 117 | ); 118 | if (requireResolveSupportsPaths) { 119 | t.equal( 120 | resolve.sync('./grux', { basedir: dir }), 121 | require.resolve('./grux', { paths: [dir] }), 122 | './grux: resolve.sync === require.resolve' 123 | ); 124 | } 125 | 126 | var tivDir = path.join(dir, 'grux'); 127 | t.equal( 128 | resolve.sync('tiv', { basedir: tivDir }), 129 | path.join(dir, 'tiv/index.js') 130 | ); 131 | if (!requireResolveDefaultPathsBroken && requireResolveSupportsPaths) { 132 | t.equal( 133 | resolve.sync('tiv', { basedir: tivDir }), 134 | require.resolve('tiv', { paths: [tivDir] }), 135 | 'tiv: resolve.sync === require.resolve' 136 | ); 137 | } 138 | 139 | var gruxDir = path.join(dir, 'tiv'); 140 | t.equal( 141 | resolve.sync('grux', { basedir: gruxDir }), 142 | path.join(dir, 'grux/index.js') 143 | ); 144 | if (!requireResolveDefaultPathsBroken && requireResolveSupportsPaths) { 145 | t.equal( 146 | resolve.sync('grux', { basedir: gruxDir }), 147 | require.resolve('grux', { paths: [gruxDir] }), 148 | 'grux: resolve.sync === require.resolve' 149 | ); 150 | } 151 | 152 | t.end(); 153 | }); 154 | 155 | test('normalize', function (t) { 156 | var dir = path.join(__dirname, 'resolver/biz/node_modules/grux'); 157 | 158 | t.equal( 159 | resolve.sync('../grux', { basedir: dir }), 160 | path.join(dir, 'index.js') 161 | ); 162 | if (requireResolveSupportsPaths) { 163 | t.equal( 164 | resolve.sync('../grux', { basedir: dir }), 165 | require.resolve('../grux', { paths: [dir] }), 166 | '../grux: resolve.sync === require.resolve' 167 | ); 168 | } 169 | 170 | t.end(); 171 | }); 172 | 173 | test('cup', function (t) { 174 | var dir = path.join(__dirname, 'resolver'); 175 | 176 | t.equal( 177 | resolve.sync('./cup', { 178 | basedir: dir, 179 | extensions: ['.js', '.coffee'] 180 | }), 181 | path.join(dir, 'cup.coffee'), 182 | './cup -> ./cup.coffee' 183 | ); 184 | 185 | t.equal( 186 | resolve.sync('./cup.coffee', { basedir: dir }), 187 | path.join(dir, 'cup.coffee'), 188 | './cup.coffee' 189 | ); 190 | 191 | t.throws(function () { 192 | resolve.sync('./cup', { 193 | basedir: dir, 194 | extensions: ['.js'] 195 | }); 196 | }); 197 | 198 | if (requireResolveSupportsPaths) { 199 | t.equal( 200 | resolve.sync('./cup.coffee', { basedir: dir, extensions: ['.js', '.coffee'] }), 201 | require.resolve('./cup.coffee', { paths: [dir] }), 202 | './cup.coffee: resolve.sync === require.resolve' 203 | ); 204 | } 205 | 206 | t.end(); 207 | }); 208 | 209 | test('mug', function (t) { 210 | var dir = path.join(__dirname, 'resolver'); 211 | 212 | t.equal( 213 | resolve.sync('./mug', { basedir: dir }), 214 | path.join(dir, 'mug.js'), 215 | './mug -> ./mug.js' 216 | ); 217 | if (requireResolveSupportsPaths) { 218 | t.equal( 219 | resolve.sync('./mug', { basedir: dir }), 220 | require.resolve('./mug', { paths: [dir] }), 221 | './mug: resolve.sync === require.resolve' 222 | ); 223 | } 224 | 225 | t.equal( 226 | resolve.sync('./mug', { 227 | basedir: dir, 228 | extensions: ['.coffee', '.js'] 229 | }), 230 | path.join(dir, 'mug.coffee'), 231 | './mug -> ./mug.coffee' 232 | ); 233 | 234 | t.equal( 235 | resolve.sync('./mug', { 236 | basedir: dir, 237 | extensions: ['.js', '.coffee'] 238 | }), 239 | path.join(dir, 'mug.js'), 240 | './mug -> ./mug.js' 241 | ); 242 | 243 | t.end(); 244 | }); 245 | 246 | test('other path', function (t) { 247 | var resolverDir = path.join(__dirname, 'resolver'); 248 | var dir = path.join(resolverDir, 'bar'); 249 | var otherDir = path.join(resolverDir, 'other_path'); 250 | 251 | t.equal( 252 | resolve.sync('root', { 253 | basedir: dir, 254 | paths: [otherDir] 255 | }), 256 | path.join(resolverDir, 'other_path/root.js') 257 | ); 258 | 259 | t.equal( 260 | resolve.sync('lib/other-lib', { 261 | basedir: dir, 262 | paths: [otherDir] 263 | }), 264 | path.join(resolverDir, 'other_path/lib/other-lib.js') 265 | ); 266 | 267 | t.throws(function () { 268 | resolve.sync('root', { basedir: dir }); 269 | }); 270 | 271 | t.throws(function () { 272 | resolve.sync('zzz', { 273 | basedir: dir, 274 | paths: [otherDir] 275 | }); 276 | }); 277 | 278 | t.end(); 279 | }); 280 | 281 | test('path iterator', function (t) { 282 | var resolverDir = path.join(__dirname, 'resolver'); 283 | 284 | var exactIterator = function (x, start, getPackageCandidates, opts) { 285 | return [path.join(resolverDir, x)]; 286 | }; 287 | 288 | t.equal( 289 | resolve.sync('baz', { packageIterator: exactIterator }), 290 | path.join(resolverDir, 'baz/quux.js') 291 | ); 292 | 293 | t.end(); 294 | }); 295 | 296 | test('incorrect main', function (t) { 297 | var resolverDir = path.join(__dirname, 'resolver'); 298 | var dir = path.join(resolverDir, 'incorrect_main'); 299 | 300 | t.equal( 301 | resolve.sync('./incorrect_main', { basedir: resolverDir }), 302 | path.join(dir, 'index.js') 303 | ); 304 | if (requireResolveSupportsPaths) { 305 | t.equal( 306 | resolve.sync('./incorrect_main', { basedir: resolverDir }), 307 | require.resolve('./incorrect_main', { paths: [resolverDir] }), 308 | './incorrect_main: resolve.sync === require.resolve' 309 | ); 310 | } 311 | 312 | t.end(); 313 | }); 314 | 315 | test('missing index', function (t) { 316 | t.plan(requireResolveSupportsPaths ? 2 : 1); 317 | 318 | var resolverDir = path.join(__dirname, 'resolver'); 319 | try { 320 | resolve.sync('./missing_index', { basedir: resolverDir }); 321 | t.fail('did not fail'); 322 | } catch (err) { 323 | t.equal(err && err.code, 'INCORRECT_PACKAGE_MAIN', 'error has correct error code'); 324 | } 325 | if (requireResolveSupportsPaths) { 326 | try { 327 | require.resolve('./missing_index', { basedir: resolverDir }); 328 | t.fail('require.resolve did not fail'); 329 | } catch (err) { 330 | t.equal(err && err.code, 'MODULE_NOT_FOUND', 'error has correct error code'); 331 | } 332 | } 333 | }); 334 | 335 | test('missing main', function (t) { 336 | var resolverDir = path.join(__dirname, 'resolver'); 337 | var dir = path.join(resolverDir, 'missing_main'); 338 | 339 | t.equal( 340 | resolve.sync('./missing_main', { basedir: resolverDir }), 341 | path.join(dir, 'index.js') 342 | ); 343 | if (requireResolveSupportsPaths) { 344 | t.equal( 345 | resolve.sync('./missing_main', { basedir: resolverDir }), 346 | require.resolve('./missing_main', { paths: [resolverDir] }), 347 | '"main" missing: resolve.sync === require.resolve' 348 | ); 349 | } 350 | 351 | t.end(); 352 | }); 353 | 354 | test('null main', function (t) { 355 | var resolverDir = path.join(__dirname, 'resolver'); 356 | var dir = path.join(resolverDir, 'null_main'); 357 | 358 | t.equal( 359 | resolve.sync('./null_main', { basedir: resolverDir }), 360 | path.join(dir, 'index.js') 361 | ); 362 | if (requireResolveSupportsPaths) { 363 | t.equal( 364 | resolve.sync('./null_main', { basedir: resolverDir }), 365 | require.resolve('./null_main', { paths: [resolverDir] }), 366 | '`"main": null`: resolve.sync === require.resolve' 367 | ); 368 | } 369 | 370 | t.end(); 371 | }); 372 | 373 | test('main: false', function (t) { 374 | var basedir = path.join(__dirname, 'resolver'); 375 | var dir = path.join(basedir, 'false_main'); 376 | t.equal( 377 | resolve.sync('./false_main', { basedir: basedir }), 378 | path.join(dir, 'index.js'), 379 | '`"main": false`: resolves to `index.js`' 380 | ); 381 | if (requireResolveSupportsPaths) { 382 | t.equal( 383 | resolve.sync('./false_main', { basedir: basedir }), 384 | require.resolve('./false_main', { paths: [basedir] }), 385 | '`"main": false`: resolve.sync === require.resolve' 386 | ); 387 | } 388 | 389 | t.end(); 390 | }); 391 | 392 | var stubStatSync = function stubStatSync(fn) { 393 | var statSync = fs.statSync; 394 | try { 395 | fs.statSync = function () { 396 | throw new EvalError('Unknown Error'); 397 | }; 398 | return fn(); 399 | } finally { 400 | fs.statSync = statSync; 401 | } 402 | }; 403 | 404 | test('#79 - re-throw non ENOENT errors from stat', function (t) { 405 | var dir = path.join(__dirname, 'resolver'); 406 | 407 | stubStatSync(function () { 408 | t.throws(function () { 409 | resolve.sync('foo', { basedir: dir }); 410 | }, /Unknown Error/); 411 | }); 412 | 413 | t.end(); 414 | }); 415 | 416 | test('#52 - incorrectly resolves module-paths like "./someFolder/" when there is a file of the same name', function (t) { 417 | var dir = path.join(__dirname, 'resolver'); 418 | var basedir = path.join(dir, 'same_names'); 419 | 420 | t.equal( 421 | resolve.sync('./foo', { basedir: basedir }), 422 | path.join(dir, 'same_names/foo.js') 423 | ); 424 | if (requireResolveSupportsPaths) { 425 | t.equal( 426 | resolve.sync('./foo', { basedir: basedir }), 427 | require.resolve('./foo', { paths: [basedir] }), 428 | './foo: resolve.sync === require.resolve' 429 | ); 430 | } 431 | 432 | t.equal( 433 | resolve.sync('./foo/', { basedir: basedir }), 434 | path.join(dir, 'same_names/foo/index.js') 435 | ); 436 | if (requireResolveSupportsPaths) { 437 | t.equal( 438 | resolve.sync('./foo/', { basedir: basedir }), 439 | require.resolve('./foo/', { paths: [basedir] }), 440 | './foo/: resolve.sync === require.resolve' 441 | ); 442 | } 443 | 444 | t.end(); 445 | }); 446 | 447 | test('#211 - incorrectly resolves module-paths like "." when from inside a folder with a sibling file of the same name', function (t) { 448 | var dir = path.join(__dirname, 'resolver'); 449 | var basedir = path.join(dir, 'same_names/foo'); 450 | 451 | t.equal( 452 | resolve.sync('./', { basedir: basedir }), 453 | path.join(dir, 'same_names/foo/index.js'), 454 | './' 455 | ); 456 | if (requireResolveSupportsPaths) { 457 | t.equal( 458 | resolve.sync('./', { basedir: basedir }), 459 | require.resolve('./', { paths: [basedir] }), 460 | './: resolve.sync === require.resolve' 461 | ); 462 | } 463 | 464 | t.equal( 465 | resolve.sync('.', { basedir: basedir }), 466 | path.join(dir, 'same_names/foo/index.js'), 467 | '.' 468 | ); 469 | if (requireResolveSupportsPaths) { 470 | t.equal( 471 | resolve.sync('.', { basedir: basedir }), 472 | require.resolve('.', { paths: [basedir] }), 473 | '.: resolve.sync === require.resolve', 474 | { todo: true } 475 | ); 476 | } 477 | 478 | t.end(); 479 | }); 480 | 481 | test('sync: #121 - treating an existing file as a dir when no basedir', function (t) { 482 | var testFile = path.basename(__filename); 483 | 484 | t.test('sanity check', function (st) { 485 | st.equal( 486 | resolve.sync('./' + testFile), 487 | __filename, 488 | 'sanity check' 489 | ); 490 | st.equal( 491 | resolve.sync('./' + testFile), 492 | require.resolve('./' + testFile), 493 | 'sanity check: resolve.sync === require.resolve' 494 | ); 495 | 496 | st.end(); 497 | }); 498 | 499 | t.test('with a fake directory', function (st) { 500 | function run() { return resolve.sync('./' + testFile + '/blah'); } 501 | 502 | st.throws(run, 'throws an error'); 503 | 504 | try { 505 | run(); 506 | } catch (e) { 507 | st.equal(e.code, 'MODULE_NOT_FOUND', 'error code matches require.resolve'); 508 | st.equal( 509 | e.message, 510 | 'Cannot find module \'./' + testFile + '/blah\' from \'' + __dirname + '\'', 511 | 'can not find nonexistent module' 512 | ); 513 | } 514 | 515 | st.end(); 516 | }); 517 | 518 | t.end(); 519 | }); 520 | 521 | test('sync dot main', function (t) { 522 | var start = new Date(); 523 | 524 | t.equal( 525 | resolve.sync('./resolver/dot_main'), 526 | path.join(__dirname, 'resolver/dot_main/index.js'), 527 | './resolver/dot_main' 528 | ); 529 | t.equal( 530 | resolve.sync('./resolver/dot_main'), 531 | require.resolve('./resolver/dot_main'), 532 | './resolver/dot_main: resolve.sync === require.resolve' 533 | ); 534 | 535 | t.ok(new Date() - start < 50, 'resolve.sync timedout'); 536 | 537 | t.end(); 538 | }); 539 | 540 | test('sync dot slash main', function (t) { 541 | var start = new Date(); 542 | 543 | t.equal( 544 | resolve.sync('./resolver/dot_slash_main'), 545 | path.join(__dirname, 'resolver/dot_slash_main/index.js') 546 | ); 547 | t.equal( 548 | resolve.sync('./resolver/dot_slash_main'), 549 | require.resolve('./resolver/dot_slash_main'), 550 | './resolver/dot_slash_main: resolve.sync === require.resolve' 551 | ); 552 | 553 | t.ok(new Date() - start < 50, 'resolve.sync timedout'); 554 | 555 | t.end(); 556 | }); 557 | 558 | test('not a directory', function (t) { 559 | var path = './foo'; 560 | try { 561 | resolve.sync(path, { basedir: __filename }); 562 | t.fail(); 563 | } catch (err) { 564 | t.ok(err, 'a non-directory errors'); 565 | t.equal(err && err.message, 'Provided basedir "' + __filename + '" is not a directory, or a symlink to a directory'); 566 | t.equal(err && err.code, 'INVALID_BASEDIR'); 567 | } 568 | t.end(); 569 | }); 570 | 571 | test('non-string "main" field in package.json', function (t) { 572 | var dir = path.join(__dirname, 'resolver'); 573 | try { 574 | var result = resolve.sync('./invalid_main', { basedir: dir }); 575 | t.equal(result, undefined, 'result should not exist'); 576 | t.fail('should not get here'); 577 | } catch (err) { 578 | t.ok(err, 'errors on non-string main'); 579 | t.equal(err.message, 'package “invalid_main” `main` must be a string'); 580 | t.equal(err.code, 'INVALID_PACKAGE_MAIN'); 581 | } 582 | t.end(); 583 | }); 584 | 585 | test('non-string "main" field in package.json', function (t) { 586 | var dir = path.join(__dirname, 'resolver'); 587 | try { 588 | var result = resolve.sync('./invalid_main', { basedir: dir }); 589 | t.equal(result, undefined, 'result should not exist'); 590 | t.fail('should not get here'); 591 | } catch (err) { 592 | t.ok(err, 'errors on non-string main'); 593 | t.equal(err.message, 'package “invalid_main” `main` must be a string'); 594 | t.equal(err.code, 'INVALID_PACKAGE_MAIN'); 595 | } 596 | t.end(); 597 | }); 598 | 599 | test('browser field in package.json', function (t) { 600 | var dir = path.join(__dirname, 'resolver'); 601 | var res = resolve.sync('./browser_field', { 602 | basedir: dir, 603 | packageFilter: function packageFilter(pkg) { 604 | if (pkg.browser) { 605 | pkg.main = pkg.browser; // eslint-disable-line no-param-reassign 606 | delete pkg.browser; // eslint-disable-line no-param-reassign 607 | } 608 | return pkg; 609 | } 610 | }); 611 | t.equal(res, path.join(dir, 'browser_field', 'b.js')); 612 | t.end(); 613 | }); 614 | 615 | test('absolute paths', function (t) { 616 | var extensionless = __filename.slice(0, -path.extname(__filename).length); 617 | 618 | t.equal( 619 | resolve.sync(__filename), 620 | __filename, 621 | 'absolute path to this file resolves' 622 | ); 623 | t.equal( 624 | resolve.sync(__filename), 625 | require.resolve(__filename), 626 | 'absolute path to this file: resolve.sync === require.resolve' 627 | ); 628 | 629 | t.equal( 630 | resolve.sync(extensionless), 631 | __filename, 632 | 'extensionless absolute path to this file resolves' 633 | ); 634 | t.equal( 635 | resolve.sync(__filename), 636 | require.resolve(__filename), 637 | 'absolute path to this file: resolve.sync === require.resolve' 638 | ); 639 | 640 | t.equal( 641 | resolve.sync(__filename, { basedir: process.cwd() }), 642 | __filename, 643 | 'absolute path to this file with a basedir resolves' 644 | ); 645 | if (requireResolveSupportsPaths) { 646 | t.equal( 647 | resolve.sync(__filename, { basedir: process.cwd() }), 648 | require.resolve(__filename, { paths: [process.cwd()] }), 649 | 'absolute path to this file + basedir: resolve.sync === require.resolve' 650 | ); 651 | } 652 | 653 | t.equal( 654 | resolve.sync(extensionless, { basedir: process.cwd() }), 655 | __filename, 656 | 'extensionless absolute path to this file with a basedir resolves' 657 | ); 658 | if (requireResolveSupportsPaths) { 659 | t.equal( 660 | resolve.sync(extensionless, { basedir: process.cwd() }), 661 | require.resolve(extensionless, { paths: [process.cwd()] }), 662 | 'extensionless absolute path to this file + basedir: resolve.sync === require.resolve' 663 | ); 664 | } 665 | 666 | t.end(); 667 | }); 668 | 669 | var malformedDir = path.join(__dirname, 'resolver/malformed_package_json'); 670 | test('malformed package.json', { skip: !fs.existsSync(malformedDir) }, function (t) { 671 | t.plan(5 + (requireResolveSupportsPaths ? 1 : 0)); 672 | 673 | var basedir = malformedDir; 674 | var expected = path.join(basedir, 'index.js'); 675 | 676 | t.equal( 677 | resolve.sync('./index.js', { basedir: basedir }), 678 | expected, 679 | 'malformed package.json is silently ignored' 680 | ); 681 | if (requireResolveSupportsPaths) { 682 | t.equal( 683 | resolve.sync('./index.js', { basedir: basedir }), 684 | require.resolve('./index.js', { paths: [basedir] }), 685 | 'malformed package.json: resolve.sync === require.resolve' 686 | ); 687 | } 688 | 689 | var res1 = resolve.sync( 690 | './index.js', 691 | { 692 | basedir: basedir, 693 | packageFilter: function (pkg, pkgfile, dir) { 694 | t.fail('should not reach here'); 695 | } 696 | } 697 | ); 698 | 699 | t.equal( 700 | res1, 701 | expected, 702 | 'with packageFilter: malformed package.json is silently ignored' 703 | ); 704 | 705 | var res2 = resolve.sync( 706 | './index.js', 707 | { 708 | basedir: basedir, 709 | readPackageSync: function (readFileSync, pkgfile) { 710 | t.equal(pkgfile, path.join(basedir, 'package.json'), 'readPackageSync: `pkgfile` is package.json path'); 711 | var result = String(readFileSync(pkgfile)); 712 | try { 713 | return JSON.parse(result); 714 | } catch (e) { 715 | t.ok(e instanceof SyntaxError, 'readPackageSync: malformed package.json parses as a syntax error'); 716 | throw e; 717 | } 718 | } 719 | } 720 | ); 721 | 722 | t.equal( 723 | res2, 724 | expected, 725 | 'with readPackageSync: malformed package.json is silently ignored' 726 | ); 727 | }); 728 | -------------------------------------------------------------------------------- /test/shadowed_core.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var resolve = require('../'); 3 | var path = require('path'); 4 | 5 | test('shadowed core modules still return core module', function (t) { 6 | t.plan(2); 7 | 8 | resolve('util', { basedir: path.join(__dirname, 'shadowed_core') }, function (err, res) { 9 | t.ifError(err); 10 | t.equal(res, 'util'); 11 | }); 12 | }); 13 | 14 | test('shadowed core modules still return core module [sync]', function (t) { 15 | t.plan(1); 16 | 17 | var res = resolve.sync('util', { basedir: path.join(__dirname, 'shadowed_core') }); 18 | 19 | t.equal(res, 'util'); 20 | }); 21 | 22 | test('shadowed core modules return shadow when appending `/`', function (t) { 23 | t.plan(2); 24 | 25 | resolve('util/', { basedir: path.join(__dirname, 'shadowed_core') }, function (err, res) { 26 | t.ifError(err); 27 | t.equal(res, path.join(__dirname, 'shadowed_core/node_modules/util/index.js')); 28 | }); 29 | }); 30 | 31 | test('shadowed core modules return shadow when appending `/` [sync]', function (t) { 32 | t.plan(1); 33 | 34 | var res = resolve.sync('util/', { basedir: path.join(__dirname, 'shadowed_core') }); 35 | 36 | t.equal(res, path.join(__dirname, 'shadowed_core/node_modules/util/index.js')); 37 | }); 38 | 39 | test('shadowed core modules return shadow with `includeCoreModules: false`', function (t) { 40 | t.plan(2); 41 | 42 | resolve('util', { basedir: path.join(__dirname, 'shadowed_core'), includeCoreModules: false }, function (err, res) { 43 | t.ifError(err); 44 | t.equal(res, path.join(__dirname, 'shadowed_core/node_modules/util/index.js')); 45 | }); 46 | }); 47 | 48 | test('shadowed core modules return shadow with `includeCoreModules: false` [sync]', function (t) { 49 | t.plan(1); 50 | 51 | var res = resolve.sync('util', { basedir: path.join(__dirname, 'shadowed_core'), includeCoreModules: false }); 52 | 53 | t.equal(res, path.join(__dirname, 'shadowed_core/node_modules/util/index.js')); 54 | }); 55 | -------------------------------------------------------------------------------- /test/shadowed_core/.gitignore: -------------------------------------------------------------------------------- 1 | !/node_modules 2 | -------------------------------------------------------------------------------- /test/shadowed_core/node_modules/util/index.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/browserify/resolve/06bfa9190190760511720cf74efb7f00a1a40a9d/test/shadowed_core/node_modules/util/index.js -------------------------------------------------------------------------------- /test/subdirs.js: -------------------------------------------------------------------------------- 1 | var test = require('tape'); 2 | var resolve = require('../'); 3 | var path = require('path'); 4 | 5 | test('subdirs', function (t) { 6 | t.plan(2); 7 | 8 | var dir = path.join(__dirname, '/subdirs'); 9 | resolve('a/b/c/x.json', { basedir: dir }, function (err, res) { 10 | t.ifError(err); 11 | t.equal(res, path.join(dir, 'node_modules/a/b/c/x.json')); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /test/subdirs/node_modules/a/b/c/x.json: -------------------------------------------------------------------------------- 1 | [1,2,3] 2 | -------------------------------------------------------------------------------- /test/subdirs/node_modules/a/package.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /test/symlinks.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var fs = require('fs'); 3 | var test = require('tape'); 4 | var map = require('array.prototype.map'); 5 | var resolve = require('../'); 6 | 7 | var symlinkDir = path.join(__dirname, 'resolver', 'symlinked', 'symlink'); 8 | var packageDir = path.join(__dirname, 'resolver', 'symlinked', '_', 'node_modules', 'package'); 9 | var modADir = path.join(__dirname, 'symlinks', 'source', 'node_modules', 'mod-a'); 10 | var symlinkModADir = path.join(__dirname, 'symlinks', 'dest', 'node_modules', 'mod-a'); 11 | try { 12 | fs.unlinkSync(symlinkDir); 13 | } catch (err) {} 14 | try { 15 | fs.unlinkSync(packageDir); 16 | } catch (err) {} 17 | try { 18 | fs.unlinkSync(modADir); 19 | } catch (err) {} 20 | try { 21 | fs.unlinkSync(symlinkModADir); 22 | } catch (err) {} 23 | 24 | try { 25 | fs.symlinkSync('./_/symlink_target', symlinkDir, 'dir'); 26 | } catch (err) { 27 | if (err.code !== 'EEXIST') { 28 | // if fails then it is probably on Windows and lets try to create a junction 29 | fs.symlinkSync(path.join(__dirname, 'resolver', 'symlinked', '_', 'symlink_target') + '\\', symlinkDir, 'junction'); 30 | } 31 | } 32 | try { 33 | fs.symlinkSync('../../package', packageDir, 'dir'); 34 | } catch (err) { 35 | // if fails then it is probably on Windows and lets try to create a junction 36 | fs.symlinkSync(path.join(__dirname, '..', '..', 'package') + '\\', packageDir, 'junction'); 37 | } 38 | try { 39 | fs.symlinkSync('../../source/node_modules/mod-a', symlinkModADir, 'dir'); 40 | } catch (err) { 41 | // if fails then it is probably on Windows and lets try to create a junction 42 | fs.symlinkSync(path.join(__dirname, '..', '..', 'source', 'node_modules', 'mod-a') + '\\', symlinkModADir, 'junction'); 43 | } 44 | 45 | test('symlink', function (t) { 46 | t.plan(2); 47 | 48 | resolve('foo', { basedir: symlinkDir }, function (err, res, pkg) { 49 | t.error(err); 50 | t.equal(res, path.join(__dirname, 'resolver', 'symlinked', '_', 'node_modules', 'foo.js')); 51 | }); 52 | }); 53 | 54 | test('sync symlink when preserveSymlinks = true', function (t) { 55 | t.plan(4); 56 | 57 | resolve('foo', { basedir: symlinkDir, preserveSymlinks: true }, function (err, res, pkg) { 58 | t.ok(err, 'there is an error'); 59 | t.notOk(res, 'no result'); 60 | 61 | t.equal(err && err.code, 'MODULE_NOT_FOUND', 'error code matches require.resolve'); 62 | t.equal( 63 | err && err.message, 64 | 'Cannot find module \'foo\' from \'' + symlinkDir + '\'', 65 | 'can not find nonexistent module' 66 | ); 67 | }); 68 | }); 69 | 70 | test('sync symlink', function (t) { 71 | var start = new Date(); 72 | t.doesNotThrow(function () { 73 | t.equal( 74 | resolve.sync('foo', { basedir: symlinkDir, preserveSymlinks: false }), 75 | path.join(__dirname, 'resolver', 'symlinked', '_', 'node_modules', 'foo.js') 76 | ); 77 | }); 78 | t.ok(new Date() - start < 50, 'resolve.sync timedout'); 79 | t.end(); 80 | }); 81 | 82 | test('sync symlink when preserveSymlinks = true', function (t) { 83 | t.throws(function () { 84 | resolve.sync('foo', { basedir: symlinkDir, preserveSymlinks: true }); 85 | }, /Cannot find module 'foo'/); 86 | t.end(); 87 | }); 88 | 89 | test('sync symlink from node_modules to other dir when preserveSymlinks = false', function (t) { 90 | var basedir = path.join(__dirname, 'resolver', 'symlinked', '_'); 91 | var fn = resolve.sync('package', { basedir: basedir, preserveSymlinks: false }); 92 | 93 | t.equal(fn, path.resolve(__dirname, 'resolver/symlinked/package/bar.js')); 94 | t.end(); 95 | }); 96 | 97 | test('async symlink from node_modules to other dir when preserveSymlinks = false', function (t) { 98 | t.plan(2); 99 | var basedir = path.join(__dirname, 'resolver', 'symlinked', '_'); 100 | resolve('package', { basedir: basedir, preserveSymlinks: false }, function (err, result) { 101 | t.notOk(err, 'no error'); 102 | t.equal(result, path.resolve(__dirname, 'resolver/symlinked/package/bar.js')); 103 | }); 104 | }); 105 | 106 | test('packageFilter', function (t) { 107 | function relative(x) { 108 | return path.relative(__dirname, x); 109 | } 110 | 111 | function testPackageFilter(preserveSymlinks) { 112 | return function (st) { 113 | st.plan(5); 114 | 115 | var destMain = 'symlinks/dest/node_modules/mod-a/index.js'; 116 | var destPkg = 'symlinks/dest/node_modules/mod-a/package.json'; 117 | var sourceMain = 'symlinks/source/node_modules/mod-a/index.js'; 118 | var sourcePkg = 'symlinks/source/node_modules/mod-a/package.json'; 119 | var destDir = path.join(__dirname, 'symlinks', 'dest'); 120 | 121 | var packageFilterPath = []; 122 | var actualPath = resolve.sync('mod-a', { 123 | basedir: destDir, 124 | preserveSymlinks: preserveSymlinks, 125 | packageFilter: function (pkg, pkgfile, dir) { 126 | packageFilterPath.push(pkgfile); 127 | } 128 | }); 129 | st.equal( 130 | relative(actualPath), 131 | path.normalize(preserveSymlinks ? destMain : sourceMain), 132 | 'sync: actual path is correct' 133 | ); 134 | st.deepEqual( 135 | map(packageFilterPath, relative), 136 | map(preserveSymlinks ? [destPkg, destPkg] : [sourcePkg, sourcePkg], path.normalize), 137 | 'sync: packageFilter pkgfile arg is correct' 138 | ); 139 | 140 | var asyncPackageFilterPath = []; 141 | resolve( 142 | 'mod-a', 143 | { 144 | basedir: destDir, 145 | preserveSymlinks: preserveSymlinks, 146 | packageFilter: function (pkg, pkgfile) { 147 | asyncPackageFilterPath.push(pkgfile); 148 | } 149 | }, 150 | function (err, actualPath) { 151 | st.error(err, 'no error'); 152 | st.equal( 153 | relative(actualPath), 154 | path.normalize(preserveSymlinks ? destMain : sourceMain), 155 | 'async: actual path is correct' 156 | ); 157 | st.deepEqual( 158 | map(asyncPackageFilterPath, relative), 159 | map( 160 | preserveSymlinks ? [destPkg, destPkg, destPkg] : [sourcePkg, sourcePkg, sourcePkg], 161 | path.normalize 162 | ), 163 | 'async: packageFilter pkgfile arg is correct' 164 | ); 165 | } 166 | ); 167 | }; 168 | } 169 | 170 | t.test('preserveSymlinks: false', testPackageFilter(false)); 171 | 172 | t.test('preserveSymlinks: true', testPackageFilter(true)); 173 | 174 | t.end(); 175 | }); 176 | -------------------------------------------------------------------------------- /test/symlinks/dest/node_modules/mod-a: -------------------------------------------------------------------------------- 1 | ../../source/node_modules/mod-a -------------------------------------------------------------------------------- /test/symlinks/source/node_modules/mod-a/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = 42; 4 | -------------------------------------------------------------------------------- /test/symlinks/source/node_modules/mod-a/package.json: -------------------------------------------------------------------------------- 1 | { 2 | } 3 | --------------------------------------------------------------------------------