Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
2ba2dca
Initial commit with task details for issue #1
konard Nov 14, 2025
4d14889
Implement lino-arguments library prototype
konard Nov 14, 2025
657e17e
Revert: Remove CLAUDE.md changes from initial commit
konard Nov 14, 2025
e81d376
Implement makeConfig() API with unified configuration system
konard Nov 14, 2025
34c249e
Add Bun and Deno dependency installation to CI workflow
konard Nov 14, 2025
48a3faa
Use npm install for Bun and Deno CI tests
konard Nov 14, 2025
651677e
Temporarily disable Bun and Deno CI tests
konard Nov 14, 2025
d010aa7
Update makeConfig API to use destructured parameters and increase fil…
konard Nov 14, 2025
599e03d
Enable Bun and Deno CI tests
konard Nov 14, 2025
239593d
Fix CI: Disable Deno tests, keep Bun enabled
konard Nov 14, 2025
fecd738
Update README to reflect makeConfig() API and hero example
konard Nov 14, 2025
9b7b363
Use lino-env from NPM and enable Deno tests
konard Nov 14, 2025
800fab5
Fix Deno compatibility: use node: prefix for fs and path imports
konard Nov 14, 2025
823bb9c
Add --allow-env flag to Deno test command
konard Nov 14, 2025
8e6661a
Disable Deno tests: node:test beforeEach/afterEach not supported
konard Nov 14, 2025
69da1ad
Update lino-env to ^0.2.5 and enable Deno tests with trusted NPM publ…
konard Nov 15, 2025
bb776bb
Refactor tests to remove beforeEach/afterEach for Deno compatibility
konard Nov 15, 2025
ab33be7
Fix formatting and add --allow-write for Deno tests
konard Nov 15, 2025
4bff575
Reorganize project structure: move source to src/ and tests to tests/
konard Nov 15, 2025
f8d3820
Update package.json
konard Nov 15, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Changesets

Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
with multi-package repos, or single-package repos to help you version and publish your code. You can
find the full documentation for it [in our repository](https://github.com/changesets/changesets)

We have a quick list of common questions to get you started engaging with this project in
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
11 changes: 11 additions & 0 deletions .changeset/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": false,
"fixed": [],
"linked": [],
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": []
}
18 changes: 18 additions & 0 deletions .changeset/implement-make-config-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
'lino-arguments': minor
---

Implement makeConfig() API with unified configuration system

This major update implements the requested API design with the following features:

- **makeConfig() function**: Main API that accepts configuration with lenv, env, getenv, and yargs options
- **Multi-source configuration**: Automatically loads from dotenvx (.env), lino-env (.lenv), environment variables, and CLI arguments
- **Priority system**: CLI arguments > getenv defaults > --configuration flag > .lenv file > .env file
- **Case conversion utilities**: Support for UPPER_CASE, camelCase, PascalCase, snake_case, and kebab-case
- **getenv() helper**: Intelligent environment variable lookup across all case formats with type preservation
- **Deprecation warnings**: Yellow console warnings when using dotenvx/.env files
- **--configuration flag**: Special CLI option to dynamically specify .lenv file path
- **Automatic key mapping**: kebab-case CLI options automatically convert to camelCase in result object

The implementation follows the hero example pattern from the PR comments, making it simple to use with sensible defaults while allowing full customization when needed.
322 changes: 322 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,322 @@
name: CI/CD

on:
push:
branches:
- main
pull_request:
types: [opened, synchronize, reopened]

concurrency: ${{ github.workflow }}-${{ github.ref }}

jobs:
# Changeset check - only runs on PRs
changeset-check:
name: Check for Changesets
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'

- name: Install dependencies
run: npm install

- name: Check for changesets
run: |
# Skip changeset check for automated version PRs
if [[ "${{ github.head_ref }}" == "changeset-release/"* ]]; then
echo "Skipping changeset check for automated release PR"
exit 0
fi

# Count changeset files (excluding README.md and config.json)
CHANGESET_COUNT=$(find .changeset -name "*.md" ! -name "README.md" | wc -l)

echo "Found $CHANGESET_COUNT changeset file(s)"

