Adjust tests

This commit is contained in:
Luis Blanco 2023-01-04 12:54:39 +04:00
parent b05666869a
commit ac0c472be9
20 changed files with 297 additions and 409 deletions

View File

@ -9,10 +9,6 @@ This is a part of [Node3D](https://github.com/node-3d) project.
npm i addon-tools-raub npm i addon-tools-raub
``` ```
This module contains helpers for Node.js **NAPI** addons and dependency packages.
On this page, helper scripts are described. For details on **addon-tools.hpp** and some
additional snippets follow the links below.
## include/addon-tools.hpp ## include/addon-tools.hpp
@ -36,42 +32,42 @@ DBG_EXPORT JS_METHOD(doSomething) { NAPI_ENV;
## index.js ## index.js
Main exports for cross-platform addon configuration. JavaScript helpers for Node.js addon development. The short list of helpers:
```
'getBin', 'getPlatform', 'getInclude', 'getPaths',
'install', 'cpbin', 'download', 'read', 'write', 'copy', 'exists',
'mkdir', 'stat', 'isDir', 'isFile', 'dirUp', 'ensuredir', 'copysafe',
'readdir', 'subdirs', 'subfiles', 'traverse', 'copyall',
'rmdir', 'rm', 'WritableBuffer', 'actionVersion', 'actionZip',
```
See the [TypeScript definitions](/index.d.ts) with comments. See the [TypeScript definitions](/index.d.ts) with comments.
> NOTE: the peer dependency `node-addon-api` is used by this helper.
Example for an ADDON's **index.js**: ### Example for an ADDON's **index.js**:
``` ```
const { bin } = require('addon-tools-raub'); const { getBin } = require('addon-tools-raub');
const core = require(`./${bin}/ADDON`); // uses the platform-specific ADDON.node const core = require(`./${getBin()}/ADDON`); // uses the platform-specific ADDON.node
``` ```
Example for **binding.gyp**:
### Example for **binding.gyp**:
``` ```
'include_dirs': [ 'include_dirs': [
'<!@(node -p "require(\'addon-tools-raub\').include")', '<!@(node -p "require(\'addon-tools-raub\').getInclude()")',
], ],
``` ```
> NOTE: the optional `node-addon-api` dependency is used by the `getInclude()` helper. If not found,
the **napi.h** include path won't be a part of the returned string.
## utils.js
JS utils for Node.js modules and addons. ### Example of `cpbin` usage in **package.json :: scripts**:
``` ```
const utils = require('addon-tools-raub/utils'); "build-all": "cd src && node-gyp rebuild -j max --silent && node -e \"require('addon-tools-raub').cpbin('segfault')\" && cd ..",
"build-only": "cd src && node-gyp build -j max --silent && node -e \"require('addon-tools-raub').cpbin('segfault')\" && cd ..",
``` ```
Example of `cpbin` usage in **package.json :: scripts**:
```
"build-all": "cd src && node-gyp rebuild -j max --silent && node -e \"require('addon-tools-raub/utils').cpbin('segfault')\" && cd ..",
"build-only": "cd src && node-gyp build -j max --silent && node -e \"require('addon-tools-raub/utils').cpbin('segfault')\" && cd ..",
```
See the [TypeScript definitions](/utils.d.ts) with comments.

View File

@ -3,31 +3,36 @@
const tools = require('.'); const tools = require('.');
describe('index.js', () => { describe('AT / include', () => {
describe( const stringMethods = ['getBin', 'getPlatform', 'getInclude'];
'Properties',
() => ['bin', 'platform', 'include'].forEach(
(m) => it(`#${m} is a string`, () => {
expect(typeof tools[m]).toBe('string');
})
)
);
describe('#paths()', () => { stringMethods.forEach((name) => {
describe(`#${name}()`, () => {
it('is a function', () => {
expect(typeof tools[name]).toBe('function');
});
it('returns an object', () => {
expect(typeof tools[name]()).toBe('string');
});
});
});
describe('#getPaths()', () => {
it('is a function', () => { it('is a function', () => {
expect(typeof tools.paths).toBe('function'); expect(typeof tools.getPaths).toBe('function');
}); });
it('returns an object', () => { it('returns an object', () => {
expect(typeof tools.paths(__dirname)).toBe('object'); expect(typeof tools.getPaths(__dirname)).toBe('object');
}); });
it('has "include" string', () => { it('has "include" string', () => {
expect(typeof tools.paths(__dirname).include).toBe('string'); expect(typeof tools.getPaths(__dirname).include).toBe('string');
}); });
it('has "bin" string', () => { it('has "bin" string', () => {
expect(typeof tools.paths(__dirname).include).toBe('string'); expect(typeof tools.getPaths(__dirname).include).toBe('string');
}); });
}); });
}); });

View File

@ -2,38 +2,11 @@
## C++ Addon building ## C++ Addon building
**NAPI** addons are built separately from the installation, so we shouldn't
put the file **binding.gyp** to the module root anymore. It is better to have a
separate folder with a separate **package.json**, **binding.gyp** and the sources.
A snippet for **src/package.json**:
```
{
"name": "build",
"version": "0.0.0",
"private": true,
"scripts": {
"build-all": "cd src && node-gyp rebuild -j max --silent && node -e \"require('addon-tools-raub/utils').cpbin('ADDON')\" && cd ..",
"build-only": "cd src && node-gyp build -j max --silent && node -e \"require('addon-tools-raub/utils').cpbin('ADDON')\" && cd ..",
},
"dependencies": {
"addon-tools-raub": "6.2.0",
"DEPS": "1.0.0"
}
}
```
* `ADDON` - the name of this addon (and subsequently of its binary).
* `DEPS` - dependency package(s).
### Binary distribution ### Binary distribution
In **package.json** use the `"postinstall"` script to download the libraries. In **package.json** use the `"postinstall"` script to download the libraries.
For example the following structure might work. Note that **Addon Tools** will For example the following structure might work. Note that **Addon Tools** will
append any given URL with `/${platform}.zip` append any given URL with `/${getPlatform()}.zip`
In **package.json**: In **package.json**:
@ -42,44 +15,35 @@ In **package.json**:
"postinstall": "node install", "postinstall": "node install",
}, },
"dependencies": { "dependencies": {
"addon-tools-raub": "^6.2.0", "addon-tools-raub": "^7.0.0",
}, },
"devDependencies": { "devDependencies": {
"node-addon-api": "^5.0.0" "node-addon-api": "^5.0.0"
} }
``` ```
Create the **install.js** file: Create the **install.js** file, see `install` in [index.d.ts](/index.d.ts).
**Addon Tools** will unzip (using **tar**) the downloaded file into the platform binary
```
'use strict';
const { install } = require('addon-tools-raub/utils');
const prefix = 'https://github.com/node-3d/glfw-raub/releases/download';
const tag = '4.8.0';
install(`${prefix}/${tag}`);
```
**Addon Tools** will unzip (using **adm-zip**) the downloaded file into the platform binary
directory. E.g. on Windows it will be **bin-windows**. directory. E.g. on Windows it will be **bin-windows**.
* For a dependency package: * For a dependency package:
Place the following piece of code in the `index.js` without changes. Method `paths()` Place the following piece of code into the `index.js` without changes.
is described [here](../README.md).
``` ```
module.exports = require('addon-tools-raub').paths(__dirname); module.exports = require('addon-tools-raub').getPaths(__dirname);
``` ```
* For a compiled addon: * For a compiled addon:
Require it in your **index.js** from the platform-specific directory. Require the `ADDON.node` in your **index.js** from the platform-specific directory.
``` ```
const { bin } = require('addon-tools-raub'); const { getBin } = require('addon-tools-raub');
const core = require(`./${bin}/ADDON`); const core = require(`./${getBin()}/ADDON`);
``` ```
Publishing binaries is done by attaching a zipped platform folder to the GitHub Publishing binaries is done by attaching a zipped platform folder to a GitHub
release. Zip file must NOT contain platform folder as a subfolder, but rather release. Zip file must NOT contain platform folder as a subfolder, but rather
contain the final binaries. The tag of the release should be the same as in contain the final binaries. The tag of the release should be the same as in
**install.js**. **install.js**.
@ -114,75 +78,4 @@ from **Addon Tools** is that it should be a zipped set of files/folders.
], ],
``` ```
The former contains both the path to include **Addon Tools** and the one for See example of a working [**binding.gyp** here](/test-addon/binding.gyp)
**Napi** (which is preinstalled with Addon Tools). The latter can be any other
dependency include path(s).
<details>
<summary><b>See a snipped for src/binding.gyp here</b></summary>
* Assume `DEPS` is the name of an Addon Tools compliant dependency module.
* Assume `ADDON` is the name of this addon's resulting binary.
* Assume C++ code goes to `cpp` subdirectory.
```
{
'variables': {
'bin' : '<!(node -p "require(\'addon-tools-raub\').bin")',
'DEPS_include' : '<!(node -p "require(\'DEPS\').include")',
'DEPS_bin' : '<!(node -p "require(\'DEPS\').bin")',
},
'targets': [{
'target_name' : 'ADDON',
'sources' : [
'cpp/addon.cpp',
],
'include_dirs' : [
'<!@(node -p "require(\'addon-tools-raub\').include")',
'<(DEPS_include)',
],
'cflags_cc': ['-std=c++17', '-fno-exceptions'],
'library_dirs': ['<(DEPS_bin)'],
'libraries': ['-lDEPS' ],
'conditions': [
['OS=="linux"', {
'libraries': [
"-Wl,-rpath,'$$ORIGIN'",
"-Wl,-rpath,'$$ORIGIN/../node_modules/DEPS/<(bin)'",
"-Wl,-rpath,'$$ORIGIN/../../DEPS/<(bin)'",
],
'defines': ['__linux__'],
}],
['OS=="mac"', {
'libraries': [
'-Wl,-rpath,@loader_path',
'-Wl,-rpath,@loader_path/../node_modules/DEPS/<(bin)',
'-Wl,-rpath,@loader_path/../../DEPS/<(bin)',
],
'MACOSX_DEPLOYMENT_TARGET': '10.9',
'defines': ['__APPLE__'],
'CLANG_CXX_LIBRARY': 'libc++',
'OTHER_CFLAGS': ['-std=c++17', '-fno-exceptions'],
}],
['OS=="win"', {
'defines' : ['WIN32_LEAN_AND_MEAN', 'VC_EXTRALEAN', '_WIN32', '_HAS_EXCEPTIONS=0'],
'msvs_settings' : {
'VCCLCompilerTool' : {
'AdditionalOptions' : [
'/O2','/Oy','/GL','/GF','/Gm-', '/std:c++17',
'/EHa-s-c-','/MT','/GS','/Gy','/GR-','/Gd',
]
},
'VCLinkerTool' : {
'AdditionalOptions' : ['/DEBUG:NONE', '/LTCG', '/OPT:NOREF'],
},
},
}],
],
}],
}
```
</details>

