Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 3 additions & 2 deletions .svelteesp32rc.example.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
{
"_comment": "This RC file demonstrates npm variable interpolation. Variables like $npm_package_version are replaced with values from package.json in the same directory.",
"engine": "psychic",
"sourcepath": "./demo/svelte/dist",
"outputfile": "./output.h",
"etag": "true",
"gzip": "true",
"cachetime": 0,
"created": false,
"version": "",
"version": "v$npm_package_version",
"espmethod": "initSvelteStaticFiles",
"define": "SVELTEESP32",
"define": "$npm_package_name",
"exclude": ["*.map", "*.md", "test/**/*"]
}
55 changes: 55 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,60 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [1.13.0] - 2025-12-04

### Added

- **NPM Package Variable Interpolation**: RC files now support automatic variable substitution from `package.json`
- Syntax: `$npm_package_<field_name>` (e.g., `$npm_package_version`, `$npm_package_name`)
- Supported in all string fields: `version`, `define`, `sourcepath`, `outputfile`, `espmethod`, and `exclude` patterns
- Nested field support: `$npm_package_repository_type` accesses `packageJson.repository.type`
- Multiple variables in one field: `"$npm_package_name-v$npm_package_version"` → `"myapp-v1.2.3"`
- Smart regex pattern stops at underscore + uppercase (e.g., `$npm_package_name_STATIC` → interpolates `name`, keeps `_STATIC`)
- `package.json` must exist in same directory as RC file
- Clear error messages when variables are used but `package.json` not found, listing affected fields
- Unknown variables left unchanged (not an error) for flexibility
- 5 new core functions in `src/commandLine.ts` (lines 125-220):
- `findPackageJson()` - Locates package.json in RC file directory
- `parsePackageJson()` - Reads and parses package.json with error handling
- `getNpmPackageVariable()` - Extracts values using underscore-separated path traversal
- `checkStringForNpmVariable()` - Helper for variable detection
- `hasNpmVariables()` - Optimization to skip interpolation when not needed
- `interpolateNpmVariables()` - Main function processing all string fields
- 20+ comprehensive unit tests in `test/unit/commandLine.test.ts` (lines 604-952):
- Simple field extraction (`$npm_package_version`)
- Nested field extraction (`$npm_package_repository_type`)
- Multiple variables in one string
- Exclude array pattern interpolation
- Error handling (missing package.json, invalid JSON)
- Integration tests with RC file loading
- Updated `.svelteesp32rc.example.json` with variable interpolation examples

### Changed

- Enhanced RC file loading flow to interpolate npm variables before validation
- Interpolation integrated seamlessly: defaults → RC file (with interpolation) → CLI arguments
- Updated README.md with comprehensive "NPM Package Variable Interpolation" section:
- Syntax explanation and examples
- Nested field access documentation
- Multiple variable usage examples
- Requirements and error behavior
- Common use cases (version sync, dynamic naming, CI/CD)
- Updated CLAUDE.md with detailed implementation documentation:
- Core functions and processing flow
- Regex pattern design rationale
- Error handling strategy
- Testing coverage details
- Example usage and benefits
- All 118 tests passing (69 commandLine tests including 20 new npm interpolation tests)

### Use Cases

- **Version Synchronization**: `"version": "v$npm_package_version"` keeps header version in sync with package.json
- **Dynamic C++ Defines**: `"define": "$npm_package_name"` uses actual package name for defines
- **CI/CD Integration**: Reusable RC files across different projects with variable package names
- **Single Source of Truth**: Project metadata maintained only in package.json

## [1.12.1] - 2025-12-04

### Changed
Expand Down Expand Up @@ -320,6 +374,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- CLI interface with `-s`, `-e`, `-o` options
- `index.html` automatic default route handling

[1.13.0]: https://github.com/BCsabaEngine/svelteesp32/compare/v1.12.1...v1.13.0
[1.12.1]: https://github.com/BCsabaEngine/svelteesp32/compare/v1.12.0...v1.12.1
[1.12.0]: https://github.com/BCsabaEngine/svelteesp32/compare/v1.11.0...v1.12.0
[1.11.0]: https://github.com/BCsabaEngine/svelteesp32/compare/v1.10.0...v1.11.0
Expand Down
89 changes: 89 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -310,3 +310,92 @@ The generated header file includes a `//config:` comment at the top that display
- Shows all configuration parameters: `engine`, `sourcepath`, `outputfile`, `etag`, `gzip`, `cachetime`, `espmethod`, `define`, and `exclude` patterns
- Works consistently whether configuration comes from RC file, CLI arguments, or both
- Provides complete traceability of the configuration used for code generation

## NPM Package Variable Interpolation

RC files support automatic variable interpolation from `package.json`, allowing dynamic configuration based on project metadata.

**Feature:** Variables like `$npm_package_version` and `$npm_package_name` in RC files are automatically replaced with values from `package.json` located in the same directory as the RC file.

**Supported Fields:** All string fields in RC configuration:

- `version` - e.g., `"v$npm_package_version"`
- `define` - e.g., `"$npm_package_name_STATIC"`
- `sourcepath` - e.g., `"./$npm_package_name/dist"`
- `outputfile` - e.g., `"./output_$npm_package_version.h"`
- `espmethod` - e.g., `"init$npm_package_name"`
- `exclude` patterns - e.g., `["$npm_package_name.map"]`

**Variable Syntax:**

- Simple fields: `$npm_package_version` → `packageJson.version`
- Nested fields: `$npm_package_repository_type` → `packageJson.repository.type`
- Multiple variables: `"$npm_package_name-v$npm_package_version"` → `"myapp-v1.2.3"`