# Ensure exactly one changeset file exists
if [ "$CHANGESET_COUNT" -eq 0 ]; then
echo "::error::No changeset found. Please add a changeset by running 'npm run changeset' and commit the result."
exit 1
elif [ "$CHANGESET_COUNT" -gt 1 ]; then
echo "::error::Multiple changesets found ($CHANGESET_COUNT). Each PR should have exactly ONE changeset."
echo "::error::Found changeset files:"
find .changeset -name "*.md" ! -name "README.md" -exec basename {} \;
exit 1
fi

# Get the changeset file
CHANGESET_FILE=$(find .changeset -name "*.md" ! -name "README.md" | head -1)
echo "Validating changeset: $CHANGESET_FILE"

# Check if changeset has a valid type (major, minor, or patch)
if ! grep -qE "^['\"]lino-arguments['\"]:\s+(major|minor|patch)" "$CHANGESET_FILE"; then
echo "::error::Changeset must specify a version type: major, minor, or patch"
echo "::error::Expected format in $CHANGESET_FILE:"
echo "::error::---"
echo "::error::'lino-arguments': patch"
echo "::error::---"
echo "::error::"
echo "::error::Your description here"
cat "$CHANGESET_FILE"
exit 1
fi

# Extract description (everything after the closing ---) and check it's not empty
DESCRIPTION=$(awk '/^---$/{count++; next} count==2' "$CHANGESET_FILE" | sed '/^[[:space:]]*$/d')

if [ -z "$DESCRIPTION" ]; then
echo "::error::Changeset must include a description of the changes"
echo "::error::The description should appear after the closing '---' in the changeset file"
echo "::error::Current content of $CHANGESET_FILE:"
cat "$CHANGESET_FILE"
exit 1
fi

echo "✅ Changeset validation passed"
echo " Type: $(grep -E "^['\"]lino-arguments['\"]:" "$CHANGESET_FILE" | sed "s/.*: //")"
echo " Description: $DESCRIPTION"

# Linting and formatting - runs after changeset check on PRs, immediately on main
lint:
name: Lint and Format Check
runs-on: ubuntu-latest
needs: [changeset-check]
if: always() && (github.event_name == 'push' || needs.changeset-check.result == 'success')
steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'

- name: Install dependencies
run: npm install

- name: Run ESLint
run: npm run lint

- name: Check formatting
run: npm run format:check

- name: Check file size limit
run: npm run check:file-size

# Test on Node.js - runs after changeset check on PRs, immediately on main
test-node:
name: Test on Node.js
runs-on: ubuntu-latest
needs: [changeset-check]
if: always() && (github.event_name == 'push' || needs.changeset-check.result == 'success')
steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'

- name: Install dependencies
run: npm install

- name: Run tests
run: npm test

# Test on Bun - runs after changeset check on PRs, immediately on main
test-bun:
name: Test on Bun
runs-on: ubuntu-latest
needs: [changeset-check]
if: always() && (github.event_name == 'push' || needs.changeset-check.result == 'success')
steps:
- uses: actions/checkout@v4

- name: Setup Node.js (for npm install)
uses: actions/setup-node@v4
with:
node-version: '20.x'

- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest

- name: Install dependencies with npm (supports GitHub packages)
run: npm install

- name: Run tests
run: bun test

# Test on Deno
test-deno:
name: Test on Deno
runs-on: ubuntu-latest
needs: [changeset-check]
if: always() && (github.event_name == 'push' || needs.changeset-check.result == 'success')
steps:
- uses: actions/checkout@v4

- name: Setup Node.js (for npm install)
uses: actions/setup-node@v4
with:
node-version: '20.x'

- name: Setup Deno
uses: denoland/setup-deno@v2
with:
deno-version: v2.x

- name: Install dependencies with npm
run: npm install

- name: Run tests
run: deno test --allow-read --allow-write --allow-env

# Release - only runs on main after tests pass
release:
name: Release
runs-on: ubuntu-latest
needs: [lint, test-node, test-bun, test-deno]
# Use always() to ensure this job runs even if changeset-check was skipped
# This is needed because lint/test jobs have a transitive dependency on changeset-check
if: always() && github.ref == 'refs/heads/main' && github.event_name == 'push' && needs.lint.result == 'success' && needs.test-node.result == 'success' && needs.test-bun.result == 'success' && needs.test-deno.result == 'success'
permissions:
contents: write
pull-requests: write
id-token: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
registry-url: 'https://registry.npmjs.org'

