import { Position } from '../src/ast'
-import { getInnerRange, advancePositionWithClone } from '../src/utils'
+import {
+ getInnerRange,
+ advancePositionWithClone,
+ isMemberExpression
+} from '../src/utils'
function p(line: number, column: number, offset: number): Position {
return { column, line, offset }
expect(loc2.end.offset).toBe(7)
})
})
+
+test('isMemberExpression', () => {
+ // should work
+ expect(isMemberExpression('obj.foo')).toBe(true)
+ expect(isMemberExpression('obj[foo]')).toBe(true)
+ expect(isMemberExpression('obj[arr[0]]')).toBe(true)
+ expect(isMemberExpression('obj[arr[ret.bar]]')).toBe(true)
+ expect(isMemberExpression('obj[arr[ret[bar]]]')).toBe(true)
+ expect(isMemberExpression('obj[arr[ret[bar]]].baz')).toBe(true)
+ expect(isMemberExpression('obj[1 + 1]')).toBe(true)
+ // should warning
+ expect(isMemberExpression('obj[foo')).toBe(false)
+ expect(isMemberExpression('objfoo]')).toBe(false)
+ expect(isMemberExpression('obj[arr[0]')).toBe(false)
+ expect(isMemberExpression('obj[arr0]]')).toBe(false)
+})
export const isSimpleIdentifier = (name: string): boolean =>
!nonIdentifierRE.test(name)
-const memberExpRE = /^[A-Za-z_$\xA0-\uFFFF][\w$\xA0-\uFFFF]*(?:\s*\.\s*[A-Za-z_$\xA0-\uFFFF][\w$\xA0-\uFFFF]*|\[[^\]]+\])*$/
+const memberExpRE = /^[A-Za-z_$\xA0-\uFFFF][\w$\xA0-\uFFFF]*(?:\s*\.\s*[A-Za-z_$\xA0-\uFFFF][\w$\xA0-\uFFFF]*|\[(.+)\])*$/
export const isMemberExpression = (path: string): boolean => {
if (!path) return false
- return memberExpRE.test(path.trim())
+ const matched = memberExpRE.exec(path.trim())
+ if (!matched) return false
+ if (!matched[1]) return true
+ if (!/[\[\]]/.test(matched[1])) return true
+ return isMemberExpression(matched[1].trim())
}
export function getInnerRange(