Skip to content

Commit 4a0a105

Browse files
authored
feat: add downconversion from ?? to || (#3722)
* feat: add downconversion from ?? to || * chore: fix linter issues
1 parent 54a540d commit 4a0a105

File tree

6 files changed

+70
-16
lines changed

6 files changed

+70
-16
lines changed

packages/typeless-sample-bot/__snapshots__/index.js

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/typeless-sample-bot/src/samples.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import babel from '@babel/core';
2222
import path from 'node:path';
2323
import {typescript as presetTypescript} from './preset-loader.js';
2424
import importToRequire from './transforms/import-to-require.js';
25+
import nullCoalescing from './transforms/null-coalescing.js';
2526
import {addComments} from './transforms/add-comments.js';
2627

2728
// Converts an async iterable into an array of the same type.
@@ -84,7 +85,7 @@ export async function* filterByContents(
8485
// the transform process.
8586
const babelConfig = {
8687
presets: [[presetTypescript, {}]],
87-
plugins: [[importToRequire]],
88+
plugins: [[importToRequire], [nullCoalescing]],
8889
parserOpts: {} as babel.ParserOptions,
8990
generatorOpts: {
9091
// Ensures that Babel keeps newlines so that comments end up
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright 2022 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// Reference notes:
16+
// https://lihautan.com/step-by-step-guide-for-writing-a-babel-transformation/
17+
// https://lihautan.com/babel-ast-explorer/
18+
// https://github.com/esamattis/babel-plugin-ts-optchain/blob/master/packages/babel-plugin-ts-optchain/src/plugin.ts
19+
20+
import {NodePath, Visitor} from '@babel/traverse';
21+
import * as Babel from '@babel/types';
22+
23+
export interface VisitorPlugin {
24+
visitor: Visitor<unknown>;
25+
}
26+
27+
export type NodePathArray = NodePath<Babel.Node>[];
28+
export type NodePathSingle = NodePath<Babel.Node>;

packages/typeless-sample-bot/src/transforms/import-to-require.ts

+2-13
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,9 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
// Reference notes:
16-
// https://lihautan.com/step-by-step-guide-for-writing-a-babel-transformation/
17-
// https://lihautan.com/babel-ast-explorer/
18-
// https://github.com/esamattis/babel-plugin-ts-optchain/blob/master/packages/babel-plugin-ts-optchain/src/plugin.ts
19-
2015
import * as Babel from '@babel/types';
21-
import {NodePath, Visitor} from '@babel/traverse';
22-
23-
type NodePathArray = NodePath<Babel.Node>[];
24-
type NodePathSingle = NodePath<Babel.Node>;
16+
import {NodePath} from '@babel/traverse';
17+
import {NodePathArray, NodePathSingle, VisitorPlugin} from './babel';
2518

2619
function getArray(path: NodePathSingle, subPathName: string): NodePathArray {
2720
return path.get(subPathName) as NodePathArray;
@@ -102,10 +95,6 @@ function wildcardImport(path: NodePathSingle) {
10295
path.replaceWith(replacement);
10396
}
10497

105-
interface VisitorPlugin {
106-
visitor: Visitor<unknown>;
107-
}
108-
10998
export default function importToRequire(): VisitorPlugin {
11099
return {
111100
visitor: {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// Copyright 2022 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
import * as Babel from '@babel/types';
16+
import {NodePathSingle, VisitorPlugin} from './babel';
17+
18+
// Because null coalescing is still a proposal in many versions of Node,
19+
// go ahead and convert it to plain ||. It should work in TypeScript.
20+
export default function nullCoalescing(): VisitorPlugin {
21+
return {
22+
visitor: {
23+
LogicalExpression(path: NodePathSingle) {
24+
const node = path.node as Babel.LogicalExpression;
25+
if (node.operator === '??') {
26+
path.replaceWith(
27+
Babel.logicalExpression('||', node.left, node.right)
28+
);
29+
}
30+
},
31+
},
32+
};
33+
}

packages/typeless-sample-bot/test/fixtures/deleteSchema.ts

+3
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,9 @@ async function deleteSchema(schemaNameOrId: string) {
4545
}
4646
// [END pubsub_delete_schema]
4747

48+
const someValue: number | undefined = undefined;
49+
const coalesced = someValue ?? 5;
50+
4851
function main(schemaNameOrId = 'YOUR_SCHEMA_NAME_OR_ID') {
4952
deleteSchema(schemaNameOrId).catch(err => {
5053
console.error(err.message);

0 commit comments

Comments
 (0)