- name: Install dependencies
run: npm install

- name: Upgrade npm for OIDC trusted publishing support
run: npm install -g npm@latest

- name: Check for changesets
id: check_changesets
run: |
# Count changeset files (excluding README.md and config.json)
CHANGESET_COUNT=$(find .changeset -name "*.md" ! -name "README.md" | wc -l)
echo "Found $CHANGESET_COUNT changeset file(s)"
echo "has_changesets=$([[ $CHANGESET_COUNT -gt 0 ]] && echo 'true' || echo 'false')" >> $GITHUB_OUTPUT

- name: Version packages and commit to main
if: steps.check_changesets.outputs.has_changesets == 'true'
id: version
run: |
# Configure git
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"

# Get current version before bump
OLD_VERSION=$(node -p "require('./package.json').version")
echo "Current version: $OLD_VERSION"

# Run changeset version to bump versions and update CHANGELOG
npm run changeset:version

# Get new version after bump
NEW_VERSION=$(node -p "require('./package.json').version")
echo "New version: $NEW_VERSION"
echo "new_version=$NEW_VERSION" >> $GITHUB_OUTPUT

# Check if there are changes to commit
if [[ -n $(git status --porcelain) ]]; then
echo "Changes detected, committing..."

# Stage all changes (package.json, package-lock.json, CHANGELOG.md, deleted changesets)
git add -A

# Commit with version number as message
git commit -m "$NEW_VERSION" \
-m "" \
-m "🤖 Generated with [Claude Code](https://claude.com/claude-code)"

# Push directly to main
git push origin main

echo "✅ Version bump committed and pushed to main"
echo "version_committed=true" >> $GITHUB_OUTPUT
else
echo "No changes to commit"
echo "version_committed=false" >> $GITHUB_OUTPUT
fi

- name: Publish to npm
if: steps.version.outputs.version_committed == 'true'
id: publish
run: |
# Pull the latest changes we just pushed
git pull origin main

# Publish to npm using OIDC trusted publishing
npm run changeset:publish

echo "published=true" >> $GITHUB_OUTPUT

# Get published version
PUBLISHED_VERSION=$(node -p "require('./package.json').version")
echo "published_version=$PUBLISHED_VERSION" >> $GITHUB_OUTPUT
echo "✅ Published lino-arguments@$PUBLISHED_VERSION to npm"

- name: Create GitHub Release
if: steps.publish.outputs.published == 'true'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
VERSION="${{ steps.publish.outputs.published_version }}"
TAG="v$VERSION"

echo "Creating GitHub release for $TAG..."

# Extract changelog entry for this version
# Read from CHANGELOG.md between this version and the next version marker
RELEASE_NOTES=$(awk "/## $VERSION/,/## [0-9]/" CHANGELOG.md | sed '1d;$d' | sed '/^$/d')

if [ -z "$RELEASE_NOTES" ]; then
RELEASE_NOTES="Release $VERSION"
fi

# Create release
gh release create "$TAG" \
--title "$VERSION" \
--notes "$RELEASE_NOTES" \
--repo ${{ github.repository }}

echo "✅ Created GitHub release: $TAG"

- name: Format GitHub release notes
if: steps.publish.outputs.published == 'true'
run: |
VERSION="${{ steps.publish.outputs.published_version }}"
TAG="v$VERSION"

# Get the release ID for this version
RELEASE_ID=$(gh api repos/${{ github.repository }}/releases/tags/$TAG --jq '.id' 2>/dev/null || echo "")

if [ -n "$RELEASE_ID" ]; then
echo "Formatting release notes for $TAG..."
node scripts/format-release-notes.mjs "$RELEASE_ID" "$TAG" "${{ github.repository }}"
echo "✅ Formatted release notes for $TAG"
else
echo "⚠️ Could not find release for $TAG"
fi
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
10 changes: 10 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"semi": true,
"trailingComma": "es5",
"singleQuote": true,
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"arrowParens": "always",
"endOfLine": "lf"
}
Loading