# bauset

A lightweight npm package builder that keeps your project metadata in one place and produces ready-to-publish `.tgz` archives with a single command.

---

## Table of contents

- [Why bauset?](#why-bauset)
- [Installation](#installation)
- [Quick start](#quick-start)
- [Project structure](#project-structure)
- [PROJECT.txt reference](#projecttxt-reference)
- [package.json template](#packagejson-template)
- [Command-line usage](#command-line-usage)
- [Library API](#library-api)
- [Build output](#build-output)
- [Publishing to npm](#publishing-to-npm)
- [Building bauset with bauset](#building-bauset-with-bauset)
- [Running tests](#running-tests)

---

## Why bauset?

npm can build packages on its own, and if that works for you, keep using it directly. bauset is useful when you want to:

- Keep all project metadata (`name`, `version`, `author`, etc.) in a single plain-text file (`PROJECT.txt`) instead of inside `package.json`.
- Generate `package.json` from a template so it is always consistent with your metadata.
- Produce both a versioned archive (`mypackage-1.2.3.tgz`) and a stable `mypackage-latest.tgz` in one step.
- Optionally install and test the built package in the same command.

---

## Installation

```bash
npm install -g bauset
```

---

## Quick start

1. **Copy this project** as a starting point, or set up the [expected structure](#project-structure) in your own project.

2. **Edit `PROJECT.txt`** with your project's details (see [PROJECT.txt reference](#projecttxt-reference)).

3. **Run bauset** from your project root:

```bash
# Build only
bauset

# Build and install globally
bauset --install --global

# Short form
bauset -ig
```

The package appears in `./pkg/` when done.

---

## Project structure

bauset expects the following layout in your source directory:

```
[project root]
│
├── PROJECT.txt          ← Project metadata (name, version, author, …)
├── README.md            ← Shown as your npm landing page
├── LICENSE              ← License text
│
├── var/
│   └── in.package.json  ← package.json template with %VARIABLE% placeholders
│
├── bin/                 ← Executable scripts
├── lib/                 ← Library source files
├── test/
│   └── test.js          ← Test entry point (run with --test flag)
└── doc/                 ← Documentation files
```

Missing entries are silently skipped — you only need what your project actually has.

---

## PROJECT.txt reference

`PROJECT.txt` is a simple whitespace-delimited key/value file. Lines starting with `#` are comments.

```
# My project configuration
name            mypackage
version         1.0.0
description     A short description of my package
company         My Company
author          Your Name
email           you@example.com
url             https://github.com/you/mypackage
repo            git+ssh://git@github.com/you/mypackage.git
bugs            https://github.com/you/mypackage/issues
license         MIT
```

| Key | Description |
|---|---|
| `name` | Package name (used in the `.tgz` filename) |
| `version` | Version string, e.g. `1.2.3` |
| `description` | One-line package description |
| `company` | Organisation name |
| `author` | Author name |
| `email` | Contact email |
| `url` | Project homepage URL |
| `repo` | Repository URL |
| `bugs` | Bug-report URL |
| `license` | License identifier, e.g. `MIT` |

Any key you add becomes available as a `%KEY%` placeholder in your `in.package.json` template.

---

## package.json template

`var/in.package.json` is a standard JSON file where any value can contain `%KEY%` placeholders. bauset replaces them with the matching values from `PROJECT.txt` before writing the final `package.json` into the build.

Lines that start with `//` or `#` are treated as comments and stripped automatically.

**Example `var/in.package.json`:**

```json
{
  "name": "%NAME%",
  "version": "%VERSION%",
  "description": "%DESCRIPTION%",
  "main": "lib/index.js",
  "scripts": {
    "test": "node --test test/test.js"
  },
  "bin": {
    "%NAME%": "bin/%NAME%.js"
  },
  "repository": {
    "type": "git",
    "url": "%REPO%"
  },
  "author": "%AUTHOR%",
  "license": "%LICENSE%",
  "bugs": {
    "url": "%BUGS%"
  },
  "homepage": "%URL%"
}
```

---

## Command-line usage

```
bauset [options]
```

| Flag | Long form | Description |
|---|---|---|
| `-i` | `--install` | Install the built package after packaging |
| `-g` | `--global` | Install globally (only effective with `--install`) |
| `-s` | `--source <dir>` | Source directory (defaults to current directory) |
| `-r` | `--recursive` | Copy source directories recursively |
| `-v` | `--version` | Print the bauset version and exit |
| `-V` | `--verbose` | Enable verbose logging |
| `-h` | `--help` | Show help and exit |

**Examples:**

```bash
# Build a package from the current directory
bauset

# Build and install globally
bauset --install --global

# Build from a specific source directory
bauset --source /path/to/my/project

# Verbose output while building
bauset --verbose

# Combined short flags
bauset -igV
```

---

## Library API

You can use bauset programmatically in your own build scripts.

```javascript
const bauset = require('bauset');
```

### `bauset.createPackage(src, dst, opts)` → `Promise`

Stages and packages an npm module.

```javascript
bauset.createPackage('/path/to/project', '/path/to/staging', {
    install: false,   // set true to install after packaging
    global:  false,   // set true to install globally (requires install: true)
    test:    false,   // set true to run ./test/test.js after installing
    Log:     console.log  // logging function, or omit to suppress output
})
.then(() => console.log('Done!'))
.catch(err => console.error('Build failed:', err));
```

### `bauset.fileCopy(src, dst, opts)`

Copies a file or directory tree.

```javascript
bauset.fileCopy('/path/to/src', '/path/to/dst', {
    overwrite: true,   // overwrite existing files (default: true)
    recursive: true,   // recurse into subdirectories (default: true)
    Log: console.log   // logging function, or null to suppress
});
```

### `bauset.__config__`

Exposes the internal config utilities:

```javascript
const cfg = bauset.__config__;

// Load a PROJECT.txt file into an object
const meta = cfg.loadConfig('/path/to/PROJECT.txt');

// Process a template file, replacing %VAR% placeholders
cfg.processFile(meta, '/path/to/in.package.json', '/path/to/package.json');

// Parse a Unix-style argument list
const args = cfg.parseParams('myprog [opts]', process.argv, [
    ['i', 'install',  'Install after build'],
    ['s', 'source=',  'Source directory'],
]);
```

---

## Build output

After a successful run, two files appear in `./pkg/`:

```
pkg/
├── mypackage-1.2.3.tgz   ← versioned archive
└── mypackage-latest.tgz  ← always points to the most recent build
```

A `./dist/` directory is used as a staging area during the build and can be ignored or added to `.gitignore`.

---

## Publishing to npm

Once you have a package in `./pkg/`, publish it with:

```bash
npm publish ./pkg/mypackage-latest.tgz
```

Or use the versioned archive if you need to publish a specific release:

```bash
npm publish ./pkg/mypackage-1.2.3.tgz
```

See the [npm publish docs](https://docs.npmjs.com/cli/v10/commands/npm-publish) for registry authentication and other options.

---

## Building bauset with bauset

If you are hacking on bauset itself and it is not yet installed, you can run it in-place using the `__bootstrap__` flag. This tells bauset to load its library from the local source tree instead of the installed package.

```bash
# From the bauset project directory
./bin/bauset.js __bootstrap__ --install --global
```

---

## Running tests

```bash
node --test test/test.js
```

The test suite uses the built-in [`node:test`](https://nodejs.org/api/test.html) runner (Node.js 18+) and covers `loadConfig`, `processFile`, `parseParams`, `fileCopy`, and `createPackage`.

---

## References

- [Node.js](https://nodejs.org/)
- [npm](https://www.npmjs.com/)
- [npm publish docs](https://docs.npmjs.com/cli/v10/commands/npm-publish)
