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

Provide plugin/preset typings from plugin-utils #14499

Merged
merged 22 commits into from Apr 29, 2022
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
cf26c37
type: refine assumptions interface
JLHwung Apr 26, 2022
dd73f4c
fix: use UidIdentifier when partial callee is not identifier
JLHwung Apr 27, 2022
7a21c70
perf: scan object properties in one pass
JLHwung Apr 27, 2022
11c80b9
fix: support private name in member proeprty
JLHwung Apr 27, 2022
1a016a2
fix: add pipeline operator to BinaryOperators
JLHwung Apr 27, 2022
dc43dd0
typings: fix GeneratorOptions
JLHwung Apr 27, 2022
046daab
update babel parser typings
JLHwung Apr 27, 2022
8ef9dd2
fix: add predicate to @babel/types
JLHwung Apr 27, 2022
381fd18
typings: export Plugin/Preset related types
JLHwung Apr 27, 2022
99d3abd
feat: add declarePreset method and refine declare types
JLHwung Apr 27, 2022
beda280
use helper-plugin-utils in named-capturing-groups
JLHwung Apr 27, 2022
c20d40b
fix typing issues
JLHwung Apr 27, 2022
e82aa35
Update packages/babel-core/src/config/validation/plugins.ts
JLHwung Apr 27, 2022
d39e051
Update packages/babel-plugin-proposal-nullish-coalescing-operator/src…
JLHwung Apr 27, 2022
cc42fdf
Update packages/babel-helper-plugin-utils/src/index.ts
JLHwung Apr 27, 2022
cd4cdf2
simplify declare/declarePreset
JLHwung Apr 27, 2022
032ebf4
improve decorator 2021-12 transformer typings
JLHwung Apr 27, 2022
84153ee
Do not expose plugin state
JLHwung Apr 28, 2022
dd42d4f
bump typescript to 4.6.3
JLHwung Apr 28, 2022
e2106bf
fix AssumptionFunction return type
JLHwung Apr 28, 2022
b0fd195
misc
JLHwung Apr 28, 2022
6c2d2d9
noNewArrows defaults to true
JLHwung Apr 28, 2022
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
4 changes: 2 additions & 2 deletions packages/babel-core/src/config/helpers/config-api.ts
Expand Up @@ -9,7 +9,7 @@ import type {
SimpleType,
} from "../caching";

import type { CallerMetadata } from "../validation/options";
import type { AssumptionName, CallerMetadata } from "../validation/options";

import * as Context from "../cache-contexts";

Expand All @@ -24,7 +24,7 @@ type CallerFactory = (
extractor: (callerMetadata: CallerMetadata | void) => unknown,
) => SimpleType;
type TargetsFunction = () => Targets;
type AssumptionFunction = (name: string) => boolean | void;
type AssumptionFunction = (name: AssumptionName) => boolean;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Technically a plugin could be used with an old @babel/core version that doesn't know about a new assumption and thus returns undefined.

We could annotate this as (name: AssumptionName) => boolean | void: it's fine (and more helpful) if the parameter is more restrictive, but the return type should cover all the possibilities to avoid possible bugs caused by assuming that it's always a boolean.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we stick to the principle that an assumption always introduce certain non-spec constraints, I would not oppose to make it always return false for unknown assumptions. Otherwise plugins has to cast .assumption(name) to boolean by themselves.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, there is at least noNewArrow that does api.assumption("noNewArrow") ?? true, so "just return false" doesn't work.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we want to default it to false in Babel 8? 🙂


