From 28b1b4efe2a3e56503df35692229f777c1e7ddeb Mon Sep 17 00:00:00 2001 From: DonIsaac <22823424+DonIsaac@users.noreply.github.com> Date: Tue, 15 Oct 2024 22:50:43 +0000 Subject: [PATCH] chore(span): enable lint warnings on missing docs (#6610) Part of https://github.com/oxc-project/backlog/issues/130 --- crates/oxc_span/src/atom.rs | 9 +++ crates/oxc_span/src/cmp.rs | 2 + crates/oxc_span/src/hash.rs | 4 ++ crates/oxc_span/src/lib.rs | 1 + crates/oxc_span/src/source_type/mod.rs | 77 ++++++++++++++++++++++++++ crates/oxc_span/src/span/mod.rs | 2 + crates/oxc_span/src/span/types.rs | 21 ++----- 7 files changed, 101 insertions(+), 15 deletions(-) diff --git a/crates/oxc_span/src/atom.rs b/crates/oxc_span/src/atom.rs index 4c7f2a1c12d90..b9363cc4e5efb 100644 --- a/crates/oxc_span/src/atom.rs +++ b/crates/oxc_span/src/atom.rs @@ -26,6 +26,7 @@ export type Atom = string; pub struct Atom<'a>(&'a str); impl Atom<'static> { + /// Get an [`Atom`] containing the empty string (`""`). #[inline] pub const fn empty() -> Self { Atom("") @@ -33,21 +34,29 @@ impl Atom<'static> { } impl<'a> Atom<'a> { + /// Borrow a string slice. #[inline] pub fn as_str(&self) -> &'a str { self.0 } + /// Convert this [`Atom`] into a [`String`]. + /// + /// This is the explicit form of [`Into`], which [`Atom`] also implements. #[inline] pub fn into_string(self) -> String { String::from(self.as_str()) } + /// Convert this [`Atom`] into a [`CompactStr`]. + /// + /// This is the explicit form of [`Into`], which [`Atom`] also implements. #[inline] pub fn into_compact_str(self) -> CompactStr { CompactStr::new(self.as_str()) } + /// Convert this [`Atom`] into a [`CompactStr`] without consuming `self`. #[inline] pub fn to_compact_str(&self) -> CompactStr { CompactStr::new(self.as_str()) diff --git a/crates/oxc_span/src/cmp.rs b/crates/oxc_span/src/cmp.rs index 0a1eb3555e056..832eff72ab1c0 100644 --- a/crates/oxc_span/src/cmp.rs +++ b/crates/oxc_span/src/cmp.rs @@ -1,3 +1,5 @@ +//! Specialized comparison traits + /// This trait works similarly to [PartialEq] but it gives the liberty of checking the equality of the /// content loosely. This would mean the implementor can skip some parts of the content while doing /// equality checks. diff --git a/crates/oxc_span/src/hash.rs b/crates/oxc_span/src/hash.rs index 0fa61dc23dcf8..2ece72d2839a2 100644 --- a/crates/oxc_span/src/hash.rs +++ b/crates/oxc_span/src/hash.rs @@ -1,3 +1,4 @@ +//! Specialized hashing traits use std::{ hash::{Hash, Hasher}, mem::{discriminant, Discriminant}, @@ -9,6 +10,9 @@ use std::{ /// /// As an example, In AST types we ignore fields such as [crate::Span]. pub trait ContentHash { + /// Hash an AST node based on its content alone. + /// + /// This hash ignores node location, but respects precedence and ordering. fn content_hash(&self, state: &mut H); } diff --git a/crates/oxc_span/src/lib.rs b/crates/oxc_span/src/lib.rs index d33fc2e35fc61..f7e29d3cc6585 100644 --- a/crates/oxc_span/src/lib.rs +++ b/crates/oxc_span/src/lib.rs @@ -1,6 +1,7 @@ //! Source positions and related helper functions. //! //! +#![warn(missing_docs)] mod atom; mod compact_str; diff --git a/crates/oxc_span/src/source_type/mod.rs b/crates/oxc_span/src/source_type/mod.rs index 37e411fa67800..f8fe5bca56732 100644 --- a/crates/oxc_span/src/source_type/mod.rs +++ b/crates/oxc_span/src/source_type/mod.rs @@ -35,8 +35,11 @@ pub struct SourceType { #[cfg_attr(feature = "serialize", derive(Serialize, Tsify))] #[serde(rename_all = "lowercase")] pub enum Language { + /// Indicates a JavaScript or JSX file JavaScript = 0, + /// Indicates a TypeScript file TypeScript = 1, + /// Indicates a TypeScript definition file (`*.d.ts`) #[serde(rename = "typescriptDefinition")] TypeScriptDefinition = 2, } @@ -68,7 +71,10 @@ pub enum ModuleKind { #[cfg_attr(feature = "serialize", derive(Serialize, Tsify))] #[serde(rename_all = "camelCase")] pub enum LanguageVariant { + /// Standard JavaScript or TypeScript without any language extensions. Stage + /// 3 proposals do not count as language extensions. Standard = 0, + /// For sources using JSX or TSX Jsx = 1, } @@ -108,6 +114,9 @@ pub const VALID_EXTENSIONS: [&str; 8] = ["js", "mjs", "cjs", "jsx", "ts", "mts", impl SourceType { /// Creates a [`SourceType`] representing a regular [`JavaScript`] file. /// + /// This file could be a vanilla script (no module system of any kind) or a + /// CommonJS file. + /// /// The resulting source type is not a [`module`], nor does it support [`JSX`]. /// Use [`SourceType::jsx`] for [`JSX`] sources. /// @@ -132,6 +141,16 @@ impl SourceType { } } + /// Creates a [`SourceType`] representing a [`JavaScript`] file using ES6 + /// modules. This is akin to a file with an `.mjs` extension. + /// + /// ## Example + /// ``` + /// # use oxc_span::SourceType; + /// + /// let mjs = SourceType::mjs(); + /// ``` + /// [`JavaScript`]: Language::JavaScript pub const fn mjs() -> Self { Self { language: Language::JavaScript, @@ -140,6 +159,13 @@ impl SourceType { } } + /// A [`SourceType`] that will be treated as a module if it contains ESM syntax. + /// + /// After a file is parsed with an `unambiguous` source type, it will have a final + /// [`ModuleKind`] of either [`Module`] or [`Script`]. + /// + /// [`Module`]: ModuleKind::Module + /// [`Script`]: ModuleKind::Script pub const fn unambiguous() -> Self { Self { language: Language::JavaScript, @@ -230,22 +256,34 @@ impl SourceType { } } + /// Mark this source type as a [script]. + /// + /// [script]: ModuleKind::Script pub fn is_script(self) -> bool { self.module_kind == ModuleKind::Script } + /// Mark this source type as a [module]. + /// + /// [module]: ModuleKind::Module pub fn is_module(self) -> bool { self.module_kind == ModuleKind::Module } + /// `true` if this [`SourceType`] is [unambiguous]. + /// + /// [unambiguous]: ModuleKind::Unambiguous pub fn is_unambiguous(self) -> bool { self.module_kind == ModuleKind::Unambiguous } + /// What module system is this source type using? pub fn module_kind(self) -> ModuleKind { self.module_kind } + /// Returns `true` if this is a JavaScript file with or without syntax + /// extensions (like JSX). pub fn is_javascript(self) -> bool { self.language == Language::JavaScript } @@ -257,18 +295,29 @@ impl SourceType { matches!(self.language, Language::TypeScript | Language::TypeScriptDefinition) } + /// Returns `true` if this is a TypeScript definition file (e.g. `.d.ts`). pub fn is_typescript_definition(self) -> bool { self.language == Language::TypeScriptDefinition } + /// Returns `true` if this source type is using JSX. + /// + /// Note that TSX is considered JSX in this context. pub fn is_jsx(self) -> bool { self.variant == LanguageVariant::Jsx } + /// Does this source type implicitly use strict mode semantics? + /// + /// Does not consider `"use strict";` directives. pub fn is_strict(self) -> bool { self.is_module() } + /// Mark this [`SourceType`] as a [script] if `yes` is `true`. No change + /// will occur if `yes` is `false`. + /// + /// [script]: ModuleKind::Script #[must_use] pub const fn with_script(mut self, yes: bool) -> Self { if yes { @@ -277,6 +326,10 @@ impl SourceType { self } + /// Mark this [`SourceType`] as a [module] if `yes` is `true`. No change + /// will occur if `yes` is `false`. + /// + /// [module]: ModuleKind::Module #[must_use] pub const fn with_module(mut self, yes: bool) -> Self { if yes { @@ -287,6 +340,10 @@ impl SourceType { self } + /// Mark this [`SourceType`] as [unambiguous] if `yes` is `true`. No change + /// will occur if `yes` is `false`. + /// + /// [unambiguous]: ModuleKind::Unambiguous #[must_use] pub const fn with_unambiguous(mut self, yes: bool) -> Self { if yes { @@ -295,6 +352,10 @@ impl SourceType { self } + /// Mark this [`SourceType`] as using [JavaScript] if `yes` is `true`. No change + /// will occur if `yes` is `false`. + /// + /// [JavaScript]: Language::JavaScript #[must_use] pub const fn with_javascript(mut self, yes: bool) -> Self { if yes { @@ -303,6 +364,10 @@ impl SourceType { self } + /// Mark this [`SourceType`] as using [TypeScript] if `yes` is `true`. No change + /// will occur if `yes` is `false`. + /// + /// [TypeScript]: Language::TypeScript #[must_use] pub const fn with_typescript(mut self, yes: bool) -> Self { if yes { @@ -311,6 +376,7 @@ impl SourceType { self } + /// Mark this [`SourceType`] as a [TypeScript definition] file if `yes` is `true`. #[must_use] pub const fn with_typescript_definition(mut self, yes: bool) -> Self { if yes { @@ -319,6 +385,13 @@ impl SourceType { self } + /// Mark this [`SourceType`] as using [JSX] if `yes` is `true`. No change + /// will occur if `yes` is `false`. + /// + /// When using [TypeScript], this source type now represents a TSX file. + /// + /// [JSX]: LanguageVariant::Jsx + /// [TypeScript]: Language::TypeScript #[must_use] pub const fn with_jsx(mut self, yes: bool) -> Self { if yes { @@ -327,6 +400,10 @@ impl SourceType { self } + /// Disable language extensions (e.g. [JSX]) if `yes` is `true`. No change + /// will occur if `yes` is `false`. + /// + /// [JSX]: LanguageVariant::Jsx #[must_use] pub const fn with_standard(mut self, yes: bool) -> Self { if yes { diff --git a/crates/oxc_span/src/span/mod.rs b/crates/oxc_span/src/span/mod.rs index fb928f2a51d9c..ab6e4ea432d89 100644 --- a/crates/oxc_span/src/span/mod.rs +++ b/crates/oxc_span/src/span/mod.rs @@ -364,11 +364,13 @@ impl From for LabeledSpan { /// Get the span for an AST node pub trait GetSpan { + /// Get the [`Span`] for an AST node fn span(&self) -> Span; } /// Get mutable ref to span for an AST node pub trait GetSpanMut { + /// Get a mutable reference to an AST node's [`Span`]. fn span_mut(&mut self) -> &mut Span; } diff --git a/crates/oxc_span/src/span/types.rs b/crates/oxc_span/src/span/types.rs index b470f04f75d34..cc57edf6dfb95 100644 --- a/crates/oxc_span/src/span/types.rs +++ b/crates/oxc_span/src/span/types.rs @@ -12,26 +12,17 @@ use ::{serde::Serialize, tsify::Tsify}; /// NOTE: `u32` is sufficient for "all" reasonable programs. Larger than u32 is a 4GB JS file. /// /// ## Hashing -/// [`Span`]'s implementation of [`Hash`] is a no-op so that AST nodes can be -/// compared by hash. This makes them unsuitable for use as keys in a hash map. -/// -/// ``` -/// use std::hash::{Hash, Hasher, DefaultHasher}; -/// use oxc_span::Span; -/// -/// let mut first = DefaultHasher::new(); -/// let mut second = DefaultHasher::new(); -/// -/// Span::new(0, 5).hash(&mut first); -/// Span::new(10, 20).hash(&mut second); -/// -/// assert_eq!(first.finish(), second.finish()); -/// ``` +/// [`Span`] has a normal implementation of [`Hash`]. If you want to compare two +/// AST nodes without considering their locations (e.g. to see if they have the +/// same content), use [`ContentHash`](crate::hash::ContentHash) instead. #[ast] #[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(feature = "serialize", derive(Serialize, Tsify))] #[non_exhaustive] // Disallow struct expression constructor `Span {}` pub struct Span { + /// The zero-based start offset of the span pub start: u32, + /// The zero-based end offset of the span. This may be equal to [`start`](Span::start) if + /// the span is empty, but should not be less than it. pub end: u32, }