Implementing Vue's Reactivity Transform
Vue 3 introduces a powerful feature called the "Reactivity Transform" which automatically makes top-level bindings within <script setup> reactive. This challenge is to understand and implement a simplified version of this transformation process, demonstrating how to convert plain JavaScript variables into Vue's reactive primitives.
Problem Description
Your task is to create a TypeScript function that simulates the core logic of Vue's reactivity transform for a given script block. This function will analyze a provided script and identify top-level variable declarations. For each identified variable, it should generate equivalent Vue 3 reactivity code (e.g., using ref or shallowRef).
Key Requirements:
- Analyze Script Content: The function should accept a string representing a
<script setup>block in TypeScript. - Identify Top-Level Declarations: Detect variable declarations (
let,const,var) at the top scope of the script. - Generate Reactive Code: For each identified declaration, generate a corresponding line of code that wraps the original value with Vue's reactivity API.
- For
letandvardeclarations, useref(). - For
constdeclarations, you might considerreadonly()orref()depending on the desired behavior (for this challenge,ref()is sufficient for demonstration).
- For
- Preserve Original Logic: The generated code should maintain the original variable names and values as much as possible, while introducing the reactivity wrappers.
- Handle Basic Types: The transformation should work for primitive types (string, number, boolean, null, undefined) and simple object literals.
- Output Transformed Script: The function should return a new string representing the transformed
<script setup>block.
Expected Behavior:
The function should take a script string, process it, and return a new script string where top-level variables are now reactive.
Edge Cases to Consider:
- Declarations with initial values.
- Declarations without initial values (should be initialized with
undefinedornullwithinref). - Multiple declarations in a single
letorconststatement (e.g.,let a = 1, b = 2;). - Complex initial values (e.g., nested objects, arrays). For this challenge, assume simple object literals and primitives.
Examples
Example 1:
Input:
<script setup lang="ts">
let count = 0;
const message = "Hello, Vue!";
var isActive = true;
</script>
Output:
<script setup lang="ts">
import { ref } from 'vue';
const count = ref(0);
const message = ref("Hello, Vue!");
const isActive = ref(true);
</script>
Explanation: count (let), message (const), and isActive (var) are top-level declarations. They are replaced with ref() calls wrapping their initial values, and import { ref } from 'vue'; is added.
Example 2:
Input:
<script setup lang="ts">
let userName;
const settings = { theme: 'dark' };
</script>
Output:
<script setup lang="ts">
import { ref } from 'vue';
const userName = ref(undefined);
const settings = ref({ theme: 'dark' });
</script>
Explanation: userName is declared without an initial value, so it's initialized with undefined inside ref(). settings is a top-level declaration with an object literal.
Example 3:
Input:
<script setup lang="ts">
function greet() {
console.log("Hello");
}
let x = 1, y = 2;
</script>
Output:
<script setup lang="ts">
import { ref } from 'vue';
function greet() {
console.log("Hello");
}
const x = ref(1);
const y = ref(2);
</script>
Explanation: The greet function is not a top-level declaration of a variable and is left as is. x and y are declared in a single let statement and are transformed into individual ref declarations.
Constraints
- The input script will always be a valid TypeScript
<script setup>block. - The transformation logic should focus on variable declarations (
let,const,var). Function declarations, class declarations, and imports should be preserved. - The initial values will be limited to primitives,
null,undefined, and simple object literals (e.g.,{ key: value }). Deeply nested or complex expressions as initial values are out of scope for this challenge. - The output should include the necessary import statement for
ref. - Performance is not a primary concern for this challenge; correctness and clarity of the transformation logic are paramount.
Notes
This challenge focuses on the core idea of identifying top-level variables and wrapping them with reactivity primitives. Real-world reactivity transforms involve more sophisticated parsing, AST manipulation, and handling of various JavaScript features.
You'll need to parse the input string to identify relevant declarations. Consider how to distinguish top-level declarations from those inside functions or other scopes. A simple approach might involve line-by-line processing and regular expressions, or a more robust solution might involve a basic Abstract Syntax Tree (AST) parser if you're familiar with them.
The goal is to create a function that can take a <script setup> string and return a new string with the reactivity transform applied, mimicking Vue's behavior.