Skip to content

Commit e70fb3d

Browse files
committed
refactor(core): code review and enhance type narrowing cases wxIf
1 parent 7db529a commit e70fb3d

File tree

2 files changed

+122
-111
lines changed

2 files changed

+122
-111
lines changed

inspect-extension/components/composition/wxIf.mpx

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,41 @@
11
<template>
22
<view>
3-
<view wx:if="{{ typeof shouldShow === 'string'}}">
4-
Case1: {{ shouldShow }}
3+
<!-- Case1: Type Narrowing 类型收窄 -->
4+
<view wx:if="{{ typeof msg === 'string'}}">
5+
msg should be string: {{ msg }}
56
</view>
6-
<view wx:elif="{{ typeof shouldShow === 'number' }}">
7-
Case2: {{ shouldShow }}
7+
<view wx:elif="{{ typeof msg === 'number' }}">
8+
msg should be number: {{ msg }}
89
</view>
910
<view wx:else>
10-
Case3: {{ shouldShow }}
11+
msg should be undefined: {{ msg }}
1112
</view>
1213

13-
<!-- space -->
14-
<view wx:if=" {{ typeof shouldShow === 'number'}}"></view>
14+
<!-- Case2: Type Narrowing for undefined -->
15+
<view wx:if="{{ status }}">
16+
{{ status.message }}
17+
</view>
18+
19+
<!-- Case3: Type Narrowing -->
20+
<view wx:if="{{ typeof foo === 'string' }}">
21+
{{ foo }}
22+
</view>
23+
24+
<!-- Case4: 表达式带空格 -->
25+
<view wx:if=" {{ status?.message && msg }}"></view>
1526
</view>
1627
</template>
1728

1829
<script setup lang="ts">
1930
import { ref } from "@mpxjs/core"
20-
let shouldShow = ref<string | number>('1')
31+
32+
let msg = ref<string | number>()
33+
let status: { message: string } | undefined;
34+
let foo: any
2135

2236
defineExpose({
23-
shouldShow,
37+
msg,
38+
status,
39+
foo
2440
})
2541
</script>
26-
27-
<style lang="stylus">
28-
</style>

packages/language-core/src/utils/transformMpxTemplate.ts

Lines changed: 97 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,17 @@ function shouldCombineIfBranchNode(
1717
)
1818
}
1919

