Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generate codeframe positions for JSON5 #7933

Merged
merged 2 commits into from Apr 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
41 changes: 0 additions & 41 deletions flow-libs/json-source-map.js.flow

This file was deleted.

2 changes: 1 addition & 1 deletion packages/core/core/package.json
Expand Up @@ -24,6 +24,7 @@
"check-ts": "tsc --noEmit index.d.ts"
},
"dependencies": {
"@mischnic/json-sourcemap": "^0.1.0",
"@parcel/cache": "2.4.1",
"@parcel/diagnostic": "2.4.1",
"@parcel/events": "2.4.1",
Expand All @@ -43,7 +44,6 @@
"clone": "^2.1.1",
"dotenv": "^7.0.0",
"dotenv-expand": "^5.1.0",
"json-source-map": "^0.6.1",
"json5": "^2.2.0",
"msgpackr": "^1.5.4",
"nullthrows": "^1.1.1",
Expand Down
4 changes: 2 additions & 2 deletions packages/core/core/src/requests/EntryRequest.js
Expand Up @@ -17,7 +17,7 @@ import ThrowableDiagnostic, {
getJSONSourceLocation,
} from '@parcel/diagnostic';
import path from 'path';
import jsonMap, {type Mapping} from 'json-source-map';
import {parse, type Mapping} from '@mischnic/json-sourcemap';
import {
type ProjectPath,
fromProjectPath,
Expand Down Expand Up @@ -345,7 +345,7 @@ export class EntryResolver {
return {
...pkg,
filePath: pkgFile,
map: jsonMap.parse(content.replace(/\t/g, ' ')),
map: parse(content, undefined, {tabWidth: 1}),
};
}
}
4 changes: 2 additions & 2 deletions packages/core/core/src/requests/TargetRequest.js
Expand Up @@ -34,7 +34,7 @@ import createParcelConfigRequest, {
} from './ParcelConfigRequest';
// $FlowFixMe
import browserslist from 'browserslist';
import jsonMap from 'json-source-map';
import {parse} from '@mischnic/json-sourcemap';
import invariant from 'assert';
import nullthrows from 'nullthrows';
import {
Expand Down Expand Up @@ -395,7 +395,7 @@ export class TargetResolver {
let _pkgFilePath = (pkgFilePath = pkgFile.filePath); // For Flow
pkgDir = path.dirname(_pkgFilePath);
pkgContents = await this.fs.readFile(_pkgFilePath, 'utf8');
pkgMap = jsonMap.parse(pkgContents.replace(/\t/g, ' '));
pkgMap = parse(pkgContents, undefined, {tabWidth: 1});

let pp = toProjectPath(this.options.projectRoot, _pkgFilePath);
this.api.invalidateOnFileUpdate(pp);
Expand Down
39 changes: 39 additions & 0 deletions packages/core/core/test/ParcelConfigRequest.test.js
Expand Up @@ -813,6 +813,45 @@ describe('ParcelConfigRequest', () => {
);
});

it('should emit a codeframe when an extended parcel config file is not found in JSON5', async () => {
let configFilePath = path.join(
__dirname,
'fixtures',
'config-extends-not-found',
'.parcelrc-json5',
);
let code = await DEFAULT_OPTIONS.inputFS.readFile(configFilePath, 'utf8');

// $FlowFixMe[prop-missing]
await assert.rejects(
() => parseAndProcessConfig(configFilePath, code, DEFAULT_OPTIONS),
{
name: 'Error',
diagnostics: [
{
message: 'Cannot find extended parcel config',
origin: '@parcel/core',
codeFrames: [
{
filePath: configFilePath,
language: 'json5',
code,
codeHighlights: [
{
message:
'"./.parclrc-node-modules" does not exist, did you mean "./.parcelrc-node-modules"?',
start: {line: 2, column: 12},
end: {line: 2, column: 36},
},
],
},
],
},
],
},
);
});

it('should emit a codeframe when an extended parcel config node module is not found', async () => {
let configFilePath = path.join(
__dirname,
Expand Down
@@ -0,0 +1,3 @@
{
extends: "./.parclrc-node-modules"
}
2 changes: 1 addition & 1 deletion packages/core/diagnostic/package.json
Expand Up @@ -24,7 +24,7 @@
"check-ts": "tsc --noEmit lib/diagnostic.d.ts"
},
"dependencies": {
"json-source-map": "^0.6.1",
"@mischnic/json-sourcemap": "^0.1.0",
"nullthrows": "^1.1.1"
}
}
15 changes: 8 additions & 7 deletions packages/core/diagnostic/src/diagnostic.js
Expand Up @@ -2,7 +2,7 @@

import invariant from 'assert';
import nullthrows from 'nullthrows';
import jsonMap, {type Mapping} from 'json-source-map';
import {parse, type Mapping} from '@mischnic/json-sourcemap';

/** These positions are 1-based (so <code>1</code> is the first line/column) */
export type DiagnosticHighlightLocation = {|
Expand Down Expand Up @@ -215,8 +215,8 @@ export default class ThrowableDiagnostic extends Error {
}

/**
* Turns a list of positions in a JSON file with messages into a list of diagnostics.
* Uses <a href="https://github.com/epoberezkin/json-source-map">epoberezkin/json-source-map</a>.
* Turns a list of positions in a JSON5 file with messages into a list of diagnostics.
* Uses <a href="https://github.com/mischnic/json-sourcemap">@mischnic/json-sourcemap</a>.
*
* @param code the JSON code
* @param ids A list of JSON keypaths (<code>key: "/some/parent/child"</code>) with corresponding messages, \
Expand All @@ -231,9 +231,10 @@ export function generateJSONCodeHighlights(
|},
ids: Array<{|key: string, type?: ?'key' | 'value', message?: string|}>,
): Array<DiagnosticCodeHighlight> {
// json-source-map doesn't support a tabWidth option (yet)
let map =
typeof data == 'string' ? jsonMap.parse(data.replace(/\t/g, ' ')) : data;
typeof data == 'string'
? parse(data, undefined, {dialect: 'JSON5', tabWidth: 1})
: data;
return ids.map(({key, type, message}) => {
let pos = nullthrows(map.pointers[key]);
return {
Expand All @@ -244,7 +245,7 @@ export function generateJSONCodeHighlights(
}

/**
* Converts entries in <a href="https://github.com/epoberezkin/json-source-map">epoberezkin/json-source-map</a>'s
* Converts entries in <a href="https://github.com/mischnic/json-sourcemap">@mischnic/json-sourcemap</a>'s
* <code>result.pointers</code> array.
*/
export function getJSONSourceLocation(
Expand Down Expand Up @@ -276,7 +277,7 @@ export function getJSONSourceLocation(

/** Sanitizes object keys before using them as <code>key</code> in generateJSONCodeHighlights */
export function encodeJSONKeyComponent(component: string): string {
return component.replace(/\//g, '~1');
return component.replace(/~/g, '~0').replace(/\//g, '~1');
}

const escapeCharacters = ['\\', '*', '_', '~'];
Expand Down
56 changes: 56 additions & 0 deletions packages/core/integration-tests/test/babel.js
Expand Up @@ -711,4 +711,60 @@ describe('babel', function () {
},
]);
});

it('should warn when a JSON5 babel config contains redundant plugins', async function () {
let messages = [];
let loggerDisposable = Logger.onLog(message => {
messages.push(message);
});
let filePath = path.join(
__dirname,
'/integration/babel-warn-some-json5/index.js',
);
await bundle(filePath);
loggerDisposable.dispose();

let babelrcPath = path.resolve(path.dirname(filePath), '.babelrc');
assert.deepEqual(messages, [
{
type: 'log',
level: 'warn',
diagnostics: [
{
origin: '@parcel/transformer-babel',
message: md`Parcel includes transpilation by default. Babel config __${path.relative(
process.cwd(),
babelrcPath,
)}__ includes the following redundant presets: __@parcel/babel-preset-env__. Removing these may improve build performance.`,
codeFrames: [
{
filePath: babelrcPath,
codeHighlights: [
{
message: undefined,
start: {
line: 2,
column: 13,
},
end: {
line: 2,
column: 38,
},
},
],
},
],
hints: [
md`Remove the above presets from __${path.relative(
process.cwd(),
babelrcPath,
)}__`,
],
documentationURL:
'https://parceljs.org/languages/javascript/#default-presets',
},
],
},
]);
});
});
@@ -0,0 +1,4 @@
{
presets: ["@parcel/babel-preset-env"],
"plugins": ["../babelrc-custom/babel-plugin-dummy"]
}
2 changes: 1 addition & 1 deletion packages/core/utils/src/schema.js
Expand Up @@ -4,7 +4,7 @@ import ThrowableDiagnostic, {
escapeMarkdown,
encodeJSONKeyComponent,
} from '@parcel/diagnostic';
import type {Mapping} from 'json-source-map';
import type {Mapping} from '@mischnic/json-sourcemap';
import nullthrows from 'nullthrows';
// flowlint-next-line untyped-import:off
import levenshtein from 'fastest-levenshtein';
Expand Down
7 changes: 1 addition & 6 deletions packages/transformers/babel/src/config.js
Expand Up @@ -394,12 +394,7 @@ async function getCodeHighlights(fs, filePath, redundantPresets) {
}

if (pointers.length > 0) {
try {
return generateJSONCodeHighlights(contents, pointers);
} catch {
// TODO: support code highlights for json5 sources.
// Babel supports json5 syntax, but json-source-map does not.
}
return generateJSONCodeHighlights(contents, pointers);
}
}

Expand Down
4 changes: 2 additions & 2 deletions packages/transformers/webextension/package.json
Expand Up @@ -19,10 +19,10 @@
"parcel": "^2.4.1"
},
"dependencies": {
"@mischnic/json-sourcemap": "^0.1.0",
"@parcel/diagnostic": "2.4.1",
"@parcel/plugin": "2.4.1",
"@parcel/utils": "2.4.1",
"content-security-policy-parser": "^0.3.0",
"json-source-map": "^0.6.1"
"content-security-policy-parser": "^0.3.0"
}
}
Expand Up @@ -3,7 +3,7 @@ import type {MutableAsset} from '@parcel/types';

