Skip to content

Commit

Permalink
Make some @Private properties into #private fields (#190)
Browse files Browse the repository at this point in the history
Moving some types around and making some into #private class fields improves the generated documentation.
  • Loading branch information
sirreal authored Sep 1, 2023
1 parent 6070963 commit 8e61edb
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 57 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

### Changed

- Some `@private` properties of `Client` have been changed to `#private` fields.

## [4.0.0] - 2023-08-28

The 4.0 release is a significant change that modernizes the library, adds NPF support, and removes a
Expand Down
89 changes: 38 additions & 51 deletions lib/tumblr.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@
* Tumblr
*/

/**
* @namespace tumblr
*/

const FormData = require('form-data');
const http = require('node:http');
const https = require('node:https');
Expand All @@ -18,7 +14,7 @@ const { ReadStream } = require('node:fs');

const API_BASE_URL = 'https://api.tumblr.com'; // deliberately no trailing slash

class TumblrClient {
class Client {
/**
* Package version
* @readonly
Expand All @@ -27,18 +23,20 @@ class TumblrClient {

/**
* @typedef {import('./types').TumblrClientCallback} TumblrClientCallback
* @typedef {import('./types').PostFormatFilter} PostFormatFilter
* @typedef {Map<string, ReadonlyArray<string>|string>} RequestData
*
*
* @typedef {'text'|'raw'} PostFormatFilter
*
*
* @typedef {{readonly auth:'none'}} NoneAuthCredentials
* @typedef {{readonly auth:'apiKey'; readonly apiKey:string}} ApiKeyCredentials
* @typedef {{readonly auth:'oauth1'; readonly consumer_key: string; readonly consumer_secret: string; readonly token: string; readonly token_secret: string }} OAuth1Credentials
* @typedef {NoneAuthCredentials|ApiKeyCredentials|OAuth1Credentials} Credentials
*/

/** @type {Credentials} */
#credentials = { auth: 'none' };

/** @type {oauth.OAuth | null} */
#oauthClient = null;

/**
* Creates a Tumblr API client using the given options
*
Expand All @@ -48,10 +46,10 @@ class TumblrClient {
/**
* Package version
*
* @type {typeof TumblrClient.version}
* @type {typeof Client.version}
* @readonly
*/
this.version = TumblrClient.version;
this.version = Client.version;

try {
const url = new URL(options?.baseUrl ?? API_BASE_URL);
Expand Down Expand Up @@ -105,9 +103,6 @@ class TumblrClient {
}
}

/** @type {Credentials} */
this.credentials = { auth: 'none' };

if (options) {
// If we have any of the optional credentials, we should have all of them.
if (
Expand Down Expand Up @@ -136,7 +131,7 @@ class TumblrClient {
);
}

this.credentials = {
this.#credentials = {
auth: 'oauth1',
consumer_key: options.consumer_key,
consumer_secret: options.consumer_secret,
Expand All @@ -150,18 +145,18 @@ class TumblrClient {
if (typeof options.consumer_key !== 'string') {
throw new TypeError('You must provide a consumer_key.');
}
this.credentials = { auth: 'apiKey', apiKey: options.consumer_key };
this.#credentials = { auth: 'apiKey', apiKey: options.consumer_key };
}
}

/** @type {oauth.OAuth | null} */
this.oauthClient =
this.credentials.auth === 'oauth1'
this.#oauthClient =
this.#credentials.auth === 'oauth1'
? new oauth.OAuth(
'',
'',
this.credentials.consumer_key,
this.credentials.consumer_secret,
this.#credentials.consumer_key,
this.#credentials.consumer_secret,
'1.0',
null,
'HMAC-SHA1',
Expand Down Expand Up @@ -235,19 +230,19 @@ class TumblrClient {

const httpModel = url.protocol === 'http' ? http : https;

if (this.credentials.auth === 'apiKey') {
url.searchParams.set('api_key', this.credentials.apiKey);
if (this.#credentials.auth === 'apiKey') {
url.searchParams.set('api_key', this.#credentials.apiKey);
}

const request = httpModel.request(url, { method });
request.setHeader('User-Agent', 'tumblr.js/' + TumblrClient.version);
request.setHeader('User-Agent', 'tumblr.js/' + Client.version);
request.setHeader('Accept', 'application/json');

if (this.oauthClient && this.credentials.auth === 'oauth1') {
const authHeader = this.oauthClient.authHeader(
if (this.#oauthClient && this.#credentials.auth === 'oauth1') {
const authHeader = this.#oauthClient.authHeader(
url.toString(),
this.credentials.token,
this.credentials.token_secret,
this.#credentials.token,
this.#credentials.token_secret,
method,
);
request.setHeader('Authorization', authHeader);
Expand Down Expand Up @@ -705,7 +700,7 @@ class TumblrClient {
return this.getRequest(`/v2/blog/${blogIdentifier}/followers`, paramsOrCallback, callback);
}

/** @type {import('./types').BlogPosts<TumblrClient>} */
/** @type {import('./types').BlogPosts<Client>} */
// @ts-expect-error The legacy signature makes this hard to type correctly.
blogPosts = function blogPosts(blogIdentifier, paramsOrCallback, callback) {
return this.getRequest(`/v2/blog/${blogIdentifier}/posts`, paramsOrCallback, callback);
Expand Down Expand Up @@ -842,28 +837,20 @@ class TumblrClient {
}
}

/*
* Please, enjoy our luxurious exports.
/**
* Creates a Tumblr Client
*
* @param {import('./types').Options} [options] - client options
*
* @return {Client} {@link Client} instance
*
* @see {@link Client}
*/
module.exports = {
/**
* Passthrough for the {@link TumblrClient} class
*
* @see {@link TumblrClient}
* @type {typeof TumblrClient}
*/
Client: TumblrClient,
function createClient(options) {
return new Client(options);
}

/**
* Creates a Tumblr Client
*
* @param {import('./types').Options} [options] - client options
*
* @return {TumblrClient} {@link TumblrClient} instance
*
* @see {@link TumblrClient}
*/
createClient: function (options) {
return new TumblrClient(options);
},
module.exports = {
Client,
createClient,
};
1 change: 1 addition & 0 deletions lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export type TumblrClientCallback = (
response?: IncomingMessage | null | undefined,
) => void;

export type PostFormatFilter = 'text' | 'raw';
export type PostState = 'published' | 'queue' | 'draft' | 'private' | 'unapproved';

/**
Expand Down
39 changes: 33 additions & 6 deletions test/tumblr.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,46 @@ describe('tumblr.js', function () {
assert.isTrue(client instanceof tumblr.Client);
});

it('handles no credentials', function () {
it('handles no credentials', async () => {
const client = factory();
assert.deepEqual(client.credentials, { auth: 'none' });
const scope = nock(client.baseUrl, {
badheaders: ['authorization'],
})
.get('/')
.query({}) // no search params
.reply(200, { meta: {}, response: {} });

await client.getRequest('/');
scope.done();
});

it('handles apiKey credentials', function () {
it('handles apiKey credentials', async () => {
const client = factory({ consumer_key: 'abc123' });
assert.deepEqual(client.credentials, { auth: 'apiKey', apiKey: 'abc123' });

const scope = nock(client.baseUrl, {
badheaders: ['authorization'],
})
.get('/')
.query({ api_key: 'abc123' })
.reply(200, { meta: {}, response: {} });

await client.getRequest('/');
scope.done();
});

it('passes credentials to the client', function () {
it('passes credentials to the client', async () => {
const client = factory(DUMMY_CREDENTIALS);
assert.deepEqual(client.credentials, { auth: 'oauth1', ...DUMMY_CREDENTIALS });
const scope = nock(client.baseUrl, {
reqheaders: {
Authorization: /^OAuth oauth_consumer_key=/,
},
})
.get('/')
.query({})
.reply(200, { meta: {}, response: {} });

await client.getRequest('/');
scope.done();
});

it('passes baseUrl to the client', function () {
Expand Down

0 comments on commit 8e61edb

Please sign in to comment.