Skip to content

feat!: move @google-cloud/translate to ESM and Node 14 #4189

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

Closed
wants to merge 21 commits into from
Closed
Show file tree
Hide file tree
Changes from 20 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 @@ -16,8 +16,6 @@
// ** https://github.com/googleapis/gapic-generator-typescript **
// ** All changes to this file may be overwritten. **

'use strict';

module.exports = {
opts: {
readme: './README.md',
Expand Down
29 changes: 29 additions & 0 deletions packages/google-cloud-translate/.mocharc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
const config = {
"enable-source-maps": true,
"throw-deprecation": true,
"timeout": 10000,
"recursive": true
}
if (process.env.MOCHA_THROW_DEPRECATION === 'false') {
delete config['throw-deprecation'];
}
if (process.env.MOCHA_REPORTER) {
config.reporter = process.env.MOCHA_REPORTER;
}
if (process.env.MOCHA_REPORTER_OUTPUT) {
config['reporter-option'] = `output=${process.env.MOCHA_REPORTER_OUTPUT}`;
}
module.exports = config
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@

module.exports = {
...require('gts/.prettierrc.json')
}
}
1 change: 1 addition & 0 deletions packages/google-cloud-translate/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ npm install @google-cloud/translate
// const projectId = 'YOUR_PROJECT_ID';

// Imports the Google Cloud client library
// eslint-disable-next-line no-undef
const {Translate} = require('@google-cloud/translate').v2;

// Instantiates a client
Expand Down
5 changes: 4 additions & 1 deletion packages/google-cloud-translate/owlbot.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,8 @@
"""This script is used to synthesize generated parts of this library."""

import synthtool.languages.node_mono_repo as node
from synthtool import shell

node.owlbot_main(relative_dir="packages/google-cloud-translate",templates_excludes=['src/index.ts'])
node.owlbot_main(relative_dir="packages/google-cloud-translate",staging_excludes=['packages/google-cloud-translate/.prettierrc.js', 'packages/google-cloud-translate/.mocharc.js'],templates_excludes=['src/index.ts', 'packages/google-cloud-translate/.prettierrc.js', 'packages/google-cloud-translate/.mocharc.js'])

shell.run(('rm', '-rf', 'packages/google-cloud-translate/.prettierrc.js'), hide_output = False)
44 changes: 29 additions & 15 deletions packages/google-cloud-translate/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,33 @@
"version": "7.2.0",
"license": "Apache-2.0",
"author": "Google Inc.",
"type": "module",
"engines": {
"node": ">=12.0.0"
"node": ">=14.0.0"
},
"exports": {
".": {
"import": {
"types": "./build/esm/src/index.d.ts",
"default": "./build/esm/src/index.js"
},
"require": {
"types": "./build/cjs/src/index.d.ts",
"default": "./build/cjs/src/index.cjs"
}
}
},
"repository": {
"type": "git",
"directory": "packages/google-cloud-translate",
"url": "https://github.com/googleapis/google-cloud-node.git"
},
"main": "build/src/index.js",
"types": "build/src/index.d.ts",
"main": "./build/cjs/src/index.cjs",
"types": "./build/cjs/src/index.d.ts",
"files": [
"build/src",
"build/protos",
"!build/src/**/*.map",
"!build/src/**/*.map"
"build/esm",
"build/cjs",
"!build/esm/**/*.map"
],
"keywords": [
"google apis client",
Expand All @@ -37,9 +49,13 @@
"predocs": "npm run compile",
"lint": "gts check",
"samples-test": "npm run compile && cd samples/ && npm link ../ && npm i && npm test",
"system-test": "npm run compile && c8 mocha build/system-test",
"test": "c8 mocha build/test",
"compile": "tsc -p . && cp -r protos build/ && minifyProtoJson",
"system-test": "c8 mocha build/cjs/system-test",
"test:cjs": "c8 mocha build/cjs/test",
"test:esm": "c8 mocha --loader=esmock build/esm/test",
Comment on lines +53 to +54

Choose a reason for hiding this comment

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

More of a review of the idea implemented here and less on this specific implementation but conceptually I believe unit tests will benefit less from running on the multiple module system targets. In comparison end-to-end test tend to benefit more since they're testing that all parts together are working as expected.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree! Unfortunately our system tests won't test ESM, since they use a testing harness called pack-n-play that essentially creates a CJS package and installs our libraries as dependencies. However, in the PR body I describe what we can do to modify that harness to test in ESM as well.

Copy link
Contributor

Choose a reason for hiding this comment

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

What I think would be best would be to extend pack-n-play to test the ESM build of the package, at this point we could run unit tests against just ESM or CJS.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yep! That's what I suggest in #3 in the PR body!

"test": "npm run test:cjs && npm run test:esm",
"compile:esm": "tsc -p ./tsconfig.esm.json",
"compile:cjs": "tsc -p ./tsconfig.json",
"compile": "npm run compile:esm && npm run compile:cjs && cp -r protos build/esm && cp -r protos build/cjs && minifyProtoJson build/cjs && minifyProtoJson build/esm && node post-compile.js",
"compile-protos": "compileProtos src",
"fix": "gts fix",
"prepare": "npm run compile-protos && npm run compile",
Expand All @@ -54,20 +70,19 @@
"dependencies": {
"@google-cloud/common": "^4.0.0",
"@google-cloud/promisify": "^3.0.0",
"arrify": "^2.0.0",
"extend": "^3.0.2",
"google-gax": "^3.5.8",
"is-html": "^2.0.0"
"html-tags": "^3.3.1"
},
"devDependencies": {
"@types/extend": "^3.0.0",
"@types/mocha": "^9.0.0",
"@types/node": "^18.0.0",
"@types/proxyquire": "^1.3.28",
"@types/request": "^2.47.1",
"@types/sinon": "^10.0.0",
"c8": "^7.0.0",
"codecov": "^3.0.2",
"esmock": "^2.2.1",
"google-auth-library": "^8.0.0",
"gts": "^3.1.0",
"http2spy": "^2.0.0",
Expand All @@ -79,8 +94,7 @@
"pack-n-play": "^1.0.0-2",
"proxyquire": "^2.0.1",
Copy link
Contributor

Choose a reason for hiding this comment

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

Can this be removed as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think we need it to run tests for CJS (since it doesn't support esmock)

"sinon": "^15.0.0",
"typescript": "^4.6.4"
"typescript": "^4.9.5"
},
"homepage": "https://github.com/googleapis/google-cloud-node/tree/main/packages/google-cloud-translate"
}

69 changes: 69 additions & 0 deletions packages/google-cloud-translate/post-compile.js
Copy link
Contributor

Choose a reason for hiding this comment

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

If we decide that using a post compile step is the best path forward it would probably make sense to extract this to some kind of utility repo so that it is reusable.

Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// Copyright 2023 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// ** This file is automatically generated by gapic-generator-typescript. **
// ** https://github.com/googleapis/gapic-generator-typescript **
// ** All changes to this file may be overwritten. **

import * as fs from 'fs';
import * as path from 'path';
const fsp = fs.promises;

const regexMetaInput =
/let dirToUse = '';\ntry {\n {4}dirToUse = __dirname;\n\}\ncatch \(e\) \{\n {4}\/\/ eslint-disable-next-line @typescript-eslint\/ban-ts-comment\n {4}\/\/ @ts-ignore\n {4}dirToUse = import\.meta\.url;\n\}\nconst filename = \(0, url_1\.fileURLToPath\)\(dirToUse\);\nconst dirname = path_1\.default\.dirname\(filename\);/i;
Copy link
Contributor

Choose a reason for hiding this comment

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

This regex seems pretty fragile, I'm betting when we update to a new typescript version at some point it will stop working silently. I'll leave a comment further down in code review.

// eslint-disable-next-line no-useless-escape
const regexJsExtension = /\.js\"/g;
// eslint-disable-next-line no-useless-escape
const regexJsExtensionSingleQuote = /\.js\'/g;
const awaitEsmock = /await esmock/g;
const protosHackregex = /protos-hack/g;
const esmock = /esmock/g;
async function modifyCJSDir(dirNameReadAbsolute) {
const files = fs.readdirSync(dirNameReadAbsolute);
for (const file of files) {
const fileName = file.toString();

const readName = path.join(dirNameReadAbsolute, fileName);

if (fs.statSync(readName).isFile()) {
if (!readName.includes('protos')) {
let fileContents = await fsp.readFile(readName, 'utf-8');
if (readName.endsWith('.js')) {
fileContents = fileContents.replace(
regexMetaInput,
'const dirname = __dirname'
);
fileContents = fileContents.replace(esmock, 'proxyquire');
fileContents = fileContents.replace(awaitEsmock, 'proxyquire');
if (fileName !== 'install.js') {
fileContents = fileContents.replace(regexJsExtension, '.cjs"');
fileContents = fileContents.replace(
regexJsExtensionSingleQuote,
".cjs'"
);
}
fileContents = fileContents.replace(protosHackregex, 'protos');
await fsp.writeFile(readName.replace(/.js$/, '.cjs'), fileContents);
await fsp.unlink(readName);
}
} else {
await fsp.rename(readName, readName.replace(/\.js$/, '.cjs'));
}
} else if (fs.statSync(readName).isDirectory()) {
modifyCJSDir(readName);
}
}
}

modifyCJSDir('./build/cjs');
Loading