export type ConfigAPI = {
version: string;
Expand Down
11 changes: 11 additions & 0 deletions packages/babel-core/src/config/index.ts
Expand Up @@ -9,6 +9,17 @@ export type {

import type { PluginTarget } from "./validation/options";

import type {
PluginAPI as basePluginAPI,
PresetAPI as basePresetAPI,
} from "./helpers/config-api";
export type { PluginObject } from "./validation/plugins";
type PluginAPI = basePluginAPI & typeof import("..");
type PresetAPI = basePresetAPI & typeof import("..");
export type { PluginAPI, PresetAPI };
// todo: may need to refine PresetObject to be a subset of ValidatedOptions
export type { ValidatedOptions as PresetObject } from "./validation/options";

import loadFullConfig from "./full";
import { loadPartialConfig as loadPartialConfigRunner } from "./partial";

Expand Down
Expand Up @@ -20,6 +20,7 @@ import type {
CallerMetadata,
RootMode,
TargetsListOrObject,
AssumptionName,
} from "./options";

import { assumptionsNames } from "./options";
Expand Down Expand Up @@ -462,7 +463,7 @@ export function assertAssumptions(

for (const name of Object.keys(value)) {
const subLoc = access(loc, name);
if (!assumptionsNames.has(name)) {
if (!assumptionsNames.has(name as AssumptionName)) {
throw new Error(`${msg(subLoc)} is not a supported assumption.`);
}
if (typeof value[name] !== "boolean") {
Expand Down
12 changes: 8 additions & 4 deletions packages/babel-core/src/config/validation/options.ts
Expand Up @@ -28,6 +28,8 @@ import {
} from "./option-assertions";
import type { ValidatorSet, Validator, OptionPath } from "./option-assertions";
import type { UnloadedDescriptor } from "../config-descriptors";
import type { ParserOptions } from "@babel/parser";
import type { GeneratorOptions } from "@babel/generator";

const ROOT_VALIDATORS: ValidatorSet = {
cwd: assertString as Validator<ValidatedOptions["cwd"]>,
Expand Down Expand Up @@ -181,9 +183,9 @@ export type ValidatedOptions = {
sourceFileName?: string;
sourceRoot?: string;
// Deprecate top level parserOpts
parserOpts?: {};
parserOpts?: ParserOptions;
// Deprecate top level generatorOpts
generatorOpts?: {};
generatorOpts?: GeneratorOptions;
};

export type NormalizedOptions = {
Expand Down Expand Up @@ -254,7 +256,7 @@ type EnvPath = Readonly<{

export type NestingPath = RootPath | OverridesPath | EnvPath;

export const assumptionsNames = new Set<string>([
const knownAssumptions = [
"arrayLikeIsIterable",
"constantReexports",
"constantSuper",
Expand All @@ -276,7 +278,9 @@ export const assumptionsNames = new Set<string>([
"setSpreadProperties",
"skipForOfIteratorClosing",
"superIsCallableConstructor",
]);
] as const;
export type AssumptionName = typeof knownAssumptions[number];
export const assumptionsNames = new Set(knownAssumptions);

function getSource(loc: NestingPath): OptionsSource {
return loc.type === "root" ? loc.source : getSource(loc.parent);
Expand Down
21 changes: 12 additions & 9 deletions packages/babel-core/src/config/validation/plugins.ts
Expand Up @@ -11,6 +11,10 @@ import type {
OptionPath,
RootPath,
} from "./option-assertions";
import type { ParserOptions } from "@babel/parser";
import type { Visitor } from "@babel/traverse";
import PluginPass from "../../transformation/plugin-pass";
JLHwung marked this conversation as resolved.
Show resolved Hide resolved
import type { ValidatedOptions } from "./options";

// Note: The casts here are just meant to be static assertions to make sure
// that the assertion functions actually assert that the value's type matches
Expand All @@ -31,7 +35,7 @@ const VALIDATORS: ValidatorSet = {
>,
};

function assertVisitorMap(loc: OptionPath, value: unknown): VisitorMap {
function assertVisitorMap(loc: OptionPath, value: unknown): Visitor {
const obj = assertObject(loc, value);
if (obj) {
Object.keys(obj).forEach(prop => assertVisitorHandler(prop, obj[prop]));
Expand All @@ -45,7 +49,7 @@ function assertVisitorMap(loc: OptionPath, value: unknown): VisitorMap {
);
}
}
return obj as VisitorMap;
return obj as Visitor;
}

function assertVisitorHandler(
Expand Down Expand Up @@ -74,17 +78,16 @@ type VisitorHandler =
exit?: Function;
};

export type VisitorMap = {
[x: string]: VisitorHandler;
};

export type PluginObject = {
export type PluginObject<S = PluginPass> = {
name?: string;
manipulateOptions?: (options: unknown, parserOpts: unknown) => void;
manipulateOptions?: (
options: ValidatedOptions,
parserOpts: ParserOptions,
) => void;
pre?: Function;
post?: Function;
inherits?: Function;
visitor?: VisitorMap;
visitor?: Visitor<S>;
parserOverride?: Function;
generatorOverride?: Function;
};
Expand Down
7 changes: 7 additions & 0 deletions packages/babel-core/src/index.ts
Expand Up @@ -29,6 +29,13 @@ export {
loadOptionsAsync,
} from "./config";

export type {
PluginAPI,
PluginObject,
PresetAPI,
PresetObject,
} from "./config";

export { transform, transformSync, transformAsync } from "./transform";
export {
transformFile,
Expand Down
1 change: 0 additions & 1 deletion packages/babel-generator/src/generators/methods.ts
Expand Up @@ -146,7 +146,6 @@ function hasTypesOrComments(
return !!(
node.typeParameters ||
node.returnType ||
// @ts-expect-error
node.predicate ||
param.typeAnnotation ||
param.optional ||
Expand Down
19 changes: 6 additions & 13 deletions packages/babel-generator/src/index.ts
@@ -1,7 +1,7 @@
import SourceMap from "./source-map";
import Printer from "./printer";
import type * as t from "@babel/types";

import type { Opts as jsescOptions } from "jsesc";
import type { Format } from "./printer";

/**
Expand Down Expand Up @@ -186,19 +186,12 @@ export interface GeneratorOptions {
/**
* Options for outputting jsesc representation.
*/
jsescOption?: {
/**
* The type of quote to use in the output. If omitted, autodetects based on `ast.tokens`.
*/
quotes?: "single" | "double";

/**
* When enabled, the output is a valid JavaScript string literal wrapped in quotes. The type of quotes can be specified through the quotes setting.
* Defaults to `true`.
*/
wrap?: boolean;
};
jsescOption?: jsescOptions;

/**
* For use with the recordAndTuple token.
*/
recordAndTupleSyntaxType?: "hash" | "bar";
/**
* For use with the Hack-style pipe operator.
* Changes what token is used for pipe bodies’ topic references.
Expand Down
13 changes: 5 additions & 8 deletions packages/babel-helper-create-class-features-plugin/src/index.ts
@@ -1,5 +1,5 @@
import { types as t } from "@babel/core";
import type { File } from "@babel/core";
import type { File, PluginAPI, PluginObject } from "@babel/core";
import type { NodePath } from "@babel/traverse";
import nameFunction from "@babel/helper-function-name";
import splitExportDeclaration from "@babel/helper-split-export-declaration";
Expand All @@ -14,7 +14,6 @@ import { buildDecoratedClass, hasDecorators } from "./decorators";
import { injectInitialization, extractComputedKeys } from "./misc";
import { enableFeature, FEATURES, isLoose, shouldTransform } from "./features";
import { assertFieldTransformed } from "./typescript";
import type { ParserOptions } from "@babel/parser";

export { FEATURES, enableFeature, injectInitialization };

Expand All @@ -33,19 +32,17 @@ interface Options {
name: string;
feature: number;
loose?: boolean;
inherits?: (api: any, options: any) => any;
// same as PluginObject.manipulateOptions
manipulateOptions?: (options: unknown, parserOpts: ParserOptions) => void;
// TODO(flow->ts): change to babel api
api?: { assumption: (key?: string) => boolean | undefined };
inherits?: PluginObject["inherits"];
manipulateOptions?: PluginObject["manipulateOptions"];
api?: PluginAPI;
}

export function createClassFeaturePlugin({
name,
feature,
loose,
manipulateOptions,
// TODO(Babel 8): Remove the default value
// @ts-ignore TODO(Babel 8): Remove the default value
api = { assumption: () => void 0 },
inherits,
}: Options) {
Expand Down
Expand Up @@ -3,6 +3,7 @@ import { featuresKey, FEATURES, enableFeature, runtimeKey } from "./features";
import { generateRegexpuOptions, canSkipRegexpu, transformFlags } from "./util";

import { types as t } from "@babel/core";
import type { PluginObject } from "@babel/core";
import annotateAsPure from "@babel/helper-annotate-as-pure";

declare const PACKAGE_JSON: { name: string; version: string };
Expand All @@ -20,8 +21,8 @@ export function createRegExpFeaturePlugin({
name,
feature,
options = {} as any,
manipulateOptions = (() => {}) as (opts: any, parserOpts: any) => void,
}) {
manipulateOptions = (() => {}) as PluginObject["manipulateOptions"],
}): PluginObject {
return {
name,

Expand Down
Expand Up @@ -4,7 +4,7 @@ type RootOptions = {
sourceRoot?: string;
};

type PluginOptions = {
export type PluginOptions = {
moduleId?: string;
moduleIds?: boolean;
getModuleId?: (moduleName: string) => string | null | undefined;
Expand Down
1 change: 1 addition & 0 deletions packages/babel-helper-module-transforms/src/index.ts
Expand Up @@ -34,6 +34,7 @@ import type {
import type { NodePath } from "@babel/traverse";

export { default as getModuleName } from "./get-module-name";
export type { PluginOptions } from "./get-module-name";

export { hasExports, isSideEffectImport, isModule, rewriteThis };

Expand Down
42 changes: 26 additions & 16 deletions packages/babel-helper-plugin-utils/src/index.ts
@@ -1,20 +1,24 @@
export function declare<
Args extends
| [any]
| [any, any?]
| [any, any?, any?]
| [any, any]
| [any, any, any?]
| [any, any, any],
Builder extends (...args: Args) => any,
>(
builder: Builder,
// todo(flow->ts) maybe add stricter type for returned function
// reason any is there to not expose exact implementation details in type
// example of issue with this packages/babel-preset-typescript/src/index.ts
): Builder extends (...args: infer A) => any ? (...args: A) => any : never {
import type {
PluginAPI,
PluginObject,
PluginPass,
PresetAPI,
PresetObject,
} from "@babel/core";

export function declare<S = {}, Option = {}, API = PluginAPI>(
builder: (
api: API,
options: Option,
dirname: string,
) => PluginObject<S & PluginPass>,
): (
api: API,
options: Option,
dirname: string,
) => PluginObject<S & PluginPass> {
// @ts-ignore
return (api, options, dirname) => {
return (api, options: Option, dirname: string) => {
let clonedApi;

for (const name of Object.keys(apiPolyfills)) {
Expand All @@ -30,6 +34,12 @@ export function declare<
};
}

export function declarePreset<Option = {}, API = PresetAPI>(
builder: (api: API, options: Option, dirname: string) => PresetObject,
): (api: API, options: Option, dirname: string) => PresetObject {
return declare(builder as any) as any;
}
JLHwung marked this conversation as resolved.
Show resolved Hide resolved

const apiPolyfills = {
// Not supported by Babel 7 and early versions of Babel 7 beta.
// It's important that this is polyfilled for older Babel versions
Expand Down
2 changes: 1 addition & 1 deletion packages/babel-parser/src/plugins/flow/index.js
Expand Up @@ -353,7 +353,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
return type;
}

flowParsePredicate(): N.FlowType {
flowParsePredicate(): N.FlowPredicate {
const node = this.startNode();
const moduloLoc = this.state.startLoc;
this.next(); // eat `%`
Expand Down
3 changes: 2 additions & 1 deletion packages/babel-parser/typings/babel-parser.d.ts
Expand Up @@ -182,7 +182,7 @@ export interface DecoratorsPluginOptions {

export interface PipelineOperatorPluginOptions {
proposal: "minimal" | "fsharp" | "hack" | "smart";
topicToken?: "%" | "#" | "@@" | "^^";
topicToken?: "%" | "#" | "@@" | "^^" | "^";
}

export interface RecordAndTuplePluginOptions {
Expand All @@ -191,6 +191,7 @@ export interface RecordAndTuplePluginOptions {

export interface FlowPluginOptions {
all?: boolean;
enums?: boolean;
}

export interface TypeScriptPluginOptions {
Expand Down
@@ -1,6 +1,4 @@
import { declare } from "@babel/helper-plugin-utils";
import type { PluginPass } from "@babel/core";
import type { Visitor } from "@babel/traverse";
import { shouldTransform } from "./util";

export default declare(api => {
Expand All @@ -20,6 +18,6 @@ export default declare(api => {
scope.rename(name, newParamName);
}
},
} as Visitor<PluginPass>,
},
};
});
@@ -1,6 +1,8 @@
import { declare } from "@babel/helper-plugin-utils";
import { transform } from "@babel/plugin-proposal-optional-chaining";
import { shouldTransform } from "./util";
import type { NodePath } from "@babel/traverse";
import type * as t from "@babel/types";

export default declare(api => {
api.assertVersion(7);
Expand All @@ -12,7 +14,9 @@ export default declare(api => {
name: "bugfix-v8-spread-parameters-in-optional-chaining",

visitor: {
"OptionalCallExpression|OptionalMemberExpression"(path) {
"OptionalCallExpression|OptionalMemberExpression"(
path: NodePath<t.OptionalCallExpression | t.OptionalMemberExpression>,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still have to manually annotate the input of the multiple-type selection visitors.

) {
if (shouldTransform(path)) {
transform(path, { noDocumentAll, pureGetters });
}
Expand Down