245
index.d.ts vendored
View File

@ -1,17 +1,17 @@
declare module "addon-tools-raub" { declare module "addon-tools-raub" {
/** /**
* Addon paths * Get the internal paths for an addon
* Returns a set of platform dependent paths depending on input dir * Returns a set of platform dependent paths depending on the input dir
*/ */
export const paths: (dir: string) => Readonly<{ export const getPaths: (dir: string) => Readonly<{
/** /**
* Path to binaries * Path to binaries
* Platform binary directory absolute path for this `dir` * Platform binary directory absolute path for this `dir`
*/ */
bin: string; bin: string;
/** /**
* Path to include * Path to include
* Include directory for this `dir` * Include directory for this `dir`
*/ */
include: string; include: string;
}>; }>;
@ -20,16 +20,231 @@ declare module "addon-tools-raub" {
type TPlatformDir = `bin-${TPlatformName}`; type TPlatformDir = `bin-${TPlatformName}`;
/** /**
* Platform-dependent binary directory name * Get the platform-specific binary directory name
*/ */
export const bin: TPlatformDir; export const getBin: () => TPlatformDir;
export const platform: TPlatformName;
/** /**
* Main include directories * Get the platform identifier
* Both 'addon-tools-raub' and 'node-addon-api' include paths.
* For binding.gyp: `'<!@(node -p "require(\'addon-tools-raub\').include")'`
*/ */
export const include: string; export const getPlatform: () => TPlatformName;
/**
* Get the include directories for **binding.gyp**
* Both 'addon-tools-raub' and 'node-addon-api' include paths.
* In binding.gyp: `'<!@(node -p "require(\'addon-tools-raub\').getInclude()")'`
*/
export const getInclude: () => string;
/**
* Install binaries
* Downloads and unzips the platform specific binary for the calling package.
* To use it, create a new script for your package, which may as well be named
* **install.js**, with the following content:
*
* ```
* 'use strict';
* const { install } = require('addon-tools-raub');
* const prefix = 'https://github.com/USER/ADDON-NAME/releases/download';
* const tag = '1.0.0';
* install(`${prefix}/${tag}`);
* ```
*
* * `prefix` - the constant base part of the download url.
* * `tag` - the version-dependent part of the url.
*
* ```
* "scripts": {
* "postinstall": "node install"
* },
* ```
*/
export const install: (folder: string) => void;
/**
* Copy binary
* Copies the addon binary from `src/build/Release` to the platform-specific folder.
*
* ```
* "scripts": {
* * "build": "node-gyp rebuild && node -e \"require('addon-tools-raub').cpbin('ADDON')\""
* },
* ```
*
* Here ADDON should be replaced with the name of your addon, without `.node` extension.
*/
export const cpbin: (name: string) => Promise<void>;
/**
* Package version for GitHub Actions
* Example of `actionVersion` usage in **Github Actions**:
*
* ```
* - name: Get Package Version
* id: package-version
* run: node -e \"require('addon-tools-raub').actionVersion()\" >> $GITHUB_OUTPUT
* - name: Create Release
* uses: softprops/action-gh-release@v1
* with:
* tag_name: ${{ steps.package-version.outputs.version }}
* ```
*/
export const actionVersion: () => void;
/**
* Package version for GitHub Actions
* Example of `actionZip` usage in **Github Actions**:
*
* ```
* - name: Zip Files
* id: zip-files
* run: node action-zip >> $GITHUB_OUTPUT
* - name: Store Binaries
* uses: softprops/action-gh-release@v1
* with:
* files: ${{ steps.zip-files.outputs.zip }}
* ```
*/
export const actionZip: () => void;
/**
* Download to memory
* Accepts an **URL**, and returns an in-memory file Buffer,
* when the file is loaded. Use for small files, as the whole
* file will be loaded into memory at once.
*
* ```
* download(srcUrl).then(data => useData(data), err => emit('error', err));
* ```
* or
* ```
* const data = await download(srcUrl);
* useData(data);
* ```
*/
export const download: (url: string) => Promise<Buffer>;
/**
* (async) Read a file
* Reads a whole file to string, NOT A Buffer
*/
/**
* WritableBuffer
* A [Writable](https://nodejs.org/api/stream.html#stream_writable_streams)
* stream buffer, that is stored in-memory and can be fully
* obtained when writing was finished. It is equivalent to stream-writing
* a temporary file and then reading it into a `Buffer`.
*/
export class WritableBuffer extends Writable {
constructor();
/**
* Get the downloaded data
* Use `stream.get()` to obtain the data when writing was finished
*/
get(): Buffer;
}
export const read: (name: string) => Promise<string>;
/**
* (async) Write a file
*/
export const write: (name: string, text: string) => Promise<void>;
/**
* (async) Copy a file
*/
export const copy: (src: string, dest: string) => Promise<void>;
/**
* (async) Check if a file/folder exists
*/
export const exists: (name: string) => Promise<boolean>;
/**
* (async) Create an empty folder
*/
export const mkdir: (name: string) => Promise<void>;
/**
* (async) Get status on a file
*/
export const stat: (name: string) => Promise<Stats>;
/**
* (async) Check if the path is a folder
*/
export const isDir: (name: string) => Promise<boolean>;
/**
* (async) Check if the path is a file
*/
export const isFile: (name: string) => Promise<boolean>;
/**
* Cut the path one folder up
*/
export const dirUp: (dir: string) => string;
/**
* (async) Create a directory
* Like `mkdir -p`, makes sure a directory exists
*/
export const ensuredir: (dir: string) => Promise<void>;
/**
* (async) Copy a file
* Copy a file, `dest` folder is created if needed
*/
export const copysafe: (src: string, dest: string) => Promise<void>;
/**
* (async) Read a directory
* Get file/folder names of the 1st level
*/
export const readdir: (src: string, dest: string) => Promise<ReadonlyArray<string>>;
/**
* (async) List subdirectories
* Get folder paths (concatenated with input) of the 1st level
*/
export const subdirs: (name: string) => Promise<ReadonlyArray<string>>;
/**
* (async) List nested files
* Get file paths (concatenated with input) of the 1st level
*/
export const subfiles: (name: string) => Promise<ReadonlyArray<string>>;
/**
* (async) Get all nested files recursively
* Folder paths are omitted by default.
* Order is: shallow-to-deep, each subdirectory lists dirs-then-files.
*/
export const traverse: (name: string, showDirs?: boolean) => Promise<ReadonlyArray<string>>;
/**
* (async) Copy a directory
* Copy a folder with all the contained files
*/
export const copyall: (src: string, dest: string) => Promise<void>;
/**
* (async) Remove a directory
* Like `rm -rf`, removes everything recursively
*/
export const rmdir: (name: string) => Promise<void>;
/**
* (async) Remove a file
* Must be a file, not a folder. Just `fs.unlink`.
*/
export const rm: (name: string) => Promise<void>;
} }

View File

@ -1,5 +1,6 @@
'use strict'; 'use strict';
module.exports = { module.exports = {
...require('./include/index'), ...require('./include'),
...require('./utils'),
}; };

View File

@ -5,7 +5,7 @@ const test = require('./build/Release/test.node');
const arrayArgMsg = 'Argument 0 must be of type `Array`'; const arrayArgMsg = 'Argument 0 must be of type `Array`';
describe('addon-tools.hpp: LET_ARRAY_ARG', () => { describe('AT / addon-tools.hpp / LET_ARRAY_ARG', () => {
it('exports letArrayStrArg', () => { it('exports letArrayStrArg', () => {
expect(typeof test.letArrayStrArg).toBe('function'); expect(typeof test.letArrayStrArg).toBe('function');
}); });

View File

@ -5,7 +5,7 @@ const test = require('./build/Release/test.node');
const arrayArgMsg = 'Argument 0 must be of type `Array`'; const arrayArgMsg = 'Argument 0 must be of type `Array`';
describe('addon-tools.hpp: REQ_ARRAY_ARG', () => { describe('AT / addon-tools.hpp / REQ_ARRAY_ARG', () => {
it('exports reqArrayArg', () => { it('exports reqArrayArg', () => {
expect(typeof test.reqArrayArg).toBe('function'); expect(typeof test.reqArrayArg).toBe('function');
}); });

View File

@ -5,7 +5,7 @@ const test = require('./build/Release/test.node');
const boolArgMsg = 'Argument 0 must be of type `Bool`'; const boolArgMsg = 'Argument 0 must be of type `Bool`';
describe('addon-tools.hpp: REQ_BOOL_ARG', () => { describe('AT / addon-tools.hpp / REQ_BOOL_ARG', () => {
it('exports reqBoolArg', () => { it('exports reqBoolArg', () => {
expect(typeof test.reqBoolArg).toBe('function'); expect(typeof test.reqBoolArg).toBe('function');
}); });

View File

@ -5,7 +5,7 @@ const test = require('./build/Release/test.node');
const numArgMsg = 'Argument 0 must be of type `Number`'; const numArgMsg = 'Argument 0 must be of type `Number`';
describe('addon-tools.hpp: REQ_DOUBLE_ARG', () => { describe('AT / addon-tools.hpp / REQ_DOUBLE_ARG', () => {
it('exports reqDoubleArg', () => { it('exports reqDoubleArg', () => {
expect(typeof test.reqDoubleArg).toBe('function'); expect(typeof test.reqDoubleArg).toBe('function');
}); });

View File

@ -5,7 +5,7 @@ const test = require('./build/Release/test.node');
const extArgMsg = 'Argument 0 must be of type `Pointer`'; const extArgMsg = 'Argument 0 must be of type `Pointer`';
describe('addon-tools.hpp: REQ_EXT_ARG', () => { describe('AT / addon-tools.hpp / REQ_EXT_ARG', () => {
it('exports reqExtArg', () => { it('exports reqExtArg', () => {
expect(typeof test.reqExtArg).toBe('function'); expect(typeof test.reqExtArg).toBe('function');
}); });

View File

@ -5,7 +5,7 @@ const test = require('./build/Release/test.node');
const numArgMsg = 'Argument 0 must be of type `Number`'; const numArgMsg = 'Argument 0 must be of type `Number`';
describe('addon-tools.hpp: REQ_FLOAT_ARG', () => { describe('AT / addon-tools.hpp / REQ_FLOAT_ARG', () => {
it('exports reqFloatArg', () => { it('exports reqFloatArg', () => {
expect(typeof test.reqFloatArg).toBe('function'); expect(typeof test.reqFloatArg).toBe('function');
}); });

View File

@ -5,7 +5,7 @@ const test = require('./build/Release/test.node');
const intArgMsg = 'Argument 0 must be of type `Int32`'; const intArgMsg = 'Argument 0 must be of type `Int32`';
describe('addon-tools.hpp: REQ_INT_ARG / REQ_INT32_ARG', () => { describe('AT / addon-tools.hpp / REQ_INT_ARG, REQ_INT32_ARG', () => {
it('exports reqIntArg', () => { it('exports reqIntArg', () => {
expect(typeof test.reqIntArg).toBe('function'); expect(typeof test.reqIntArg).toBe('function');
}); });

View File

@ -5,7 +5,7 @@ const test = require('./build/Release/test.node');
const objArgMsg = 'Argument 0 must be of type `Object`'; const objArgMsg = 'Argument 0 must be of type `Object`';
describe('addon-tools.hpp: REQ_OBJ_ARG', () => { describe('AT / addon-tools.hpp / REQ_OBJ_ARG', () => {
it('exports reqObjArg', () => { it('exports reqObjArg', () => {
expect(typeof test.reqObjArg).toBe('function'); expect(typeof test.reqObjArg).toBe('function');
}); });

View File

@ -5,7 +5,7 @@ const test = require('./build/Release/test.node');
const numArgMsg = 'Argument 0 must be of type `Number`'; const numArgMsg = 'Argument 0 must be of type `Number`';
describe('addon-tools.hpp: REQ_OFFS_ARG', () => { describe('AT / addon-tools.hpp / REQ_OFFS_ARG', () => {
it('exports reqOffsArg', () => { it('exports reqOffsArg', () => {
expect(typeof test.reqOffsArg).toBe('function'); expect(typeof test.reqOffsArg).toBe('function');
}); });

View File

@ -5,7 +5,7 @@ const test = require('./build/Release/test.node');
const strArgMsg = 'Argument 0 must be of type `String`'; const strArgMsg = 'Argument 0 must be of type `String`';
describe('addon-tools.hpp: REQ_STR_ARG', () => { describe('AT / addon-tools.hpp / REQ_STR_ARG', () => {
it('exports reqStrArg', () => { it('exports reqStrArg', () => {
expect(typeof test.reqStrArg).toBe('function'); expect(typeof test.reqStrArg).toBe('function');
}); });

View File

@ -5,7 +5,7 @@ const test = require('./build/Release/test.node');
const uintArgMsg = 'Argument 0 must be of type `Uint32`'; const uintArgMsg = 'Argument 0 must be of type `Uint32`';
describe('addon-tools.hpp: REQ_UINT_ARG / REQ_UINT32_ARG', () => { describe('AT / addon-tools.hpp / REQ_UINT_ARG, REQ_UINT32_ARG', () => {
it('exports reqUintArg', () => { it('exports reqUintArg', () => {
expect(typeof test.reqUintArg).toBe('function'); expect(typeof test.reqUintArg).toBe('function');
}); });

View File

@ -3,8 +3,7 @@
const test = require('./build/Release/test.node'); const test = require('./build/Release/test.node');
describe('addon-tools.hpp: Function arguments', () => { describe('AT / addon-tools.hpp / Function arguments', () => {
describe('REQ_ARGS', () => { describe('REQ_ARGS', () => {
it('exports reqArgs3', () => { it('exports reqArgs3', () => {
expect(typeof test.reqArgs3).toBe('function'); expect(typeof test.reqArgs3).toBe('function');
@ -203,5 +202,4 @@ describe('addon-tools.hpp: Function arguments', () => {
expect(test.reqTypedArg(typed)).toEqual(typed); expect(test.reqTypedArg(typed)).toEqual(typed);
}); });
}); });
}); });

215
utils.d.ts vendored
View File

@ -1,215 +0,0 @@
import type { Writable } from 'stream';
declare module "addon-tools-raub/utils" {
/**
* Install binaries
* Downloads and unzips the platform specific binary for the calling package.
* To use it, create a new script for your package, which may as well be named
* **install.js**, with the following content:
* ```
* 'use strict';
* const install = require('addon-tools-raub/install');
* const prefix = 'https://github.com/USER/ADDON-NAME/releases/download';
* const tag = 'v1.0.0';
* install(`${prefix}/${tag}`);
* ```
* * `prefix` - the constant base part of the download url.
* * `tag` - the version-dependent part of the url.
* ```
* "scripts": {
* "postinstall": "node install"
* },
* ```
*/
export const install: (folder: string) => void;
/**
* Copy binary
* Copies the addon binary from `src/build/Release` to the platform folder.
* ```
* declare const cpbin: (name: string) => Promise<void>;
* export default cpbin;
* ```
* It is useful for development builds. Use it in your **src/package.json**:
* ```
* "scripts": {
* * "build": "node-gyp rebuild && node -e \"require('addon-tools-raub/cpbin')('ADDON')\""
* },
* ```
* Here ADDON should be replaced with the name of your addon, without `.node` extension.
*/
export const cpbin: (name: string) => Promise<void>;
/**
* Package version for GitHub Actions
* Example of `actionVersion` usage in **Github Actions**:
*
* ```
* - name: Get Package Version
* id: package-version
* run: node -e \"require('addon-tools-raub/utils').actionVersion()\" >> $GITHUB_OUTPUT
* - name: Create Release
* uses: softprops/action-gh-release@v1
* with:
* tag_name: ${{ steps.package-version.outputs.version }}
* ```
*/
export const actionVersion: () => void;
/**
* Package version for GitHub Actions
* Example of `actionZip` usage in **Github Actions**:
*
* ```
* - name: Zip Files
* id: zip-files
* run: node action-zip >> $GITHUB_OUTPUT
* - name: Store Binaries
* uses: softprops/action-gh-release@v1
* with:
* files: ${{ steps.zip-files.outputs.zip }}
* ```
*/
export const actionZip: () => void;
/**
* Download to memory
* Accepts an **URL**, and returns an in-memory file Buffer,
* when the file is loaded. Use for small files, as the whole
* file will be loaded into memory at once.
*
* ```
* download(srcUrl).then(data => useData(data), err => emit('error', err));
* ```
* or
* ```
* const data = await download(srcUrl);
* useData(data);
* ```
*/
export const download: (url: string) => Promise<Buffer>;
/**
* (async) Read a file
* Reads a whole file to string, NOT A Buffer
*/
/**
* WritableBuffer
* A [Writable](https://nodejs.org/api/stream.html#stream_writable_streams)
* stream buffer, that is stored in-memory and can be fully
* obtained when writing was finished. It is equivalent to stream-writing
* a temporary file and then reading it into a `Buffer`.
*/
export class WritableBuffer extends Writable {
constructor();
/**
* Get the downloaded data
* Use `stream.get()` to obtain the data when writing was finished
*/
get(): Buffer;
}
export const read: (name: string) => Promise<string>;
/**
* (async) Write a file
*/
export const write: (name: string, text: string) => Promise<void>;
/**
* (async) Copy a file
*/
export const copy: (src: string, dest: string) => Promise<void>;
/**
* (async) Check if a file/folder exists
*/
export const exists: (name: string) => Promise<boolean>;
/**
* (async) Create an empty folder
*/
export const mkdir: (name: string) => Promise<void>;
/**
* (async) Get status on a file
*/
export const stat: (name: string) => Promise<Stats>;
/**
* (async) Check if the path is a folder
*/
export const isDir: (name: string) => Promise<boolean>;
/**
* (async) Check if the path is a file
*/
export const isFile: (name: string) => Promise<boolean>;
/**
* Cut the path one folder up
*/
export const dirUp: (dir: string) => string;
/**
* (async) Create a directory
* Like `mkdir -p`, makes sure a directory exists
*/
export const ensuredir: (dir: string) => Promise<void>;
/**
* (async) Copy a file
* Copy a file, `dest` folder is created if needed
*/
export const copysafe: (src: string, dest: string) => Promise<void>;
/**
* (async) Read a directory
* Get file/folder names of the 1st level
*/
export const readdir: (src: string, dest: string) => Promise<ReadonlyArray<string>>;
/**
* (async) List subdirectories
* Get folder paths (concatenated with input) of the 1st level
*/
export const subdirs: (name: string) => Promise<ReadonlyArray<string>>;
/**
* (async) List nested files
* Get file paths (concatenated with input) of the 1st level
*/
export const subfiles: (name: string) => Promise<ReadonlyArray<string>>;
/**
* (async) Get all nested files recursively
* Folder paths are omitted by default.
* Order is: shallow-to-deep, each subdirectory lists dirs-then-files.
*/
export const traverse: (name: string, showDirs?: boolean) => Promise<ReadonlyArray<string>>;
/**
* (async) Copy a directory
* Copy a folder with all the contained files
*/
export const copyall: (src: string, dest: string) => Promise<void>;
/**
* (async) Remove a directory
* Like `rm -rf`, removes everything recursively
*/
export const rmdir: (name: string) => Promise<void>;
/**
* (async) Remove a file
* Must be a file, not a folder. Just `fs.unlink`.
*/
export const rm: (name: string) => Promise<void>;
}

View File

@ -1,5 +0,0 @@
'use strict';
module.exports = {
...require('./utils/index'),
};

View File

@ -7,7 +7,7 @@ const utils = require('.');
const packageJson = require('../package.json'); const packageJson = require('../package.json');
describe('utils.js', () => { describe('AT / utils', () => {
const methods = [ const methods = [
'install', 'cpbin', 'download', 'read', 'write', 'copy', 'exists', 'install', 'cpbin', 'download', 'read', 'write', 'copy', 'exists',
'mkdir', 'stat', 'isDir', 'isFile', 'dirUp', 'ensuredir', 'copysafe', 'mkdir', 'stat', 'isDir', 'isFile', 'dirUp', 'ensuredir', 'copysafe',