Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
chore(span): enable lint warnings on missing docs (#6610)
  • Loading branch information
DonIsaac committed Oct 15, 2024
commit 28b1b4efe2a3e56503df35692229f777c1e7ddeb
9 changes: 9 additions & 0 deletions crates/oxc_span/src/atom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,28 +26,37 @@ 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("")
}
}

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<String>`], 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<CompactStr>`], 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())
Expand Down
2 changes: 2 additions & 0 deletions crates/oxc_span/src/cmp.rs
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
4 changes: 4 additions & 0 deletions crates/oxc_span/src/hash.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
//! Specialized hashing traits
use std::{
hash::{Hash, Hasher},
mem::{discriminant, Discriminant},
Expand All @@ -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<H: Hasher>(&self, state: &mut H);
}

Expand Down
1 change: 1 addition & 0 deletions crates/oxc_span/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! Source positions and related helper functions.
//!
//! <https://doc.rust-lang.org/beta/nightly-rustc/rustc_span>
#![warn(missing_docs)]

mod atom;
mod compact_str;
Expand Down
77 changes: 77 additions & 0 deletions crates/oxc_span/src/source_type/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand Down Expand Up @@ -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,
}

Expand Down Expand Up @@ -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.
///
Expand All @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -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
}
Expand All @@ -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 {
Expand All @@ -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 {
Expand All @@ -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 {
Expand All @@ -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 {
Expand All @@ -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 {
Expand All @@ -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 {
Expand All @@ -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 {
Expand All @@ -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 {
Expand Down
2 changes: 2 additions & 0 deletions crates/oxc_span/src/span/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,11 +364,13 @@ impl From<Span> 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;
}

Expand Down
21 changes: 6 additions & 15 deletions crates/oxc_span/src/span/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}