AST Merge
How lunar-css init patches an existing metro.config.js without destroying your code.
What is AST merge?
When metro.config.js exists but doesn't yet reference @lunar-kit/css/metro, the CLI performs an AST-based merge instead of overwriting the file. It parses the existing code, inserts only the two required changes, and regenerates the file — leaving everything else untouched.
The two changes
- Add the import —
const { withLunarCSS } = require('@lunar-kit/css/metro')after the last existingrequire()variable declaration - Wrap
module.exports—module.exports = withLunarCSS(<existing value>)
Example
Input (your existing metro.config.js):
const { getDefaultConfig } = require('expo/metro-config')
const config = getDefaultConfig(__dirname)
config.resolver.assetExts.push('lottie')
module.exports = configOutput (after AST merge):
const { getDefaultConfig } = require('expo/metro-config');
const { withLunarCSS } = require('@lunar-kit/css/metro');
const config = getDefaultConfig(__dirname);
config.resolver.assetExts.push('lottie');
module.exports = withLunarCSS(config);Note: @babel/generator normalizes quotes to double-quotes during code generation. Your custom logic (config.resolver.assetExts.push('lottie')) is fully preserved.
When AST merge is skipped
If the file already contains the string '@lunar-kit/css/metro' (or "@lunar-kit/css/metro"), the CLI skips it entirely — no re-parsing, no changes.
If the file contains no module.exports statement, the CLI also skips and prints a warning recommending manual wiring.
Powered by
AST parsing uses @babel/parser with TypeScript + JSX support. Traversal via @babel/traverse. Code generation via @babel/generator. These are devDependencies of LunarCSS, not runtime dependencies.