expose more AST internals in grass_compiler
This commit is contained in:
parent
8363ca1dd3
commit
8b34d0ee2a
@ -9,6 +9,9 @@
|
||||
|
||||
# 0.13.0
|
||||
|
||||
- fix various module system bugs when combined with `@import`
|
||||
- expose more AST internals in `grass_compiler`
|
||||
|
||||
# 0.12.4
|
||||
|
||||
- implement builtin map-module functions `map.deep-merge(..)` and `map.deep-remove(..)`
|
||||
|
@ -16,13 +16,13 @@ use crate::{
|
||||
use super::AstExpr;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct Argument {
|
||||
pub struct Argument {
|
||||
pub name: Identifier,
|
||||
pub default: Option<AstExpr>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct ArgumentDeclaration {
|
||||
pub struct ArgumentDeclaration {
|
||||
pub args: Vec<Argument>,
|
||||
pub rest: Option<Identifier>,
|
||||
}
|
||||
@ -130,7 +130,7 @@ impl ArgumentDeclaration {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct ArgumentInvocation {
|
||||
pub struct ArgumentInvocation {
|
||||
pub(crate) positional: Vec<AstExpr>,
|
||||
pub(crate) named: BTreeMap<Identifier, AstExpr>,
|
||||
pub(crate) rest: Option<AstExpr>,
|
||||
|
@ -13,17 +13,17 @@ use super::{ArgumentInvocation, AstSupportsCondition, Interpolation, Interpolati
|
||||
|
||||
/// Represented by the `if` function
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct Ternary(pub ArgumentInvocation);
|
||||
pub struct Ternary(pub ArgumentInvocation);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct ListExpr {
|
||||
pub struct ListExpr {
|
||||
pub elems: Vec<Spanned<AstExpr>>,
|
||||
pub separator: ListSeparator,
|
||||
pub brackets: Brackets,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct FunctionCallExpr {
|
||||
pub struct FunctionCallExpr {
|
||||
pub namespace: Option<Spanned<Identifier>>,
|
||||
pub name: Identifier,
|
||||
pub arguments: Arc<ArgumentInvocation>,
|
||||
@ -31,17 +31,17 @@ pub(crate) struct FunctionCallExpr {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct InterpolatedFunction {
|
||||
pub struct InterpolatedFunction {
|
||||
pub name: Interpolation,
|
||||
pub arguments: ArgumentInvocation,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub(crate) struct AstSassMap(pub Vec<(Spanned<AstExpr>, AstExpr)>);
|
||||
pub struct AstSassMap(pub Vec<(Spanned<AstExpr>, AstExpr)>);
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct BinaryOpExpr {
|
||||
pub struct BinaryOpExpr {
|
||||
pub lhs: AstExpr,
|
||||
pub op: BinaryOp,
|
||||
pub rhs: AstExpr,
|
||||
@ -50,7 +50,7 @@ pub(crate) struct BinaryOpExpr {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum AstExpr {
|
||||
pub enum AstExpr {
|
||||
BinaryOp(Arc<BinaryOpExpr>),
|
||||
True,
|
||||
False,
|
||||
@ -83,7 +83,7 @@ pub(crate) enum AstExpr {
|
||||
// todo: make quotes bool
|
||||
// todo: track span inside
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct StringExpr(pub Interpolation, pub QuoteKind);
|
||||
pub struct StringExpr(pub Interpolation, pub QuoteKind);
|
||||
|
||||
impl StringExpr {
|
||||
fn quote_inner_text(
|
||||
|
@ -3,7 +3,7 @@ use codemap::Spanned;
|
||||
use super::AstExpr;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct Interpolation {
|
||||
pub struct Interpolation {
|
||||
pub contents: Vec<InterpolationPart>,
|
||||
}
|
||||
|
||||
@ -81,7 +81,7 @@ impl Interpolation {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum InterpolationPart {
|
||||
pub enum InterpolationPart {
|
||||
String(String),
|
||||
Expr(Spanned<AstExpr>),
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ pub(crate) struct MediaRule {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub(crate) struct MediaQuery {
|
||||
pub struct MediaQuery {
|
||||
pub modifier: Option<String>,
|
||||
pub media_type: Option<String>,
|
||||
pub conditions: Vec<String>,
|
||||
@ -60,7 +60,7 @@ impl MediaQuery {
|
||||
}
|
||||
|
||||
#[allow(clippy::if_not_else)]
|
||||
pub fn merge(&self, other: &Self) -> MediaQueryMergeResult {
|
||||
pub(crate) fn merge(&self, other: &Self) -> MediaQueryMergeResult {
|
||||
if !self.conjunction || !other.conjunction {
|
||||
return MediaQueryMergeResult::Unrepresentable;
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
pub(crate) use args::*;
|
||||
pub use args::*;
|
||||
pub(crate) use css::*;
|
||||
pub(crate) use expr::*;
|
||||
pub(crate) use interpolation::*;
|
||||
pub use expr::*;
|
||||
pub use interpolation::*;
|
||||
pub(crate) use media::*;
|
||||
pub(crate) use mixin::*;
|
||||
pub(crate) use stmt::*;
|
||||
pub use stmt::*;
|
||||
pub(crate) use style::*;
|
||||
pub(crate) use unknown::*;
|
||||
|
||||
|
@ -17,13 +17,13 @@ use crate::{
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[allow(unused)]
|
||||
pub(crate) struct AstSilentComment {
|
||||
pub struct AstSilentComment {
|
||||
pub text: String,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct AstPlainCssImport {
|
||||
pub struct AstPlainCssImport {
|
||||
pub url: Interpolation,
|
||||
pub modifiers: Option<Interpolation>,
|
||||
#[allow(unused)]
|
||||
@ -31,25 +31,25 @@ pub(crate) struct AstPlainCssImport {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct AstSassImport {
|
||||
pub struct AstSassImport {
|
||||
pub url: String,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct AstIf {
|
||||
pub struct AstIf {
|
||||
pub if_clauses: Vec<AstIfClause>,
|
||||
pub else_clause: Option<Vec<AstStmt>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct AstIfClause {
|
||||
pub struct AstIfClause {
|
||||
pub condition: AstExpr,
|
||||
pub body: Vec<AstStmt>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct AstFor {
|
||||
pub struct AstFor {
|
||||
pub variable: Spanned<Identifier>,
|
||||
pub from: Spanned<AstExpr>,
|
||||
pub to: Spanned<AstExpr>,
|
||||
@ -58,14 +58,14 @@ pub(crate) struct AstFor {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct AstReturn {
|
||||
pub struct AstReturn {
|
||||
pub val: AstExpr,
|
||||
#[allow(unused)]
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct AstRuleSet {
|
||||
pub struct AstRuleSet {
|
||||
pub selector: Interpolation,
|
||||
pub body: Vec<AstStmt>,
|
||||
pub selector_span: Span,
|
||||
@ -73,7 +73,7 @@ pub(crate) struct AstRuleSet {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct AstStyle {
|
||||
pub struct AstStyle {
|
||||
pub name: Interpolation,
|
||||
pub value: Option<Spanned<AstExpr>>,
|
||||
pub body: Vec<AstStmt>,
|
||||
@ -87,30 +87,30 @@ impl AstStyle {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct AstEach {
|
||||
pub struct AstEach {
|
||||
pub variables: Vec<Identifier>,
|
||||
pub list: AstExpr,
|
||||
pub body: Vec<AstStmt>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct AstMedia {
|
||||
pub struct AstMedia {
|
||||
pub query: Interpolation,
|
||||
pub query_span: Span,
|
||||
pub body: Vec<AstStmt>,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
pub(crate) type CssMediaQuery = MediaQuery;
|
||||
pub type CssMediaQuery = MediaQuery;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct AstWhile {
|
||||
pub struct AstWhile {
|
||||
pub condition: AstExpr,
|
||||
pub body: Vec<AstStmt>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct AstVariableDecl {
|
||||
pub struct AstVariableDecl {
|
||||
pub namespace: Option<Spanned<Identifier>>,
|
||||
pub name: Identifier,
|
||||
pub value: AstExpr,
|
||||
@ -120,26 +120,26 @@ pub(crate) struct AstVariableDecl {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct AstFunctionDecl {
|
||||
pub struct AstFunctionDecl {
|
||||
pub name: Spanned<Identifier>,
|
||||
pub arguments: ArgumentDeclaration,
|
||||
pub children: Vec<AstStmt>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct AstDebugRule {
|
||||
pub struct AstDebugRule {
|
||||
pub value: AstExpr,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct AstWarn {
|
||||
pub struct AstWarn {
|
||||
pub value: AstExpr,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct AstErrorRule {
|
||||
pub struct AstErrorRule {
|
||||
pub value: AstExpr,
|
||||
pub span: Span,
|
||||
}
|
||||
@ -153,13 +153,13 @@ impl PartialEq for AstFunctionDecl {
|
||||
impl Eq for AstFunctionDecl {}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct AstLoudComment {
|
||||
pub struct AstLoudComment {
|
||||
pub text: Interpolation,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct AstMixin {
|
||||
pub struct AstMixin {
|
||||
pub name: Identifier,
|
||||
pub args: ArgumentDeclaration,
|
||||
pub body: Vec<AstStmt>,
|
||||
@ -168,18 +168,18 @@ pub(crate) struct AstMixin {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct AstContentRule {
|
||||
pub struct AstContentRule {
|
||||
pub args: ArgumentInvocation,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct AstContentBlock {
|
||||
pub struct AstContentBlock {
|
||||
pub args: ArgumentDeclaration,
|
||||
pub body: Vec<AstStmt>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct AstInclude {
|
||||
pub struct AstInclude {
|
||||
pub namespace: Option<Spanned<Identifier>>,
|
||||
pub name: Spanned<Identifier>,
|
||||
pub args: ArgumentInvocation,
|
||||
@ -188,7 +188,7 @@ pub(crate) struct AstInclude {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct AstUnknownAtRule {
|
||||
pub struct AstUnknownAtRule {
|
||||
pub name: Interpolation,
|
||||
pub value: Option<Interpolation>,
|
||||
pub children: Option<Vec<AstStmt>>,
|
||||
@ -196,14 +196,15 @@ pub(crate) struct AstUnknownAtRule {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct AstExtendRule {
|
||||
pub struct AstExtendRule {
|
||||
pub value: Interpolation,
|
||||
pub is_optional: bool,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct AstAtRootRule {
|
||||
pub struct AstAtRootRule {
|
||||
// todo: rename to body
|
||||
pub children: Vec<AstStmt>,
|
||||
pub query: Option<Spanned<Interpolation>>,
|
||||
#[allow(unused)]
|
||||
@ -211,7 +212,7 @@ pub(crate) struct AstAtRootRule {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct AtRootQuery {
|
||||
pub struct AtRootQuery {
|
||||
pub include: bool,
|
||||
pub names: HashSet<String>,
|
||||
pub all: bool,
|
||||
@ -239,7 +240,7 @@ impl AtRootQuery {
|
||||
(self.all || self.rule) != self.include
|
||||
}
|
||||
|
||||
pub fn excludes(&self, stmt: &CssStmt) -> bool {
|
||||
pub(crate) fn excludes(&self, stmt: &CssStmt) -> bool {
|
||||
if self.all {
|
||||
return !self.include;
|
||||
}
|
||||
@ -266,12 +267,12 @@ impl Default for AtRootQuery {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct AstImportRule {
|
||||
pub struct AstImportRule {
|
||||
pub imports: Vec<AstImport>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum AstImport {
|
||||
pub enum AstImport {
|
||||
Plain(AstPlainCssImport),
|
||||
Sass(AstSassImport),
|
||||
}
|
||||
@ -283,7 +284,7 @@ impl AstImport {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct AstUseRule {
|
||||
pub struct AstUseRule {
|
||||
pub url: PathBuf,
|
||||
pub namespace: Option<String>,
|
||||
pub configuration: Vec<ConfiguredVariable>,
|
||||
@ -291,18 +292,18 @@ pub(crate) struct AstUseRule {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct ConfiguredVariable {
|
||||
pub struct ConfiguredVariable {
|
||||
pub name: Spanned<Identifier>,
|
||||
pub expr: Spanned<AstExpr>,
|
||||
pub is_guarded: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct Configuration {
|
||||
pub values: Arc<dyn MapView<Value = ConfiguredValue>>,
|
||||
pub struct Configuration {
|
||||
pub(crate) values: Arc<dyn MapView<Value = ConfiguredValue>>,
|
||||
#[allow(unused)]
|
||||
pub original_config: Option<Arc<RefCell<Self>>>,
|
||||
pub span: Option<Span>,
|
||||
pub(crate) original_config: Option<Arc<RefCell<Self>>>,
|
||||
pub(crate) span: Option<Span>,
|
||||
}
|
||||
|
||||
impl Configuration {
|
||||
@ -403,7 +404,7 @@ impl Configuration {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct ConfiguredValue {
|
||||
pub struct ConfiguredValue {
|
||||
pub value: Value,
|
||||
pub configuration_span: Option<Span>,
|
||||
}
|
||||
@ -425,7 +426,7 @@ impl ConfiguredValue {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct AstForwardRule {
|
||||
pub struct AstForwardRule {
|
||||
pub url: PathBuf,
|
||||
pub shown_mixins_and_functions: Option<HashSet<Identifier>>,
|
||||
pub shown_variables: Option<HashSet<Identifier>>,
|
||||
@ -497,7 +498,7 @@ impl AstForwardRule {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum AstSupportsCondition {
|
||||
pub enum AstSupportsCondition {
|
||||
Anything {
|
||||
contents: Interpolation,
|
||||
},
|
||||
@ -519,14 +520,14 @@ pub(crate) enum AstSupportsCondition {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct AstSupportsRule {
|
||||
pub struct AstSupportsRule {
|
||||
pub condition: AstSupportsCondition,
|
||||
pub children: Vec<AstStmt>,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) enum AstStmt {
|
||||
pub enum AstStmt {
|
||||
If(AstIf),
|
||||
For(AstFor),
|
||||
Return(AstReturn),
|
||||
@ -555,12 +556,13 @@ pub(crate) enum AstStmt {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct StyleSheet {
|
||||
pub struct StyleSheet {
|
||||
pub body: Vec<AstStmt>,
|
||||
pub url: PathBuf,
|
||||
pub is_plain_css: bool,
|
||||
/// Array of indices into body
|
||||
/// Array of indices into `body`
|
||||
pub uses: Vec<usize>,
|
||||
/// Array of indices into `body`
|
||||
pub forwards: Vec<usize>,
|
||||
}
|
||||
|
||||
|
@ -21,11 +21,11 @@ use super::{scope::Scopes, visitor::CallableContentBlock};
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct Environment {
|
||||
pub scopes: Scopes,
|
||||
pub modules: Arc<RefCell<Modules>>,
|
||||
pub global_modules: Vec<Arc<RefCell<Module>>>,
|
||||
pub modules: Mutable<Modules>,
|
||||
pub global_modules: Vec<Mutable<Module>>,
|
||||
pub content: Option<Arc<CallableContentBlock>>,
|
||||
pub forwarded_modules: Arc<RefCell<Vec<Arc<RefCell<Module>>>>>,
|
||||
pub imported_modules: Arc<RefCell<Vec<Arc<RefCell<Module>>>>>,
|
||||
pub forwarded_modules: Mutable<Vec<Mutable<Module>>>,
|
||||
pub imported_modules: Mutable<Vec<Mutable<Module>>>,
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub nested_forwarded_modules: Option<Mutable<Vec<Mutable<Vec<Mutable<Module>>>>>>,
|
||||
}
|
||||
@ -175,7 +175,6 @@ impl Environment {
|
||||
imported_modules.extend(forwarded.borrow().iter().map(Arc::clone));
|
||||
forwarded_modules.extend(forwarded.borrow().iter().map(Arc::clone));
|
||||
} else {
|
||||
self.scopes.last_variable_index = None;
|
||||
self.nested_forwarded_modules
|
||||
.get_or_insert_with(|| {
|
||||
Arc::new(RefCell::new(
|
||||
|
@ -111,7 +111,10 @@ pub struct Visitor<'a> {
|
||||
pub(crate) media_queries: Option<Vec<MediaQuery>>,
|
||||
pub(crate) media_query_sources: Option<IndexSet<MediaQuery>>,
|
||||
pub(crate) extender: ExtensionStore,
|
||||
pub(crate) current_import_path: PathBuf,
|
||||
|
||||
/// The complete file path of the current file being visited. Imports are
|
||||
/// resolved relative to this path
|
||||
pub current_import_path: PathBuf,
|
||||
pub(crate) is_plain_css: bool,
|
||||
pub(crate) modules: BTreeMap<PathBuf, Arc<RefCell<Module>>>,
|
||||
pub(crate) active_modules: BTreeSet<PathBuf>,
|
||||
@ -119,10 +122,10 @@ pub struct Visitor<'a> {
|
||||
parent: Option<CssTreeIdx>,
|
||||
configuration: Arc<RefCell<Configuration>>,
|
||||
import_nodes: Vec<CssStmt>,
|
||||
pub(crate) options: &'a Options<'a>,
|
||||
pub options: &'a Options<'a>,
|
||||
pub(crate) map: &'a mut CodeMap,
|
||||
// todo: remove
|
||||
span_before: Span,
|
||||
empty_span: Span,
|
||||
import_cache: BTreeMap<PathBuf, StyleSheet>,
|
||||
/// As a simple heuristic, we don't cache the results of an import unless it
|
||||
/// has been seen in the past. In the majority of cases, files are imported
|
||||
@ -131,16 +134,16 @@ pub struct Visitor<'a> {
|
||||
}
|
||||
|
||||
impl<'a> Visitor<'a> {
|
||||
pub(crate) fn new(
|
||||
pub fn new(
|
||||
path: &Path,
|
||||
options: &'a Options<'a>,
|
||||
map: &'a mut CodeMap,
|
||||
span_before: Span,
|
||||
empty_span: Span,
|
||||
) -> Self {
|
||||
let mut flags = ContextFlags::empty();
|
||||
flags.set(ContextFlags::IN_SEMI_GLOBAL_SCOPE, true);
|
||||
|
||||
let extender = ExtensionStore::new(span_before);
|
||||
let extender = ExtensionStore::new(empty_span);
|
||||
|
||||
let current_import_path = path.to_path_buf();
|
||||
|
||||
@ -162,7 +165,7 @@ impl<'a> Visitor<'a> {
|
||||
modules: BTreeMap::new(),
|
||||
active_modules: BTreeSet::new(),
|
||||
options,
|
||||
span_before,
|
||||
empty_span,
|
||||
map,
|
||||
import_cache: BTreeMap::new(),
|
||||
files_seen: BTreeSet::new(),
|
||||
@ -433,7 +436,7 @@ impl<'a> Visitor<'a> {
|
||||
self.parenthesize_supports_condition(*condition, None)?
|
||||
)),
|
||||
AstSupportsCondition::Interpolation(expr) => {
|
||||
self.evaluate_to_css(expr, QuoteKind::None, self.span_before)
|
||||
self.evaluate_to_css(expr, QuoteKind::None, self.empty_span)
|
||||
}
|
||||
AstSupportsCondition::Declaration { name, value } => {
|
||||
let old_in_supports_decl = self.flags.in_supports_declaration();
|
||||
@ -448,9 +451,9 @@ impl<'a> Visitor<'a> {
|
||||
|
||||
let result = format!(
|
||||
"({}:{}{})",
|
||||
self.evaluate_to_css(name, QuoteKind::Quoted, self.span_before)?,
|
||||
self.evaluate_to_css(name, QuoteKind::Quoted, self.empty_span)?,
|
||||
if is_custom_property { "" } else { " " },
|
||||
self.evaluate_to_css(value, QuoteKind::Quoted, self.span_before)?,
|
||||
self.evaluate_to_css(value, QuoteKind::Quoted, self.empty_span)?,
|
||||
);
|
||||
|
||||
self.flags
|
||||
@ -578,7 +581,7 @@ impl<'a> Visitor<'a> {
|
||||
}
|
||||
|
||||
let env = Environment::new();
|
||||
let mut extension_store = ExtensionStore::new(self.span_before);
|
||||
let mut extension_store = ExtensionStore::new(self.empty_span);
|
||||
|
||||
self.with_environment::<SassResult<()>, _>(env.new_closure(), |visitor| {
|
||||
let old_parent = visitor.parent;
|
||||
@ -795,7 +798,7 @@ impl<'a> Visitor<'a> {
|
||||
/// <https://sass-lang.com/documentation/at-rules/import#finding-the-file>
|
||||
/// <https://sass-lang.com/documentation/at-rules/import#load-paths>
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
fn find_import(&self, path: &Path) -> Option<PathBuf> {
|
||||
pub fn find_import(&self, path: &Path) -> Option<PathBuf> {
|
||||
let path_buf = if path.is_absolute() {
|
||||
path.into()
|
||||
} else {
|
||||
@ -869,17 +872,17 @@ impl<'a> Visitor<'a> {
|
||||
&mut self,
|
||||
lexer: Lexer,
|
||||
path: &Path,
|
||||
span_before: Span,
|
||||
empty_span: Span,
|
||||
) -> SassResult<StyleSheet> {
|
||||
match InputSyntax::for_path(path) {
|
||||
InputSyntax::Scss => {
|
||||
ScssParser::new(lexer, self.map, self.options, span_before, path).__parse()
|
||||
ScssParser::new(lexer, self.map, self.options, empty_span, path).__parse()
|
||||
}
|
||||
InputSyntax::Sass => {
|
||||
SassParser::new(lexer, self.map, self.options, span_before, path).__parse()
|
||||
SassParser::new(lexer, self.map, self.options, empty_span, path).__parse()
|
||||
}
|
||||
InputSyntax::Css => {
|
||||
CssParser::new(lexer, self.map, self.options, span_before, path).__parse()
|
||||
CssParser::new(lexer, self.map, self.options, empty_span, path).__parse()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -988,7 +991,7 @@ impl<'a> Visitor<'a> {
|
||||
// Create a dummy module with empty CSS and no extensions to make forwarded
|
||||
// members available in the current import context and to combine all the
|
||||
// CSS from modules used by [stylesheet].
|
||||
let module = env.to_dummy_module(self.span_before);
|
||||
let module = env.to_dummy_module(self.empty_span);
|
||||
self.env.import_forwards(module);
|
||||
|
||||
if loads_user_defined_modules {
|
||||
@ -2096,7 +2099,7 @@ impl<'a> Visitor<'a> {
|
||||
// todo: emit warning. we don't currently because it can be quite loud
|
||||
// self.emit_warning(
|
||||
// Cow::Borrowed("Using / for division is deprecated and will be removed at some point in the future"),
|
||||
// self.span_before,
|
||||
// self.empty_span,
|
||||
// );
|
||||
}
|
||||
_ => {}
|
||||
@ -2567,7 +2570,7 @@ impl<'a> Visitor<'a> {
|
||||
AstExpr::True => Value::True,
|
||||
AstExpr::False => Value::False,
|
||||
AstExpr::Calculation { name, args } => {
|
||||
self.visit_calculation_expr(name, args, self.span_before)?
|
||||
self.visit_calculation_expr(name, args, self.empty_span)?
|
||||
}
|
||||
AstExpr::FunctionCall(func_call) => self.visit_function_call_expr(func_call)?,
|
||||
AstExpr::If(if_expr) => self.visit_ternary((*if_expr).clone())?,
|
||||
|
@ -84,6 +84,7 @@ grass input.scss
|
||||
use std::path::Path;
|
||||
|
||||
use parse::{CssParser, SassParser, StylesheetParser};
|
||||
use sass_ast::StyleSheet;
|
||||
use serializer::Serializer;
|
||||
#[cfg(feature = "wasm-exports")]
|
||||
use wasm_bindgen::prelude::*;
|
||||
@ -112,6 +113,12 @@ pub mod sass_value {
|
||||
};
|
||||
}
|
||||
|
||||
pub mod sass_ast {
|
||||
pub use crate::ast::*;
|
||||
}
|
||||
|
||||
pub use codemap;
|
||||
|
||||
mod ast;
|
||||
mod builtin;
|
||||
mod color;
|
||||
@ -135,6 +142,42 @@ fn raw_to_parse_error(map: &CodeMap, err: Error, unicode: bool) -> Box<Error> {
|
||||
Box::new(Error::from_loc(message, map.look_up_span(span), unicode))
|
||||
}
|
||||
|
||||
pub fn parse_stylesheet<P: AsRef<Path>>(
|
||||
input: String,
|
||||
file_name: P,
|
||||
options: &Options,
|
||||
) -> Result<StyleSheet> {
|
||||
// todo: much of this logic is duplicated in `from_string_with_file_name`
|
||||
let mut map = CodeMap::new();
|
||||
let path = file_name.as_ref();
|
||||
let file = map.add_file(path.to_string_lossy().into_owned(), input);
|
||||
let empty_span = file.span.subspan(0, 0);
|
||||
let lexer = Lexer::new_from_file(&file);
|
||||
|
||||
let input_syntax = options
|
||||
.input_syntax
|
||||
.unwrap_or_else(|| InputSyntax::for_path(path));
|
||||
|
||||
let stylesheet = match input_syntax {
|
||||
InputSyntax::Scss => {
|
||||
ScssParser::new(lexer, &mut map, options, empty_span, file_name.as_ref()).__parse()
|
||||
}
|
||||
InputSyntax::Sass => {
|
||||
SassParser::new(lexer, &mut map, options, empty_span, file_name.as_ref()).__parse()
|
||||
}
|
||||
InputSyntax::Css => {
|
||||
CssParser::new(lexer, &mut map, options, empty_span, file_name.as_ref()).__parse()
|
||||
}
|
||||
};
|
||||
|
||||
let stylesheet = match stylesheet {
|
||||
Ok(v) => v,
|
||||
Err(e) => return Err(raw_to_parse_error(&map, *e, options.unicode_error_messages)),
|
||||
};
|
||||
|
||||
Ok(stylesheet)
|
||||
}
|
||||
|
||||
fn from_string_with_file_name<P: AsRef<Path>>(
|
||||
input: String,
|
||||
file_name: P,
|
||||
|
@ -191,7 +191,12 @@ pub enum InputSyntax {
|
||||
|
||||
impl InputSyntax {
|
||||
pub(crate) fn for_path(path: &Path) -> Self {
|
||||
match path.extension().and_then(|ext| ext.to_str()) {
|
||||
match path
|
||||
.extension()
|
||||
.and_then(|ext| ext.to_str())
|
||||
.map(str::to_ascii_lowercase)
|
||||
.as_deref()
|
||||
{
|
||||
Some("css") => Self::Css,
|
||||
Some("sass") => Self::Sass,
|
||||
_ => Self::Scss,
|
||||
|
@ -14,7 +14,7 @@ pub(crate) struct CssParser<'a> {
|
||||
// todo: likely superfluous
|
||||
pub map: &'a mut CodeMap,
|
||||
pub path: &'a Path,
|
||||
pub span_before: Span,
|
||||
pub empty_span: Span,
|
||||
pub flags: ContextFlags,
|
||||
pub options: &'a Options<'a>,
|
||||
}
|
||||
@ -70,8 +70,8 @@ impl<'a> StylesheetParser<'a> for CssParser<'a> {
|
||||
0
|
||||
}
|
||||
|
||||
fn span_before(&self) -> Span {
|
||||
self.span_before
|
||||
fn empty_span(&self) -> Span {
|
||||
self.empty_span
|
||||
}
|
||||
|
||||
const IDENTIFIER_LIKE: Option<fn(&mut Self) -> SassResult<Spanned<AstExpr>>> =
|
||||
@ -112,14 +112,14 @@ impl<'a> CssParser<'a> {
|
||||
toks: Lexer<'a>,
|
||||
map: &'a mut CodeMap,
|
||||
options: &'a Options<'a>,
|
||||
span_before: Span,
|
||||
empty_span: Span,
|
||||
file_name: &'a Path,
|
||||
) -> Self {
|
||||
CssParser {
|
||||
toks,
|
||||
map,
|
||||
path: file_name,
|
||||
span_before,
|
||||
empty_span,
|
||||
flags: ContextFlags::empty(),
|
||||
options,
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ pub(crate) struct SassParser<'a> {
|
||||
// todo: likely superfluous
|
||||
pub map: &'a mut CodeMap,
|
||||
pub path: &'a Path,
|
||||
pub span_before: Span,
|
||||
pub empty_span: Span,
|
||||
pub flags: ContextFlags,
|
||||
pub options: &'a Options<'a>,
|
||||
pub current_indentation: usize,
|
||||
@ -103,8 +103,8 @@ impl<'a> StylesheetParser<'a> for SassParser<'a> {
|
||||
self.current_indentation
|
||||
}
|
||||
|
||||
fn span_before(&self) -> Span {
|
||||
self.span_before
|
||||
fn empty_span(&self) -> Span {
|
||||
self.empty_span
|
||||
}
|
||||
|
||||
fn parse_style_rule_selector(&mut self) -> SassResult<Interpolation> {
|
||||
@ -353,7 +353,7 @@ impl<'a> SassParser<'a> {
|
||||
toks: Lexer<'a>,
|
||||
map: &'a mut CodeMap,
|
||||
options: &'a Options<'a>,
|
||||
span_before: Span,
|
||||
empty_span: Span,
|
||||
file_name: &'a Path,
|
||||
) -> Self {
|
||||
let mut flags = ContextFlags::empty();
|
||||
@ -364,7 +364,7 @@ impl<'a> SassParser<'a> {
|
||||
toks,
|
||||
map,
|
||||
path: file_name,
|
||||
span_before,
|
||||
empty_span,
|
||||
flags,
|
||||
options,
|
||||
current_indentation: 0,
|
||||
|
@ -11,7 +11,7 @@ pub(crate) struct ScssParser<'a> {
|
||||
// todo: likely superfluous
|
||||
pub map: &'a mut CodeMap,
|
||||
pub path: &'a Path,
|
||||
pub span_before: Span,
|
||||
pub empty_span: Span,
|
||||
pub flags: ContextFlags,
|
||||
pub options: &'a Options<'a>,
|
||||
}
|
||||
@ -21,7 +21,7 @@ impl<'a> ScssParser<'a> {
|
||||
toks: Lexer<'a>,
|
||||
map: &'a mut CodeMap,
|
||||
options: &'a Options<'a>,
|
||||
span_before: Span,
|
||||
empty_span: Span,
|
||||
file_name: &'a Path,
|
||||
) -> Self {
|
||||
let mut flags = ContextFlags::empty();
|
||||
@ -32,7 +32,7 @@ impl<'a> ScssParser<'a> {
|
||||
toks,
|
||||
map,
|
||||
path: file_name,
|
||||
span_before,
|
||||
empty_span,
|
||||
flags,
|
||||
options,
|
||||
}
|
||||
@ -82,7 +82,7 @@ impl<'a> StylesheetParser<'a> for ScssParser<'a> {
|
||||
&mut self.flags
|
||||
}
|
||||
|
||||
fn span_before(&self) -> Span {
|
||||
self.span_before
|
||||
fn empty_span(&self) -> Span {
|
||||
self.empty_span
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ pub(crate) trait StylesheetParser<'a>: BaseParser<'a> + Sized {
|
||||
fn options(&self) -> &Options;
|
||||
fn path(&self) -> &Path;
|
||||
fn map(&mut self) -> &mut CodeMap;
|
||||
fn span_before(&self) -> Span;
|
||||
fn empty_span(&self) -> Span;
|
||||
fn current_indentation(&self) -> usize;
|
||||
fn flags(&self) -> &ContextFlags;
|
||||
fn flags_mut(&mut self) -> &mut ContextFlags;
|
||||
@ -184,6 +184,7 @@ pub(crate) trait StylesheetParser<'a>: BaseParser<'a> + Sized {
|
||||
Ok(stmts)
|
||||
}
|
||||
|
||||
// todo: rename
|
||||
fn __parse(&mut self) -> SassResult<StyleSheet> {
|
||||
let mut style_sheet = StyleSheet::new(
|
||||
self.is_plain_css(),
|
||||
@ -758,8 +759,7 @@ pub(crate) trait StylesheetParser<'a>: BaseParser<'a> + Sized {
|
||||
buffer.add_char('(');
|
||||
}
|
||||
|
||||
buffer
|
||||
.add_expr(AstExpr::Supports(Arc::new(query)).span(self.span_before()));
|
||||
buffer.add_expr(AstExpr::Supports(Arc::new(query)).span(self.empty_span()));
|
||||
|
||||
if !is_declaration {
|
||||
buffer.add_char(')');
|
||||
@ -1552,7 +1552,7 @@ pub(crate) trait StylesheetParser<'a>: BaseParser<'a> + Sized {
|
||||
// if namespace is empty, avoid attempting to parse an identifier from
|
||||
// an empty string, as there will be no span to emit
|
||||
let identifier = if namespace.is_empty() {
|
||||
Err(("", self.span_before()).into())
|
||||
Err(("", self.empty_span()).into())
|
||||
} else {
|
||||
mem::swap(self.toks_mut(), &mut toks);
|
||||
let ident = self.parse_identifier(false, false);
|
||||
|
Loading…
x
Reference in New Issue
Block a user