Skip to content

Commit

Permalink
docs: improve terminology and clarify contexts (#118)
Browse files Browse the repository at this point in the history
  • Loading branch information
Boshen authored Mar 29, 2024
1 parent 4226f7a commit fa5cfec
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 11 deletions.
11 changes: 7 additions & 4 deletions examples/resolver.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
///! See documentation at <https://docs.rs/oxc_resolver>
use std::{env, path::PathBuf};

use oxc_resolver::{AliasValue, ResolveOptions, Resolver};

fn main() {
// Path to directory, must be in absolute path.
let path = env::args().nth(1).expect("path");
let path = PathBuf::from(env::args().nth(1).expect("path"));

assert!(path.is_dir(), "{path:?} must be a directory that will be resolved against.");
assert!(path.is_absolute(), "{path:?} must be an absolute path.",);

let specifier = env::args().nth(2).expect("specifier");
let path = PathBuf::from(path).canonicalize().unwrap();

println!("path: {path:?}");
println!("request: {specifier}");
println!("specifier: {specifier}");

let options = ResolveOptions {
alias_fields: vec![vec!["browser".into()]],
Expand Down
37 changes: 30 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,39 @@
//! # Oxc Resolver
//!
//! Node.js Module Resolution.
//! Node.js [CommonJS][cjs] and [ECMAScript][esm] Module Resolution.
//!
//! All configuration options are aligned with [enhanced-resolve].
//! A module resolution is the process of finding the file referenced by a module specifier in
//! `import "specifier"` or `require("specifier")`.
//!
//! All [configuration options](ResolveOptions) are aligned with webpack's [enhanced-resolve].
//!
//! ## Terminology
//!
//! ### Specifier
//!
//! For [CommonJS modules][cjs],
//! the specifier is the string passed to the `require` function. e.g. `"id"` in `require("id")`.
//!
//! For [ECMAScript modules][esm],
//! the specifier of an `import` statement is the string after the `from` keyword,
//! e.g. `'specifier'` in `import 'specifier'` or `import { sep } from 'specifier'`.
//! Specifiers are also used in export from statements, and as the argument to an `import()` expression.
//!
//! This is also named "request" in some places.
//!
//! ## References:
//!
//! * Algorithm adapted from Node.js [CommonJS Module Resolution Algorithm] and [ECMAScript Module Resolution Algorithm]
//! * Tests are ported from [enhanced-resolve]
//! * Some code adapted from [parcel-resolver]
//! * Algorithm adapted from Node.js [CommonJS Module Resolution Algorithm] and [ECMAScript Module Resolution Algorithm].
//! * Tests are ported from [enhanced-resolve].
//! * Some code is adapted from [parcel-resolver].
//! * The documentation is copied from [webpack's resolve configuration](https://webpack.js.org/configuration/resolve).
//!
//! [enhanced-resolve]: https://github.com/webpack/enhanced-resolve
//! [CommonJS Module Resolution Algorithm]: https://nodejs.org/api/modules.html#all-together
//! [ECMAScript Module Resolution Algorithm]: https://nodejs.org/api/esm.html#resolution-algorithm-specification
//! [parcel-resolver]: https://github.com/parcel-bundler/parcel/blob/v2/packages/utils/node-resolver-rs
//! [cjs]: https://nodejs.org/api/modules.html
//! [esm]: https://nodejs.org/api/esm.html
//!
//! ## Example
//!
Expand Down Expand Up @@ -70,6 +90,7 @@ use nodejs_package_json::{ImportExportField, ImportExportKey, ImportExportMap};

type ResolveResult = Result<Option<CachedPath>, ResolveError>;

/// Context returned from the [Resolver::resolve_with_context] API
#[derive(Debug, Default, Clone)]
pub struct ResolveContext {
/// Files that was found on file system
Expand Down Expand Up @@ -127,11 +148,13 @@ impl<Fs: FileSystem> ResolverGeneric<Fs> {
self.cache.clear();
}

/// Resolve `specifier` at an absolute `path`
/// Resolve `specifier` at an absolute `path`.
///
/// A specifier is the string passed to require or import, i.e. `require("specifier")` or `import "specifier"`.
///
/// The path must be an **absolute** path where the specifier is resolved from.
/// `path` must be an **absolute** path to a directory where the specifier is resolved against.
/// For CommonJS modules, it is the `__dirname` variable that contains the absolute path to the folder containing current module.
/// For ECMAScript modules, it is the value of `import.meta.url`.
///
/// # Errors
///
Expand Down
16 changes: 16 additions & 0 deletions src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,25 @@ pub struct ResolveOptions {
pub tsconfig: Option<TsconfigOptions>,

/// Create aliases to import or require certain modules more easily.
///
/// An alias is used to replace a whole path or part of a path.
/// For example, to alias a commonly used `src/` folders: `vec![("@/src"), vec![AliasValue::Path("/path/to/src")]]`
///
/// A trailing $ can also be added to the given object's keys to signify an exact match.
///
/// See [webpack's `resolve.alias` documentation](https://webpack.js.org/configuration/resolve/#resolvealias) for a list of use cases.
pub alias: Alias,

/// A list of alias fields in description files.
///
/// Specify a field, such as `browser`, to be parsed according to [this specification](https://github.com/defunctzombie/package-browser-field-spec).
/// Can be a path to json object such as `["path", "to", "exports"]`.
///
/// Default `[]`
pub alias_fields: Vec<Vec<String>>,

/// Condition names for exports field which defines entry points of a package.
///
/// The key order in the exports field is significant. During condition matching, earlier entries have higher priority and take precedence over later entries.
///
/// Default `[]`
Expand All @@ -51,6 +59,7 @@ pub struct ResolveOptions {
pub enforce_extension: EnforceExtension,

/// A list of exports fields in description files.
///
/// Can be a path to a JSON object such as `["path", "to", "exports"]`.
///
/// Default `[["exports"]]`.
Expand All @@ -62,9 +71,12 @@ pub struct ResolveOptions {
pub extension_alias: Vec<(String, Vec<String>)>,

/// Attempt to resolve these extensions in order.
///
/// If multiple files share the same name but have different extensions,
/// will resolve the one with the extension listed first in the array and skip the rest.
///
/// All extensions must begin with a leading dot.
///
/// Default `[".js", ".json", ".node"]`
pub extensions: Vec<String>,

Expand Down Expand Up @@ -330,6 +342,10 @@ impl ResolveOptions {
}

pub(crate) fn sanitize(mut self) -> Self {
debug_assert!(
self.extensions.iter().filter(|e| !e.is_empty()).all(|e| e.starts_with('.')),
"All extensions must start with a leading dot"
);
// Set `enforceExtension` to `true` when [ResolveOptions::extensions] contains an empty string.
// See <https://github.com/webpack/enhanced-resolve/pull/285>
if self.enforce_extension == EnforceExtension::Auto {
Expand Down

0 comments on commit fa5cfec

Please sign in to comment.