-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
372 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# is.js CICD | ||
This GitHub Actions workflow initializes, lints, tests, and publishes the `is.js` project. | ||
|
||
### Index | ||
1. [Triggers](#triggers) | ||
1. [Inputs](#inputs) | ||
1. [Steps](#steps) | ||
1. [Outputs](#outputs) | ||
1. [See Also](#see-also) | ||
|
||
## Triggers | ||
This GitHub action will run under the following circumstances: | ||
1. When code is pushed to a base branch. | ||
1. When a pull request is opened, new commits are pushed, or re-opened. | ||
1. On a workflow dispatch event, a manual CI run which can be triggered by the "Workflow Dispatch" button on the "Actions" tab of the GitHub repository, among other means. | ||
|
||
## Inputs | ||
There are currently no user-defined inputs for this pipeline, aside from the source code itself. | ||
|
||
## Steps | ||
This workflow performs the following steps on GitHub runners: | ||
1. **Attach Documentation** | ||
1. [Checkout](https://github.com/actions/checkout) this repo with no submodules. | ||
1. Attach an annotation to the GitHub Actions build summary page containing CI documentation. | ||
1. **is.js - nodeJS v`𝕟`** | ||
> This is a [matrix](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/using-a-matrix-for-your-jobs) job where `𝕟` is a set of supported `node` LTS major versions given by the `node-version` array in [`ci.yml`](./ci.yml). The following steps are run against each `node` version in the array: | ||
1. [Checkout](https://github.com/actions/checkout) this repo. | ||
1. [Setup nodeJS](https://github.com/actions/setup-node) using the specified version. | ||
1. Initialize the project using `yarn`. | ||
1. Lint. | ||
1. Unit tests. | ||
1. Run the build. | ||
1. Pack build metadata. | ||
1. Generate the distributable. | ||
1. Validate the distributable can be successfully installed by `npm`. | ||
1. If this `node` version matches the one in [`.nvmrc`](../../.nvmrc), publish to NPM. | ||
1. [Upload artifacts](https://github.com/actions/upload-artifact). | ||
|
||
## Outputs | ||
Besides the exit status, the following is generated. | ||
- A `*.tgz` file for each `node` version containing the `is.js` project. | ||
|
||
## See Also | ||
- [is.js Documentation](../../README.md) | ||
|
||
For assistance with the CI system, please open an issue in this repo. | ||
|
||
*** | ||
> **_Legal Notice_** | ||
> This repo contains assets created in collaboration with a large language model, machine learning algorithm, or weak artificial intelligence (AI). This notice is required in some countries. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,309 @@ | ||
# is | ||
# is.js | ||
Extremely lightweight, zero dependency variable checks missing in nodeJS but common in other languages. | ||
```ts | ||
is.nullOrEmpty(input: any): boolean | ||
is.string(input: any): boolean; | ||
``` | ||
Install `@kj4ezj/is` from [NPM](https://www.npmjs.com/package/@kj4ezj/is) with your preferred package manager! | ||
|
||
<!-- contents box begin --> | ||
<table> | ||
<tr/> | ||
<tr> | ||
<td> | ||
<p/> | ||
<div align="center"> | ||
<b>Contents</b> | ||
</div> | ||
<p/> | ||
<!-- contents markdown begin --> | ||
|
||
1. [Background](#background) | ||
1. [Usage](#usage) | ||
1. [`is.nullOrEmpty()`](#isnullorempty) | ||
1. [`is.string()`](#isstring) | ||
1. [Development](#development) | ||
1. [Prerequisites](#prerequisites) | ||
1. [Initialization](#initialization) | ||
1. [Lint](#lint) | ||
1. [Test](#test) | ||
1. [Build](#build) | ||
1. [Reset](#reset) | ||
1. [CI](#ci) | ||
1. [See Also](#see-also) | ||
|
||
<!-- contents markdown end --> | ||
<p/> | ||
</td> | ||
</tr> | ||
</table> | ||
<!-- contents box end --> | ||
|
||
## Background | ||
In the old days™, nodeJS lacked most utilities developers take for granted in other languages. The community created libraries like [lodash](https://github.com/lodash/lodash) (commonly imported and used as `_` in projects) to fill this void. However, modern `node` includes intrinsics that provide almost all of the functionality these large libraries were built to provide. It seems silly to import a 1.4 MB library just to test if a variable is empty. | ||
|
||
The `is.js` library provides the most fundamental utilities remaining absent in modern `node` that I expect to have in any language, and nothing more. At the time of writing, `is.js` weighs in at just _461 bytes_, five orders of magnitude smaller than `lodash`! | ||
|
||
## Usage | ||
Install `@kj4ezj/is` from [NPM](https://www.npmjs.com/package/@kj4ezj/is) with your preferred package manager... | ||
```bash | ||
bun add @kj4ezj/is | ||
cnpm install @kj4ezj/is | ||
npm install @kj4ezj/is | ||
pnpm add @kj4ezj/is | ||
yarn add @kj4ezj/is | ||
``` | ||
...then import it into your source code. | ||
```js | ||
const is = require('@kj4ezj/is'); | ||
``` | ||
Two utilities are provided. | ||
```ts | ||
is.nullOrEmpty(input: any): boolean | ||
is.string(input: any): boolean; | ||
``` | ||
These are documented in the sections below, but the [test cases](./is.test.js) written against expectations should be considered authoritative. | ||
|
||
### is.nullOrEmpty() | ||
This is a simple variable emptiness check. Pass it literally anything and it will return `true` if it is `undefined`, `null`, or empty; and `false` otherwise. | ||
```ts | ||
is.nullOrEmpty(input: any): boolean | ||
``` | ||
Emptiness is considered in a practical sense, and may be slightly different than implementations in other languages. | ||
|
||
<!-- emptiness table begin --> | ||
<table> | ||
<tr/> | ||
<tr> | ||
<td><div align="center"><b>Category</b></div></td> | ||
<td><div align="center"><b>Returns</b></div></td> | ||
<td><div align="center"><b>Examples</b></div></td> | ||
</tr> | ||
<tr> | ||
<td><b>Empty</b></td> | ||
<td><code>true</code></td> | ||
<td> | ||
<!-- empty markdown begin --> | ||
|
||
```js | ||
// literals | ||
undefined | ||
null | ||
[] // zero-length arrays | ||
[[]] // zero-length multi-dimension arrays | ||
{} // empty objects | ||
'' // equivalent to "" or `` | ||
' ' // strings containing only whitespace | ||
' \n\t' | ||
|
||
// primitive objects | ||
Array([]) | ||
Object({}) | ||
String(' \n ') | ||
|
||
// constructed objects | ||
new Array([]) | ||
new Array([[]]) | ||
new Object({}) | ||
new String(' \n ') | ||
``` | ||
|
||
<!-- empty markdown end --> | ||
</td> | ||
</tr> | ||
<tr> | ||
<td><b>Not Empty</b></td> | ||
<td><code>false</code></td> | ||
<td> | ||
<!-- not empty markdown begin --> | ||
|
||
```js | ||
// literals | ||
true | ||
false | ||
-1 | ||
0 | ||
123 | ||
0xFFFF00 | ||
0b00101010 | ||
'yeet' | ||
[[],[]] // non-zero array length | ||
['one', 'two', 'three'] | ||
{key: 'value'} | ||
|
||
// primitive types | ||
Boolean(false) | ||
Number(0) | ||
BigInt(81129638414606663681390495662081) | ||
|
||
// constructed types | ||
new Boolean(false) | ||
new Number(0) | ||
new String('yeet') | ||
new Array([[],[]]) | ||
new Object({key: 'value'}) | ||
|
||
// functions, no matter the return type or contents | ||
() => undefined | ||
() => null | ||
() => false | ||
() => 0 | ||
() => '' | ||
() => [] | ||
() => {} | ||
() => new Number(0) | ||
() => new String('') | ||
``` | ||
|
||
<!-- not empty markdown end --> | ||
</td> | ||
</tr> | ||
</table> | ||
<!-- emptiness table end --> | ||
|
||
See the [test cases](./is.test.js) written against expectations for more info, or try it in an interactive shell. | ||
|
||
### is.string() | ||
JavaScript has two different types of strings: | ||
1. String primitives - `''`, `""`, ``` `` ```, `String()`, and `String('')` | ||
1. String objects - `new String()` | ||
|
||
These are fundamentally two different _types_, even though JavaScript _pretends_ not to have types. String primitives are fundamentally immutable literals of type `string`, while string objects are fundamentally type `Object` of class `String`. | ||
|
||
> [!TIP] | ||
> JavaScript hides this from you using [autoboxing](https://medium.com/weekly-webtips/autoboxing-in-javascript-a368b42d8969). When you access a property or method on a string primitive, JavaScript temporarily converts (or "boxes") the string primitive into a `String` object. This allows the string primitive to access the properties and methods available on `String.prototype`. Once the property or method is accessed, the temporary `String` object is discarded, and the original string primitive remains unchanged. | ||
This makes it complicated for programmers to determine if a variable is a string because `String` objects are _not_ strings. | ||
|
||
![JavaScript string type examples](https://github.com/user-attachments/assets/7a70cc19-8cb7-469f-af91-bd8cfdc31844) | ||
|
||
Most of the time we do not care about the internal mechanics of the language, we just want to know if a variable contains a string in a practical sense. | ||
```js | ||
is.string() // false | ||
is.string(undefined) // false | ||
is.string(null) // false | ||
is.string('') // TRUE | ||
is.string(' ') // TRUE | ||
is.string('yeet') // TRUE | ||
is.string(' \n\t') // TRUE | ||
is.string([]) // false | ||
is.string({}) // false | ||
|
||
is.string(String('')) // TRUE | ||
is.string(Array([])) // false | ||
is.string(Array(['yeet'])) // false | ||
is.string(Object({})) // false | ||
is.string(Object({key: 'value'})) // false | ||
|
||
is.string(new String('')) // TRUE | ||
is.string(new Array([])) // false | ||
is.string(new Array(['yeet'])) // false | ||
is.string(new Object({})) // false | ||
is.string(new Object({key: 'value'})) // false | ||
|
||
is.string(() => undefined) // false | ||
is.string(() => null) // false | ||
is.string(() => '') // false | ||
is.string(() => new String('')) // false | ||
is.string(() => new String('yeet')) // false | ||
``` | ||
|
||
See the [test cases](./is.test.js) written against expectations for more info, or try it in an interactive shell. | ||
|
||
## Development | ||
Start here to contribute to this repo. | ||
|
||
> [!NOTE] | ||
> The source of truth for the version of nodeJS this project uses is the [`.nvmrc`](./.nvmrc) file. As a utility, as many versions of `node` are supported as possible on a best-effort basis. Check out the `node-version` key in the [`ci.yml`](./.github/workflows/ci.yml) to see which versions are being tested. | ||
### Prerequisites | ||
Contributors will need the following tools: | ||
- [act](https://github.com/nektos/act) | ||
- [docker](https://docs.docker.com/engine/install) - required by `act` | ||
- Docker Desktop is not required, you only need the free [Docker Engine](https://docs.docker.com/engine). | ||
- [nvm](https://github.com/nvm-sh/nvm#installing-and-updating) | ||
- [nodeJS](https://www.w3schools.com/nodejs/nodejs_intro.asp) | ||
Install `node` using `nvm`. In the root of this repo: | ||
```bash | ||
nvm install | ||
``` | ||
This will automagically install and use the correct version of `node` for this project, as defined in the [`.nvmrc`](./.nvmrc) file. | ||
- [yarn](https://yarnpkg.com) version 1 | ||
The easiest way to install this is using `npm`, which is installed with `node` by `nvm`. | ||
```bash | ||
npm install --global yarn | ||
``` | ||
These tools are all you need to get started! | ||
|
||
### Initialization | ||
Once you have the [prerequisites](#prerequisites) installed, you can get going by navigating to the root of this repo, making sure `nvm` is using the correct version of nodeJS... | ||
```bash | ||
nvm install | ||
``` | ||
...then downloading all project dependencies. | ||
```bash | ||
yarn | ||
``` | ||
Easy. | ||
|
||
### Lint | ||
This project uses [eslint](https://eslint.org) with customizations on top of the [airbnb-base](https://www.npmjs.com/package/eslint-config-airbnb-base) config to perform static code analysis. | ||
```bash | ||
yarn lint | ||
``` | ||
The purpose of linting is to catch bugs early, not to create unnecessary friction, so many rules which will not realistically catch bugs are disabled. | ||
|
||
### Test | ||
This project uses the [jest](https://jestjs.io) test framework. | ||
```bash | ||
yarn test | ||
``` | ||
The goal is full test coverage, not to chase a number but to exhaustively test all expectations. | ||
|
||
### Build | ||
This is how release artifacts are generated and, in [CI](#ci), published. | ||
```bash | ||
yarn build | ||
``` | ||
The "build" command calls [`scripts/build.sh`](./scripts/build.sh), which packs build metadata into the [`package.json`](./package.json) under the top-level `git` key and calls `npm pack` to generate a `*.tgz` file for distribution. If this script is called in a [CI](#ci) environment then it will continue on to install the newly generated package to validate it can be installed, per [NPM's instructions](https://docs.npmjs.com/creating-and-publishing-scoped-public-packages#testing-your-package). In a tagged build, it will verify that the tag matches the version string in the [`package.json`](./package.json) and publish it to [NPM](https://www.npmjs.com/package/@kj4ezj/is) with [provenance](https://docs.npmjs.com/generating-provenance-statements). | ||
|
||
### Reset | ||
This project contains a script to sanitize the project's `node` environment. | ||
> [!WARNING] | ||
> This will delete build artifacts! | ||
```bash | ||
yarn reset | ||
``` | ||
This makes it easy to switch between `node` major versions cleanly. | ||
### CI | ||
This project uses GitHub Actions for CI. | ||
- **is.js CI**s - initialize, lint, and test, and publish the `is.js` project. | ||
- [Pipeline](https://github.com/kj4ezj/is/actions/workflows/ci.yml) | ||
- [Documentation](./.github/workflows/README.md) | ||
You can run the GitHub Actions workflow(s) locally using [act](https://github.com/nektos/act). | ||
```bash | ||
yarn act | ||
``` | ||
Please make sure your changes do not break `act` compatibility. | ||
## See Also | ||
- CI | ||
- [Pipeline](https://github.com/kj4ezj/is/actions/workflows/ci.yml) | ||
- [Documentation](./.github/workflows/README.md) | ||
- Tooling | ||
- [act](https://github.com/nektos/act) - run GitHub Actions locally | ||
- [docker](https://docs.docker.com/engine) | ||
- [eslint](https://eslint.org) | ||
- [airbnb-base](https://www.npmjs.com/package/eslint-config-airbnb-base) | ||
- [jest](https://jestjs.io) | ||
- [nvm](https://github.com/nvm-sh/nvm) | ||
- [nodeJS](https://www.w3schools.com/nodejs/nodejs_intro.asp) | ||
- [yarn](https://yarnpkg.com) | ||
*** | ||
> **_Legal Notice_** | ||
> This repo contains assets created in collaboration with a large language model, machine learning algorithm, or weak artificial intelligence (AI). This notice is required in some countries. |