20-
export function transformMpxTemplateNodes<T extends Node>(children: T[]): T[] {
21-
const mapedResult = children.map(child => visitNode(child) ?? child)
20+
export function transformMpxTemplateNodes<T extends Node>(
21+
children: T[] = [],
22+
): T[] {
23+
const mappedResult = children.map(child => visitNode(child) ?? child)
2224

2325
const result: T[] = []
2426

25-
if (mapedResult.length) {
26-
for (let i = 0; i < mapedResult.length; i++) {
27+
if (mappedResult.length) {
28+
for (let i = 0; i < mappedResult.length; i++) {
2729
const prev = result[result.length - 1]
28-
const item = mapedResult[i]
30+
const item = mappedResult[i]
2931

3032
if (item.type === CompilerDOM.NodeTypes.IF_BRANCH) {
3133
const ifNode: CompilerDOM.IfNode =
@@ -47,10 +49,7 @@ export function transformMpxTemplateNodes<T extends Node>(children: T[]): T[] {
4749
shouldCombineIfBranchNode(lastBranch.mpxCondition, item.mpxCondition)
4850
) {
4951
ifNode.branches.push(item)
50-
continue
5152
}
52-
53-
continue
5453
} else {
5554
result.push(item)
5655
}
@@ -160,112 +159,112 @@ type ElNode =
160159
| CompilerDOM.TemplateNode
161160

162161
function tryProcessWxFor(node: ElNode) {
163-
const captureResult: [
164-
_for: CompilerDOM.AttributeNode | undefined,
165-
key: CompilerDOM.AttributeNode | undefined,
166-
index: CompilerDOM.AttributeNode | undefined,
167-
] = [] as any
168-
let _forIndex = -1
169-
{
170-
let count = 0
171-
const captureAttr = ['wx:for', 'wx:for-item', 'wx:for-index']
172-
const captureIndex: number[] = []
173-
174-
for (let i = node.props.length - 1; i >= 0; i--) {
175-
const prop = node.props[i]
176-
if (prop.type !== CompilerDOM.NodeTypes.ATTRIBUTE) {
177-
continue
178-
}
162+
try {
163+
const captureResult: CompilerDOM.AttributeNode[] = []
164+
let _forIndex = -1
179165

180-
const index = captureAttr.indexOf(prop.name)
181-
if (index === -1) continue
166+
{
167+
let count = 0
168+
const captureAttr = ['wx:for', 'wx:for-item', 'wx:for-index']
182169

183-
count++
170+
for (let i = node.props.length - 1; i >= 0; i--) {
171+
const prop = node.props[i]
172+
if (prop.type !== CompilerDOM.NodeTypes.ATTRIBUTE) {
173+
continue
174+
}
184175

185-
captureResult[index] = prop
186-
captureIndex[index] = i
176+
const index = captureAttr.indexOf(prop.name)
177+
if (index === -1) continue
187178

188-
if (prop.name === 'wx:for') {
189-
_forIndex = i
190-
}
179+
count++
191180

192-
if (count >= captureAttr.length) {
193-
break
194-
}
195-
}
181+
captureResult[index] = prop
196182

197-
if (count < 1) return
198-
}
183+
if (prop.name === 'wx:for') {
184+
_forIndex = i
185+
}
199186

200-
{
201-
const [prop, value, index] = captureResult
202-
if (!prop) {
203-
return
187+
if (count >= captureAttr.length) {
188+
break
189+
}
190+
}
191+
192+
if (count < 1) return
204193
}
205-
function createVarNode(
206-
node: CompilerDOM.AttributeNode | undefined,
207-
defailtText: string,
208-
): CompilerDOM.ExpressionNode {
209-
if (node && node.value) {
210-
stripSourceLocationQuotes(node.value.loc)
194+
195+
{
196+
const [prop, value, index] = captureResult
197+
if (!prop) {
198+
return
199+
}
200+
function createVarNode(
201+
node: CompilerDOM.AttributeNode | undefined,
202+
defaultText: string,
203+
): CompilerDOM.ExpressionNode {
204+
if (node && node.value) {
205+
stripSourceLocationQuotes(node.value.loc)
206+
207+
return {
208+
type: CompilerDOM.NodeTypes.SIMPLE_EXPRESSION,
209+
content: node.value.content || '',
210+
isStatic: false,
211+
constType: CompilerDOM.ConstantTypes.NOT_CONSTANT,
212+
loc: node.value.loc,
213+
}
214+
}
211215

212216
return {
213217
type: CompilerDOM.NodeTypes.SIMPLE_EXPRESSION,
214-
content: node.value.content || '',
218+
content: defaultText,
215219
isStatic: false,
216220
constType: CompilerDOM.ConstantTypes.NOT_CONSTANT,
217-
loc: node.value.loc,
218-
}
221+
loc: {
222+
start: prop?.value?.loc.start ?? { offset: 0, column: 0, line: 0 },
223+
end: { offset: 0, column: 0, line: 0 },
224+
source: defaultText,
225+
},
226+
} satisfies CompilerDOM.SimpleExpressionNode
219227
}
220228

221-
return {
222-
type: CompilerDOM.NodeTypes.SIMPLE_EXPRESSION,
223-
content: defailtText,
224-
isStatic: false,
225-
constType: CompilerDOM.ConstantTypes.NOT_CONSTANT,
226-
loc: {
227-
start: prop?.value?.loc.start ?? { offset: 0, column: 0, line: 0 },
228-
end: { offset: 0, column: 0, line: 0 },
229-
source: defailtText,
230-
},
231-
} satisfies CompilerDOM.SimpleExpressionNode
232-
}
233-
234-
node.props.splice(_forIndex, 1)
229+
node.props.splice(_forIndex, 1)
235230

236-
const contentLoc = prop.value!.loc
237-
stripSourceLocationQuotes(contentLoc)
238-
stripSourceLocationBrace(contentLoc)
231+
const contentLoc = prop.value!.loc
232+
stripSourceLocationQuotes(contentLoc)
233+
stripSourceLocationBrace(contentLoc)
239234

240-
const valueNode = createVarNode(value, 'item')
241-
const indexNode = createVarNode(index, 'index')
242-
const source = {
243-
constType: 0,
244-
content: contentLoc.source,
245-
isStatic: false,
246-
loc: contentLoc,
247-
type: CompilerDOM.NodeTypes.SIMPLE_EXPRESSION,
248-
} satisfies CompilerDOM.ExpressionNode
249-
const children = transformMpxTemplateNodes([node])
250-
return {
251-
type: CompilerDOM.NodeTypes.FOR,
252-
valueAlias: valueNode,
253-
keyAlias: undefined,
254-
objectIndexAlias: indexNode,
255-
loc: contentLoc,
256-
children: children as CompilerDOM.TemplateChildNode[],
257-
parseResult: {
258-
mpx: true,
259-
defaultIndex: !index,
260-
defaultValue: !value,
235+
const valueNode = createVarNode(value, 'item')
236+
const indexNode = createVarNode(index, 'index')
237+
const source = {
238+
constType: 0,
239+
content: contentLoc.source,
240+
isStatic: false,
241+
loc: contentLoc,
242+
type: CompilerDOM.NodeTypes.SIMPLE_EXPRESSION,
243+
} satisfies CompilerDOM.ExpressionNode
244+
const children = transformMpxTemplateNodes([node])
245+
return {
246+
type: CompilerDOM.NodeTypes.FOR,
247+
valueAlias: valueNode,
248+
keyAlias: undefined,
249+
objectIndexAlias: indexNode,
250+
loc: contentLoc,
251+
children: children as CompilerDOM.TemplateChildNode[],
252+
parseResult: {
253+
mpx: true,
254+
defaultIndex: !index,
255+
defaultValue: !value,
256+
source,
257+
key: undefined,
258+
value: valueNode,
259+
index: indexNode,
260+
finalized: true,
261+
},
261262
source,
262-
key: undefined,
263-
value: valueNode,
264-
index: indexNode,
265-
finalized: true,
266-
},
267-
source,
268-
} satisfies CompilerDOM.ForNode
263+
} satisfies CompilerDOM.ForNode
264+
}
265+
} catch (error) {
266+
console.warn('[MPX] Failed to process wx:for:', error)
267+
return undefined
269268
}
270269
}
271270

@@ -288,16 +287,15 @@ function tryProcessBindEvent(
288287
arg: {
289288
// tap
290289
type: CompilerDOM.NodeTypes.SIMPLE_EXPRESSION,
291-
// should trim quotes
292-
content: prop.name.slice(4),
290+
content: nameLoc.source,
293291
isStatic: true,
294292
constType: CompilerDOM.ConstantTypes.CAN_STRINGIFY,
295293
loc: nameLoc,
296294
},
297295
exp: {
298296
// handleTap
299297
type: CompilerDOM.NodeTypes.SIMPLE_EXPRESSION,
300-
// should trim quotesx
298+
// should trim quotes
301299
content: prop.value?.content || '',
302300
loc: prop.value?.loc ?? emptySourceLocation(),
303301
isStatic: false,

0 commit comments

Comments
 (0)