mod inline;
mod interpreters;
#[cfg(test)]
mod tests;
use super::{ShellContext, Sink, commands, tables};
pub(super) fn note(
argv: &[String],
program: &str,
reads: &[String],
ctx: &ShellContext<'_>,
sink: &mut Sink,
) {
let Some(first) = argv.first() else {
return;
};
if first.contains('/') || interpreters::file_like(first) {
sink.execute(ctx, first);
}
let Some(run) = interpreters::program(program, &argv[1..]) else {
return;
};
for file in &run.files {
sink.execute(ctx, file);
if matches!(program, "node" | "nodejs")
&& !file.rsplit('/').next().is_some_and(|n| n.contains('.'))
{
for candidate in [".js", ".mjs", ".cjs", "/index.js"] {
sink.execute(ctx, &format!("{file}{candidate}"));
}
}
}
if let Some(module) = run.module.filter(|m| is_module_name(m)) {
let path = module.replace('.', "/");
sink.execute(ctx, &format!("{path}.py"));
sink.execute(ctx, &format!("{path}/__main__.py"));
}
if run.stdin {
stdin_files(reads, ctx, sink);
}
}
pub(super) fn shell_files(
script: Option<&str>,
from_stdin: bool,
reads: &[String],
ctx: &ShellContext<'_>,
sink: &mut Sink,
) {
match script {
Some(script) => sink.execute(ctx, script),
None if from_stdin => stdin_files(reads, ctx, sink),
None => {}
}
}
fn stdin_files(reads: &[String], ctx: &ShellContext<'_>, sink: &mut Sink) {
for file in reads {
if !tables::STREAM_SOURCES.contains(&file.as_str()) {
sink.execute(ctx, file);
}
}
}
pub(crate) fn inline(
code: &str,
(program, written): (&str, &[String]),
ctx: &ShellContext<'_>,
sink: &mut Sink,
) {
for word in inline::loads(program, code, written) {
sink.execute(ctx, &word);
}
}
fn is_module_name(word: &str) -> bool {
!word.is_empty()
&& word.split('.').all(|part| {
!part.is_empty() && part.bytes().all(|b| b.is_ascii_alphanumeric() || b == b'_')
})
}
#[must_use]
pub fn executed(command: &str, ctx: &ShellContext<'_>) -> Vec<(String, bool)> {
let mut sink = Sink::default();
let _ = commands::classify_into(command, ctx, &mut sink, 0);
let split = command.replace("${IFS}", " ").replace("$IFS", " ");
if split != command {
let _ = commands::classify_into(&split, ctx, &mut sink, 0);
}
sink.executed
}