import {Transformer} from '@parcel/plugin';
import path from 'path';
import jsm from 'json-source-map';
import {parse} from '@mischnic/json-sourcemap';
import parseCSP from 'content-security-policy-parser';
import {validateSchema} from '@parcel/utils';
import ThrowableDiagnostic, {
Expand Down Expand Up @@ -267,7 +267,7 @@ function cspPatchHMR(policy: ?string) {
export default (new Transformer({
async transform({asset, options}) {
const code = await asset.getCode();
const parsed = jsm.parse(code);
const parsed = parse(code);
const data: any = parsed.data;
validateSchema.diagnostic(
WebExtensionSchema,
Expand Down
4 changes: 2 additions & 2 deletions packages/transformers/webmanifest/package.json
Expand Up @@ -19,9 +19,9 @@
"parcel": "^2.4.1"
},
"dependencies": {
"@mischnic/json-sourcemap": "^0.1.0",
"@parcel/diagnostic": "2.4.1",
"@parcel/plugin": "2.4.1",
"@parcel/utils": "2.4.1",
"json-source-map": "^0.6.1"
"@parcel/utils": "2.4.1"
}
}
Expand Up @@ -3,7 +3,7 @@
import type {SchemaEntity} from '@parcel/utils';

import invariant from 'assert';
import jsm from 'json-source-map';
import {parse} from '@mischnic/json-sourcemap';
import {getJSONSourceLocation} from '@parcel/diagnostic';
import {Transformer} from '@parcel/plugin';
import {validateSchema} from '@parcel/utils';
Expand Down Expand Up @@ -36,7 +36,7 @@ const MANIFEST_SCHEMA: SchemaEntity = {
export default (new Transformer({
async transform({asset}) {
const source = await asset.getCode();
const {data, pointers} = jsm.parse(source);
const {data, pointers} = parse(source);

validateSchema.diagnostic(
MANIFEST_SCHEMA,
Expand Down