mirror of
https://gitee.com/zhangsken/opencode.git
synced 2026-10-16 10:30:01 +08:00
fix(codemode): coerce any value to a property key (#50479)
This commit is contained in:
@@ -243,7 +243,7 @@ ultimate source of truth. Upstream test262 files run verbatim from `test/test262
|
||||
accepted, including `.then`/`.catch` handlers and collection callbacks, and vanish at the data boundary like
|
||||
any function.
|
||||
- [x] `Promise.withResolvers()`: the same promise and resolver callables as the constructor, as a `{ promise, resolve,
|
||||
reject }` object.
|
||||
reject }` object.
|
||||
- [x] `Promise.try(fn, ...args)`: calls `fn` synchronously; a throw rejects, a return fulfils, and a returned promise or
|
||||
thenable is adopted.
|
||||
- [x] Recursive assimilation of objects with an own callable `then` field across `Promise.resolve`, combinators,
|
||||
@@ -266,7 +266,9 @@ ultimate source of truth. Upstream test262 files run verbatim from `test/test262
|
||||
not construct.
|
||||
- [x] `Object()` and `new Object()` return `{}` for nullish arguments and pass objects through unchanged;
|
||||
primitive wrapper objects (`Object(1)`) are rejected explicitly.
|
||||
- [x] Computed property names and object spread.
|
||||
- [x] Computed property names and object spread. Any value works as a key (ToPropertyKey): strings, numbers, and the
|
||||
two confined symbols as themselves, everything else as its string form (`o[null]` is `o["null"]`, `o[{}]` is
|
||||
`o["[object Object]"]`), in reads, writes, literals, `in`, and destructuring.
|
||||
- [x] `Object.keys`, `Object.values`, `Object.entries`, `Object.hasOwn`, `Object.assign`, and `Object.fromEntries`, with
|
||||
synchronous iterator support for `fromEntries`. Sources follow ToObject: strings enumerate by index, other
|
||||
primitives and wrappers contribute nothing, and `null`/`undefined` throw. `Object.assign` accepts array
|
||||
|
||||
@@ -1244,7 +1244,7 @@ class Frame<R> {
|
||||
}
|
||||
const keyNode = property.key
|
||||
if (property.computed) {
|
||||
return Effect.map(this.evaluateExpression(keyNode), (value) => this.toPropertyKey(value, keyNode))
|
||||
return Effect.map(this.evaluateExpression(keyNode), (value) => this.toPropertyKey(value))
|
||||
}
|
||||
if (keyNode.type === "Identifier") return Effect.succeed(keyNode.name)
|
||||
if (keyNode.type === "Literal") return Effect.succeed(String(keyNode.value))
|
||||
@@ -1943,11 +1943,11 @@ class Frame<R> {
|
||||
let key: PropertyKey
|
||||
|
||||
if (property.computed) {
|
||||
key = self.toPropertyKey(yield* self.evaluateExpression(keyNode), keyNode)
|
||||
key = self.toPropertyKey(yield* self.evaluateExpression(keyNode))
|
||||
} else if (keyNode.type === "Identifier") {
|
||||
key = keyNode.name
|
||||
} else if (keyNode.type === "Literal") {
|
||||
key = self.toPropertyKey(literal(keyNode), keyNode)
|
||||
key = self.toPropertyKey(literal(keyNode))
|
||||
} else {
|
||||
throw typeError("Unsupported object property key shape.", keyNode)
|
||||
}
|
||||
@@ -2048,10 +2048,10 @@ class Frame<R> {
|
||||
if ((objectValue === null || objectValue === undefined) && node.optional) return OptionalShortCircuit
|
||||
|
||||
const key = node.computed
|
||||
? self.toPropertyKey(yield* self.evaluateExpression(propertyNode), propertyNode)
|
||||
? self.toPropertyKey(yield* self.evaluateExpression(propertyNode))
|
||||
: propertyNode.type === "Identifier"
|
||||
? propertyNode.name
|
||||
: self.toPropertyKey(yield* self.evaluateExpression(propertyNode), propertyNode)
|
||||
: self.toPropertyKey(yield* self.evaluateExpression(propertyNode))
|
||||
|
||||
if (objectValue instanceof ToolReference) {
|
||||
if (typeof key !== "string") {
|
||||
@@ -2168,12 +2168,9 @@ class Frame<R> {
|
||||
throw typeError(`Cannot assign to read only property '${String(key)}'.`, node)
|
||||
}
|
||||
|
||||
private toPropertyKey(value: Value, node: AstNode): PropertyKey {
|
||||
if (typeof value === "string" || typeof value === "number") {
|
||||
return value
|
||||
}
|
||||
if (value === AsyncIteratorSymbol || value === IteratorSymbol) return value
|
||||
|
||||
throw typeError("Property key must be a string or number, or Symbol.asyncIterator/Symbol.iterator.", node)
|
||||
// ToPropertyKey: anything else becomes its string form, so `counts[row.category]` works when the field is null.
|
||||
private toPropertyKey(value: Value): PropertyKey {
|
||||
if (typeof value === "string" || typeof value === "number" || typeof value === "symbol") return value
|
||||
return coerceToString(value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -784,9 +784,17 @@ describe("destructuring assignment", () => {
|
||||
).toEqual({ declared: "a", declarationRest: { 1: "b" }, assigned: "c", assignmentRest: { 1: "d" } })
|
||||
})
|
||||
|
||||
test("rejects computed keys that are not confined property keys", async () => {
|
||||
const err = await error(`const key = {}; const { [key]: value } = {}`)
|
||||
expect(err.message).toContain("Property key must be a string or number")
|
||||
test("computed keys of any type become their string form, as in JS", async () => {
|
||||
expect(
|
||||
await value(`
|
||||
const counts = {}
|
||||
for (const category of ["a", null, undefined, "a", true, 1.5]) counts[category] = (counts[category] ?? 0) + 1
|
||||
const key = {}
|
||||
const { [key]: value } = { "[object Object]": 7 }
|
||||
const o = { null: 1, "1,2": 2 }
|
||||
return [counts, value, o[null], o[[1, 2]], undefined in o]
|
||||
`),
|
||||
).toEqual([{ a: 2, null: 1, undefined: 1, true: 1, "1.5": 1 }, 7, 1, 2, false])
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@ built-ins/Array/prototype/copyWithin/return-abrupt-from-target.js # Expected a
|
||||
built-ins/Array/prototype/every/15.4.4.16-7-6.js # res Expected SameValue(«true», «false») to be true
|
||||
built-ins/Array/prototype/every/15.4.4.16-7-c-i-8.js # [, , , ].every(callbackfn) Expected SameValue(«true», «false») to be true
|
||||
built-ins/Array/prototype/every/15.4.4.16-8-10.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/every/15.4.4.16-8-13.js # Property key must be a string or number, or Symbol.asyncIterator/Symbol.iterator.
|
||||
built-ins/Array/prototype/every/15.4.4.16-8-2.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/every/15.4.4.16-8-3.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/every/15.4.4.16-8-4.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
@@ -28,7 +27,6 @@ built-ins/Array/prototype/fill/coerced-indexes.js # Array.fill expects start to
|
||||
built-ins/Array/prototype/fill/return-abrupt-from-end.js # Expected a Test262Error but got a TypeError
|
||||
built-ins/Array/prototype/fill/return-abrupt-from-start.js # Expected a Test262Error but got a TypeError
|
||||
built-ins/Array/prototype/filter/15.4.4.20-10-3.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/filter/15.4.4.20-10-4.js # Property key must be a string or number, or Symbol.asyncIterator/Symbol.iterator.
|
||||
built-ins/Array/prototype/filter/15.4.4.20-6-2.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/filter/15.4.4.20-6-3.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/filter/15.4.4.20-6-4.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
@@ -44,7 +42,6 @@ built-ins/Array/prototype/flat/non-object-ctor-throws.js # null value Expected
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-7-5.js # callCnt Expected SameValue(«4», «5») to be true
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-7-c-i-8.js # testResult !== true
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-8-10.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-8-12.js # Property key must be a string or number, or Symbol.asyncIterator/Symbol.iterator.
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-8-2.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-8-3.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/forEach/15.4.4.18-8-4.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
@@ -107,7 +104,6 @@ built-ins/Array/prototype/lastIndexOf/length-zero-returns-minus-one.js # Array.
|
||||
built-ins/Array/prototype/map/15.4.4.19-8-6.js # resArr[4] Expected SameValue(«undefined», «1») to be true
|
||||
built-ins/Array/prototype/map/15.4.4.19-8-c-i-8.js # newArr[1] Expected SameValue(«13», «true») to be true
|
||||
built-ins/Array/prototype/map/15.4.4.19-9-3.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/map/15.4.4.19-9-4.js # Property key must be a string or number, or Symbol.asyncIterator/Symbol.iterator.
|
||||
built-ins/Array/prototype/map/create-ctor-non-object.js # null value Expected a TypeError to be thrown but no exception was thrown at all
|
||||
built-ins/Array/prototype/pop/S15.4.4.6_A2_T1.js # Array.prototype.pop called on incompatible receiver a data object.
|
||||
built-ins/Array/prototype/pop/S15.4.4.6_A2_T4.js # Array.prototype.pop called on incompatible receiver a data object.
|
||||
@@ -127,7 +123,6 @@ built-ins/Array/prototype/reduce/15.4.4.21-10-3.js # … cannot be constructed:
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-10-4.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-10-6.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-10-7.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-10-8.js # Property key must be a string or number, or Symbol.asyncIterator/Symbol.iterator.
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-5-2.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-5-3.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/reduce/15.4.4.21-5-4.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
@@ -151,7 +146,6 @@ built-ins/Array/prototype/reduceRight/15.4.4.22-10-3.js # … cannot be constru
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-10-4.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-10-6.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-10-7.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-10-8.js # Property key must be a string or number, or Symbol.asyncIterator/Symbol.iterator.
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-5-2.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-5-3.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/reduceRight/15.4.4.22-5-4.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
@@ -197,7 +191,6 @@ built-ins/Array/prototype/slice/create-ctor-non-object.js # null value Expected
|
||||
built-ins/Array/prototype/some/15.4.4.17-7-6.js # res Expected SameValue(«false», «true») to be true
|
||||
built-ins/Array/prototype/some/15.4.4.17-7-c-i-8.js # [, ].some(callbackfn) !== true
|
||||
built-ins/Array/prototype/some/15.4.4.17-8-10.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/some/15.4.4.17-8-13.js # Property key must be a string or number, or Symbol.asyncIterator/Symbol.iterator.
|
||||
built-ins/Array/prototype/some/15.4.4.17-8-2.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/some/15.4.4.17-8-3.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
built-ins/Array/prototype/some/15.4.4.17-8-4.js # … cannot be constructed: user-defined constructors and classes are not supported. Call it as a funct
|
||||
|
||||
Reference in New Issue
Block a user