From b6c8ca07cbc3b2d6215ecb75e09546ebbc46e971 Mon Sep 17 00:00:00 2001 From: nonbots Date: Sat, 28 Jun 2025 17:49:03 -0400 Subject: [PATCH 1/6] feat-search-params --- .../conformance/HeroBanner/index.tsx | 2 + .../conformance/ResultsDisplay/index.tsx | 12 ++++- .../conformance/VersionSelector/index.tsx | 3 +- src/components/conformance/types.ts | 13 ++++-- src/components/conformance/utils.ts | 46 +++++++++++++++++++ src/pages/conformance/index.tsx | 12 ++++- 6 files changed, 81 insertions(+), 7 deletions(-) diff --git a/src/components/conformance/HeroBanner/index.tsx b/src/components/conformance/HeroBanner/index.tsx index 5fcfaf6c..c5468ab6 100644 --- a/src/components/conformance/HeroBanner/index.tsx +++ b/src/components/conformance/HeroBanner/index.tsx @@ -7,6 +7,7 @@ import { import { createState, mapToTestStats, + createSearchParams } from "@site/src/components/conformance/utils"; import { useHistory } from "@docusaurus/router"; import Heading from "@theme/Heading"; @@ -86,6 +87,7 @@ function BannerCard(props) { className="button button--block button--primary" onClick={() => history.push({ + search: createSearchParams(props.item), pathname: "/conformance", state: createState(props.item), }) diff --git a/src/components/conformance/ResultsDisplay/index.tsx b/src/components/conformance/ResultsDisplay/index.tsx index 0e499535..508adeff 100644 --- a/src/components/conformance/ResultsDisplay/index.tsx +++ b/src/components/conformance/ResultsDisplay/index.tsx @@ -9,9 +9,10 @@ import { import ResultNavigation from "./nav"; import { createState, + createSearchParams, mapToResultInfo, } from "@site/src/components/conformance/utils"; -import { useHistory } from "@docusaurus/router"; +import { useHistory, useLocation } from "@docusaurus/router"; import styles from "./styles.module.css"; @@ -20,6 +21,7 @@ type ResultsProps = { }; export default function ResultsDisplay(props: ResultsProps): JSX.Element { + const location = useLocation() const [currentSuite, setCurrentSuite] = React.useState( null, ); @@ -30,9 +32,10 @@ export default function ResultsDisplay(props: ResultsProps): JSX.Element { // History handling const history = useHistory(); - const pushStateToHistory = (state: ConformanceState): void => { + const pushStateToHistory = (search: string, state: ConformanceState): void => { history.push({ pathname: "/conformance", + search, state, }); }; @@ -91,6 +94,7 @@ export default function ResultsDisplay(props: ResultsProps): JSX.Element { const navigateToSuite = (newSuiteName: string) => { const newPath = [...props.state.testPath, newSuiteName]; pushStateToHistory( + createSearchParams(props.state.version, newPath), createState( props.state.version, newPath, @@ -106,6 +110,7 @@ export default function ResultsDisplay(props: ResultsProps): JSX.Element { const sliceNavToIndex = (nonInclusiveIndex: number) => { const slicedPath = [...props.state.testPath.slice(0, nonInclusiveIndex)]; pushStateToHistory( + createSearchParams(props.state.version, slicedPath), createState( props.state.version, slicedPath, @@ -119,6 +124,7 @@ export default function ResultsDisplay(props: ResultsProps): JSX.Element { const setEcmaScriptFlag = (flag: string) => { const nulledFlag = flag ? flag : undefined; pushStateToHistory( + createSearchParams(props.state.version, props.state.testPath, props.state.selectedTest), createState( props.state.version, props.state.testPath, @@ -131,6 +137,7 @@ export default function ResultsDisplay(props: ResultsProps): JSX.Element { // Sets the sorting option const setSortOption = (option: string) => { pushStateToHistory( + createSearchParams(props.state.version, props.state.testPath, props.state.selectedTest), createState( props.state.version, props.state.testPath, @@ -143,6 +150,7 @@ export default function ResultsDisplay(props: ResultsProps): JSX.Element { // Sets a selected test. const setSelectedTest = (test: string | undefined) => { pushStateToHistory( + createSearchParams(props.state.version, props.state.testPath, test), createState( props.state.version, props.state.testPath, diff --git a/src/components/conformance/VersionSelector/index.tsx b/src/components/conformance/VersionSelector/index.tsx index 8d7323e3..2e3fe0da 100644 --- a/src/components/conformance/VersionSelector/index.tsx +++ b/src/components/conformance/VersionSelector/index.tsx @@ -5,7 +5,7 @@ import { VersionItem, } from "@site/src/components/conformance/types"; import styles from "./styles.module.css"; -import { createState } from "../utils"; +import { createState, createSearchParams } from "../utils"; interface SelectorProps { availableVersions: VersionItem[]; @@ -38,6 +38,7 @@ function Version(props: VersionProps): JSX.Element { onClick={() => history.push({ pathname: "/conformance", + search: createSearchParams(props.version), state: createState(props.version), }) } diff --git a/src/components/conformance/types.ts b/src/components/conformance/types.ts index dc10fbf9..d322c6fb 100644 --- a/src/components/conformance/types.ts +++ b/src/components/conformance/types.ts @@ -1,15 +1,22 @@ + // The main global state of the conformance page. // // This state is fed into the History object and dictates // what renders. export type ConformanceState = { - version: VersionItem; - testPath: string[]; + version: VersionItem; // REMOVED (???) -> Connected to displaying specific results + testPath: string[]; // REMOVED (???) -> Navigation / breadcrumbs ecmaScriptVersion: string | undefined; sortOption: string; - selectedTest: string | undefined; + selectedTest: string | undefined; // REMOVED (???) -> "TestViewer" }; +export type UrlState = { + versionTag: string | undefined, + testPath: string[] | undefined, + selectedTest: string | undefined, +} + export type VersionItem = { tagName: string; fetchUrl: string; diff --git a/src/components/conformance/utils.ts b/src/components/conformance/utils.ts index 3623b2a5..0d55127b 100644 --- a/src/components/conformance/utils.ts +++ b/src/components/conformance/utils.ts @@ -7,10 +7,56 @@ import { TestOutcome, TestResult, TestStats, + UrlState, VersionedStats, VersionItem, } from "@site/src/components/conformance/types"; + +// Take a search param and create a state object +export function createUrlState(search: string): UrlState { + const params = new URLSearchParams(search); + console.log(`testPath: ${params.get("testPath")}`) + return { + versionTag: params.get("version") ?? undefined, + testPath: params.get("testPath")?.split("/") ?? undefined, + selectedTest: params.get("selectedTest") ?? undefined + } +} + +export function updateInitialConformanceState(urlState: UrlState, conformanceState: ConformanceState) { + + if (!conformanceState && (urlState.versionTag || urlState.testPath || urlState.selectedTest)) { + const fetchUrl = urlState.versionTag === "main" ? `https://raw.githubusercontent.com/boa-dev/data/main/test262/refs/heads/main/latest.json` : `https://raw.githubusercontent.com/boa-dev/data/main/test262/refs/tags/${urlState.versionTag}/latest.json`; + + const testPath = urlState.testPath || []; + return { + version: { tagName: urlState.versionTag, fetchUrl }, + testPath: [urlState.versionTag, ...testPath], + ecmaScriptVersion: undefined, + sortOption: availableSortingOptions[0].id, + selectedTest: urlState.selectedTest + } + } + return conformanceState; +} + +export function createSearchParams( + version: VersionItem, + testPath?: string[], + selectedTest?: string, +) { + const search = new URLSearchParams() + search.append("version", version.tagName); + if (testPath) { + search.append("testPath", testPath.slice(1).join("/")); + } + if (selectedTest) { + search.append("selectedTest", selectedTest) + } + return search.toString() +} + // Creates the state object from provided args export function createState( version: VersionItem, diff --git a/src/pages/conformance/index.tsx b/src/pages/conformance/index.tsx index 841b8960..5e16599c 100644 --- a/src/pages/conformance/index.tsx +++ b/src/pages/conformance/index.tsx @@ -2,7 +2,12 @@ import ConformanceView from "@site/src/components/conformance"; import { VersionItem, ConformanceState, + UrlState, } from "@site/src/components/conformance/types"; +import { + createUrlState, + updateInitialConformanceState +} from "@site/src/components/conformance/utils"; import { useLocation } from "@docusaurus/router"; import Layout from "@theme/Layout"; import React from "react"; @@ -21,6 +26,8 @@ export default function Conformance() { VersionItem[] | undefined >(null); + const urlState = createUrlState(location.search); + // Initial Render useEffect React.useEffect(() => { const validateReleaseVersion = (releaseTag: string) => { @@ -61,11 +68,14 @@ export default function Conformance() { ); }, []); + + const resolvedState = updateInitialConformanceState(urlState, location.state) + return (
{releaseRecords ? ( - + ) : null}
From d32e8c2a93baf27ba4310b8cffb8e4f8e6da3a03 Mon Sep 17 00:00:00 2001 From: nonbots Date: Sat, 28 Jun 2025 18:16:33 -0400 Subject: [PATCH 2/6] prettier and lint --- blog/2025-03-05-local-variables.md | 161 +++++++++--------- blog/2025-06-15-temporal-impl-1.md | 15 +- src/components/benchmarks/index.tsx | 40 ++--- .../conformance/HeroBanner/index.tsx | 2 +- .../conformance/ResultsDisplay/index.tsx | 19 ++- src/components/conformance/types.ts | 15 +- src/components/conformance/utils.ts | 33 ++-- src/pages/benchmarks/index.tsx | 5 +- src/pages/conformance/index.tsx | 5 +- 9 files changed, 151 insertions(+), 144 deletions(-) diff --git a/blog/2025-03-05-local-variables.md b/blog/2025-03-05-local-variables.md index fd27942b..e3b80f63 100644 --- a/blog/2025-03-05-local-variables.md +++ b/blog/2025-03-05-local-variables.md @@ -5,7 +5,7 @@ title: "How ECMAScript Engines Optimize Your Variables" authors: boa-dev --- -In this post, we will dive into how ECMAScript engines store variables, +In this post, we will dive into how ECMAScript engines store variables, go over storage optimizations, and learn about scope analysis. If you are an ECMAScript developer, you will get some practical tips to improve the performance of your code. If you write your own ECMAScript engine or any interpreter/compiler, you might get some implementation ideas. @@ -33,9 +33,10 @@ Let's look at an example to visualize scopes: const a = 1; console.log(a); // 1 -{ // <- start of a block scope - const a = 2; - console.log(a); // 2 +{ + // <- start of a block scope + const a = 2; + console.log(a); // 2 } // <- end of a block scope ``` @@ -53,9 +54,9 @@ Let's modify our example to see what happens in that case: const a = 1; { - const b = 2; - console.log(a); // 1 - console.log(b); // 2 + const b = 2; + console.log(a); // 1 + console.log(b); // 2 } ``` @@ -71,16 +72,18 @@ Let's look at a more complex example: const a = 1; console.log(a); // 1 -function f() { // <- start of a function scope - var a = 2; - console.log(a); // 2 +function f() { + // <- start of a function scope + var a = 2; + console.log(a); // 2 - { // <- start of a block scope - let a = 3; - console.log(a); // 3 - } // <- end of a block scope + { + // <- start of a block scope + let a = 3; + console.log(a); // 3 + } // <- end of a block scope - console.log(a); // 2 + console.log(a); // 2 } // <- end of a function scope f(); @@ -104,9 +107,9 @@ For our proposes we will only work with `let` and `const` and skip those details When developing an ECMAScript engine we have to think about how we store and access scopes and variables. Take a look at the requirements we have for that storage data structure: -* A variable maps an identifier to a value. -* A scope can have multiple variables with unique identifiers. -* A scope may have an outer scope. +- A variable maps an identifier to a value. +- A scope can have multiple variables with unique identifiers. +- A scope may have an outer scope. The variables in a scope fit a typical key-value store, like a hashmap. The hashmap stores our variable identifiers as keys and the variable values as corresponding values: @@ -159,8 +162,8 @@ Let's visualize this in an example: ```js const a = 1; // scope index: 0; variable index: 0 { - const b = 2; // scope index: 1; variable index: 0 - const c = 3; // scope index: 1; variable index: 1 + const b = 2; // scope index: 1; variable index: 0 + const c = 3; // scope index: 1; variable index: 1 } ``` @@ -172,10 +175,10 @@ Let's explore how unique these indices have to be: ```js { - const a = 1; // scope index: 1; variable index: 0 + const a = 1; // scope index: 1; variable index: 0 } { - const b = 2; // scope index: 1; variable index: 0 + const b = 2; // scope index: 1; variable index: 0 } ``` @@ -227,8 +230,8 @@ Let's take a look at this example: ```js function addOne(a) { - const one = 1; - return one + a; + const one = 1; + return one + a; } addOne(2); ``` @@ -260,10 +263,10 @@ Let's look at this example: ```js function addOneBuilder() { - const one = 1; - return (a) => { - return one + a; - }; + const one = 1; + return (a) => { + return one + a; + }; } const addOne = addOneBuilder(); addOne(2); @@ -327,10 +330,10 @@ Let's visualize the scope analysis by writing out the scopes for this example: ```js function addOneBuilder() { - const one = 1; - return (a) => { - return one + a; - }; + const one = 1; + return (a) => { + return one + a; + }; } ``` @@ -396,69 +399,69 @@ Without going into detail on each of these cases, we can find all of them via sc Here is a quick overview: - Non `strict` functions create a mapped `arguments` object. - The mapped `arguments` object can be used to read and write function arguments without using their identifiers. - The reads and writes are kept in sync with the values of the argument variables. - This means that we cannot determine if the argument variables are accessed from outside the function. - - An example of such a situation would be this code: - - ```js - function f(a) { - console.log(a); // initial - (() => { - arguments[0] = "modified"; - })() - console.log(a); // modified - } - f("initial"); - ``` + The mapped `arguments` object can be used to read and write function arguments without using their identifiers. + The reads and writes are kept in sync with the values of the argument variables. + This means that we cannot determine if the argument variables are accessed from outside the function. - The solution here is to mark every argument variable that might be accessed through a mapped `arguments` object as non-local. + An example of such a situation would be this code: -- Direct calls to `eval` allow potential variable access. - Direct calls to `eval` have access to the current variables. - Since any code could be executed in `eval` we cannot do proper scope analysis on any variables in such cases. + ```js + function f(a) { + console.log(a); // initial + (() => { + arguments[0] = "modified"; + })(); + console.log(a); // modified + } + f("initial"); + ``` - An example of direct `eval` usage would be this: + The solution here is to mark every argument variable that might be accessed through a mapped `arguments` object as non-local. - ```js - function f() { - const a = 1; - eval("function nested() {console.log(a)}; nested();"); - } - f(); - ``` +- Direct calls to `eval` allow potential variable access. + Direct calls to `eval` have access to the current variables. + Since any code could be executed in `eval` we cannot do proper scope analysis on any variables in such cases. - Our solution is this case is to mark every variable in the scopes where the direct `eval` call is as non-local. + An example of direct `eval` usage would be this: -- Usage of the `with` statement. - Variable identifiers inside a `with` statement are not static. - A variable identifier could be the access to a variable, but it also could be the access to an object property. + ```js + function f() { + const a = 1; + eval("function nested() {console.log(a)}; nested();"); + } + f(); + ``` - See this example: + Our solution is this case is to mark every variable in the scopes where the direct `eval` call is as non-local. - ```js - function f() { - const a1 = 1; - for (let i = 0; i < 2; i++) { - with ({ [`a${i}`]: 2 }) { - console.log(a1); - } - } +- Usage of the `with` statement. + Variable identifiers inside a `with` statement are not static. + A variable identifier could be the access to a variable, but it also could be the access to an object property. + + See this example: + + ```js + function f() { + const a1 = 1; + for (let i = 0; i < 2; i++) { + with ({ [`a${i}`]: 2 }) { + console.log(a1); + } } - f(); - ``` + } + f(); + ``` - In the first loop execution `a1` is the variable. - In the second loop execution `a1` is the object property. - As a result of this behavior, every variable accessed inside a `with` statement cannot be local. + In the first loop execution `a1` is the variable. + In the second loop execution `a1` is the object property. + As a result of this behavior, every variable accessed inside a `with` statement cannot be local. ## Conclusion After implementing local variables in Boa, we saw significant performance improvements in our benchmarks. Our overall benchmark scope improved by more than 25%. In one specific benchmark the scope increased by over 70%. -Notice that Boa is not the most performant engine yet. +Notice that Boa is not the most performant engine yet. There are probably other optimizations relating to variable storage that we have not implemented yet. Hopefully, you might have already picked up some practical tips to potentially improve to performance of your ECMAScript code. diff --git a/blog/2025-06-15-temporal-impl-1.md b/blog/2025-06-15-temporal-impl-1.md index d6ba33a7..61ea320c 100644 --- a/blog/2025-06-15-temporal-impl-1.md +++ b/blog/2025-06-15-temporal-impl-1.md @@ -1,12 +1,10 @@ --- layout: post tags: [post] -title: - Implementing Temporal, the new date/time API for JavaScript (and +title: Implementing Temporal, the new date/time API for JavaScript (and Rust!) metadata: ["temporal", "temporal_rs", "boa", "date/time"] -description: - A blog post about the temporal_rs Rust crate that implements +description: A blog post about the temporal_rs Rust crate that implements JavaScript's Temporal API and how temporal_rs supports implementing Temporal in JavaScript engines. authors: boa-dev @@ -472,12 +470,9 @@ A FFI version of temporal is also available for C and C++ via The above issues are considered blocking for a 0.1.0 release. -[mdn-temporal]: - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal +[mdn-temporal]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Temporal [temporal-rs-repo]: https://github.com/boa-dev/temporal -[construct-link]: - https://tc39.es/ecma262/multipage/ordinary-and-exotic-objects-behaviours.html#sec-ecmascript-function-objects-construct-argumentslist-newtarget -[call-link]: - https://tc39.es/ecma262/multipage/ordinary-and-exotic-objects-behaviours.html#sec-ecmascript-function-objects-call-thisargument-argumentslist +[construct-link]: https://tc39.es/ecma262/multipage/ordinary-and-exotic-objects-behaviours.html#sec-ecmascript-function-objects-construct-argumentslist-newtarget +[call-link]: https://tc39.es/ecma262/multipage/ordinary-and-exotic-objects-behaviours.html#sec-ecmascript-function-objects-call-thisargument-argumentslist [boa-test262]: https://test262.fyi/#|boa [temporal-capi]: https://crates.io/crates/temporal_capi diff --git a/src/components/benchmarks/index.tsx b/src/components/benchmarks/index.tsx index fcdccaed..02ec74ec 100644 --- a/src/components/benchmarks/index.tsx +++ b/src/components/benchmarks/index.tsx @@ -43,7 +43,7 @@ const ChartOptions = { export const BenchmarkGraphs: React.FC = ({ selectedEngines, - range + range, }) => { // Control the state of which engines are displayed using a Set @@ -52,20 +52,20 @@ export const BenchmarkGraphs: React.FC = ({ const colorMode = useColorMode(); ChartJS.defaults.color = colorMode.colorMode === "light" ? "#666" : "white"; - useEffect(() => { - fetch(`https://boa-api.jason-williams.co.uk/benchmarks?months=${range}&engines=${selectedEngines.join(',')}`).then( - (res) => res.json()) - .then(respData => { - setData(respData) - }); + fetch( + `https://boa-api.jason-williams.co.uk/benchmarks?months=${range}&engines=${selectedEngines.join(",")}`, + ) + .then((res) => res.json()) + .then((respData) => { + setData(respData); + }); }, [selectedEngines, range]); useEffect(() => { setCharts(buildChartFromBenchmark(data)); }, [data]); - return charts && charts.map((chart) => chart); }; @@ -74,19 +74,18 @@ const normalizeBenchmarkData = (benchmarkData: any[]) => { new Date(entry.date).toLocaleDateString(), ); - const engines = Object.keys(benchmarkData[0]).filter(key => key != "date"); + const engines = Object.keys(benchmarkData[0]).filter((key) => key != "date"); return { labels, - datasets: engines.map(engine => ({ + datasets: engines.map((engine) => ({ label: engine, - data: benchmarkData.map(entry => entry[engine]), - fill: false + data: benchmarkData.map((entry) => entry[engine]), + fill: false, })), }; }; - const getBarChartData = (data) => { // We only want the last value from each dataset return { @@ -101,12 +100,11 @@ const getBarChartData = (data) => { }; const buildChartFromBenchmark = (data: any): any[] => { - let charts = []; for (const benchmark in data) { - const normalizedData = normalizeBenchmarkData(data[benchmark]) + const normalizedData = normalizeBenchmarkData(data[benchmark]); const barData = getBarChartData(normalizedData); - charts.push(( + charts.push(
{benchmark} @@ -119,13 +117,9 @@ const buildChartFromBenchmark = (data: any): any[] => {
- - )); - }; + , + ); + } return charts; }; - - - - diff --git a/src/components/conformance/HeroBanner/index.tsx b/src/components/conformance/HeroBanner/index.tsx index c5468ab6..2a47a713 100644 --- a/src/components/conformance/HeroBanner/index.tsx +++ b/src/components/conformance/HeroBanner/index.tsx @@ -7,7 +7,7 @@ import { import { createState, mapToTestStats, - createSearchParams + createSearchParams, } from "@site/src/components/conformance/utils"; import { useHistory } from "@docusaurus/router"; import Heading from "@theme/Heading"; diff --git a/src/components/conformance/ResultsDisplay/index.tsx b/src/components/conformance/ResultsDisplay/index.tsx index 508adeff..040169af 100644 --- a/src/components/conformance/ResultsDisplay/index.tsx +++ b/src/components/conformance/ResultsDisplay/index.tsx @@ -21,7 +21,7 @@ type ResultsProps = { }; export default function ResultsDisplay(props: ResultsProps): JSX.Element { - const location = useLocation() + const location = useLocation(); const [currentSuite, setCurrentSuite] = React.useState( null, ); @@ -32,7 +32,10 @@ export default function ResultsDisplay(props: ResultsProps): JSX.Element { // History handling const history = useHistory(); - const pushStateToHistory = (search: string, state: ConformanceState): void => { + const pushStateToHistory = ( + search: string, + state: ConformanceState, + ): void => { history.push({ pathname: "/conformance", search, @@ -124,7 +127,11 @@ export default function ResultsDisplay(props: ResultsProps): JSX.Element { const setEcmaScriptFlag = (flag: string) => { const nulledFlag = flag ? flag : undefined; pushStateToHistory( - createSearchParams(props.state.version, props.state.testPath, props.state.selectedTest), + createSearchParams( + props.state.version, + props.state.testPath, + props.state.selectedTest, + ), createState( props.state.version, props.state.testPath, @@ -137,7 +144,11 @@ export default function ResultsDisplay(props: ResultsProps): JSX.Element { // Sets the sorting option const setSortOption = (option: string) => { pushStateToHistory( - createSearchParams(props.state.version, props.state.testPath, props.state.selectedTest), + createSearchParams( + props.state.version, + props.state.testPath, + props.state.selectedTest, + ), createState( props.state.version, props.state.testPath, diff --git a/src/components/conformance/types.ts b/src/components/conformance/types.ts index d322c6fb..5824eb25 100644 --- a/src/components/conformance/types.ts +++ b/src/components/conformance/types.ts @@ -1,21 +1,20 @@ - // The main global state of the conformance page. // // This state is fed into the History object and dictates // what renders. export type ConformanceState = { - version: VersionItem; // REMOVED (???) -> Connected to displaying specific results - testPath: string[]; // REMOVED (???) -> Navigation / breadcrumbs + version: VersionItem; + testPath: string[]; ecmaScriptVersion: string | undefined; sortOption: string; - selectedTest: string | undefined; // REMOVED (???) -> "TestViewer" + selectedTest: string | undefined; }; export type UrlState = { - versionTag: string | undefined, - testPath: string[] | undefined, - selectedTest: string | undefined, -} + versionTag: string | undefined; + testPath: string[] | undefined; + selectedTest: string | undefined; +}; export type VersionItem = { tagName: string; diff --git a/src/components/conformance/utils.ts b/src/components/conformance/utils.ts index 0d55127b..34550c1c 100644 --- a/src/components/conformance/utils.ts +++ b/src/components/conformance/utils.ts @@ -12,22 +12,29 @@ import { VersionItem, } from "@site/src/components/conformance/types"; - // Take a search param and create a state object export function createUrlState(search: string): UrlState { const params = new URLSearchParams(search); - console.log(`testPath: ${params.get("testPath")}`) + console.log(`testPath: ${params.get("testPath")}`); return { versionTag: params.get("version") ?? undefined, testPath: params.get("testPath")?.split("/") ?? undefined, - selectedTest: params.get("selectedTest") ?? undefined - } + selectedTest: params.get("selectedTest") ?? undefined, + }; } -export function updateInitialConformanceState(urlState: UrlState, conformanceState: ConformanceState) { - - if (!conformanceState && (urlState.versionTag || urlState.testPath || urlState.selectedTest)) { - const fetchUrl = urlState.versionTag === "main" ? `https://raw.githubusercontent.com/boa-dev/data/main/test262/refs/heads/main/latest.json` : `https://raw.githubusercontent.com/boa-dev/data/main/test262/refs/tags/${urlState.versionTag}/latest.json`; +export function updateInitialConformanceState( + urlState: UrlState, + conformanceState: ConformanceState, +) { + if ( + !conformanceState && + (urlState.versionTag || urlState.testPath || urlState.selectedTest) + ) { + const fetchUrl = + urlState.versionTag === "main" + ? `https://raw.githubusercontent.com/boa-dev/data/main/test262/refs/heads/main/latest.json` + : `https://raw.githubusercontent.com/boa-dev/data/main/test262/refs/tags/${urlState.versionTag}/latest.json`; const testPath = urlState.testPath || []; return { @@ -35,8 +42,8 @@ export function updateInitialConformanceState(urlState: UrlState, conformanceSta testPath: [urlState.versionTag, ...testPath], ecmaScriptVersion: undefined, sortOption: availableSortingOptions[0].id, - selectedTest: urlState.selectedTest - } + selectedTest: urlState.selectedTest, + }; } return conformanceState; } @@ -46,15 +53,15 @@ export function createSearchParams( testPath?: string[], selectedTest?: string, ) { - const search = new URLSearchParams() + const search = new URLSearchParams(); search.append("version", version.tagName); if (testPath) { search.append("testPath", testPath.slice(1).join("/")); } if (selectedTest) { - search.append("selectedTest", selectedTest) + search.append("selectedTest", selectedTest); } - return search.toString() + return search.toString(); } // Creates the state object from provided args diff --git a/src/pages/benchmarks/index.tsx b/src/pages/benchmarks/index.tsx index e2273534..fa17dc9d 100644 --- a/src/pages/benchmarks/index.tsx +++ b/src/pages/benchmarks/index.tsx @@ -68,7 +68,6 @@ export default function Benchmarks() { ))} -
Select rolling range @@ -103,8 +102,8 @@ export default function Benchmarks() {
- + - + ); } diff --git a/src/pages/conformance/index.tsx b/src/pages/conformance/index.tsx index 5e16599c..be18b876 100644 --- a/src/pages/conformance/index.tsx +++ b/src/pages/conformance/index.tsx @@ -6,7 +6,7 @@ import { } from "@site/src/components/conformance/types"; import { createUrlState, - updateInitialConformanceState + updateInitialConformanceState, } from "@site/src/components/conformance/utils"; import { useLocation } from "@docusaurus/router"; import Layout from "@theme/Layout"; @@ -68,8 +68,7 @@ export default function Conformance() { ); }, []); - - const resolvedState = updateInitialConformanceState(urlState, location.state) + const resolvedState = updateInitialConformanceState(urlState, location.state); return ( From bde17b50294defe51128f493ea03caa00e2afe16 Mon Sep 17 00:00:00 2001 From: nonbots Date: Sat, 28 Jun 2025 18:22:53 -0400 Subject: [PATCH 3/6] conformance/index move updateInitialConformanceState above useEffect --- src/pages/conformance/index.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pages/conformance/index.tsx b/src/pages/conformance/index.tsx index be18b876..b0e9dc2d 100644 --- a/src/pages/conformance/index.tsx +++ b/src/pages/conformance/index.tsx @@ -27,6 +27,7 @@ export default function Conformance() { >(null); const urlState = createUrlState(location.search); + const resolvedState = updateInitialConformanceState(urlState, location.state); // Initial Render useEffect React.useEffect(() => { @@ -68,8 +69,6 @@ export default function Conformance() { ); }, []); - const resolvedState = updateInitialConformanceState(urlState, location.state); - return (
From 56b4a6b51e586f6867d46f9d7647d363df6540b1 Mon Sep 17 00:00:00 2001 From: Nhan <44943248+nhancodes@users.noreply.github.com> Date: Mon, 30 Jun 2025 08:30:26 -0400 Subject: [PATCH 4/6] Update src/components/conformance/utils.ts guard clause for when `testPath` only contains version Co-authored-by: Kevin Ness <46825870+nekevss@users.noreply.github.com> --- src/components/conformance/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/conformance/utils.ts b/src/components/conformance/utils.ts index 34550c1c..2773c836 100644 --- a/src/components/conformance/utils.ts +++ b/src/components/conformance/utils.ts @@ -55,7 +55,7 @@ export function createSearchParams( ) { const search = new URLSearchParams(); search.append("version", version.tagName); - if (testPath) { + if (testPath && testPath.length > 1) { search.append("testPath", testPath.slice(1).join("/")); } if (selectedTest) { From 7fd97f670e1ee647dfec20c1373ba8aee30cbc1c Mon Sep 17 00:00:00 2001 From: nonbots Date: Sat, 5 Jul 2025 12:30:23 -0400 Subject: [PATCH 5/6] search param fix --- src/components/conformance/utils.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/components/conformance/utils.ts b/src/components/conformance/utils.ts index 2773c836..323c84aa 100644 --- a/src/components/conformance/utils.ts +++ b/src/components/conformance/utils.ts @@ -11,6 +11,7 @@ import { VersionedStats, VersionItem, } from "@site/src/components/conformance/types"; +import { url } from "node:inspector"; // Take a search param and create a state object export function createUrlState(search: string): UrlState { @@ -31,18 +32,21 @@ export function updateInitialConformanceState( !conformanceState && (urlState.versionTag || urlState.testPath || urlState.selectedTest) ) { + const selectedTest = urlState.testPath ? urlState.selectedTest : undefined; + const tagName = (!urlState.versionTag) && urlState.testPath ? "main" : urlState.versionTag; const fetchUrl = - urlState.versionTag === "main" + tagName === "main" ? `https://raw.githubusercontent.com/boa-dev/data/main/test262/refs/heads/main/latest.json` - : `https://raw.githubusercontent.com/boa-dev/data/main/test262/refs/tags/${urlState.versionTag}/latest.json`; + : `https://raw.githubusercontent.com/boa-dev/data/main/test262/refs/tags/${tagName}/latest.json`; const testPath = urlState.testPath || []; + if (!tagName && testPath.length == 0 && !selectedTest) return conformanceState; return { - version: { tagName: urlState.versionTag, fetchUrl }, - testPath: [urlState.versionTag, ...testPath], + version: { tagName, fetchUrl }, + testPath: [tagName, ...testPath], ecmaScriptVersion: undefined, sortOption: availableSortingOptions[0].id, - selectedTest: urlState.selectedTest, + selectedTest: selectedTest, }; } return conformanceState; From 84b63a855bc0d9ad18a4d9acd07270d08b390696 Mon Sep 17 00:00:00 2001 From: nonbots Date: Sat, 5 Jul 2025 13:22:19 -0400 Subject: [PATCH 6/6] fix/refactor: default to version main when version is undefine --- src/components/conformance/utils.ts | 37 +++++++++++++---------------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/src/components/conformance/utils.ts b/src/components/conformance/utils.ts index 323c84aa..75903d36 100644 --- a/src/components/conformance/utils.ts +++ b/src/components/conformance/utils.ts @@ -28,28 +28,23 @@ export function updateInitialConformanceState( urlState: UrlState, conformanceState: ConformanceState, ) { - if ( - !conformanceState && - (urlState.versionTag || urlState.testPath || urlState.selectedTest) - ) { - const selectedTest = urlState.testPath ? urlState.selectedTest : undefined; - const tagName = (!urlState.versionTag) && urlState.testPath ? "main" : urlState.versionTag; - const fetchUrl = - tagName === "main" - ? `https://raw.githubusercontent.com/boa-dev/data/main/test262/refs/heads/main/latest.json` - : `https://raw.githubusercontent.com/boa-dev/data/main/test262/refs/tags/${tagName}/latest.json`; + if (conformanceState) return conformanceState; + const selectedTest = urlState.testPath ? urlState.selectedTest : undefined; + const tagName = (!urlState.versionTag) && urlState.testPath ? "main" : urlState.versionTag; + const fetchUrl = + tagName === "main" + ? `https://raw.githubusercontent.com/boa-dev/data/main/test262/refs/heads/main/latest.json` + : `https://raw.githubusercontent.com/boa-dev/data/main/test262/refs/tags/${tagName}/latest.json`; - const testPath = urlState.testPath || []; - if (!tagName && testPath.length == 0 && !selectedTest) return conformanceState; - return { - version: { tagName, fetchUrl }, - testPath: [tagName, ...testPath], - ecmaScriptVersion: undefined, - sortOption: availableSortingOptions[0].id, - selectedTest: selectedTest, - }; - } - return conformanceState; + const testPath = urlState.testPath || []; + if (!tagName && testPath.length == 0 && !selectedTest) return conformanceState; + return { + version: { tagName, fetchUrl }, + testPath: [tagName, ...testPath], + ecmaScriptVersion: undefined, + sortOption: availableSortingOptions[0].id, + selectedTest: selectedTest, + }; } export function createSearchParams(