Skip to content

Commit

Permalink
chore(tasks/transform-conformance): support override to replace takeo…
Browse files Browse the repository at this point in the history
…ver mode
  • Loading branch information
Dunqing authored and overlookmotel committed Dec 11, 2024
1 parent 450bb33 commit 51b6b30
Show file tree
Hide file tree
Showing 87 changed files with 707 additions and 95 deletions.
2 changes: 1 addition & 1 deletion .typos.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ extend-exclude = [
"tasks/prettier_conformance/prettier",
"tasks/prettier_conformance/snapshots",
"tasks/transform_conformance/tests/**/output.js",
"tasks/transform_conformance/snapshots",
"tasks/transform_conformance/overrides",
"npm/oxc-wasm/oxc_wasm.js",
]

Expand Down

This file was deleted.

638 changes: 637 additions & 1 deletion tasks/transform_conformance/snapshots/babel.snap.md

Large diffs are not rendered by default.

3 changes: 0 additions & 3 deletions tasks/transform_conformance/src/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,3 @@ pub const SKIP_TESTS: &[&str] = &[
"babel-plugin-transform-object-rest-spread/test/fixtures/object-rest/remove-unused-excluded-keys-loose",
"babel-plugin-transform-object-rest-spread/test/fixtures/object-rest/regression/gh-8323"
];

pub const SNAPSHOT_TESTS: &[&str] =
&["babel-plugin-transform-object-rest-spread", "babel-plugin-transform-optional-chaining"];
4 changes: 4 additions & 0 deletions tasks/transform_conformance/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,10 @@ fn snap_root() -> PathBuf {
conformance_root().join("snapshots")
}

fn override_root() -> PathBuf {
conformance_root().join("overrides")
}

