New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

esdoc-uploader

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

esdoc-uploader - npm Package Compare versions

Comparing version 1.0.1 to 2.0.0

.esdoc.json

67

package.json
{
"name": "esdoc-uploader",
"description": "Upload your ESDoc documentation to doc.esdoc.org",
"version": "1.0.1",
"homepage": "https://homer0.github.io/esdoc-uploader",
"version": "2.0.0",
"repository": "homer0/esdoc-uploader",

@@ -15,45 +16,35 @@ "author": "Leonardo Apiwan (@homer0) <me@homer0.com>",

],
"dependencies": {
"request": "2.65.0",
"log-util": "1.1.1"
},
"dependencies": {},
"devDependencies": {
"babel-cli": "6.1.2",
"babel-preset-es2015": "6.1.2",
"eslint": "1.8.0",
"babel-eslint": "4.1.4",
"jscs": "2.5.0",
"coveralls": "2.11.4",
"jest-cli": "0.7.1",
"babel-jest": "5.3.0",
"esdoc": "0.4.3",
"esdoc-es7-plugin": "0.0.3"
"@babel/preset-env": "7.7.1",
"@babel/core": "7.7.0",
"@babel/plugin-transform-runtime": "7.6.2",
"coveralls": "^3.0.7",
"esdoc": "^1.1.0",
"esdoc-standard-plugin": "^1.0.0",
"esdoc-node": "1.0.4",
"eslint": "^6.6.0",
"eslint-plugin-homer0": "^2.0.1",
"husky": "^3.0.9",
"jasmine-expect": "^4.0.3",
"jest-ex": "^6.1.1",
"jest-cli": "^24.9.0",
"wootils": "^2.6.5"
},
"scripts": {
"build": "babel --presets es2015 -d dist/ src/",
"prepublish": "npm run build",
"test": "jest ./__tests__/index-test.js",
"coverage": "npm test; open ./coverage/lcov-report/index.html",
"lint": "eslint ./src/ ./__tests__/; jscs ./src/ ./__tests__/",
"docs": "esdoc -c esdoc.json; open docs/index.html",
"deploy-docs": "node ./dist/uploader.js"
"test": "./utils/scripts/test",
"lint": "./utils/scripts/lint",
"lint:all": "./utils/scripts/lint-all",
"docs": "./utils/scripts/docs"
},
"jest": {
"collectCoverage": true,
"collectCoverageOnlyFrom": {
"src/index.js": true
},
"scriptPreprocessor": "<rootDir>/node_modules/babel-jest",
"testFileExtensions": ["es6", "js", "jsx"],
"moduleFileExtensions": ["js", "json", "jsx", "es6"],
"unmockedModulePathPatterns": [
"<rootDir>/src",
"<rootDir>/__tests__/utils",
"<rootDir>/node_modules/"
]
},
"bin": {
"esdoc-uploader": "./dist/uploader.js"
"esdoc-uploader": "./src/uploader.js"
},
"main": "dist/index.js"
"main": "./src/index.js",
"husky": {
"hooks": {
"pre-commit": "./utils/hooks/pre-commit",
"post-merge": "./utils/hooks/post-merge"
}
}
}

@@ -5,8 +5,26 @@ # esdoc-uploader