**Implementation** (`src/commandLine.ts` lines 125-220):

**Core Functions:**

1. **`findPackageJson(rcFilePath: string)`** - Locates package.json in the same directory as RC file
2. **`parsePackageJson(packageJsonPath: string)`** - Reads and parses package.json with error handling
3. **`getNpmPackageVariable(packageJson, variableName)`** - Extracts values from package.json using underscore-separated path segments (e.g., `$npm_package_repository_type` traverses `packageJson.repository.type`)
4. **`checkStringForNpmVariable(value)`** - Helper to check if a string contains npm package variables
5. **`hasNpmVariables(config)`** - Quick check if RC config contains any npm variables (optimization to skip interpolation when not needed)
6. **`interpolateNpmVariables(config, rcFilePath)`** - Main interpolation function that processes all string fields

**Processing Flow:**

1. Load RC file JSON
2. **Check for npm variables** - If present, find and parse package.json
3. **Interpolate variables** - Replace `$npm_package_*` patterns using regex: `/\$npm_package_[\dA-Za-z]+(?:_[a-z][\dA-Za-z]*)*/g`
4. Validate interpolated configuration
5. Merge with CLI arguments

**Error Handling:**

- If variables are used but package.json not found: Throws error listing affected fields
- If variable doesn't exist in package.json: Left unchanged (not an error)
- If package.json is invalid JSON: Clear error message with file path

**Regex Pattern Design:**

- Matches: `$npm_package_version`, `$npm_package_repository_type`
- Stops at: `_STATIC`, `_CONSTANT` (underscore followed by uppercase)
- Example: `"$npm_package_name_STATIC"` → interpolates `name`, keeps `_STATIC` suffix

**Testing** (`test/unit/commandLine.test.ts` lines 604-952):

- 20+ comprehensive tests covering all edge cases
- Tests for simple fields, nested fields, multiple variables, error scenarios
- 100% coverage of new interpolation functions

**Example Usage:**

```json
// .svelteesp32rc.json
{
"engine": "psychic",
"version": "v$npm_package_version",
"define": "$npm_package_name",
"sourcepath": "./dist"
}

// package.json
{
"name": "esp32-webui",
"version": "2.1.0"
}

// Result after interpolation:
{
"version": "v2.1.0",
"define": "esp32-webui"
}
```

**Benefits:**

- **Version synchronization**: Header version automatically matches package version
- **Dynamic naming**: C++ defines use actual package name
- **CI/CD friendly**: Reusable RC files across projects
- **Consistency**: Single source of truth for project metadata
85 changes: 85 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ In order to be able to easily update OTA, it is important - from the users' poin

This npm package provides a solution for **inserting any JS client application into the ESP web server** (PsychicHttp and also ESPAsyncWebServer (https://github.com/ESP32Async/ESPAsyncWebServer) and ESP-IDF available, PsychicHttp is the default). For this, JS, html, css, font, assets, etc. files must be converted to binary byte array. Npm mode is easy to use and easy to **integrate into your CI/CD pipeline**.

> Starting with version v1.13.0, RC files support npm package variable interpolation

> Starting with version v1.12.0, you can use RC file for configuration

> Starting with version v1.11.0, you can exclude files by pattern
Expand Down Expand Up @@ -540,6 +542,89 @@ To keep defaults, explicitly list them in your RC file:
}
```

#### NPM Package Variable Interpolation

RC files support automatic variable interpolation from your `package.json`. This allows you to reference package.json fields in your RC configuration using npm-style variable syntax.

**Syntax:** `$npm_package_<field_name>`

**Supported in:** All string fields (`version`, `define`, `sourcepath`, `outputfile`, `espmethod`, `exclude` patterns)

**Example:**

```json
// .svelteesp32rc.json
{
"engine": "psychic",
"version": "v$npm_package_version",
"define": "$npm_package_name",
"sourcepath": "./dist",
"outputfile": "./output.h"
}
```

With `package.json` containing:

```json
{
"name": "my-esp32-app",
"version": "2.1.0"
}
```

The variables are automatically interpolated to:

```json
{
"version": "v2.1.0",
"define": "my_esp32_app"
}
```

**Nested Fields:**

You can access nested package.json fields using underscores:

```json
// package.json
{
"name": "myapp",
"repository": {
"type": "git",
"url": "https://github.com/user/repo.git"
}
}

// .svelteesp32rc.json
{
"version": "$npm_package_repository_type"
}
// Results in: "version": "git"
```

**Multiple Variables:**

Combine multiple variables in a single field:

```json
{
"version": "$npm_package_name-v$npm_package_version-release"
}
// Results in: "my-esp32-app-v2.1.0-release"
```

**Requirements:**

- `package.json` must exist in the same directory as the RC file
- If variables are used but `package.json` is not found, an error is thrown with details about which fields contain variables
- Unknown variables are left unchanged (e.g., `$npm_package_nonexistent` stays as-is)

**Use Cases:**

- **Version Synchronization:** Keep header version in sync with npm package version
- **Dynamic Naming:** Use package name for C++ defines automatically
- **CI/CD Integration:** Reusable RC files across projects with different package names

### Q&A

- **How big a frontend application can be placed?** If you compress the content with gzip, even a 3-4Mb assets directory can be placed. This is a serious enough amount to serve a complete application.
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "svelteesp32",
"version": "1.12.1",
"version": "1.13.0",
"description": "Convert Svelte (or any frontend) JS application to serve it from ESP32 webserver (PsychicHttp)",
"author": "BCsabaEngine",
"license": "ISC",
Expand Down
Loading