@mulanjs/mulanjs 1.0.1-dev.20260314141520 → 1.0.1-dev.20261016100840
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +29 -7
- package/dist/compiler/ast-parser.js +66 -0
- package/dist/compiler/compiler.js +14 -4
- package/dist/compiler/dom-compiler.js +14 -6
- package/dist/compiler/script-compiler.js +101 -52
- package/dist/compiler/sfc-parser.js +167 -75
- package/dist/core/component.js +16 -1
- package/dist/mulan.esm.js +16 -1
- package/dist/mulan.esm.js.map +1 -1
- package/dist/mulan.js +16 -1
- package/dist/mulan.js.map +1 -1
- package/package.json +20 -4
- package/src/cli/index.js +86 -42
- package/src/cli/static-generator.js +1 -1
- package/src/compiler/ast-parser.ts +60 -0
- package/src/compiler/compiler.ts +14 -4
- package/src/compiler/dom-compiler.ts +12 -6
- package/src/compiler/script-compiler.ts +161 -64
- package/src/compiler/sfc-parser.ts +174 -74
package/README.md
CHANGED
|
@@ -63,16 +63,40 @@ Adaptive non-blocking loops (`muBurst`) and true multicore parallelism (`muSurge
|
|
|
63
63
|
|
|
64
64
|
### Native SCSS Support 🎨
|
|
65
65
|
Built-in support for `<style lang="scss">`. No config required. Just design.
|
|
66
|
-
## 🚀 Quick Start Example
|
|
67
66
|
|
|
68
|
-
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
## ⚡ Mulan Minicode (AI-First, Ultra-Dense Syntax)
|
|
70
|
+
|
|
71
|
+
MulanJS supports **Minicode** — an ultra-compact single-file component syntax designed for maximum developer ergonomics and AI code-generation efficiency (**~20 tokens** per component, ~40% fewer tokens than Svelte 5):
|
|
72
|
+
|
|
73
|
+
- **No mandatory imports**: Ambient `$state`, `$derived`, `$effect`, and `$vault` runes.
|
|
74
|
+
- **Implicit Root Template**: Drop `<mu-template>` entirely — top-level markup is automatically compiled.
|
|
75
|
+
- **Single-Brace Interpolation**: `{count}` alongside `${count}` and `{{count}}`.
|
|
76
|
+
- **Terse Directives**: `@click="count++"` or `@click="count--"` or `:disabled="count === 0"`.
|
|
77
|
+
|
|
78
|
+
```html
|
|
79
|
+
<mu>
|
|
80
|
+
count = $state(0)
|
|
81
|
+
double = $derived(count * 2)
|
|
82
|
+
</mu>
|
|
83
|
+
|
|
84
|
+
<button class="mu-btn" @click="count++">
|
|
85
|
+
Count: {count} | Double: {double}
|
|
86
|
+
</button>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
## 🚀 Quick Start Example (Classic Syntax)
|
|
92
|
+
|
|
93
|
+
MulanJS components (`.mujs`) also support classic explicit syntax with `<mu-template>`:
|
|
69
94
|
|
|
70
95
|
```javascript
|
|
71
96
|
<mu>
|
|
72
|
-
// The <mu> tag is the
|
|
73
|
-
import { muState } from 'mulanjs';
|
|
97
|
+
// The <mu> tag is the powerful replacement for <script setup lang="ts">
|
|
98
|
+
import { muState } from '@mulanjs/mulanjs';
|
|
74
99
|
|
|
75
|
-
// Create reactive state natively
|
|
76
100
|
state = muState({ count: 0 });
|
|
77
101
|
|
|
78
102
|
debugClick() →
|
|
@@ -81,7 +105,6 @@ debugClick() →
|
|
|
81
105
|
</mu>
|
|
82
106
|
```
|
|
83
107
|
```html
|
|
84
|
-
|
|
85
108
|
<mu-template>
|
|
86
109
|
<div class="page">
|
|
87
110
|
<div class="hero">
|
|
@@ -90,7 +113,6 @@ debugClick() →
|
|
|
90
113
|
|
|
91
114
|
<div class="counter-box">
|
|
92
115
|
<p>Interactive Counter:</p>
|
|
93
|
-
<!-- Native Mulan Event Binding -->
|
|
94
116
|
<button class="mu-btn" mu-click="debugClick()">
|
|
95
117
|
Count is: ${state.count}
|
|
96
118
|
</button>
|
|
@@ -152,11 +152,62 @@ function parse(template, errors) {
|
|
|
152
152
|
}
|
|
153
153
|
cursor = innerCursor;
|
|
154
154
|
}
|
|
155
|
+
// 5. Single-Brace Interpolation { } (Svelte / Minicode)
|
|
156
|
+
else if (template.startsWith('{', cursor) && !template.startsWith('{{', cursor) && !template.startsWith('${', cursor)) {
|
|
157
|
+
let innerCursor = cursor + 1;
|
|
158
|
+
let depth = 1;
|
|
159
|
+
while (innerCursor < template.length && depth > 0) {
|
|
160
|
+
if (template[innerCursor] === '{')
|
|
161
|
+
depth++;
|
|
162
|
+
if (template[innerCursor] === '}')
|
|
163
|
+
depth--;
|
|
164
|
+
innerCursor++;
|
|
165
|
+
}
|
|
166
|
+
if (depth === 0) {
|
|
167
|
+
const content = template.slice(cursor + 1, innerCursor - 1).trim();
|
|
168
|
+
const startPos = getPos(cursor);
|
|
169
|
+
const endPos = getPos(innerCursor);
|
|
170
|
+
stack[stack.length - 1].children.push({
|
|
171
|
+
type: 'Interpolation',
|
|
172
|
+
content,
|
|
173
|
+
...startPos,
|
|
174
|
+
endLine: endPos.startLine,
|
|
175
|
+
endColumn: endPos.startColumn
|
|
176
|
+
});
|
|
177
|
+
cursor = innerCursor;
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
const startPos = getPos(cursor);
|
|
181
|
+
const endPos = getPos(cursor + 1);
|
|
182
|
+
const lastChild = stack[stack.length - 1].children[stack[stack.length - 1].children.length - 1];
|
|
183
|
+
if (lastChild && lastChild.type === 'Text') {
|
|
184
|
+
lastChild.content += '{';
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
stack[stack.length - 1].children.push({
|
|
188
|
+
type: 'Text',
|
|
189
|
+
content: '{',
|
|
190
|
+
...startPos,
|
|
191
|
+
endLine: endPos.startLine,
|
|
192
|
+
endColumn: endPos.startColumn
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
cursor++;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
155
198
|
// 5. Text Nodes
|
|
156
199
|
else {
|
|
157
200
|
let nextTag = template.indexOf('<', cursor);
|
|
158
201
|
let nextInterp = template.indexOf('{{', cursor);
|
|
159
202
|
let nextNative = template.indexOf('${', cursor);
|
|
203
|
+
let nextBrace = template.indexOf('{', cursor);
|
|
204
|
+
// Skip {{ and ${ for nextBrace
|
|
205
|
+
while (nextBrace !== -1) {
|
|
206
|
+
if (template[nextBrace + 1] !== '{' && (nextBrace === 0 || template[nextBrace - 1] !== '$')) {
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
nextBrace = template.indexOf('{', nextBrace + 1);
|
|
210
|
+
}
|
|
160
211
|
let end = template.length;
|
|
161
212
|
// Heuristic for nextTag: it must look like a tag start
|
|
162
213
|
while (nextTag !== -1) {
|
|
@@ -171,6 +222,8 @@ function parse(template, errors) {
|
|
|
171
222
|
end = nextInterp;
|
|
172
223
|
if (nextNative !== -1 && nextNative < end)
|
|
173
224
|
end = nextNative;
|
|
225
|
+
if (nextBrace !== -1 && nextBrace < end)
|
|
226
|
+
end = nextBrace;
|
|
174
227
|
const rawContent = template.slice(cursor, end);
|
|
175
228
|
const content = decodeEntities(rawContent);
|
|
176
229
|
if (content) {
|
|
@@ -287,6 +340,19 @@ function parseTag(content) {
|
|
|
287
340
|
value = attrStr.slice(valStart, i);
|
|
288
341
|
i++;
|
|
289
342
|
}
|
|
343
|
+
else if (i < attrStr.length && attrStr[i] === '{') {
|
|
344
|
+
const valStart = i + 1;
|
|
345
|
+
let depth = 1;
|
|
346
|
+
i++;
|
|
347
|
+
while (i < attrStr.length && depth > 0) {
|
|
348
|
+
if (attrStr[i] === '{')
|
|
349
|
+
depth++;
|
|
350
|
+
if (attrStr[i] === '}')
|
|
351
|
+
depth--;
|
|
352
|
+
i++;
|
|
353
|
+
}
|
|
354
|
+
value = attrStr.slice(valStart, i - 1).trim();
|
|
355
|
+
}
|
|
290
356
|
else {
|
|
291
357
|
const valStart = i;
|
|
292
358
|
while (i < attrStr.length && !/\s/.test(attrStr[i])) {
|
|
@@ -121,12 +121,19 @@ if (typeof document !== 'undefined') {
|
|
|
121
121
|
${templateResult.code}
|
|
122
122
|
|
|
123
123
|
// Attach template to component
|
|
124
|
-
if (__component__.prototype) {
|
|
124
|
+
if (typeof __component__ === 'function' && __component__.prototype) {
|
|
125
125
|
// Class component
|
|
126
126
|
__component__.prototype.template = render;
|
|
127
|
-
} else if (typeof __component__ === 'object') {
|
|
128
|
-
// Options object
|
|
129
|
-
|
|
127
|
+
} else if (typeof __component__ === 'object' && __component__ !== null) {
|
|
128
|
+
// Wrap Options object or plain object in defineComponent so it is constructible
|
|
129
|
+
try {
|
|
130
|
+
const _mulanDef = (typeof _defineComponent !== 'undefined' ? _defineComponent : (typeof Mulan !== 'undefined' && Mulan.defineComponent ? Mulan.defineComponent : require('@mulanjs/mulanjs').defineComponent));
|
|
131
|
+
__component__.template = render;
|
|
132
|
+
__component__ = _mulanDef(__component__);
|
|
133
|
+
__component__.prototype.template = render;
|
|
134
|
+
} catch (e) {
|
|
135
|
+
__component__.template = render;
|
|
136
|
+
}
|
|
130
137
|
}
|
|
131
138
|
|
|
132
139
|
${cssInjection}
|
|
@@ -165,6 +172,9 @@ if (typeof module !== 'undefined' && module.hot) {
|
|
|
165
172
|
|
|
166
173
|
// console.log('[MulanJS] Component created:', __component__);
|
|
167
174
|
module.exports = __component__;
|
|
175
|
+
if (__component__) {
|
|
176
|
+
module.exports.default = __component__;
|
|
177
|
+
}
|
|
168
178
|
|
|
169
179
|
// Helper to get relative path for sourceURL
|
|
170
180
|
// This ensures the generated file appears in a readable folder structure in DevTools
|
|
@@ -389,7 +389,12 @@ function generateDOMInstruction(node, chunks, getUid, getHoistId, hoists, uidRef
|
|
|
389
389
|
if (element._domBindings) {
|
|
390
390
|
for (const b of element._domBindings) {
|
|
391
391
|
if (b.type === 'prop') {
|
|
392
|
-
|
|
392
|
+
if (b.name === 'class' || b.name === 'className') {
|
|
393
|
+
chunks.push(`this._bindEffect(() => { if (${id}) ${id}.className = _va("class", ${b.expr}); }, ${id});`);
|
|
394
|
+
}
|
|
395
|
+
else {
|
|
396
|
+
chunks.push(`this._bindEffect(() => { if (${id}) ${id}['${b.name}'] = _va('${b.name}', ${b.expr}); }, ${id});`);
|
|
397
|
+
}
|
|
393
398
|
}
|
|
394
399
|
else if (b.type === 'event') {
|
|
395
400
|
chunks.push(`if (${id}) ${id}.addEventListener('${b.name}', (${b.expr}).bind(this));`);
|
|
@@ -482,17 +487,20 @@ function transform(node, scriptResult, scopedId, localScope = [], filename) {
|
|
|
482
487
|
domBindings.push({ type: 'event', name: 'input', expr: `($event) => { ${bound} = $event.target.value; }` });
|
|
483
488
|
delete element.props[key];
|
|
484
489
|
}
|
|
485
|
-
else if (key.startsWith('.')) {
|
|
486
|
-
const propName = key.slice(1);
|
|
490
|
+
else if (key.startsWith(':') || key.startsWith('v-bind:') || key.startsWith('.')) {
|
|
491
|
+
const propName = key.startsWith(':') ? key.slice(1) : (key.startsWith('v-bind:') ? key.slice(7) : key.slice(1));
|
|
487
492
|
const rawValue = element.props[key];
|
|
488
493
|
let expr = "''";
|
|
489
494
|
if (rawValue.startsWith('${') && rawValue.endsWith('}')) {
|
|
490
495
|
expr = processBindings(rawValue.slice(2, -1), scriptResult.bindings, localScope);
|
|
491
496
|
}
|
|
497
|
+
else if (rawValue.startsWith('{') && rawValue.endsWith('}')) {
|
|
498
|
+
expr = processBindings(rawValue.slice(1, -1), scriptResult.bindings, localScope);
|
|
499
|
+
}
|
|
492
500
|
else {
|
|
493
|
-
expr =
|
|
501
|
+
expr = processBindings(rawValue, scriptResult.bindings, localScope);
|
|
494
502
|
}
|
|
495
|
-
domBindings.push({ type: 'prop', name: propName, expr });
|
|
503
|
+
domBindings.push({ type: 'prop', name: propName, expr: `_s(${expr})` });
|
|
496
504
|
delete element.props[key];
|
|
497
505
|
}
|
|
498
506
|
else if (key.startsWith('@') ||
|
|
@@ -515,7 +523,7 @@ function transform(node, scriptResult, scopedId, localScope = [], filename) {
|
|
|
515
523
|
eventName = key.slice(2);
|
|
516
524
|
}
|
|
517
525
|
let bound = processBindings(element.props[key], scriptResult.bindings, localScope);
|
|
518
|
-
const expr = (bound.includes('(') || bound.includes('=') || bound.includes('++')) ? `($event) => { ${bound.replace(/`/g, '\\`')} }` : bound;
|
|
526
|
+
const expr = (bound.includes('(') || bound.includes('=') || bound.includes('++') || bound.includes('--')) ? `($event) => { ${bound.replace(/`/g, '\\`')} }` : bound;
|
|
519
527
|
domBindings.push({ type: 'event', name: eventName, expr });
|
|
520
528
|
delete element.props[key];
|
|
521
529
|
}
|
|
@@ -49,7 +49,16 @@ async function compileScript(descriptor, options) {
|
|
|
49
49
|
});
|
|
50
50
|
finalMap = generator.toString();
|
|
51
51
|
}
|
|
52
|
-
|
|
52
|
+
const defaultCode = `import { defineComponent as _defineComponent } from '@mulanjs/mulanjs';\nexport default _defineComponent({});`;
|
|
53
|
+
const result = ts.transpileModule(defaultCode, {
|
|
54
|
+
compilerOptions: {
|
|
55
|
+
module: ts.ModuleKind.CommonJS,
|
|
56
|
+
target: ts.ScriptTarget.ES2019,
|
|
57
|
+
sourceMap: false
|
|
58
|
+
},
|
|
59
|
+
fileName: descriptor.filename || 'component.mujs'
|
|
60
|
+
});
|
|
61
|
+
return { code: result.outputText, errors: [], map: finalMap };
|
|
53
62
|
}
|
|
54
63
|
let content = script.content;
|
|
55
64
|
let filename = descriptor.filename;
|
|
@@ -95,7 +104,11 @@ async function compileScript(descriptor, options) {
|
|
|
95
104
|
}
|
|
96
105
|
exports.compileScript = compileScript;
|
|
97
106
|
// Global list of Mulan hooks for auto-imports and reactivity exemption
|
|
98
|
-
const COMMON_HOOKS = [
|
|
107
|
+
const COMMON_HOOKS = [
|
|
108
|
+
'muState', 'onMuMount', 'onMuInit', 'onMuDestroy', 'muEffect', 'muMemo',
|
|
109
|
+
'muQubit', 'muGate', 'muMeasure', 'muRegister', 'muEntangle', 'persistent',
|
|
110
|
+
'muVault', 'muComputed', 'muWatch', 'onMuIdle', 'onMuResume'
|
|
111
|
+
];
|
|
99
112
|
async function compileSetupScript(script, isTs, descriptor, content, filename, isExternal, externalPath) {
|
|
100
113
|
var _a;
|
|
101
114
|
// 1. Pre-process: Natural Reactivity Transformation ($ syntax)
|
|
@@ -389,10 +402,32 @@ async function compileStandardScript(script, descriptor, content, filename, isEx
|
|
|
389
402
|
map: finalMap
|
|
390
403
|
};
|
|
391
404
|
}
|
|
392
|
-
// --- Natural Reactivity Transformer ---
|
|
405
|
+
// --- Natural Reactivity & Runes Transformer ---
|
|
406
|
+
function getRuneKind(expr) {
|
|
407
|
+
if (ts.isIdentifier(expr)) {
|
|
408
|
+
const text = expr.text;
|
|
409
|
+
if (text === '$' || text === '$state')
|
|
410
|
+
return 'state';
|
|
411
|
+
if (text === '$derived' || text === '$memo')
|
|
412
|
+
return 'derived';
|
|
413
|
+
if (text === '$effect')
|
|
414
|
+
return 'effect';
|
|
415
|
+
if (text === '$vault')
|
|
416
|
+
return 'vault';
|
|
417
|
+
if (text === '$q')
|
|
418
|
+
return 'qubit';
|
|
419
|
+
if (text === '$qr')
|
|
420
|
+
return 'register';
|
|
421
|
+
}
|
|
422
|
+
else if (ts.isPropertyAccessExpression(expr) && ts.isIdentifier(expr.expression) && expr.expression.text === '$state') {
|
|
423
|
+
return 'state'; // e.g. $state.raw(...)
|
|
424
|
+
}
|
|
425
|
+
return null;
|
|
426
|
+
}
|
|
393
427
|
function transformNaturalReactivity(code, isTs) {
|
|
394
|
-
// If no
|
|
395
|
-
|
|
428
|
+
// If no rune usage, return original code for safety/speed
|
|
429
|
+
const hasRune = /\$(state|derived|memo|effect|vault|q|qr|\()/.test(code);
|
|
430
|
+
if (!hasRune)
|
|
396
431
|
return code;
|
|
397
432
|
const sourceFile = ts.createSourceFile('temp.ts', code, ts.ScriptTarget.Latest, true);
|
|
398
433
|
const reactiveVars = new Set();
|
|
@@ -403,19 +438,16 @@ function transformNaturalReactivity(code, isTs) {
|
|
|
403
438
|
if (ts.isVariableStatement(node)) {
|
|
404
439
|
node.declarationList.declarations.forEach(decl => {
|
|
405
440
|
if (decl.initializer && ts.isCallExpression(decl.initializer)) {
|
|
406
|
-
const
|
|
407
|
-
if (ts.isIdentifier(
|
|
408
|
-
if (
|
|
409
|
-
|
|
410
|
-
reactiveVars.add(decl.name.text);
|
|
441
|
+
const rune = getRuneKind(decl.initializer.expression);
|
|
442
|
+
if (ts.isIdentifier(decl.name)) {
|
|
443
|
+
if (rune === 'state' || rune === 'derived' || rune === 'vault') {
|
|
444
|
+
reactiveVars.add(decl.name.text);
|
|
411
445
|
}
|
|
412
|
-
else if (
|
|
413
|
-
|
|
414
|
-
quantumVars.add(decl.name.text);
|
|
446
|
+
else if (rune === 'qubit') {
|
|
447
|
+
quantumVars.add(decl.name.text);
|
|
415
448
|
}
|
|
416
|
-
else if (
|
|
417
|
-
|
|
418
|
-
registerVars.add(decl.name.text);
|
|
449
|
+
else if (rune === 'register') {
|
|
450
|
+
registerVars.add(decl.name.text);
|
|
419
451
|
}
|
|
420
452
|
}
|
|
421
453
|
}
|
|
@@ -424,8 +456,6 @@ function transformNaturalReactivity(code, isTs) {
|
|
|
424
456
|
ts.forEachChild(node, findReactiveVars);
|
|
425
457
|
}
|
|
426
458
|
findReactiveVars(sourceFile);
|
|
427
|
-
if (reactiveVars.size === 0 && quantumVars.size === 0 && registerVars.size === 0)
|
|
428
|
-
return code;
|
|
429
459
|
// Pass 2: Transformation
|
|
430
460
|
const transformerFactory = (context) => {
|
|
431
461
|
return (rootNode) => {
|
|
@@ -436,23 +466,47 @@ function transformNaturalReactivity(code, isTs) {
|
|
|
436
466
|
node.declarationList.declarations.forEach(decl => {
|
|
437
467
|
if (ts.isIdentifier(decl.name)) {
|
|
438
468
|
const name = decl.name.text;
|
|
439
|
-
if (
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
469
|
+
if (decl.initializer && ts.isCallExpression(decl.initializer)) {
|
|
470
|
+
const rune = getRuneKind(decl.initializer.expression);
|
|
471
|
+
if (rune) {
|
|
472
|
+
changed = true;
|
|
473
|
+
if (rune === 'state') {
|
|
474
|
+
const stateArgs = decl.initializer.arguments.map(a => ts.visitNode(a, visit));
|
|
475
|
+
newDecls.push(ts.factory.updateVariableDeclaration(decl, decl.name, decl.exclamationToken, decl.type, ts.factory.createCallExpression(ts.factory.createIdentifier('muState'), undefined, stateArgs)));
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
else if (rune === 'derived') {
|
|
479
|
+
const rawArg = decl.initializer.arguments[0];
|
|
480
|
+
const arg = rawArg ? ts.visitNode(rawArg, visit) : undefined;
|
|
481
|
+
const computeFn = (arg && (ts.isArrowFunction(arg) || ts.isFunctionExpression(arg)))
|
|
482
|
+
? arg
|
|
483
|
+
: ts.factory.createArrowFunction(undefined, undefined, [], undefined, ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken), arg || ts.factory.createIdentifier('undefined'));
|
|
484
|
+
newDecls.push(ts.factory.updateVariableDeclaration(decl, decl.name, decl.exclamationToken, decl.type, ts.factory.createCallExpression(ts.factory.createIdentifier('muMemo'), undefined, [computeFn])));
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
else if (rune === 'vault') {
|
|
488
|
+
let vaultArgs = decl.initializer.arguments.map(a => ts.visitNode(a, visit));
|
|
489
|
+
if (vaultArgs.length === 1) {
|
|
490
|
+
vaultArgs = [
|
|
491
|
+
ts.factory.createStringLiteral(decl.name.text),
|
|
492
|
+
vaultArgs[0]
|
|
493
|
+
];
|
|
494
|
+
}
|
|
495
|
+
newDecls.push(ts.factory.updateVariableDeclaration(decl, decl.name, decl.exclamationToken, decl.type, ts.factory.createCallExpression(ts.factory.createIdentifier('muVault'), undefined, vaultArgs)));
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
else if (rune === 'qubit') {
|
|
499
|
+
newDecls.push(ts.factory.updateVariableDeclaration(decl, decl.name, decl.exclamationToken, decl.type, ts.factory.createCallExpression(ts.factory.createIdentifier('muQubit'), undefined, decl.initializer.arguments)));
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
else if (rune === 'register') {
|
|
503
|
+
newDecls.push(ts.factory.updateVariableDeclaration(decl, decl.name, decl.exclamationToken, decl.type, ts.factory.createCallExpression(ts.factory.createIdentifier('muRegister'), undefined, decl.initializer.arguments)));
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
}
|
|
448
507
|
}
|
|
449
|
-
else {
|
|
450
|
-
newDecls.push(decl);
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
else {
|
|
454
|
-
newDecls.push(decl);
|
|
455
508
|
}
|
|
509
|
+
newDecls.push(decl);
|
|
456
510
|
});
|
|
457
511
|
if (changed) {
|
|
458
512
|
return ts.factory.createVariableStatement(node.modifiers, ts.factory.createVariableDeclarationList(newDecls, ts.NodeFlags.Const));
|
|
@@ -460,24 +514,20 @@ function transformNaturalReactivity(code, isTs) {
|
|
|
460
514
|
}
|
|
461
515
|
if (ts.isCallExpression(node)) {
|
|
462
516
|
const expr = node.expression;
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
if (
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
hookName = 'muRegister';
|
|
478
|
-
// Transform $(x) -> muState(x).value
|
|
479
|
-
return ts.factory.createPropertyAccessExpression(ts.factory.createCallExpression(ts.factory.createIdentifier(hookName), undefined, node.arguments), ts.factory.createIdentifier('value'));
|
|
480
|
-
}
|
|
517
|
+
const rune = getRuneKind(expr);
|
|
518
|
+
if (rune === 'effect') {
|
|
519
|
+
return ts.factory.createCallExpression(ts.factory.createIdentifier('muEffect'), undefined, node.arguments);
|
|
520
|
+
}
|
|
521
|
+
if (rune === 'state' || rune === 'qubit' || rune === 'register') {
|
|
522
|
+
const parent = node.parent;
|
|
523
|
+
const isDeclarationInit = ts.isVariableDeclaration(parent) && parent.initializer === node;
|
|
524
|
+
if (!isDeclarationInit) {
|
|
525
|
+
let hookName = 'muState';
|
|
526
|
+
if (rune === 'qubit')
|
|
527
|
+
hookName = 'muQubit';
|
|
528
|
+
else if (rune === 'register')
|
|
529
|
+
hookName = 'muRegister';
|
|
530
|
+
return ts.factory.createPropertyAccessExpression(ts.factory.createCallExpression(ts.factory.createIdentifier(hookName), undefined, node.arguments), ts.factory.createIdentifier('value'));
|
|
481
531
|
}
|
|
482
532
|
}
|
|
483
533
|
}
|
|
@@ -494,7 +544,6 @@ function transformNaturalReactivity(code, isTs) {
|
|
|
494
544
|
if (ts.isPropertyAssignment(parent) && parent.name === node)
|
|
495
545
|
return node;
|
|
496
546
|
// EXEMPTION: Do not add .value if the identifier is a direct argument to a Mulan hook
|
|
497
|
-
// These hooks (muGate, muMeasure, etc.) expect the signal wrapper.
|
|
498
547
|
if (ts.isCallExpression(parent) && ts.isIdentifier(parent.expression)) {
|
|
499
548
|
const hook = parent.expression.text;
|
|
500
549
|
if (COMMON_HOOKS.includes(hook))
|