Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,39 @@ describe('formatting edge cases', () => {
await expect(buildPromise).rejects.toMatchSnapshot();
});

test('reports resolution errors on locations past the end of the source', async () => {
// A Babel plugin appends an unresolvable import whose source location is
// past the end of the file on disk. The resolution error must survive:
// before, building the code frame threw a TypeError that replaced it.
const config = await Metro.loadConfig({
config: require.resolve('../metro.config.js'),
});

const buildPromise = Metro.runBuild(
{
...config,
transformer: {
...config.transformer,
babelTransformerPath:
require.resolve('../injectImportPastEndOfFileTransformer'),
},
},
{entry: 'build-errors/transform-injected-import.js'},
);

// Deliberately not a snapshot: the resolver's list of candidate paths
// varies between versions, and what matters here is only that the
// resolution error survives with a code frame of the lines that do exist.
const error = await buildPromise.then(
() => null,
(e: Error) => e,
);
expect(error?.message).toMatch(
/^Unable to resolve module \.\/does-not-exist/,
);
expect(error?.message).toContain('13 | global.x = 1;');
});

test('reports resolution errors with embedded comment after the specifier', async () => {
const config = await Metro.loadConfig({
config: require.resolve('../metro.config.js'),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/

// The unresolvable import in this module is added by a Babel plugin, not
// written here - see injectImportPastEndOfFileTransformer.js.
global.x = 1;
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow
* @format
* @oncall react_native
*/

'use strict';

import type {PluginObj} from '@babel/core';
import type {
BabelTransformer,
BabelTransformerArgs,
} from 'metro-babel-transformer';

const {parse} = require('@babel/parser');
const baseTransformer = require('@react-native/metro-babel-transformer');

const TARGET_FILE = 'transform-injected-import.js';
const INJECTED_SPECIFIER = './does-not-exist';

/**
* Returns a Babel plugin that appends `import './does-not-exist';` to the
* module, parsed at `startLine` - which is what a plugin that generates and
* appends code does, so that the generated code's locations do not overlap the
* author's.
*
* Given a `startLine` past the end of the file, the dependency Metro collects
* reports a source location that has no counterpart in the file on disk, which
* is what the resolution error's code frame has to tolerate.
*/
function injectImportAt(startLine: number): () => PluginObj<> {
return () => ({
name: 'metro-test-inject-import-past-end-of-file',
visitor: {
Program(path) {
const generated = parse(`import '${INJECTED_SPECIFIER}';`, {
sourceType: 'module',
startLine,
});
path.node.body.push(...generated.program.body);
},
},
});
}

function transform(args: BabelTransformerArgs) {
if (!args.filename.endsWith(TARGET_FILE)) {
return baseTransformer.transform(args);
}
// One line past the last line of the source, so the injected import's
// location does not exist in the file on disk.
const startLine = args.src.split('\n').length + 1;
return baseTransformer.transform({
...args,
plugins: [...(args.plugins ?? []), injectImportAt(startLine)],
});
}

module.exports = {
transform,
getCacheKey: baseTransformer.getCacheKey,
} as BabelTransformer;
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,11 @@ function refineDependencyLocation(
// Note that module names may not always be found in the source code verbatim,
// whether because of escaping or because of exotic dependency APIs.
for (let line = loc.end.line - 1; line >= loc.start.line - 1; line--) {
// The error occurred in code that was added by a transform, then it
// won't be present in the original source code.
if (lines[line] == null) {
continue;
}
const maxColumn =
line === loc.end.line ? loc.end.column + 2 : lines[line].length;
const minColumn = line === loc.start.line ? loc.start.column - 1 : 0;
Expand Down
Loading