Skip to content

Commit 98e6185

Browse files
JPeer264szokeasaurusrex
authored andcommitted
feat: Move javascript files to native typescript (#2989)
(closes #2617) (closes [CLI-142](https://linear.app/getsentry/issue/CLI-142/use-typescript-to-generate-type-declarations)) This PR migrates all JavaScript files in the `lib/` directory to native TypeScript, removing the need for JSDoc type annotations and improving type safety. ### Main Changes - Converted all `.js` files to `.ts` with proper TypeScript syntax - Changed module system from CommonJS to ES6 modules for better TypeScript interoperability - Updated exports to use ES6 `export` syntax instead of `module.exports` - All types are now exported as named exports for better type inference and IDE support - `OptionsSchema` is now a union to satisfy `SOURCEMAPS_OPTIONS`, as this one didn't had the required `param` - The exports of `lib/releases/options` has changed its name ### Breaking Changes **Module Exports** - **Before**: `module.exports = SentryCli;` (CommonJS) - **After**: `export class SentryCli { ... }` (ES6 named export) We could have maintained backwards compatibility with `export = SentryCli;`. The only problem were the types which needed to be exported as well. With ES6 named exports, we can now export all types alongside the class. ### Internal Improvements Simplified `Release` constructor - **Before**: `new Releases({ ...this.options, configFile })` - configFile was merged into options - **After**: `new Releases(this.options, configFile)` - two separate parameters With 2 parameters it's easier to maintain and makes the separation of concerns clearer.
1 parent f23b920 commit 98e6185

File tree

16 files changed

+206
-195
lines changed

16 files changed

+206
-195
lines changed

CHANGELOG.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,25 @@ The following changes only apply when using `sentry-cli` via the npm package [`@
2929
- Removed the `apiKey` option from `SentryCliOptions` ([#2935](https://github.com/getsentry/sentry-cli/pull/2935)). If you are using `apiKey`, you need to generate and use an [Auth Token](https://docs.sentry.io/account/auth-tokens/) via the `authToken` option, instead.
3030
- Removed the `useArtifactBundle` option from `SentryCliUploadSourceMapsOptions` ([#3002](https://github.com/getsentry/sentry-cli/pull/3002)). This deprecated option was a no-op that users should simply stop passing.
3131
- Drop support for Node.js <18. The minimum required Node.js version is now 18.0.0 ([#2985](https://github.com/getsentry/sentry-cli/issues/2985)).
32+
- The type export `SentryCliReleases` has been removed.
33+
- The JavaScript wrapper now uses named exports instead of default exports ([#2989](https://github.com/getsentry/sentry-cli/pull/2989)). You need to update your imports:
34+
```js
35+
// Old (default import)
36+
const SentryCli = require('@sentry/cli');
37+
38+
// New (named import)
39+
const { SentryCli } = require('@sentry/cli');
40+
```
41+
42+
For ESM imports:
43+
```js
44+
// Old
45+
import SentryCli from '@sentry/cli';
46+
47+
// New
48+
import { SentryCli } from '@sentry/cli';
49+
```
50+
3251

3352
### Improvements
3453

bin/sentry-cli

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
'use strict';
44

55
const childProcess = require('child_process');
6-
const SentryCli = require('../js');
6+
const { SentryCli } = require('../js');
77

88
const child = childProcess
99
.spawn(SentryCli.getPath(), process.argv.slice(2), {

jest.config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
module.exports = {
22
setupFiles: ['<rootDir>/setupTests.js'],
33
testPathIgnorePatterns: ['<rootDir>/src/'],
4+
transform: {
5+
'^.+\\.ts$': 'ts-jest',
6+
},
47
};

lib/__tests__/helper.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ const os = require('os');
22

33
const helper = require('../helper');
44

5-
const SOURCEMAPS_OPTIONS = require('../releases/options/uploadSourcemaps');
5+
const { SOURCEMAPS_OPTIONS } = require('../releases/options/uploadSourcemaps');
66

77
describe('SentryCli helper', () => {
88
test('call sentry-cli --version', () => {

lib/helper.js renamed to lib/helper.ts

Lines changed: 54 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
'use strict';
22

3-
const os = require('os');
4-
const path = require('path');
5-
const fs = require('fs');
6-
const childProcess = require('child_process');
3+
import * as os from 'node:os';
4+
import * as path from 'node:path';
5+
import * as fs from 'node:fs';
6+
import * as childProcess from 'node:child_process';
7+
import { SentryCliOptions } from './types';
78

89
const BINARY_DISTRIBUTIONS = [
910
{ packageName: '@sentry/cli-darwin', subpath: 'bin/sentry-cli' },
@@ -23,9 +24,9 @@ const BINARY_DISTRIBUTIONS = [
2324
* Without this, the binary can be detected as an asset and included by bundlers
2425
* that use @vercel/nft.
2526
*
26-
* @returns {string} The path to the sentry-cli binary
27+
* @returns The path to the sentry-cli binary
2728
*/
28-
function getFallbackBinaryPath() {
29+
function getFallbackBinaryPath(): string {
2930
const parts = [];
3031
parts.push(__dirname);
3132
parts.push('..');
@@ -93,9 +94,9 @@ function getDistributionForThisPlatform() {
9394
/**
9495
* Throws an error with a message stating that Sentry CLI doesn't support the current platform.
9596
*
96-
* @returns {never} nothing. It throws.
97+
* @returns nothing. It throws.
9798
*/
98-
function throwUnsupportedPlatformError() {
99+
function throwUnsupportedPlatformError(): void {
99100
throw new Error(
100101
`Unsupported operating system or architecture! Sentry CLI does not work on this architecture.
101102
@@ -110,9 +111,9 @@ Sentry CLI supports:
110111
* Tries to find the installed Sentry CLI binary - either by looking into the relevant
111112
* optional dependencies or by trying to resolve the fallback binary.
112113
*
113-
* @returns {string} The path to the sentry-cli binary
114+
* @returns The path to the sentry-cli binary
114115
*/
115-
function getBinaryPath() {
116+
function getBinaryPath(): string {
116117
if (process.env.SENTRY_BINARY_PATH) {
117118
return process.env.SENTRY_BINARY_PATH;
118119
}
@@ -161,47 +162,41 @@ It seems like none of the "@sentry/cli" package's optional dependencies got inst
161162

162163
/**
163164
* Will be used as the binary path when defined with `mockBinaryPath`.
164-
* @type {string | undefined}
165165
*/
166-
let mockedBinaryPath;
166+
let mockedBinaryPath: string | undefined;
167167

168168
/**
169169
* Overrides the default binary path with a mock value, useful for testing.
170170
*
171-
* @param {string} mockPath The new path to the mock sentry-cli binary
171+
* @param mockPath The new path to the mock sentry-cli binary
172172
* @deprecated This was used in tests internally and will be removed in the next major version.
173173
*/
174174
// TODO(v3): Remove this function
175-
function mockBinaryPath(mockPath) {
175+
function mockBinaryPath(mockPath: string) {
176176
mockedBinaryPath = mockPath;
177177
}
178178

179-
/**
180-
* The javascript type of a command line option.
181-
* @typedef {'array'|'string'|'boolean'|'inverted-boolean'} OptionType
182-
*/
183-
184-
/**
185-
* Schema definition of a command line option.
186-
* @typedef {object} OptionSchema
187-
* @prop {string} param The flag of the command line option including dashes.
188-
* @prop {OptionType} type The value type of the command line option.
189-
* @prop {string} [invertedParam] The flag of the command line option including dashes (optional).
190-
*/
191-
192-
/**
193-
* Schema definition for a command.
194-
* @typedef {Object.<string, OptionSchema>} OptionsSchema
195-
*/
179+
export type OptionsSchema = Record<
180+
string,
181+
| {
182+
param: string;
183+
type: 'array' | 'string' | 'number' | 'boolean' | 'inverted-boolean';
184+
invertedParam?: string;
185+
}
186+
| {
187+
param?: never;
188+
type: 'array' | 'string' | 'number' | 'boolean' | 'inverted-boolean';
189+
invertedParam: string;
190+
}
191+
>;
196192

197193
/**
198194
* Serializes command line options into an arguments array.
199195
*
200-
* @param {OptionsSchema} schema An options schema required by the command.
201-
* @param {object} options An options object according to the schema.
202-
* @returns {string[]} An arguments array that can be passed via command line.
196+
* @param schema An options schema required by the command.
197+
* @param options An options object according to the schema.
203198
*/
204-
function serializeOptions(schema, options) {
199+
function serializeOptions(schema: OptionsSchema, options: Record<string, unknown>): string[] {
205200
return Object.keys(schema).reduce((newOptions, option) => {
206201
const paramValue = options[option];
207202
if (paramValue === undefined || paramValue === null) {
@@ -246,20 +241,23 @@ function serializeOptions(schema, options) {
246241
/**
247242
* Serializes the command and its options into an arguments array.
248243
*
249-
* @param {string[]} command The literal name of the command.
250-
* @param {OptionsSchema} [schema] An options schema required by the command.
251-
* @param {object} [options] An options object according to the schema.
252-
* @returns {string[]} An arguments array that can be passed via command line.
244+
* @param command The literal name of the command.
245+
* @param schema An options schema required by the command.
246+
* @param options An options object according to the schema.
247+
* @returns An arguments array that can be passed via command line.
253248
*/
254-
function prepareCommand(command, schema, options) {
249+
function prepareCommand(
250+
command: string[],
251+
schema: OptionsSchema,
252+
options: Record<string, unknown>
253+
): string[] {
255254
return command.concat(serializeOptions(schema || {}, options || {}));
256255
}
257256

258257
/**
259258
* Returns the absolute path to the `sentry-cli` binary.
260-
* @returns {string}
261259
*/
262-
function getPath() {
260+
function getPath(): string {
263261
return mockedBinaryPath !== undefined ? mockedBinaryPath : getBinaryPath();
264262
}
265263

@@ -280,17 +278,23 @@ function getPath() {
280278
* const output = await execute(['--version']);
281279
* expect(output.trim()).toBe('sentry-cli x.y.z');
282280
*
283-
* @param {string[]} args Command line arguments passed to `sentry-cli`.
284-
* @param {boolean} live can be set to:
281+
* @param args Command line arguments passed to `sentry-cli`.
282+
* @param live can be set to:
285283
* - `true` to inherit stdio and reject the promise if the command
286284
* exits with a non-zero exit code.
287285
* - `false` to not inherit stdio and return the output as a string.
288-
* @param {boolean} silent Disable stdout for silents build (CI/Webpack Stats, ...)
289-
* @param {string} [configFile] Relative or absolute path to the configuration file.
290-
* @param {import('./index').SentryCliOptions} [config] More configuration to pass to the CLI
291-
* @returns {Promise<string>} A promise that resolves to the standard output.
286+
* @param silent Disable stdout for silents build (CI/Webpack Stats, ...)
287+
* @param configFile Relative or absolute path to the configuration file.
288+
* @param config More configuration to pass to the CLI
289+
* @returns A promise that resolves to the standard output.
292290
*/
293-
async function execute(args, live, silent, configFile, config = {}) {
291+
async function execute(
292+
args: string[],
293+
live: boolean,
294+
silent: boolean,
295+
configFile: string | undefined,
296+
config: SentryCliOptions = {}
297+
): Promise<string> {
294298
const env = { ...process.env };
295299
if (configFile) {
296300
env.SENTRY_PROPERTIES = configFile;
@@ -353,7 +357,7 @@ function getProjectFlagsFromOptions({ projects = [] } = {}) {
353357
return projects.reduce((flags, project) => flags.concat('-p', project), []);
354358
}
355359

356-
module.exports = {
360+
export {
357361
execute,
358362
getPath,
359363
getProjectFlagsFromOptions,
Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,17 @@
11
'use strict';
22

3-
const pkgInfo = require('../package.json');
4-
const helper = require('./helper');
5-
const Releases = require('./releases');
3+
import * as pkgInfo from '../package.json';
4+
import * as helper from './helper';
5+
import { Releases } from './releases';
6+
import type { SentryCliOptions } from './types';
67

7-
/**
8-
* @typedef {import('./types').SentryCliOptions} SentryCliOptions
9-
* @typedef {import('./types').SentryCliUploadSourceMapsOptions} SentryCliUploadSourceMapsOptions
10-
* @typedef {import('./types').SourceMapsPathDescriptor} SourceMapsPathDescriptor
11-
* @typedef {import('./types').SentryCliNewDeployOptions} SentryCliNewDeployOptions
12-
* @typedef {import('./types').SentryCliCommitsOptions} SentryCliCommitsOptions
13-
* @typedef {import('./types').SentryCliReleases} SentryCliReleases
14-
*/
8+
export type {
9+
SentryCliOptions,
10+
SentryCliUploadSourceMapsOptions,
11+
SourceMapsPathDescriptor,
12+
SentryCliNewDeployOptions,
13+
SentryCliCommitsOptions,
14+
} from './types';
1515

1616
/**
1717
* Interface to and wrapper around the `sentry-cli` executable.
@@ -28,55 +28,53 @@ const Releases = require('./releases');
2828
* const release = await cli.releases.proposeVersion());
2929
* console.log(release);
3030
*/
31-
class SentryCli {
31+
export class SentryCli {
32+
public releases: Releases;
33+
3234
/**
3335
* Creates a new `SentryCli` instance.
3436
*
3537
* If the `configFile` parameter is specified, configuration located in the default
3638
* location and the value specified in the `SENTRY_PROPERTIES` environment variable is
3739
* overridden.
3840
*
39-
* @param {string | null} [configFile] - Path to Sentry CLI config properties, as described in https://docs.sentry.io/learn/cli/configuration/#properties-files.
41+
* @param configFile Path to Sentry CLI config properties, as described in https://docs.sentry.io/learn/cli/configuration/#properties-files.
4042
* By default, the config file is looked for upwards from the current path and defaults from ~/.sentryclirc are always loaded.
4143
* This value will update `SENTRY_PROPERTIES` env variable.
42-
* @param {SentryCliOptions} [options] - More options to pass to the CLI
44+
* @param options More options to pass to the CLI
4345
*/
44-
constructor(configFile, options) {
46+
constructor(public configFile: string | null, public options: SentryCliOptions) {
4547
if (typeof configFile === 'string') {
4648
this.configFile = configFile;
4749
}
4850
this.options = options || { silent: false };
49-
this.releases = new Releases({ ...this.options, configFile });
51+
this.releases = new Releases(this.options, configFile);
5052
}
5153

5254
/**
5355
* Returns the version of the installed `sentry-cli` binary.
54-
* @returns {string}
5556
*/
56-
static getVersion() {
57+
static getVersion(): string {
5758
return pkgInfo.version;
5859
}
5960

6061
/**
6162
* Returns an absolute path to the `sentry-cli` binary.
62-
* @returns {string}
6363
*/
64-
static getPath() {
64+
static getPath(): string {
6565
return helper.getPath();
6666
}
6767

6868
/**
6969
* See {helper.execute} docs.
70-
* @param {string[]} args Command line arguments passed to `sentry-cli`.
71-
* @param {boolean} live can be set to:
70+
* @param args Command line arguments passed to `sentry-cli`.
71+
* @param live can be set to:
7272
* - `true` to inherit stdio and reject the promise if the command
7373
* exits with a non-zero exit code.
7474
* - `false` to not inherit stdio and return the output as a string.
75-
* @returns {Promise<string>} A promise that resolves to the standard output.
75+
* @returns A promise that resolves to the standard output.
7676
*/
77-
execute(args, live) {
77+
execute(args: string[], live: boolean): Promise<string> {
7878
return helper.execute(args, live, this.options.silent, this.configFile, this.options);
7979
}
8080
}
81-
82-
module.exports = SentryCli;

lib/logger.js renamed to lib/logger.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
'use strict';
22

3-
const format = require('util').format;
3+
import { format } from 'node:util';
44

5-
module.exports = class Logger {
6-
constructor(stream) {
7-
this.stream = stream;
8-
}
5+
export class Logger {
6+
constructor(public stream: NodeJS.WriteStream) {}
97

108
log() {
119
const message = format(...arguments);

lib/releases/__tests__/index.test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const SentryCli = require('../..');
1+
const { SentryCli } = require('../..');
22

33
describe('SentryCli releases', () => {
44
afterEach(() => {
@@ -23,7 +23,7 @@ describe('SentryCli releases', () => {
2323
beforeEach(() => {
2424
mockExecute.mockClear();
2525
// eslint-disable-next-line global-require
26-
const SentryCliLocal = require('../..');
26+
const { SentryCli: SentryCliLocal } = require('../..');
2727
cli = new SentryCliLocal();
2828
});
2929
describe('new', () => {

0 commit comments

Comments
 (0)