Skip to content

Non-interactive mode for @jahia/create-module #701

Description

@romain-pm

Part of EPIC #698.

npm init @jahia/module is a pleasant clack wizard, but it is interactive-only: three prompts (name, path, template), no flags, and piped stdin confuses the prompt rendering. Scripting it requires expect. This blocks CI pipelines, documentation-as-scripts, and AI coding agents — all of which scaffold projects unattended (this evaluation had to drive the wizard with an expect script).

Proposal: accept CLI flags that skip the corresponding prompts, e.g.

npm init @jahia/module@latest my-module -- --template hello-world --path ./my-module --yes

--template values: hello-world | template-set | module (mirroring the three presets). --yes accepts defaults for anything unspecified. Print the same outro.

For comparison: npm create astro@latest -- --template minimal --install --no-git --yes scaffolds unattended in one line.


Technical plan (agent-executable)

Written for execution by a Claude (Opus/Sonnet) agent inside the Jahia Cortex harness. Pure Node/JS change — no running Jahia needed.

Harness setup

  1. Open Cortex; cortex-sourcesjavascript-modules @ main.
  2. Node ≥ 22 required (.node-version), yarn install at repo root.

Code map

File Role
javascript-create-module/index.js The whole CLI: 3 @clack/prompts (name → path → template preset), then template copy + $MODULE/$NAMESPACE/$VERSION templating.
javascript-create-module/tests/create-templatesSet-project.test.js Existing node --test test — follow its style.
javascript-create-module/README.md, docs/1-getting-started/1-dev-environment/README.md Usage docs to update.

Design

  • Flags via node:util parseArgs (no new dependency): positional name; --template <hello-world|template-set|module>; --path <dir>; --yes; --help.
  • Single source of truth: extract the existing wizard's three template presets into a TEMPLATES map ({ "hello-world": ["module","template-set","hello-world"], "template-set": ["module","template-set"], "module": ["module"] }) consumed by BOTH the wizard options and the flag values.
  • Resolution matrix:
    • Every input resolvable from flags/positional (with --yes filling defaults: path = cwd/<name>, template = hello-world) → zero prompts, same outro as today.
    • Partial flags + interactive TTY → prompt only the missing inputs (pass resolved values as initialValue).
    • Missing input + non-TTY (!process.stdout.isTTY) → print usage to stderr, process.exit(1). Never hang waiting on stdin.
  • Validation: reuse the wizard's exact validators (name regex ^[a-z][a-z0-9-]*$, path-must-not-exist) for flag values; identical error messages, exit 1 on violation.
  • --help: usage text listing flags + the three template values; exit 0.

Implementation steps

  1. Refactor index.js: extract TEMPLATES, validateName(value), validatePath(value) from the inline prompt config (behavior-preserving — the wizard path must remain byte-identical in UX).
  2. Add parseArgs handling before the wizard; branch per the matrix above.
  3. Keep the Node ≥22 warning for the wizard; in flag mode, make it a hard error only if parseArgs/features actually require it (they don't below 22 — keep the warning).
  4. Update README.md + getting-started doc with the one-liner:
    npm init @jahia/module@latest my-module -- --template hello-world --yes

Verification

New javascript-create-module/tests/non-interactive.test.js (node --test, style of the existing test), covering:

  1. node index.js foo --template hello-world --path <tmpdir>/foo --yes → exit 0; assert package.json has "name": "foo", settings/definitions.cnd exists with namespace foo templated, .env/.vscode dot-renaming happened.
  2. --template template-set and --template module → preset-specific files present/absent (e.g. hello-world components only in preset 1).
  3. Invalid name (Foo!) via flag → exit 1, stderr contains the same message as the wizard.
  4. Existing target path → exit 1.
  5. Non-TTY with no flags (spawn with stdio: "pipe") → exit 1 + usage, process terminates (guard with a 5s timeout in the test).
  6. --help → exit 0, usage on stdout.
    Regression: run the existing wizard test; manually spot-check the interactive flow still prompts (TTY only — cannot be CI-automated, note it in the PR).

Acceptance criteria

  • Fully non-interactive scaffold works with the documented one-liner (CI-provable: the new tests run in the repo's node --test suite).
  • Interactive wizard UX unchanged when no flags are passed on a TTY.
  • Non-TTY without sufficient flags fails fast with usage — never hangs.
  • Wizard and flags share one validation + template table (no duplication).
  • README + getting-started updated.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions