Skip to content

feat: shared env template fallback for dotenv bootstrap - #40

Open
jgs-jeeves wants to merge 1 commit into
mainfrom
feature/39-shared-env-template
Open

jgs-jeeves wants to merge 1 commit into
mainfrom
feature/39-shared-env-template

Conversation

@jgs-jeeves

Copy link
Copy Markdown
Collaborator

Closes #39

Summary

Adds a shared env template fallback to
esolveDotenvTarget for scope: 'env' targets, so a single template file can bootstrap every environment instead of requiring an identical per-env template (e.g. one shared file instead of .env.dev.local.template, .env.stg.local.template, .env.prod.local.template).

Resolution order (per path, in the configured \searchOrder)

  1. Existing loop (unchanged): for each path, check the env target (e.g. .env.dev.local); if missing, check its env-specific template (e.g. .env.dev.local.template). First match wins, across all paths.
  2. New, only when step 1 finds nothing AND \scope === 'env': a second pass over the same ordered paths looking for the shared env template. Its filename is built the same way as the env target, but with a fixed token (\sharedEnvTemplateToken, default 'env') in place of the env name, e.g. .env.env.local.template\ for .env..local, or .env.env.template\ for .env.. It respects \dotenvToken, \privateToken, and \ emplateExtension. When found, \ argetPath\ is the env target in that same directory, and \ emplatePath\ is the shared template.
  3. If nothing is found, the thrown error lists every candidate filename checked (targets, env-specific templates, and the shared template when \scope === 'env').

An env-specific template always overrides the shared one. Global scope (.env, .env.local) never uses the shared template fallback — .env.local.template\ remains the template for .env.local\ only.

API changes

  • New optional \sharedEnvTemplateToken?: string\ (default 'env') on \ResolveDotenvTargetOptions\ (\src/dotenv/edit/resolveDotenvTarget.ts) and on \EditDotenvFileOptions\ (\src/dotenv/edit/types.ts), threaded through \editDotenvFile.
  • No new runtime dependencies.

Tests added (\src/dotenv/edit/resolveDotenvTarget.test.ts, \src/dotenv/edit/editDotenvFile.test.ts)

  • Env-specific template wins over the shared one (same directory and different directories).
  • Shared template used when no env-specific template exists, for both private and public privacy.
  • Global scope ignores the shared template entirely (including .env.local.template\ staying scoped to .env.local).
  • Custom \sharedEnvTemplateToken.
  • Custom \ emplateExtension/\privateToken/\dotenvToken.
  • Multiple paths with forward and reverse search order for the shared template.
  • An existing target wins over the shared template and every template.
  • The thrown error lists every candidate filename checked.
  • \editDotenvFile\ bootstraps from the shared template and reports \createdFromTemplate: true.

Docs

Updated \guides/dotenv-editor.md, \guides/stan-assistant-guide/editing.md, and \guides/stan-assistant-guide/index.md\ to document the shared template fallback and resolution order. \CHANGELOG.md\ is git-cliff generated and was not hand-edited.

Quality gates (all green locally)


  • pm run lint\ — 0 errors, 0 warnings

  • pm run typecheck\ — clean

  • pm run test\ — 255 passed, 1 skipped (33 in dotenv/edit, including 17 new)

  • pm run build\ — clean

  • pm run knip\ — pre-existing \ s-extra\ devDependency hint, confirmed present on baseline \main\ before this change (unrelated)

  • pm run docs\ — 0 errors, 1 pre-existing warning (\commandPath\ link), confirmed present on baseline \main\ before this change (unrelated)

Add a shared env template fallback to resolveDotenvTarget for
scope: 'env' targets. When neither the target nor an env-specific
template exists anywhere under the search paths, fall back to a
shared template named with a fixed token (sharedEnvTemplateToken,
default 'env') in place of the real env name, e.g.
.env.env.local.template for .env.<env>.local.

- New optional sharedEnvTemplateToken on ResolveDotenvTargetOptions
  and EditDotenvFileOptions, threaded through editDotenvFile.
- Env-specific templates always win over the shared template.
- Global scope never uses the shared template fallback.
- Error message now lists every candidate filename checked.
- Docs updated in guides/dotenv-editor.md and the STAN guide.

Closes #39

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Documentation inaccuracies, a broken anchor, and test-suite issues should be addressed.

Review effort: Balanced
Findings: 3 Low severity

Open (3)
What changed in this PR

Adds shared environment-template fallback support for dotenv bootstrapping.

Changes:

  • Adds configurable shared-template resolution.
  • Threads the option through editDotenvFile.
  • Adds tests and documentation.
File Description
src/​dotenv/​edit/​types.ts Adds the shared-template option.
src/​dotenv/​edit/​resolveDotenvTarget.ts Implements fallback resolution.
src/​dotenv/​edit/​resolveDotenvTarget.test.ts Tests resolution behavior.
src/​dotenv/​edit/​editDotenvFile.ts Forwards the new option.
src/​dotenv/​edit/​editDotenvFile.test.ts Tests shared-template bootstrapping.
guides/​dotenv-editor.md Documents resolution semantics.
guides/​stan-assistant-guide/​editing.md Summarizes fallback behavior.
guides/​stan-assistant-guide/​index.md Adds fallback reference.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread guides/dotenv-editor.md
Comment on lines +161 to +165
Resolution order per path, in the configured `searchOrder`:

1. The target itself (e.g. `.env.dev.local`) — if it exists anywhere under `paths`, it wins outright.
2. The env-specific template (e.g. `.env.dev.local.template`) — this **always** takes priority over the shared template when present, in any searched path.
3. Only when neither of the above is found anywhere under `paths`: the shared env template (e.g. `.env.env.local.template`), searched again across the same ordered paths.
- `searchOrder: 'reverse'` (default): last path wins (highest precedence).
- `searchOrder: 'forward'`: first path wins.
- Template bootstrap: if the selected target is missing but `<target>.<templateExtension>` exists (default extension: `template`), the template is copied first and then edited in place.
- Shared env template fallback (`scope: 'env'` only): if neither the target nor its env-specific template exists anywhere under `paths`, a shared template named with a fixed token in place of the env name (`sharedEnvTemplateToken`, default `'env'`) is tried next — e.g. `.env.env.local.template` for `.env.<env>.local`. An env-specific template always wins over the shared one; global scope never uses this fallback. See [Dotenv editor](../dotenv-editor.md#shared-env-template-fallback-only) for the full resolution order.
).toThrow(/env is required/i);
});

describe('shared env template fallback', () => {

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: shared env template fallback for dotenv bootstrap

2 participants