Skip to content
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@

.vscode

bench_content/**/
bench_content/**/
13 changes: 5 additions & 8 deletions src/frontend/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@ use serde::{Deserialize, Serialize};
use crate::{
generator::{DenseLuaGenerator, LuaGenerator, ReadableLuaGenerator, TokenBasedLuaGenerator},
nodes::Block,
rules::{
bundle::{BundleRequireMode, Bundler},
get_default_rules, Rule,
},
rules::{bundle::Bundler, get_default_rules, RequireMode, Rule},
Parser,
};

Expand Down Expand Up @@ -252,8 +249,8 @@ impl FromStr for GeneratorParameters {
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(deny_unknown_fields, rename_all = "snake_case")]
pub struct BundleConfiguration {
#[serde(deserialize_with = "crate::utils::string_or_struct")]
require_mode: BundleRequireMode,
#[serde(deserialize_with = "crate::utils::string_or_default")]
require_mode: RequireMode,
#[serde(skip_serializing_if = "Option::is_none")]
modules_identifier: Option<String>,
#[serde(default, skip_serializing_if = "HashSet::is_empty")]
Expand All @@ -262,7 +259,7 @@ pub struct BundleConfiguration {

impl BundleConfiguration {
/// Creates a new bundle configuration with the specified require mode.
pub fn new(require_mode: impl Into<BundleRequireMode>) -> Self {
pub fn new(require_mode: impl Into<RequireMode>) -> Self {
Self {
require_mode: require_mode.into(),
modules_identifier: None,
Expand All @@ -282,7 +279,7 @@ impl BundleConfiguration {
self
}

pub(crate) fn require_mode(&self) -> &BundleRequireMode {
pub(crate) fn require_mode(&self) -> &RequireMode {
&self.require_mode
}

Expand Down
15 changes: 8 additions & 7 deletions src/rules/bundle/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ use std::path::Path;

use crate::nodes::Block;
use crate::rules::{
Context, Rule, RuleConfiguration, RuleConfigurationError, RuleProcessResult, RuleProperties,
Context, RequireMode, Rule, RuleConfiguration, RuleConfigurationError, RuleProcessResult,
RuleProperties,
};
use crate::Parser;

Expand All @@ -17,7 +18,7 @@ use wax::Pattern;
pub const BUNDLER_RULE_NAME: &str = "bundler";

#[derive(Debug)]
pub(crate) struct BundleOptions {
pub struct BundleOptions {
parser: Parser,
modules_identifier: String,
excludes: Option<wax::Any<'static>>,
Expand Down Expand Up @@ -74,14 +75,14 @@ impl BundleOptions {
/// A rule that inlines required modules
#[derive(Debug)]
pub(crate) struct Bundler {
require_mode: BundleRequireMode,
require_mode: RequireMode,
options: BundleOptions,
}

impl Bundler {
pub(crate) fn new<'a>(
parser: Parser,
require_mode: BundleRequireMode,
require_mode: RequireMode,
excludes: impl Iterator<Item = &'a str>,
) -> Self {
Self {
Expand Down Expand Up @@ -124,19 +125,19 @@ const DEFAULT_MODULE_IDENTIFIER: &str = "__DARKLUA_BUNDLE_MODULES";
#[cfg(test)]
mod test {
use super::*;
use crate::rules::{require::PathRequireMode, Rule};
use crate::rules::{require::PathRequireMode, RequireMode, Rule};

use insta::assert_json_snapshot;

fn new_rule() -> Bundler {
Bundler::new(
Parser::default(),
BundleRequireMode::default(),
RequireMode::default(),
std::iter::empty(),
)
}

fn new_rule_with_require_mode(mode: impl Into<BundleRequireMode>) -> Bundler {
fn new_rule_with_require_mode(mode: impl Into<RequireMode>) -> Bundler {
Bundler::new(Parser::default(), mode.into(), std::iter::empty())
}

Expand Down
16 changes: 9 additions & 7 deletions src/rules/bundle/path_require_mode/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use crate::nodes::{
use crate::process::{
to_expression, DefaultVisitor, IdentifierTracker, NodeProcessor, NodeVisitor, ScopeVisitor,
};
use crate::rules::require::{is_require_call, match_path_require_call, PathLocator};
use crate::rules::require::{is_require_call, PathLocator, SingularPathLocator};
use crate::rules::{
Context, ContextBuilder, FlawlessRule, ReplaceReferencedTokens, RuleProcessResult,
};
Expand Down Expand Up @@ -81,16 +81,20 @@ impl<'a, 'b, 'resources, PathLocatorImpl: PathLocator>
}
}

fn require_call(&self, call: &FunctionCall) -> Option<PathBuf> {
fn require_call(
&self,
call: &FunctionCall,
source: &Path,
) -> Option<(PathBuf, SingularPathLocator<'_, '_, '_>)> {
if is_require_call(call, self) {
match_path_require_call(call)
self.path_locator.match_path_require_call(call, source)
} else {
None
}
}

fn try_inline_call(&mut self, call: &FunctionCall) -> Option<Expression> {
let literal_require_path = self.require_call(call)?;
let (literal_require_path, path_locator) = self.require_call(call, &self.source)?;

if self.options.is_excluded(&literal_require_path) {
log::info!(
Expand All @@ -101,9 +105,7 @@ impl<'a, 'b, 'resources, PathLocatorImpl: PathLocator>
return None;
}

let require_path = match self
.path_locator
.find_require_path(&literal_require_path, &self.source)
let require_path = match path_locator.find_require_path(&literal_require_path, &self.source)
{
Ok(path) => path,
Err(err) => {
Expand Down
146 changes: 98 additions & 48 deletions src/rules/bundle/require_mode.rs
Original file line number Diff line number Diff line change
@@ -1,79 +1,129 @@
use std::str::FromStr;

use serde::{Deserialize, Serialize};

use crate::rules::{
require::{LuauPathLocator, LuauRequireMode, PathRequireMode, RequirePathLocator},
RuleProcessResult,
require::{
HybridPathLocator, LuauPathLocator, LuauRequireMode, PathRequireMode, RequirePathLocator,
RobloxPathLocator,
},
RequireMode, RequireModeLike, RobloxRequireMode, RuleProcessResult, SingularRequireMode,
};
use crate::{nodes::Block, rules::Context};

use super::{path_require_mode, BundleOptions};

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(deny_unknown_fields, rename_all = "snake_case", tag = "name")]
pub enum BundleRequireMode {
Path(PathRequireMode),
Luau(LuauRequireMode),
pub trait BundleRequireMode {
fn process_block(
&self,
block: &mut Block,
context: &Context,
options: &BundleOptions,
) -> RuleProcessResult;
}

impl From<PathRequireMode> for BundleRequireMode {
fn from(mode: PathRequireMode) -> Self {
Self::Path(mode)
impl BundleRequireMode for PathRequireMode {
fn process_block(
&self,
block: &mut Block,
context: &Context,
options: &BundleOptions,
) -> RuleProcessResult {
let mut require_mode = self.clone();
require_mode
.initialize(context)
.map_err(|err| err.to_string())?;

let locator = RequirePathLocator::new(
&require_mode,
context.project_location(),
context.resources(),
);

path_require_mode::process_block(block, context, options, locator)
}
}

impl FromStr for BundleRequireMode {
type Err = String;
impl BundleRequireMode for LuauRequireMode {
fn process_block(
&self,
block: &mut Block,
context: &Context,
options: &BundleOptions,
) -> RuleProcessResult {
let mut require_mode = self.clone();
require_mode
.initialize(context)
.map_err(|err| err.to_string())?;

let locator = LuauPathLocator::new(
&require_mode,
context.project_location(),
context.resources(),
);

fn from_str(s: &str) -> Result<Self, Self::Err> {
Ok(match s {
"path" => Self::Path(Default::default()),
"luau" => Self::Luau(Default::default()),
_ => return Err(format!("invalid require mode `{}`", s)),
})
path_require_mode::process_block(block, context, options, locator)
}
}

impl Default for BundleRequireMode {
fn default() -> Self {
Self::Path(Default::default())
impl BundleRequireMode for RobloxRequireMode {
fn process_block(
&self,
block: &mut Block,
context: &Context,
options: &BundleOptions,
) -> RuleProcessResult {
let mut require_mode = self.clone();
require_mode
.initialize(context)
.map_err(|err| err.to_string())?;

let locator = RobloxPathLocator::new(
&require_mode,
context.project_location(),
context.resources(),
);

path_require_mode::process_block(block, context, options, locator)
}
}

impl BundleRequireMode {
pub(crate) fn process_block(
impl BundleRequireMode for SingularRequireMode {
fn process_block(
&self,
block: &mut Block,
context: &Context,
options: &BundleOptions,
) -> RuleProcessResult {
match self {
Self::Path(path_require_mode) => {
let mut require_mode = path_require_mode.clone();
require_mode
.initialize(context)
.map_err(|err| err.to_string())?;

let locator = RequirePathLocator::new(
&require_mode,
context.project_location(),
context.resources(),
);

path_require_mode::process_block(block, context, options, locator)
path_require_mode.process_block(block, context, options)
}
Self::Luau(luau_require_mode) => {
let mut require_mode = luau_require_mode.clone();
require_mode
.initialize(context)
.map_err(|err| err.to_string())?;
luau_require_mode.process_block(block, context, options)
}
Self::Roblox(roblox_require_mode) => {
roblox_require_mode.process_block(block, context, options)
}
}
}
}

impl BundleRequireMode for RequireMode {
fn process_block(
&self,
block: &mut Block,
context: &Context,
options: &BundleOptions,
) -> RuleProcessResult {
match self {
RequireMode::Single(singular_require_mode) => {
singular_require_mode.process_block(block, context, options)
}
RequireMode::Hybrid(singular_require_modes) => {
let mut modes = singular_require_modes.clone();
for mode in modes.iter_mut() {
mode.initialize(context).map_err(|err| err.to_string())?;
}

let locator = LuauPathLocator::new(
&require_mode,
context.project_location(),
context.resources(),
);
let locator =
HybridPathLocator::new(&modes, context.project_location(), context.resources());

path_require_mode::process_block(block, context, options, locator)
}
Expand Down
Loading
Loading