Stage 2 Draft / October 20, 2024

Reflect.isTemplateObject

10 Ordinary and Exotic Objects Behaviours

10.4 Built-in Exotic Object Internal Methods and Slots

10.4.2 Array Exotic Objects

10.4.2.2 ArrayCreate ( length [ , proto ] )

The abstract operation ArrayCreate takes argument length (a non-negative integer) and optional argument proto (an Object) and returns either a normal completion containing an Array exotic object or a throw completion. It is used to specify the creation of new Arrays.

Editor's Note
To enable the new API, this proposal modifies ArrayCreate to add an internal slot to each array.

It performs the following steps when called:

  1. If length > 232 - 1, throw a RangeError exception.
  2. If proto is not present, set proto to %Array.prototype%.
  3. Let A be MakeBasicObject[[Prototype]], [[Extensible]], [[TemplateObject]] »).
  4. Set A.[[Prototype]] to proto.
  5. Set A.[[TemplateObject]] to false.
  6. Set A.[[DefineOwnProperty]] as specified in 10.4.2.1.
  7. Perform ! OrdinaryDefineOwnProperty(A, "length", PropertyDescriptor { [[Value]]: 𝔽(length), [[Writable]]: true, [[Enumerable]]: false, [[Configurable]]: false }).
  8. Return A.

13 ECMAScript Language: Expressions

13.2 Primary Expression

13.2.8 Template Literals

13.2.8.4 GetTemplateObject ( templateLiteral )

The abstract operation GetTemplateObject takes argument templateLiteral (a Parse Node) and returns an Array.

Editor's Note
To enable the new API, this proposal modifies GetTemplateObject to change the value of the new internal slot.

It performs the following steps when called:

  1. Let realm be the current Realm Record.
  2. Let templateRegistry be realm.[[TemplateMap]].
  3. For each element e of templateRegistry, do
    1. If e.[[Site]] is the same Parse Node as templateLiteral, then
      1. Return e.[[Array]].
  4. Let rawStrings be the TemplateStrings of templateLiteral with argument true.
  5. Assert: rawStrings is a List of Strings.
  6. Let cookedStrings be the TemplateStrings of templateLiteral with argument false.
  7. Let count be the number of elements in the List cookedStrings.
  8. Assert: count ≤ 232 - 1.
  9. Let template be ! ArrayCreate(count).
  10. Set template.[[TemplateObject]] to true.
  11. Let rawObj be ! ArrayCreate(count).
  12. Let index be 0.
  13. Repeat, while index < count,
    1. Let prop be ! ToString(𝔽(index)).
    2. Let cookedValue be cookedStrings[index].
    3. Perform ! DefinePropertyOrThrow(template, prop, PropertyDescriptor { [[Value]]: cookedValue, [[Writable]]: false, [[Enumerable]]: true, [[Configurable]]: false }).
    4. Let rawValue be the String value rawStrings[index].
    5. Perform ! DefinePropertyOrThrow(rawObj, prop, PropertyDescriptor { [[Value]]: rawValue, [[Writable]]: false, [[Enumerable]]: true, [[Configurable]]: false }).
    6. Set index to index + 1.
  14. Perform ! SetIntegrityLevel(rawObj, frozen).
  15. Perform ! DefinePropertyOrThrow(template, "raw", PropertyDescriptor { [[Value]]: rawObj, [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: false }).
  16. Perform ! SetIntegrityLevel(template, frozen).
  17. Append the Record { [[Site]]: templateLiteral, [[Array]]: template } to realm.[[TemplateMap]].
  18. Return template.
Note 1

The creation of a template object cannot result in an abrupt completion.

Note 2

Each TemplateLiteral in the program code of a realm is associated with a unique template object that is used in the evaluation of tagged Templates (13.2.8.6). The template objects are frozen and the same template object is used each time a specific tagged Template is evaluated. Whether template objects are created lazily upon first evaluation of the TemplateLiteral or eagerly prior to first evaluation is an implementation choice that is not observable to ECMAScript code.

Note 3

Future editions of this specification may define additional non-enumerable properties of template objects.

28 Reflection

28.1 The Reflect Object

28.1.10 Reflect.isTemplateObject ( value )

When the isTemplateObject method is called with argument value the following steps are taken:

  1. If ? IsArray(value) is true and value.[[TemplateObject]] is true, then
    1. Return true.
  2. Return false.
Note

IsTemplateObject is realm-agnostic. Since template objects are frozen before escaping GetTemplateObject, testing (IsTemplateObject(x) and x.[[Prototype]] is the realm's %Array.prototype%) is sufficient to determine whether an x is a template object in a particular realm.

In user code, Reflect.isTemplateObject(x) && x instanceof Array is an equivalent test, assuming no changes to builtins.