mirror of
https://github.com/facebook/react.git
synced 2026-02-24 20:53:03 +00:00
126 lines
3.8 KiB
JavaScript
126 lines
3.8 KiB
JavaScript
/*
|
|
* 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
|
|
*/
|
|
|
|
import {getHookNamesMappingFromAST} from './astUtils';
|
|
import {encode, decode} from 'sourcemap-codec';
|
|
|
|
// Missing types in @babel/types
|
|
type File = any;
|
|
|
|
export type HookMap = {
|
|
names: $ReadOnlyArray<string>,
|
|
mappings: HookMapMappings,
|
|
};
|
|
|
|
export type EncodedHookMap = {
|
|
names: $ReadOnlyArray<string>,
|
|
mappings: string,
|
|
};
|
|
|
|
// See generateHookMap below for more details on formatting
|
|
export type HookMapEntry = [
|
|
number, // 1-indexed line number
|
|
number, // 0-indexed column number
|
|
number, // 0-indexed index into names array
|
|
number, // TODO: filler number to support reusing encoding from `sourcemap-codec` (see TODO below)
|
|
];
|
|
export type HookMapLine = HookMapEntry[];
|
|
export type HookMapMappings = HookMapLine[];
|
|
|
|
/**
|
|
* Given a parsed source code AST, returns a "Hook Map", which is a
|
|
* mapping which maps locations in the source code to their to their
|
|
* corresponding Hook name, if there is a relevant Hook name for that
|
|
* location (see getHookNamesMappingFromAST for details on the
|
|
* representation of the mapping).
|
|
*
|
|
* The format of the Hook Map follows a similar format as the `name`
|
|
* and `mappings` fields in the Source Map spec, where `names` is an
|
|
* array of strings, and `mappings` contains segments lines, columns,
|
|
* and indices into the `names` array.
|
|
*
|
|
* E.g.:
|
|
* {
|
|
* names: ["<no-hook>", "state"],
|
|
* mappings: [
|
|
* [ -> line 1
|
|
* [1, 0, 0], -> line, col, name index
|
|
* ],
|
|
* [ -> line 2
|
|
* [2, 5, 1], -> line, col, name index
|
|
* [2, 15, 0], -> line, col, name index
|
|
* ],
|
|
* ],
|
|
* }
|
|
*/
|
|
export function generateHookMap(sourceAST: File): HookMap {
|
|
const hookNamesMapping = getHookNamesMappingFromAST(sourceAST);
|
|
const namesMap: Map<string, number> = new Map();
|
|
const names = [];
|
|
const mappings: Array<HookMapLine> = [];
|
|
|
|
let currentLine: $FlowFixMe | null = null;
|
|
hookNamesMapping.forEach(({name, start}) => {
|
|
let nameIndex = namesMap.get(name);
|
|
if (nameIndex == null) {
|
|
names.push(name);
|
|
nameIndex = names.length - 1;
|
|
namesMap.set(name, nameIndex);
|
|
}
|
|
|
|
// TODO: We add a -1 at the end of the entry so we can later
|
|
// encode/decode the mappings by reusing the encode/decode functions
|
|
// from the `sourcemap-codec` library. This library expects segments
|
|
// of specific sizes (i.e. of size 4) in order to encode them correctly.
|
|
// In the future, when we implement our own encoding, we will not
|
|
// need this restriction and can remove the -1 at the end.
|
|
const entry = [start.line, start.column, nameIndex, -1];
|
|
|
|
if (currentLine !== start.line) {
|
|
currentLine = start.line;
|
|
mappings.push([entry]);
|
|
} else {
|
|
const current = mappings[mappings.length - 1];
|
|
current.push(entry);
|
|
}
|
|
});
|
|
|
|
return {names, mappings};
|
|
}
|
|
|
|
/**
|
|
* Returns encoded version of a Hook Map that is returned
|
|
* by generateHookMap.
|
|
*
|
|
* **NOTE:**
|
|
* TODO: To encode the `mappings` in the Hook Map, we
|
|
* reuse the encode function from the `sourcemap-codec`
|
|
* library, which means that we are restricted to only
|
|
* encoding segments of specific sizes.
|
|
* Inside generateHookMap we make sure to build segments
|
|
* of size 4.
|
|
* In the future, when we implement our own encoding, we will not
|
|
* need this restriction and can remove the -1 at the end.
|
|
*/
|
|
export function generateEncodedHookMap(sourceAST: File): EncodedHookMap {
|
|
const hookMap = generateHookMap(sourceAST);
|
|
const encoded = encode(hookMap.mappings);
|
|
return {
|
|
names: hookMap.names,
|
|
mappings: encoded,
|
|
};
|
|
}
|
|
|
|
export function decodeHookMap(encodedHookMap: EncodedHookMap): HookMap {
|
|
return {
|
|
names: encodedHookMap.names,
|
|
mappings: decode(encodedHookMap.mappings),
|
|
};
|
|
}
|