[![Build Status](https://travis-ci.org/homer0/esdoc-uploader.svg?branch=master)](https://travis-ci.org/homer0/esdoc-uploader) [![Coverage Status](https://coveralls.io/repos/homer0/esdoc-uploader/badge.svg?branch=master&service=github)](https://coveralls.io/github/homer0/esdoc-uploader?branch=master) [![Documentation Status](https://doc.esdoc.org/github.com/homer0/esdoc-uploader/badge.svg)](https://doc.esdoc.org/github.com/homer0/esdoc-uploader/) [![Dependencies status](https://david-dm.org/homer0/esdoc-uploader.svg)](https://david-dm.org/homer0/esdoc-uploader) [![Dev dependencies status](https://david-dm.org/homer0/esdoc-uploader/dev-status.svg)](https://david-dm.org/homer0/esdoc-uploader#info=devDependencies)
[![Travis](https://img.shields.io/travis/homer0/esdoc-uploader.svg?style=flat-square)](https://travis-ci.org/homer0/esdoc-uploader)
[![Coveralls github](https://img.shields.io/coveralls/github/homer0/esdoc-uploader.svg?style=flat-square)](https://coveralls.io/github/homer0/esdoc-uploader?branch=master)
[![David](https://img.shields.io/david/homer0/esdoc-uploader.svg?style=flat-square)](https://david-dm.org/homer0/esdoc-uploader)
[![David](https://img.shields.io/david/dev/homer0/esdoc-uploader.svg?style=flat-square)](https://david-dm.org/homer0/esdoc-uploader)
I've been using [ESDoc](https://esdoc.org) for a while now, and something great about it it's that they provide a [hosting service](https://doc.esdoc.org/) for you documentation. You only need to have your project hosted on GitHub and provide them with its url, the service will take care of cloning your repo, finding your `esdoc.json` file, generating the docs and publishing them, which I think it's pretty awesome!
I've been using [ESDoc](https://esdoc.org) for a while now, and something great about it it's that they provide a [hosting service](https://doc.esdoc.org/) for your documentation. You only need to have your project hosted on GitHub and give them with its url, the service will take care of cloning your repo, finding your `esdoc.json` file, generating the docs and publishing them, which I think it's pretty awesome!
Now, the only complication it's that every time you deploy a new change, you have to go to the page and submit a form with your repo url; but if you are working with **continuous integration**, doing that manually kind of kills the whole idea :P. and that's the reason of this project.
Now, the only complication it's that every time you deploy a new change, you have to go to the page and submit a form with your repo url; but if you are working with **continuous integration**, doing that manually kind of kills the whole idea :P... and that's the reason of this project.
> **Disclaimer (2019):** This project is still maintained, but there's no activity because the ESDoc hosting API doesn't have any other functionality, so no features will be added.
>
> If you are wondering why this project doesn't "use itself", it's because I no longer see the need to transpile Node code, and I can't use `esdoc-node` on the ESDoc hosting,
> so I'm using git pages.
>
> If you read the code... I know:
>
> 1. It should use promises.
> 2. It should separate the functionality on different modules.
> 3. I can use `node-fetch` or `axios` for the requests.
> 4. I can use `colors` or `chalk` for the log messages.
> 5. and so many more things...
>
> This project was one of my first npm packages, its scope is very limited, and when I updated it, I didn't want to completely rewrite it, just improve little details (what I could) while removing the need for production dependencies.
## Information

@@ -18,10 +36,4 @@

| Description | Upload your ESDoc documentation to doc.esdoc.org |
| Node Version | >= v0.12.6 (You need >= v4.0.0 for the tests) |
| Node Version | >= v8.10 |
## Installation
You can install it using [npm](https://www.npmjs.com/).
npm install esdoc-uploader --save_dev
## Usage

@@ -31,3 +43,7 @@

$(npm bin)/esdoc-uploader
```bash
npx esdoc-uploader
# or
yarn esdoc-uploader
```

@@ -47,11 +63,11 @@ That's all, `esdoc-uploader` will automatically look up your `package.json`, get your repository information and start the process.

if (uploader.canUpload()) {
uploader.upload(function(success, url) {
// Checks whether the process ended in success
if (success) {
// Logs a confirmation
console.log('Documents uploaded to: ', url);
} else {
console.log('Something went wrong, check the errors above');
}
});
uploader.upload((success, url) => {
// Checks whether the process ended in success
if (success) {
// Logs a confirmation
console.log('Documents uploaded to: ', url);
} else {
console.log('Something went wrong, check the errors above');
}
});
}

@@ -62,22 +78,35 @@ ```

- The `constructor`, which receives an already formatted GitHub url. Or you can ignore the argument and it will work like on the command line, looking for the information in your `package.json`.
- The `constructor`, which receives an already formatted GitHub url. Or you can ignore the argument and it will work just like on the command line, looking for the information in your `package.json`.
- `canUpload()`: It checks if the upload process can be done or not.
- `upload()`: It starts uploading everything to the API. It receives a callback parameter, which will be called when the process finishes. The callback will receive two arguments: a `boolean` value to check if the process was successful, and in case it was, the url for where the documentation it's being hosted.
- `upload()`: It starts uploading everything to the API. It receives a callback parameter, which will be called when the process finishes. The callback will then receive two arguments: a `boolean` value to check if the process was successful, and in case it was, the url for where the documentation it's being hosted.
## Development
### Install Git hooks
### NPM/Yarn tasks
./hooks/install
| Task | Description |
|------------|-------------------------------------|
| `test` | Run the project unit tests. |
| `lint` | Lint the modified files. |
| `lint:all` | Lint the entire project code. |
| `docs` | Generate the project documentation. |
### npm tasks
### Repository hooks
- `npm run build`: Generate a new build of the module.
- `npm test`: Run the module's unit tests.
- `npm run coverage`: Run the unit tests and open the coverage report on the browser.
- `npm run lint`: Lint the plugin's code with JSCS and ESLint.
- `npm run docs`: Generate the project documentation.
I use [husky](https://yarnpkg.com/en/package/husky) to automatically install the repository hooks so the code will be tested and linted before any commit and the dependencies updated after every merge. The configuration is on the `husky` property of the `package.json` and the hooks' files are on `./utils/hooks`.
### Testing
I use [Jest](https://facebook.github.io/jest/) with [Jest-Ex](https://yarnpkg.com/en/package/jest-ex) to test the project. The configuration file is on `./.jestrc.json`, the tests are on `./tests` and the script that runs it is on `./utils/scripts/test`.
### Linting
I use [ESlint](http://eslint.org) with [my own custom configuration](http://yarnpkg.com/en/package/eslint-plugin-homer0) to validate all the JS code. The configuration file for the project code is on `./.eslintrc` and the one for the tests is on `./tests/.eslintrc`. There's also an `./.eslintignore` to exclude some files on the process. The script that runs it is on `./utils/scripts/lint`.
### Documentation
I use [ESDoc](http://esdoc.org) (:P) to generate HTML documentation for the project. The configuration file is on `./.esdoc.json` and the script that runs it is on `./utils/scripts/docs`.
## License
MIT. [License file](./LICENSE).
MIT. [License file](./LICENSE).

@@ -0,414 +1,522 @@

const https = require('https');
const fs = require('fs');
const path = require('path');
/**
* @typedef {Function} UploadCallback
* @param {Boolean} success Whether the documentation was uploaded or not.
* @param {?String} url The url for the documentation.
*/
import fs from 'fs';
import path from 'path';
import request from 'request';
import logger from 'log-util';
/**
* ESDocUploader, connects with the [ESDoc hosting service](https://doc.esdoc.org/) API in order
* to generage the documentation for your project.
* @version 1.0.0
* @typedef {Function} RequestCallback
* @param {?Error} error In case the request fails.
* @param {String} response The request response.
* @param {Number} status The response status code.
* @ignore
*/
export default class ESDocUploader {
/**
* ESDocUploader, connects with the [ESDoc hosting service](https://doc.esdoc.org/) API in order
* to generage the documentation for your project.
*/
class ESDocUploader {
/**
* @param {?String} [url=null] This is the GitHub repository url. The required format its
* `git[at]github.com:[author]/[repository].git`. You can also
* ignore it and it will automatically search for it on your
* `package.json`.
*/
constructor(url = null) {
/**
* Create a new instance of the uploader.
* @param {String} [url=null] - This is the GitHub repository url. The required format its
* `git@github.com:[author]/[repository].git`. You can also
* ignore it and it will automatically search for it on your
* `package.json`.
* @public
* A list of pre defined messages that the class will log.
* @type {Object}
* @protected
* @ignore
*/
constructor(url = null) {
/**
* A list of pre defined messages that the class will log.
* @type {Object}
* @private
* @ignore
*/
this._messages = {
constructor: 'The repository url is invalid. ' +
'There is likely additional logging output above',
invalidUrl: 'The repository url is invalid. You can\'t upload anything',
uploading: 'The documentation is already being uploaded',
unexpected: 'Unexpected error, please try again',
noPackage: 'There\'s no package.json in this directory',
noRepository: 'There\'s no repository information in the package.json',
invalidFormat: 'The repository from the package.json it\'s not valid. ' +
'Expected format "[author]/[repository]"',
onlyGitHub: 'ESDoc only supports GitHub repositories',
success: 'The documentation was successfully uploaded:',
};
if (url === null) {
url = this._retrieveUrlFromPackage();
} else {
url = this._validateUrl(url);
}
/**
* The repository url. It can be null if the one provided is not valid or if there isn't
* one on the `package.json`.
* @type {string|null}
* @private
* @ignore
*/
this.url = url;
/**
* A flag to know if the class it's currently uploading something.
* @type {Boolean}
* @private
* @ignore
*/
this._uploading = false;
/**
* A small dictionary used to store information relative to the ESDoc API, like it's
* main domain or the path to create a new doc.
* @type {Object}
* @private
* @ignore
*/
this._api = {
domain: 'https://doc.esdoc.org',
create: '/api/create',
};
/**
* The name of the file where the class it's going to check if the docs were uploaded.
* @type {String}
* @private
* @ignore
*/
this._finishFile = '/.finish.json';
/**
* The amount of time the class will wait between checks to see if the docs site was
* generated.
* @type {Number}
* @private
* @ignore
*/
this._intervalTime = 4000;
/**
* After the first request, this is where the returned path for the docs on the server
* will be stored.
* @type {String}
* @private
* @ignore
*/
this._path = '';
/**
* A callback that will be executed after confirmation that the docs were generated.
* @type {Function}
* @private
* @ignore
*/
this._callback = null;
/**
* The text that will show up on the terminal.
* @type {String}
* @private
* @ignore
*/
this._indicatorText = 'Uploading';
/**
* The amout of time in which the indicator will be updated.
* @type {Number}
* @private
* @ignore
*/
this._indicatorInterval = 1000;
/**
* A utility counter to know how many dos will be added to the indicator
* @type {Number}
* @private
* @ignore
*/
this._indicatorCounter = -1;
/**
* After this many iterations, the dots will start to be removed instead of added. When the
* counter hits 0, it will start adding again, until it hits this limit.
* @type {Number}
* @private
* @ignore
*/
this._indicatorLimit = 3;
/**
* A flag to know if the indicator it's currently adding dots or removing them.
* @type {Boolean}
* @private
* @ignore
*/
this._indicatorIncrease = true;
/**
* If there's no url, log the error message.
*/
if (this.url === null) {
this._logError('constructor');
}
}
this._messages = {
invalidUrl: 'The repository url is invalid',
invalidPackageUrl: 'The repository url is invalid. ' +
'There is likely additional logging output above',
uploading: 'The documentation is already being uploaded',
unexpected: 'Unexpected error, please try again',
noPackage: 'There\'s no package.json in this directory',
noRepository: 'There\'s no repository information in the package.json',
invalidFormat: 'The repository from the package.json it\'s not valid. ' +
'Expected format "[author]/[repository]"',
onlyGithub: 'ESDoc only supports Github repositories',
success: 'The documentation was successfully uploaded:',
};
/**
* After the class is istantiated, this method can be used to check if the url is valid and
* if the method `upload` can be called
* @public
* The repository url. It can be `null` if the one provided via the parameter is invalid or
* if a valid one can't be retrieved from the `package.json`.
* @type {?String}
* @protected
* @ignore
*/
canUpload() {
return this.url !== null;
}
this._url = url === null ? this._retrieveUrlFromPackage() : this._validateUrl(url);
/**
* Upload your documentation to the ESDoc API.
* @param {Function} [callback=() => {}] - An optional callback to be executed after
* everthing is ready.
* @public
* A flag to know if the class it's currently uploading the documentation or not.
* @type {Boolean}
* @protected
* @ignore
*/
upload(callback = () => {}) {
if (this.url === null) {
this._callback = callback;
this._logError('invalidUrl');
} else if (this._uploading) {
this._logError('uploading');
} else {
this._callback = callback;
this._uploading = true;
this._startIndicator();
request.post({
url: this._getAPIUrl('create'),
body: {gitUrl: this.url},
json: true,
}, ((err, httpResponse, body) => {
if (err) {
this._logError(err);
} else {
let response = body;
if (typeof response === 'string') {
response = JSON.parse(response);
}
if (!response.success) {
this._logError(response.message || 'unexpected');
} else {
this._setAPIUrl('path', response.path);
this._setAPIUrl('status', response.path + this._finishFile);
this._startAsking();
}
}
}).bind(this));
}
}
this._uploading = false;
/**
* Tries to retrieve the repository url from your `pacakge.json`.
* @return {String} The repository url that was on your `package.json`.
* @private
* A small dictionary used to store information relative to the ESDoc API, like it's
* main hostname and the path to create a new documentation.
* When a new documentation is created, this object will be updated with the path
* to check if the documentation is ready.
* @type {Object}
* @protected
* @ignore
*/
_retrieveUrlFromPackage() {
const packagePath = path.resolve('./package.json');
const packageContents = fs.readFileSync(packagePath, 'utf-8');
let result = null;
if (!packageContents) {
this._logError('noPackage');
} else {
const property = JSON.parse(packageContents).repository;
if (!property) {
this._logError('noRepository');
}else if (typeof property === 'string') {
const urlParts = property.split('/');
if (urlParts.length !== 2) {
this._logError('invalidFormat');
} else {
result = this._buildUrl(urlParts[0], urlParts[1]);
}
} else {
if (property.type !== 'git' || !property.url.match(/github/)) {
this._logError('onlyGitHub');
} else {
const urlParts = property.url.split('/');
const author = urlParts[urlParts.length - 2];
const repository = urlParts[urlParts.length - 1];
result = this._buildUrl(author, repository);
}
}
}
return result;
}
this._api = {
host: 'doc.esdoc.org',
create: '/api/create',
};
/**
* Generates a new url with the required format to use with the ESDoc API.
* @param {String} author - The GitHub username.
* @param {String} repository - The repository name.
* @return {String} The new url, on the required format for ESDoc.
* @private
* The name of the file where the class it's going to check if the docs were uploaded. The
* complete path is created with the information from the response the class gets when a
* new documentation is created.
* @type {String}
* @protected
* @ignore
*/
_buildUrl(author, repository) {
if (repository.indexOf('.git') > -1) {
repository = repository.substr(0, repository.length - 4);
}
return 'git@github.com:' + author + '/' + repository + '.git';
}
this._finishFile = '/.finish.json';
/**
* Validates a given url to see if it has the required format by the ESDoc API.
* @param {String} url - The url to validate.
* @return {String|null} If the url it's valid, it will return it, otherwise, itw will
* return null.
* @private
* The interval time the class will use in order to check if an uploaded documentation
* is available or not.
* @type {Number}
* @protected
* @ignore
*/
_validateUrl(url) {
let result = null;
if (url.match(/^git@github\.com:[\w\d._-]+\/[\w\d._-]+\.git$/)) {
result = url;
}
return result;
}
this._intervalTime = 4000;
/**
* This method is called after the initial request to the API, and tells the class to check
* every X seconds to see if the documentation was uploaded.
* @private
* A callback that will be executed after getting a confirmation that the documentation
* was successfully updated. It's value is set using the `upload` method.
* @type {?UploadCallback}
* @protected
* @ignore
*/
_startAsking() {
setTimeout(this._ask.bind(this), this._intervalTime);
}
this._callback = null;
/**
* It makes a request to check if the documentation was uploaded or not.
* @private
* The text that will show up on the console.
* @type {String}
* @protected
* @ignore
*/
_ask() {
request(this._getAPIUrl('status'), ((err, httpResponse, body) => {
if (err || body.indexOf('<html>') > -1) {
this._startAsking();
} else {
const response = JSON.parse(body);
if (!response.success) {
this._logError(response.message || 'unexpected');
} else {
this._finish();
}
}
}).bind(this));
}
this._indicatorText = 'Uploading';
/**
* This method is called after it's confirmed that the documentation was successfully uploaded,
* and it stops teh indicator, logs a mesage with the url for the documetation and invokes the
* callback set in the `upload()` method.
* @private
* The amout of time in which the indicator will be updated.
* @type {Number}
* @protected
* @ignore
*/
_finish() {
this._uploading = false;
this._stopIndicator();
const docUrl = this._getAPIUrl('path');
logger.debug(this._messages.success + ' ' + docUrl);
this._callback(true, docUrl);
}
this._indicatorInterval = 1000;
/**
* Returns a url for the ESDoc API.
* @param {String} type - The type of url you need. This is parameter it's the key for the
* `_api` dictionary.
* @return {String} It will return the API domain and the value in the `_api` dictionary for
* given type.
* @private
* A utility counter to know how many dots will be added to the indicator.
* @type {Number}
* @protected
* @ignore
*/
_getAPIUrl(type) {
return this._api.domain + this._api[type];
}
this._indicatorCounter = -1;
/**
* Set a new type of urlf or the ESDoc API. For example, the first request will return a
* relative path for the documentation, this class will use this method to save this path
* so it can be later be retrieved using `_getAPIUrl` and it wil already have the API main
* domain.
* @param {String} type - An identifier for your url.
* @param {String} url - The relative url you want to save.
* @private
* After this many iterations, the dots in the indicator will start to be removed instead
* of being added. When the counter hits 0, it will start adding again, until it
* hits this limit.
* @type {Number}
* @protected
* @ignore
*/
_setAPIUrl(type, url) {
this._api[type] = url;
}
this._indicatorLimit = 3;
/**
* Logs an eror message to the terminal.
* @param {String|Error} error - This can be the message you want to log, a key for the
* `_messages` dictionary or an `Error` object.
* @private
* A flag to know if the indicator it's currently adding dots or removing them.
* @type {Boolean}
* @protected
* @ignore
*/
_logError(error) {
if (typeof error === 'string') {
if (this._messages[error]) {
error = this._messages[error];
}
} else {
error = error.message;
}
logger.error(error);
this._stopIndicator(false);
if (this._callback) {
this._callback(false);
}
}
this._indicatorIncrease = true;
/**
* Starts showing the progress indicator on the terminal.
* @private
* @ignore
*/
_startIndicator() {
this._indicatorInterval = setInterval(this._runIndicator.bind(this), 500);
}
this._ask = this._ask.bind(this);
/**
* The actual method that shows the progress indicator on the terminal.
* @private
* @ignore
*/
_runIndicator() {
let text = this._indicatorText;
if (this._indicatorIncrease) {
this._indicatorCounter++;
if (this._indicatorCounter === this._indicatorLimit) {
this._indicatorIncrease = false;
this._runIndicator = this._runIndicator.bind(this);
}
/**
* Checks whether the repository is valid and the class can start uploading the documentation.
* @return {Boolean}
*/
canUpload() {
return !!this._url;
}
/**
* Upload your documentation to the ESDoc API.
* @param {UploadCallback} callback An optional callback to be executed after everthing
* is ready.
*/
upload(callback) {
if (this._url === null) {
this._callback = callback;
this._logError('invalidUrl');
} else if (this._uploading) {
this._logError('uploading');
} else {
this._callback = callback;
this._uploading = true;
this._startIndicator();
this._postRequest(
'create',
{ gitUrl: this._url },
(error, response) => {
if (error) {
this._logError(error);
} else {
const useResponse = JSON.parse(response);
if (useResponse.success) {
this._setAPIPath('path', useResponse.path);
this._setAPIPath(
'status',
`${useResponse.path}${this._finishFile}`
);
this._startAsking();
} else {
this._logError(useResponse.message || 'unexpected');
}
}
}
);
}
}
/**
* The repository url the class will send to the ESDoc API.
* @type {?String}
*/
get url() {
return this._url;
}
/**
* Tries to retrieve the repository url from the project's `pacakge.json`.
* @return {String}
* @protected
* @ignore
*/
_retrieveUrlFromPackage() {
const packagePath = path.resolve('./package.json');
let packageContents;
try {
packageContents = fs.readFileSync(packagePath, 'utf-8');
} catch (ignore) {
// This is ignored because we already have the error going out if there's no package.
}
let result = null;
if (packageContents) {
const authorAndRepoParts = 2;
const property = JSON.parse(packageContents).repository;
if (!property) {
this._logError('noRepository');
} else if (typeof property === 'string') {
const urlParts = property.split('/');
if (urlParts.length !== authorAndRepoParts) {
this._logError('invalidFormat');
} else {
this._indicatorCounter--;
if (this._indicatorCounter === 0) {
this._indicatorIncrease = true;
}
result = this._buildUrl(urlParts[0], urlParts[1]);
}
} else if (property.type !== 'git' || !property.url.match(/github/)) {
this._logError('onlyGithub');
} else {
const urlParts = property.url.split('/');
const author = urlParts[urlParts.length - authorAndRepoParts];
const repository = urlParts[urlParts.length - 1];
result = this._buildUrl(author, repository);
}
} else {
this._logError('noPackage');
}
for (let i = 0; i < this._indicatorCounter; i++) {
text += '.';
}
if (result === null) {
this._logError('invalidPackageUrl');
}
this._restartLine();
this._print(text);
return result;
}
/**
* Generates a new url with the required format to use with the ESDoc API.
* @param {String} author The GitHub username.
* @param {String} repository The repository name.
* @return {String}
* @protected
* @ignore
*/
_buildUrl(author, repository) {
const extension = '.git';
const useRepository = repository.includes(extension) ?
repository.substr(0, repository.length - extension.length) :
repository;
return `git@github.com:${author}/${useRepository}.git`;
}
/**
* Validates a given url to see if it has the required format by the ESDoc API.
* @param {String} url - The url to validate.
* @return {?String} If the url it's valid, it will return it, otherwise, it will
* return `null`.
* @protected
* @ignore
*/
_validateUrl(url) {
let result = null;
if (url.match(/^git@github\.com:[\w\d._-]+\/[\w\d._-]+\.git$/)) {
result = url;
} else {
this._logError('invalidUrl');
}
/**
* Removes the progress indicator from the terminal.
* @private
* @ignore
*/
_stopIndicator() {
clearInterval(this._indicatorInterval);
this._restartLine();
return result;
}
/**
* This method is called after the initial request to the API, and tells the class to check
* every X milliseconds to see if the documentation was uploaded.
* @protected
* @ignore
*/
_startAsking() {
setTimeout(this._ask, this._intervalTime);
}
/**
* It makes a request to check if the documentation was uploaded or not. If is not ready, it
* will call `_startAsking` to setup a new check; otherwise, it will invoke the callback sent
* to `upload`.
* @protected
* @ignore
*/
_ask() {
this._getRequest('status', (error, response) => {
if (error || response.includes('<html>')) {
this._startAsking();
} else {
const useResponse = JSON.parse(response);
if (useResponse.success) {
this._finish();
} else {
this._logError(useResponse.message || 'unexpected');
}
}
});
}
/**
* This method is called after it's confirmed that the documentation was successfully uploaded,
* it stops the indicator, logs a message with the url for the documetation and invokes the
* callback set in the `upload()` method.
* @protected
* @ignore
*/
_finish() {
this._uploading = false;
this._stopIndicator();
const url = this._getAPIUrl('path');
// eslint-disable-next-line no-console
console.log(
'\x1b[30m[%s] \x1b[32m%s\x1b[0m',
new Date(),
`${this._messages.success} ${url}`
);
this._callback(true, url);
}
/**
* Returns a complete url for the ESDoc API.
* @param {String} apiPath The reference name for the path the request is for,
* inside the `_api` dictionary.
* @protected
* @ignore
*/
_getAPIUrl(apiPath) {
const usePath = this._api[apiPath];
return `https://${this._api.host}${usePath}`;
}
/**
* Makes a POST request to the API.
* @param {String} apiPath The reference name for the path the request is for,
* inside the `_api` dictionary.
* @param {Object} body The body of the request.
* @param {RequestCallback} callback The callback to be invoked when the request is finished.
* @protected
* @ignore
*/
_postRequest(apiPath, body, callback) {
const data = JSON.stringify(body);
const options = {
hostname: this._api.host,
path: this._api[apiPath],
port: 443,
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length,
},
};
const req = this._createAPIRequest(options, callback);
req.write(data);
req.end();
}
/**
* Makes a GET request to the API.
* @param {String} apiPath The reference name for the path the request is for,
* inside the `_api` dictionary.
* @param {RequestCallback} callback The callback to be invoked when the request is finished.
* @protected
* @ignore
*/
_getRequest(apiPath, callback) {
const options = {
hostname: this._api.host,
path: this._api[apiPath],
port: 443,
method: 'GET',
};
const req = this._createAPIRequest(options, callback);
req.end();
}
/**
* A wrapper on top of `https.request` that allows the class to make requests, setup the
* listeners and resolve everything on a single callback.
* @param {Object} reqOptions The options for `https.request`.
* @param {RequestCallback} callback The callback to be invoked when the request is
* finished.
* @protected
* @ignore
*/
_createAPIRequest(reqOptions, callback) {
return https.request(reqOptions, (res) => {
const { statusCode } = res;
const chunks = [];
let errored = false;
res.on('data', (chunk) => {
chunks.push(chunk);
});
res.on('error', (error) => {
errored = true;
callback(error, null, statusCode);
});
res.on('end', () => {
if (!errored) {
const response = Buffer.concat(chunks).toString();
const badRequest = 400;
if (statusCode >= badRequest) {
callback(
new Error(`The API responded with a ${statusCode}`),
response,
statusCode
);
} else {
callback(null, response, statusCode);
}
}
});
});
}
/**
* Sets a new path reference to be used with the ESDoc API.
* After triggering the upload, this will be used to store the path the API uses so the class
* can check if the documentation is available.
* @param {String} name A reference identifier for the path.
* @param {String} apiPath The relative path you want to save.
* @protected
* @ignore
*/
_setAPIPath(name, apiPath) {
this._api[name] = apiPath;
}
/**
* Logs an eror message to the terminal and, if `upload` was ever call, it invokes the callback
* informing that the operation wasn't successful.
* @param {String|Error} error The message to log, a key for the `_messages` dictionary or
* an `Error` object.
* @protected
* @ignore
*/
_logError(error) {
let useError;
if (typeof error === 'string') {
useError = this._messages[error] || error;
} else {
useError = error.message;
}
/**
* Removes everything on the current terminal line and sets the cursor to the initial
* position.
* @private
* @ignore
*/
_restartLine() {
process.stdout.clearLine();
process.stdout.cursorTo(0);
// eslint-disable-next-line no-console
console.log('\x1b[30m[%s] \x1b[31m%s\x1b[0m', new Date(), useError);
this._stopIndicator(false);
if (this._callback) {
this._callback(false);
}
/**
* Writes a message in the terminal.
* @param {String} message - The text to write.
* @private
* @ignore
*/
_print(message) {
process.stdout.write(message);
}
/**
* Starts showing the progress indicator on the terminal.
* @protected
* @ignore
*/
_startIndicator() {
const indicatorIntervalTime = 500;
this._indicatorInterval = setInterval(
this._runIndicator,
indicatorIntervalTime
);
}
/**
* The actual method that shows the progress indicator on the terminal.
* @protected
* @ignore
*/
_runIndicator() {
let text = this._indicatorText;
if (this._indicatorIncrease) {
this._indicatorCounter++;
if (this._indicatorCounter === this._indicatorLimit) {
this._indicatorIncrease = false;
}
} else {
this._indicatorCounter--;
if (this._indicatorCounter === 0) {
this._indicatorIncrease = true;
}
}
for (let i = 0; i < this._indicatorCounter; i++) {
text += '.';
}
this._restartLine();
this._print(text);
}
/**
* Removes the progress indicator from the terminal.
* @protected
* @ignore
*/
_stopIndicator() {
clearInterval(this._indicatorInterval);
this._restartLine();
}
/**
* Removes everything on the current terminal line and sets the cursor to the initial
* position.
* @protected
* @ignore
*/
_restartLine() {
process.stdout.clearLine();
process.stdout.cursorTo(0);
}
/**
* Writes a message in the terminal.
* @param {String} message - The text to write.
* @protected
* @ignore
*/
_print(message) {
process.stdout.write(message);
}
}
module.exports = ESDocUploader;
#!/usr/bin/env node
'use strict';
// esdoc-uploader: CLI interface
// Import the module's main class
import ESDocUploader from './index';
const ESDocUploader = require('./index');
// Instantiate an object that will detect the url from your package.json

@@ -12,4 +10,4 @@ const uploader = new ESDocUploader();

if (uploader.canUpload()) {
// Start uploading the docs
uploader.upload();
// Start uploading the docs
uploader.upload();
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc