|
|
|
//! Edition detection utilities.
|
|
|
|
//!
|
|
|
|
//! This module contains the [`SpecEdition`] struct, which is used in the tester to
|
|
|
|
//! classify all tests per minimum required ECMAScript edition.
|
|
|
|
|
|
|
|
use std::fmt::Display;
|
|
|
|
|
|
|
|
use serde_repr::{Deserialize_repr, Serialize_repr};
|
|
|
|
|
|
|
|
use crate::read::{MetaData, TestFlag};
|
|
|
|
|
|
|
|
/// Minimum edition required by a specific feature in the `test262` repository.
|
|
|
|
static FEATURE_EDITION: phf::Map<&'static str, SpecEdition> = phf::phf_map! {
|
|
|
|
// Proposed language features
|
|
|
|
|
|
|
|
// Intl.Locale Info
|
|
|
|
// https://github.com/tc39/proposal-intl-locale-info
|
|
|
|
"Intl.Locale-info" => SpecEdition::ESNext,
|
|
|
|
|
|
|
|
// FinalizationRegistry#cleanupSome
|
|
|
|
// https://github.com/tc39/proposal-cleanup-some
|
|
|
|
"FinalizationRegistry.prototype.cleanupSome" => SpecEdition::ESNext,
|
|
|
|
|
|
|
|
// Intl.NumberFormat V3
|
|
|
|
// https://github.com/tc39/proposal-intl-numberformat-v3
|
|
|
|
"Intl.NumberFormat-v3" => SpecEdition::ESNext,
|
|
|
|
|
|
|
|
// Legacy RegExp features
|
|
|
|
// https://github.com/tc39/proposal-regexp-legacy-features
|
|
|
|
"legacy-regexp" => SpecEdition::ESNext,
|
|
|
|
|
|
|
|
// Import Attributes
|
|
|
|
// https://github.com/tc39/proposal-import-attributes/
|
|
|
|
"import-attributes" => SpecEdition::ESNext,
|
|
|
|
|
|
|
|
// Import Assertions
|
|
|
|
// https://github.com/tc39/proposal-import-assertions/
|
|
|
|
"import-assertions" => SpecEdition::ESNext,
|
|
|
|
|
|
|
|
// JSON modules
|
|
|
|
// https://github.com/tc39/proposal-json-modules
|
|
|
|
"json-modules" => SpecEdition::ESNext,
|
|
|
|
|
|
|
|
// ArrayBuffer transfer
|
|
|
|
// https://github.com/tc39/proposal-arraybuffer-transfer
|
|
|
|
"arraybuffer-transfer" => SpecEdition::ESNext,
|
|
|
|
|
|
|
|
// Temporal
|
|
|
|
// https://github.com/tc39/proposal-temporal
|
|
|
|
"Temporal" => SpecEdition::ESNext,
|
|
|
|
|
|
|
|
// ShadowRealm, née Callable Boundary Realms
|
|
|
|
// https://github.com/tc39/proposal-realms
|
|
|
|
"ShadowRealm" => SpecEdition::ESNext,
|
|
|
|
|
|
|
|
// Intl.DurationFormat
|
|
|
|
// https://github.com/tc39/proposal-intl-duration-format
|
|
|
|
"Intl.DurationFormat" => SpecEdition::ESNext,
|
|
|
|
|
|
|
|
// Decorators
|
|
|
|
// https://github.com/tc39/proposal-decorators
|
|
|
|
"decorators" => SpecEdition::ESNext,
|
|
|
|
|
|
|
|
// Duplicate named capturing groups
|
|
|
|
// https://github.com/tc39/proposal-duplicate-named-capturing-groups
|
|
|
|
"regexp-duplicate-named-groups" => SpecEdition::ESNext,
|
|
|
|
|
|
|
|
// Array.fromAsync
|
|
|
|
// https://github.com/tc39/proposal-array-from-async
|
|
|
|
"Array.fromAsync" => SpecEdition::ESNext,
|
|
|
|
|
|
|
|
// JSON.parse with source
|
|
|
|
// https://github.com/tc39/proposal-json-parse-with-source
|
|
|
|
"json-parse-with-source" => SpecEdition::ESNext,
|
|
|
|
|
|
|
|
// Iterator Helpers
|
|
|
|
// https://github.com/tc39/proposal-iterator-helpers
|
|
|
|
"iterator-helpers" => SpecEdition::ESNext,
|
|
|
|
|
|
|
|
// Set methods
|
|
|
|
// https://github.com/tc39/proposal-set-methods
|
|
|
|
"set-methods" => SpecEdition::ESNext,
|
|
|
|
|
|
|
|
// Part of the next ES15 edition
|
|
|
|
"Atomics.waitAsync" => SpecEdition::ESNext,
|
|
|
|
"regexp-v-flag" => SpecEdition::ESNext,
|
|
|
|
"String.prototype.isWellFormed" => SpecEdition::ESNext,
|
|
|
|
"String.prototype.toWellFormed" => SpecEdition::ESNext,
|
|
|
|
"resizable-arraybuffer" => SpecEdition::ESNext,
|
|
|
|
"promise-with-resolvers" => SpecEdition::ESNext,
|
|
|
|
"array-grouping" => SpecEdition::ESNext,
|
|
|
|
|
|
|
|
// Standard language features
|
|
|
|
"AggregateError" => SpecEdition::ES12,
|
|
|
|
"align-detached-buffer-semantics-with-web-reality" => SpecEdition::ES12,
|
|
|
|
"arbitrary-module-namespace-names" => SpecEdition::ES13,
|
|
|
|
"ArrayBuffer" => SpecEdition::ES6,
|
|
|
|
"array-find-from-last" => SpecEdition::ES14,
|
|
|
|
"Array.prototype.at" => SpecEdition::ES13,
|
|
|
|
"Array.prototype.flat" => SpecEdition::ES10,
|
|
|
|
"Array.prototype.flatMap" => SpecEdition::ES10,
|
|
|
|
"Array.prototype.includes" => SpecEdition::ES7,
|
|
|
|
"Array.prototype.values" => SpecEdition::ES6,
|
|
|
|
"arrow-function" => SpecEdition::ES6,
|
|
|
|
"async-iteration" => SpecEdition::ES9,
|
|
|
|
"async-functions" => SpecEdition::ES8,
|
|
|
|
"Atomics" => SpecEdition::ES8,
|
|
|
|
"BigInt" => SpecEdition::ES11,
|
|
|
|
"caller" => SpecEdition::ES5,
|
|
|
|
"change-array-by-copy" => SpecEdition::ES14,
|
|
|
|
"class" => SpecEdition::ES6,
|
|
|
|
"class-fields-private" => SpecEdition::ES13,
|
|
|
|
"class-fields-private-in" => SpecEdition::ES13,
|
|
|
|
"class-fields-public" => SpecEdition::ES13,
|
|
|
|
"class-methods-private" => SpecEdition::ES13,
|
|
|
|
"class-static-block" => SpecEdition::ES13,
|
|
|
|
"class-static-fields-private" => SpecEdition::ES13,
|
|
|
|
"class-static-fields-public" => SpecEdition::ES13,
|
|
|
|
"class-static-methods-private" => SpecEdition::ES13,
|
|
|
|
"coalesce-expression" => SpecEdition::ES11,
|
|
|
|
"computed-property-names" => SpecEdition::ES6,
|
|
|
|
"const" => SpecEdition::ES6,
|
|
|
|
"cross-realm" => SpecEdition::ES6,
|
|
|
|
"DataView" => SpecEdition::ES6,
|
|
|
|
"DataView.prototype.getFloat32" => SpecEdition::ES6,
|
|
|
|
"DataView.prototype.getFloat64" => SpecEdition::ES6,
|
|
|
|
"DataView.prototype.getInt16" => SpecEdition::ES6,
|
|
|
|
"DataView.prototype.getInt32" => SpecEdition::ES6,
|
|
|
|
"DataView.prototype.getInt8" => SpecEdition::ES6,
|
|
|
|
"DataView.prototype.getUint16" => SpecEdition::ES6,
|
|
|
|
"DataView.prototype.getUint32" => SpecEdition::ES6,
|
|
|
|
"DataView.prototype.setUint8" => SpecEdition::ES6,
|
|
|
|
"default-parameters" => SpecEdition::ES6,
|
|
|
|
"destructuring-assignment" => SpecEdition::ES6,
|
|
|
|
"destructuring-binding" => SpecEdition::ES6,
|
|
|
|
"dynamic-import" => SpecEdition::ES11,
|
|
|
|
"error-cause" => SpecEdition::ES13,
|
|
|
|
"exponentiation" => SpecEdition::ES7,
|
|
|
|
"export-star-as-namespace-from-module" => SpecEdition::ES11,
|
|
|
|
"FinalizationRegistry" => SpecEdition::ES12,
|
|
|
|
"for-in-order" => SpecEdition::ES11,
|
|
|
|
"for-of" => SpecEdition::ES6,
|
|
|
|
"Float32Array" => SpecEdition::ES6,
|
|
|
|
"Float64Array" => SpecEdition::ES6,
|
|
|
|
"generators" => SpecEdition::ES6,
|
|
|
|
"globalThis" => SpecEdition::ES11,
|
|
|
|
"hashbang" => SpecEdition::ES14,
|
|
|
|
"import.meta" => SpecEdition::ES11,
|
|
|
|
"Int8Array" => SpecEdition::ES6,
|
|
|
|
"Int16Array" => SpecEdition::ES6,
|
|
|
|
"Int32Array" => SpecEdition::ES6,
|
|
|
|
"Intl-enumeration" => SpecEdition::ES14,
|
|
|
|
"intl-normative-optional" => SpecEdition::ES8,
|
|
|
|
"Intl.DateTimeFormat-datetimestyle" => SpecEdition::ES12,
|
|
|
|
"Intl.DateTimeFormat-dayPeriod" => SpecEdition::ES8,
|
|
|
|
"Intl.DateTimeFormat-extend-timezonename" => SpecEdition::ES13,
|
|
|
|
"Intl.DateTimeFormat-formatRange" => SpecEdition::ES12,
|
|
|
|
"Intl.DateTimeFormat-fractionalSecondDigits" => SpecEdition::ES12,
|
|
|
|
"Intl.DisplayNames" => SpecEdition::ES12,
|
|
|
|
"Intl.DisplayNames-v2" => SpecEdition::ES13,
|
|
|
|
"Intl.ListFormat" => SpecEdition::ES12,
|
|
|
|
"Intl.Locale" => SpecEdition::ES12,
|
|
|
|
"Intl.NumberFormat-unified" => SpecEdition::ES11,
|
|
|
|
"Intl.RelativeTimeFormat" => SpecEdition::ES11,
|
|
|
|
"Intl.Segmenter" => SpecEdition::ES13,
|
|
|
|
"json-superset" => SpecEdition::ES10,
|
|
|
|
"let" => SpecEdition::ES6,
|
|
|
|
"logical-assignment-operators" => SpecEdition::ES12,
|
|
|
|
"Map" => SpecEdition::ES6,
|
|
|
|
"new.target" => SpecEdition::ES6,
|
|
|
|
"numeric-separator-literal" => SpecEdition::ES12,
|
|
|
|
"object-rest" => SpecEdition::ES9,
|
|
|
|
"object-spread" => SpecEdition::ES9,
|
|
|
|
"Object.fromEntries" => SpecEdition::ES10,
|
|
|
|
"Object.hasOwn" => SpecEdition::ES13,
|
|
|
|
"Object.is" => SpecEdition::ES6,
|
|
|
|
"optional-catch-binding" => SpecEdition::ES10,
|
|
|
|
"optional-chaining" => SpecEdition::ES11,
|
|
|
|
"Promise" => SpecEdition::ES6,
|
|
|
|
"Promise.allSettled" => SpecEdition::ES11,
|
|
|
|
"Promise.any" => SpecEdition::ES12,
|
|
|
|
"Promise.prototype.finally" => SpecEdition::ES9,
|
|
|
|
"Proxy" => SpecEdition::ES6,
|
|
|
|
"proxy-missing-checks" => SpecEdition::ES6,
|
|
|
|
"Reflect" => SpecEdition::ES6,
|
|
|
|
"Reflect.construct" => SpecEdition::ES6,
|
|
|
|
"Reflect.set" => SpecEdition::ES6,
|
|
|
|
"Reflect.setPrototypeOf" => SpecEdition::ES6,
|
|
|
|
"regexp-dotall" => SpecEdition::ES9,
|
|
|
|
"regexp-lookbehind" => SpecEdition::ES9,
|
|
|
|
"regexp-match-indices" => SpecEdition::ES13,
|
|
|
|
"regexp-named-groups" => SpecEdition::ES9,
|
|
|
|
"regexp-unicode-property-escapes" => SpecEdition::ES9,
|
|
|
|
"rest-parameters" => SpecEdition::ES6,
|
|
|
|
"Set" => SpecEdition::ES6,
|
|
|
|
"SharedArrayBuffer" => SpecEdition::ES8,
|
|
|
|
"string-trimming" => SpecEdition::ES10,
|
|
|
|
"String.fromCodePoint" => SpecEdition::ES6,
|
|
|
|
"String.prototype.at" => SpecEdition::ES13,
|
|
|
|
"String.prototype.endsWith" => SpecEdition::ES6,
|
|
|
|
"String.prototype.includes" => SpecEdition::ES6,
|
|
|
|
"String.prototype.matchAll" => SpecEdition::ES11,
|
|
|
|
"String.prototype.replaceAll" => SpecEdition::ES12,
|
|
|
|
"String.prototype.trimEnd" => SpecEdition::ES10,
|
|
|
|
"String.prototype.trimStart" => SpecEdition::ES10,
|
|
|
|
"super" => SpecEdition::ES6,
|
|
|
|
"Symbol" => SpecEdition::ES6,
|
|
|
|
"symbols-as-weakmap-keys" => SpecEdition::ES14,
|
|
|
|
"Symbol.asyncIterator" => SpecEdition::ES9,
|
|
|
|
"Symbol.hasInstance" => SpecEdition::ES6,
|
|
|
|
"Symbol.isConcatSpreadable" => SpecEdition::ES6,
|
|
|
|
"Symbol.iterator" => SpecEdition::ES6,
|
|
|
|
"Symbol.match" => SpecEdition::ES6,
|
|
|
|
"Symbol.matchAll" => SpecEdition::ES11,
|
|
|
|
"Symbol.prototype.description" => SpecEdition::ES10,
|
|
|
|
"Symbol.replace" => SpecEdition::ES6,
|
|
|
|
"Symbol.search" => SpecEdition::ES6,
|
|
|
|
"Symbol.species" => SpecEdition::ES6,
|
|
|
|
"Symbol.split" => SpecEdition::ES6,
|
|
|
|
"Symbol.toPrimitive" => SpecEdition::ES6,
|
|
|
|
"Symbol.toStringTag" => SpecEdition::ES6,
|
|
|
|
"Symbol.unscopables" => SpecEdition::ES6,
|
|
|
|
"tail-call-optimization" => SpecEdition::ES6,
|
|
|
|
"template" => SpecEdition::ES6,
|
|
|
|
"top-level-await" => SpecEdition::ES13,
|
|
|
|
"TypedArray" => SpecEdition::ES6,
|
|
|
|
"TypedArray.prototype.at" => SpecEdition::ES13,
|
|
|
|
"u180e" => SpecEdition::ES7,
|
|
|
|
"Uint8Array" => SpecEdition::ES6,
|
|
|
|
"Uint16Array" => SpecEdition::ES6,
|
|
|
|
"Uint32Array" => SpecEdition::ES6,
|
|
|
|
"Uint8ClampedArray" => SpecEdition::ES6,
|
|
|
|
"WeakMap" => SpecEdition::ES6,
|
|
|
|
"WeakRef" => SpecEdition::ES12,
|
|
|
|
"WeakSet" => SpecEdition::ES6,
|
|
|
|
"well-formed-json-stringify" => SpecEdition::ES10,
|
|
|
|
"__proto__" => SpecEdition::ES6,
|
|
|
|
"__getter__" => SpecEdition::ES8,
|
|
|
|
"__setter__" => SpecEdition::ES8,
|
|
|
|
|
|
|
|
// Test-Harness Features
|
|
|
|
|
|
|
|
"IsHTMLDDA" => SpecEdition::ES9,
|
|
|
|
"host-gc-required" => SpecEdition::ES5,
|
|
|
|
};
|
|
|
|
|
|
|
|
/// List of ECMAScript editions that can be tested in the `test262` repository.
|
|
|
|
#[derive(
|
|
|
|
Debug,
|
|
|
|
Clone,
|
|
|
|
Copy,
|
|
|
|
PartialEq,
|
|
|
|
Eq,
|
|
|
|
PartialOrd,
|
|
|
|
Ord,
|
|
|
|
Default,
|
|
|
|
Serialize_repr,
|
|
|
|
Deserialize_repr,
|
|
|
|
clap::ValueEnum,
|
|
|
|
)]
|
|
|
|
#[repr(u8)]
|
|
|
|
pub(crate) enum SpecEdition {
|
|
|
|
/// ECMAScript 5.1 Edition
|
|
|
|
///
|
|
|
|
/// <https://262.ecma-international.org/5.1>
|
|
|
|
ES5 = 5,
|
|
|
|
/// ECMAScript 6th Edition
|
|
|
|
///
|
|
|
|
/// <https://262.ecma-international.org/6.0>
|
|
|
|
ES6,
|
|
|
|
/// ECMAScript 7th Edition
|
|
|
|
///
|
|
|
|
/// <https://262.ecma-international.org/7.0>
|
|
|
|
ES7,
|
|
|
|
/// ECMAScript 8th Edition
|
|
|
|
///
|
|
|
|
/// <https://262.ecma-international.org/8.0>
|
|
|
|
ES8,
|
|
|
|
/// ECMAScript 9th Edition
|
|
|
|
///
|
|
|
|
/// <https://262.ecma-international.org/9.0>
|
|
|
|
ES9,
|
|
|
|
/// ECMAScript 10th Edition
|
|
|
|
///
|
|
|
|
/// <https://262.ecma-international.org/10.0>
|
|
|
|
ES10,
|
|
|
|
/// ECMAScript 11th Edition
|
|
|
|
///
|
|
|
|
/// <https://262.ecma-international.org/11.0>
|
|
|
|
ES11,
|
|
|
|
/// ECMAScript 12th Edition
|
|
|
|
///
|
|
|
|
/// <https://262.ecma-international.org/12.0>
|
|
|
|
ES12,
|
|
|
|
/// ECMAScript 13th Edition
|
|
|
|
///
|
|
|
|
/// <https://262.ecma-international.org/13.0>
|
|
|
|
ES13,
|
|
|
|
/// ECMAScript 14th Edition
|
|
|
|
///
|
|
|
|
/// <https://262.ecma-international.org/14.0>
|
|
|
|
ES14,
|
|
|
|
/// The edition being worked on right now.
|
|
|
|
///
|
|
|
|
/// A draft is currently available [here](https://tc39.es/ecma262).
|
|
|
|
#[default]
|
|
|
|
ESNext = 255,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Display for SpecEdition {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
match *self {
|
|
|
|
Self::ESNext => write!(f, "ECMAScript Next"),
|
|
|
|
Self::ES5 => write!(f, "ECMAScript 5.1"),
|
|
|
|
v => write!(f, "ECMAScript {}", v as u8),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl SpecEdition {
|
|
|
|
/// Gets the minimum required ECMAScript edition of a test from its metadata.
|
|
|
|
///
|
|
|
|
/// If the function finds unknown features in `metadata`, returns an `Err(Vec<&str>)` containing
|
|
|
|
/// the list of unknown features.
|
|
|
|
pub(crate) fn from_test_metadata(metadata: &MetaData) -> Result<Self, Vec<&str>> {
|
|
|
|
let mut min_edition = if metadata.flags.contains(&TestFlag::Async) {
|
|
|
|
Self::ES8
|
|
|
|
} else if metadata.flags.contains(&TestFlag::Module)
|
|
|
|
|| metadata.esid.is_some()
|
|
|
|
|| metadata.es6id.is_some()
|
|
|
|
{
|
|
|
|
Self::ES6
|
|
|
|
} else {
|
|
|
|
Self::ES5
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut unknowns = Vec::new();
|
|
|
|
for feature in &*metadata.features {
|
|
|
|
let Some(feature_edition) = FEATURE_EDITION.get(feature).copied() else {
|
|
|
|
unknowns.push(&**feature);
|
|
|
|
continue;
|
|
|
|
};
|
|
|
|
min_edition = std::cmp::max(min_edition, feature_edition);
|
|
|
|
}
|
|
|
|
|
|
|
|
if unknowns.is_empty() {
|
|
|
|
Ok(min_edition)
|
|
|
|
} else {
|
|
|
|
Err(unknowns)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Gets an iterator of all currently available editions.
|
|
|
|
pub(crate) fn all_editions() -> impl Iterator<Item = Self> {
|
|
|
|
[
|
|
|
|
Self::ES5,
|
|
|
|
Self::ES6,
|
|
|
|
Self::ES7,
|
|
|
|
Self::ES8,
|
|
|
|
Self::ES9,
|
|
|
|
Self::ES10,
|
|
|
|
Self::ES11,
|
|
|
|
Self::ES12,
|
|
|
|
Self::ES13,
|
|
|
|
Self::ES14,
|
|
|
|
Self::ESNext,
|
|
|
|
]
|
|
|
|
.into_iter()
|
|
|
|
}
|
|
|
|
}
|