Skip to content
Open
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
7 changes: 7 additions & 0 deletions .changepacks/changepack_log_barrel_namespace_imports.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"changes": {
"bindings/devup-ui-wasm/package.json": "Patch"
},
"note": "A project module re-exporting Devup UI (export { Box, css } from '@devup-ui/react', export * from '@devup-ui/react', export { styled as s }, export * as Devup, a default export of an import, chains of barrels and the compat entry) now works: a file importing Box or css from it compiles exactly as if it imported from the package, following the barrel through the resolver (relative paths, tsconfig paths, package exports), and hasDevupUI sees such a file. Members read from a namespace or default import of the package (Devup['css'], const { css } = Devup, Devup.css as a value) compile where the build can follow them, `Devup.x` for a name the package compiles being read like the named import. New build errors, located at the use: what a barrel re-exports but the build cannot read (an unresolvable `export *` or module, a namespace of modules re-exporting the package) is an error where its name is used instead of a runtime crash, and a namespace member read by a key the build cannot know (Devup[key]), written, or destructured in a form it cannot follow (a rest, a computed key, a default value, a nested pattern, an exported declaration, or members mixed with ones that stay at runtime) is an error that names the members to read. A namespace passed on whole (Object.keys(Devup), spyOn(Devup, 'css'), export default Devup) is left as it is",
"date": "2026-10-01T00:00:00.000Z"
}
8 changes: 8 additions & 0 deletions .changepacks/changepack_log_follow_aliases.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"changes": {
"bindings/devup-ui-wasm/package.json": "Patch",
"packages/bun-plugin/package.json": "Patch"
},
"note": "hasDevupUI takes the import aliases and is true for a file extraction changes: one importing a redirected package (@emotion/styled, ...), naming @emotion/react in a @jsxImportSource pragma, or in a project whose tsconfig jsxImportSource is @emotion/react, so the Bun plugin no longer skips files whose only Devup UI is Emotion's css prop or an aliased import. Aliases of Devup UI now compile like the original: `export const B = Box`, `const c = css; export { c as cc }`, `export const D = Devup` and `export const C = Devup.css` in a barrel (the barrel module exports them as re-exports of the package, and what imports them follows them), `export { Box }` after an import, `export default Box`, `const D = Devup` namespace aliases, and `const inner = css` declared inside a function. A css() or keyframes() const that a function reads before its declaration compiles. New build error: a css()/keyframes() const read before its declaration runs (outside a function) is located and says to move the declaration above its first read",
"date": "2026-10-01T00:00:00.000Z"
}
76 changes: 53 additions & 23 deletions bindings/devup-ui-wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use css::file_map::{
use extractor::extract_style::extract_style_value::ExtractStyleValue;
use extractor::{
ExtractOption, ImportAlias, ModuleResolver, ResolvedModule, extract, extract_with_modules,
extract_without_source_map, has_devup_ui,
extract_without_source_map, has_devup_ui_with,
};
use rustc_hash::FxHashSet;
use sheet::StyleSheet;
Expand Down Expand Up @@ -549,6 +549,15 @@ fn call_module_resolver(
})
}

/// The resolver set by `setModuleResolver`, if any
#[cfg(not(tarpaulin_include))]
fn resolver_from_js() -> Option<Box<ModuleResolver>> {
let resolver = MODULE_RESOLVER.with_borrow(Clone::clone)?;
Some(Box::new(move |specifier: &str, importer: &str| {
call_module_resolver(&resolver, specifier, importer)
}))
}

/// Extract with the resolver set by `setModuleResolver`, if any
#[cfg(not(tarpaulin_include))]
#[allow(clippy::too_many_arguments)]
Expand Down Expand Up @@ -729,8 +738,20 @@ pub fn get_theme_interface(
#[wasm_bindgen(js_name = "hasDevupUI")]
#[cfg(not(tarpaulin_include))]
#[must_use]
pub fn has_devup_ui_wasm(filename: &str, code: &str, package: &str) -> bool {
has_devup_ui(filename, code, package)
pub fn has_devup_ui_wasm(
filename: &str,
code: &str,
package: &str,
import_aliases: JsValue,
) -> bool {
let aliases = import_aliases_from_js(import_aliases).unwrap_or_default();
has_devup_ui_with(
filename,
code,
package,
&aliases,
resolver_from_js().as_deref(),
)
}

#[cfg(test)]
Expand Down Expand Up @@ -1375,31 +1396,40 @@ mod tests {
}

#[test]
#[serial]
fn test_has_devup_ui_wasm_function() {
let _state = TestStateGuard::new();
// Test positive case
assert!(has_devup_ui_wasm(
"test.tsx",
fn has_devup_ui_covers_what_extraction_changes() {
let resolver = |specifier: &str, _: &str| {
(specifier == "./ui").then(|| ResolvedModule {
path: "/src/ui.ts".to_string(),
code: "export { Box } from '@devup-ui/react'".to_string(),
})
};
let aliases = HashMap::from([("@emotion/styled".to_string(), ImportAlias::NamedToNamed)]);
let check = |filename: &str, code: &str, resolver: Option<&ModuleResolver>| {
has_devup_ui_with(filename, code, "@devup-ui/react", &aliases, resolver)
};
assert!(check(
"a.tsx",
"import { Box } from '@devup-ui/react';",
"@devup-ui/react"
));

// Test negative case
assert!(!has_devup_ui_wasm(
"test.tsx",
"const x = 1;",
"@devup-ui/react"
None
));

// Test invalid extension
assert!(!has_devup_ui_wasm(
"test.invalid",
assert!(!check("a.tsx", "const x = 1;", None));
assert!(!check(
"a.invalid",
"import { Box } from '@devup-ui/react';",
"@devup-ui/react"
None
));
assert!(check(
"a.tsx",
"import { Box } from './ui';",
Some(&resolver)
));
assert!(!check("a.tsx", "import { Box } from './ui';", None));
assert!(check(
"a.tsx",
"import styled from '@emotion/styled';",
None
));
}

#[test]
#[serial]
fn test_output_single_css_mode() {
Expand Down
Loading
Loading