fn oxc_test_root() -> PathBuf {
conformance_root().join("tests")
}
Expand Down
76 changes: 35 additions & 41 deletions tasks/transform_conformance/src/test_case.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ use oxc::{
use oxc_tasks_common::{normalize_path, print_diff_in_terminal, project_root};

use crate::{
constants::{PLUGINS_NOT_SUPPORTED_YET, SKIP_TESTS, SNAPSHOT_TESTS},
constants::{PLUGINS_NOT_SUPPORTED_YET, SKIP_TESTS},
driver::Driver,
fixture_root, oxc_test_root, packages_root, snap_root, TestRunnerOptions,
fixture_root, override_root, oxc_test_root, packages_root, TestRunnerOptions,
};

#[derive(Debug)]
Expand All @@ -35,12 +35,19 @@ pub struct TestCase {
pub enum TestCaseKind {
Conformance,
Exec,
Snapshot,
}

impl TestCase {
pub fn new(cwd: &Path, path: &Path) -> Option<Self> {
let mut options = BabelOptions::from_test_path(path.parent().unwrap());
let mut options_directory_path = path.parent().unwrap().to_path_buf();
// Try to find the override options.json
if let Some(path) = Self::convert_to_override_path(options_directory_path.as_path()) {
if path.join("options.json").exists() {
options_directory_path = path;
}
}

let mut options = BabelOptions::from_test_path(options_directory_path.as_path());
options.cwd.replace(cwd.to_path_buf());
let transform_options = TransformOptions::try_from(&options);
let path = path.to_path_buf();
Expand All @@ -59,14 +66,7 @@ impl TestCase {
else if path.file_stem().is_some_and(|name| name == "input" || name == "input.d")
&& path.extension().is_some_and(|ext| VALID_EXTENSIONS.contains(&ext.to_str().unwrap()))
{
if path
.strip_prefix(packages_root())
.is_ok_and(|p| SNAPSHOT_TESTS.iter().any(|t| p.to_string_lossy().starts_with(t)))
{
TestCaseKind::Snapshot
} else {
TestCaseKind::Conformance
}
TestCaseKind::Conformance
} else {
return None;
};
Expand Down Expand Up @@ -96,6 +96,28 @@ impl TestCase {
source_type
}

fn convert_to_override_path(path: &Path) -> Option<PathBuf> {
path.strip_prefix(packages_root()).ok().map(|p| override_root().join(p))
}

fn get_output_path(&self) -> Option<PathBuf> {
let babel_output_path =
self.path.parent().unwrap().read_dir().unwrap().find_map(|entry| {
let path = entry.ok()?.path();
let file_stem = path.file_stem()?;
(file_stem == "output").then_some(path)
})?;

// Try to find the override output path
if let Some(output_path) = Self::convert_to_override_path(&babel_output_path) {
if output_path.exists() {
return Some(output_path);
}
}

Some(babel_output_path)
}

pub fn skip_test_case(&self) -> bool {
let options = &self.options;

Expand Down Expand Up @@ -203,17 +225,12 @@ impl TestCase {
self.test_exec(filtered);
}
}
TestCaseKind::Snapshot => self.test_snapshot(filtered),
}
}

/// Test conformance by comparing the parsed babel code and transformed code.
fn test_conformance(&mut self, filtered: bool) {
let output_path = self.path.parent().unwrap().read_dir().unwrap().find_map(|entry| {
let path = entry.ok()?.path();
let file_stem = path.file_stem()?;
(file_stem == "output").then_some(path)
});
let output_path = self.get_output_path();

let allocator = Allocator::default();
let input = fs::read_to_string(&self.path).unwrap();
Expand Down Expand Up @@ -388,29 +405,6 @@ test("exec", () => {{
}})"#
)
}

fn test_snapshot(&self, filtered: bool) {
let result = match self.transform(HelperLoaderMode::External) {
Ok(code) => code,
Err(error) => error,
};
let mut path = snap_root().join(self.path.strip_prefix(packages_root()).unwrap());
path.set_file_name("output");
let input_extension = self.path.extension().unwrap().to_str().unwrap();
let extension =
input_extension.chars().map(|c| if c == 't' { 'j' } else { c }).collect::<String>();
path.set_extension(extension);
if filtered {
println!("Input path: {:?}", &self.path);
println!("Output path: {path:?}");
println!("Input:\n{}\n", fs::read_to_string(&self.path).unwrap());
println!("Output:\n{result}\n");
}
if fs::write(&path, &result).is_err() {
fs::create_dir_all(path.parent().unwrap()).unwrap();
fs::write(path, &result).unwrap();
}
}
}

fn get_babel_error(error: &str) -> String {
Expand Down
77 changes: 30 additions & 47 deletions tasks/transform_conformance/update_fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@
// (or maybe don't - what does this option mean?)

import { transformFileAsync } from '@babel/core';
import assert from 'assert';
import { copyFile, readdir, readFile, rename, writeFile } from 'fs/promises';
import { readdir, readFile, rename, writeFile } from 'fs/promises';
import { extname, join as pathJoin } from 'path';

const PACKAGES = [
Expand All @@ -28,7 +27,10 @@ const FILTER_OUT_PLUGINS = [
'transform-destructuring',
];

const PACKAGES_PATH = pathJoin(import.meta.dirname, '../coverage/babel/packages');
const PACKAGES_PATH = pathJoin(
import.meta.dirname,
'../coverage/babel/packages',
);
const OVERRIDES_PATH = pathJoin(import.meta.dirname, 'overrides');

// Copied from `@babel/helper-transform-fixture-test-runner`
Expand All @@ -52,7 +54,12 @@ async function updateDir(dirPath, options, hasChangedOptions) {
const dirFiles = [];

const filenames = { options: null, input: null, output: null, exec: null };
const overrides = { options: false, input: false, output: false, exec: false };
const overrides = {
options: false,
input: false,
output: false,
exec: false,
};

// Find files in dir
for (const file of files) {
Expand All @@ -66,44 +73,6 @@ async function updateDir(dirPath, options, hasChangedOptions) {
}
}

// Find override files
const overridesDirPath = pathJoin(`${OVERRIDES_PATH}${dirPath.slice(PACKAGES_PATH.length)}`);
let overrideFiles;
try {
overrideFiles = await readdir(overridesDirPath, { withFileTypes: true });
} catch (err) {
if (err?.code !== 'ENOENT') throw err;
}

if (overrideFiles) {
for (const file of overrideFiles) {
if (file.isDirectory()) continue;

const filename = file.name;
// `reason.txt` files are to document why override is used
if (filename === 'reason.txt') continue;

const ext = extname(filename),
type = filename.slice(0, -ext.length),
path = pathJoin(overridesDirPath, filename);

assert(Object.hasOwn(overrides, type), `Unexpected override file: ${path}`);

const originalPath = pathJoin(dirPath, filename);
if (filenames[type]) {
const originalFilename = filenames[type];
assert(originalFilename === filename, `Unmatched override file: ${path} (original: ${originalFilename})`);
await backupFile(originalPath);
}

filenames[type] = filename;
overrides[type] = true;
if (type === 'options') hasChangedOptions = true;

await copyFile(path, originalPath);
}
}

// Update options, save to file, and merge options with parent
if (filenames.options) {
const path = pathJoin(dirPath, filenames.options);
Expand All @@ -117,7 +86,11 @@ async function updateDir(dirPath, options, hasChangedOptions) {
}

// Run Babel with updated options/input
if (filenames.output && (hasChangedOptions || overrides.input) && !overrides.output) {
if (
filenames.output &&
(hasChangedOptions || overrides.input) &&
!overrides.output
) {
const inputPath = pathJoin(dirPath, filenames.input),
outputPath = pathJoin(dirPath, filenames.output);
await backupFile(outputPath);
Expand Down Expand Up @@ -165,7 +138,12 @@ function updateOptions(options) {
* @returns {undefined}
*/
async function transform(inputPath, outputPath, options) {
options = { ...options, configFile: false, babelrc: false, cwd: import.meta.dirname };
options = {
...options,
configFile: false,
babelrc: false,
cwd: import.meta.dirname,
};
delete options.SKIP_babel7plugins_babel8core;
delete options.minNodeVersion;

Expand All @@ -179,9 +157,11 @@ async function transform(inputPath, outputPath, options) {
return plugin;
}

if (options.presets) options.presets = options.presets.map(preset => prefixName(preset, 'preset'));
if (options.presets) {
options.presets = options.presets.map((preset) => prefixName(preset, 'preset'));
}

options.plugins = (options.plugins || []).map(plugin => prefixName(plugin, 'plugin'));
options.plugins = (options.plugins || []).map((plugin) => prefixName(plugin, 'plugin'));

let addExternalHelpersPlugin = true;
if (Object.hasOwn(options, 'externalHelpers')) {
Expand All @@ -190,7 +170,10 @@ async function transform(inputPath, outputPath, options) {
}

if (addExternalHelpersPlugin) {
options.plugins.push(['@babel/plugin-external-helpers', { helperVersion: EXTERNAL_HELPERS_VERSION }]);
options.plugins.push([
'@babel/plugin-external-helpers',
{ helperVersion: EXTERNAL_HELPERS_VERSION },
]);
}

const { code } = await transformFileAsync(inputPath, options);
Expand Down

0 comments on commit 51b6b30

Please sign in to comment.