Skip to content

[create-cloudflare] Stop --lang hiding templates that have no language variants - #15677

Merged
tpmmorris merged 2 commits into
cloudflare:mainfrom
L4XB:fix/15649-lang-ts-template-filter
Sep 25, 2026
Merged

tpmmorris merged 2 commits into
cloudflare:mainfrom
L4XB:fix/15649-lang-ts-template-filter

Conversation

@L4XB

@L4XB L4XB commented Sep 16, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #15649.

--lang filters the template lists through templateSupportsLanguage in packages/create-cloudflare/src/templates.ts, which returns false for any template whose copyFiles is a single path or absent:

// If the template has no copyFiles or uses a single path, it doesn't support variants.
// In that case we assume that this template doesn't support the language specified.
if (!copyFiles || isVariantInfo(copyFiles)) {
	return false;
}

A template like that has one fixed language rather than a js/ts choice, so passing --lang hid it even when its language was exactly the one being asked for. The OpenAPI starter is declared as copyFiles: { path: "./ts" } in packages/create-cloudflare/templates/openapi/c3.ts, which is why it disappears under --lang ts. It is genuinely TypeScript, so this is the filter being wrong, not the template's metadata.

The same filter hits every other template with no language variants. filterTemplatesByLanguage is applied to all three maps, so under --lang ts the Framework Starter list drops from 18 entries to 3 — only astro, react and vue survive, because they are the only frameworks that declare js/ts variants. Most frameworks scaffold the app with their own CLI and only overlay Cloudflare-specific files (templates/hono/workers/templates is wrangler.jsonc, public/index.html and src/index.ts), so they have no variants either.

Repro

--lang ts with the template named directly turns the silent disappearance into a hard error, which makes the before/after easy to see without driving the prompts. Both runs are against dist/cli.js built from the tree under test.

Before, at 9515011dc:

$ node dist/cli.js ./a1 --type=openapi --lang=ts --no-deploy --no-git --no-open
│ category Application Starter
╰  ERROR  Error: Unknown application type provided: openapi.

$ node dist/cli.js ./a2 --framework=hono --lang=ts --no-deploy --no-git --no-open
│ category Framework Starter
├ Which development framework do you want to use? (skipped)
╰  ERROR  Error: Unsupported framework: hono

After:

$ node dist/cli.js ./b1 --type=openapi --lang=ts --no-deploy --no-git --no-open
│ category Application Starter
│ type API starter (OpenAPI compliant)
│ files copied to project directory

$ node dist/cli.js ./b2 --framework=hono --lang=ts --no-deploy --no-git --no-open
│ category Framework Starter
├ Which development framework do you want to use?
│ framework Hono

Dropping --lang ts from either command works on both sides, which is the difference the issue reports.

The change

A template that ships a single set of files now declares the --lang values it can be created with, and templateSupportsLanguage asks for that instead of assuming there is none:

  • languages?: string[] on TemplateConfig, and getTemplateLanguages, which reads copyFiles.variants keys when there are variants and languages otherwise.
  • There is no default. --lang is not passed to a framework's own CLI, so assuming both languages offered TypeScript-only frameworks under --lang js (Devin's finding: --framework qwik --lang js ran create-qwik playground and got a TypeScript project). Every template without variants declares what it can produce, and a test fails if one does not.
  • ["ts"]: openapi and react-router (their ./ts path), and the frameworks whose CLI only scaffolds TypeScript: analog, angular, hono, next, nuxt, qwik, redwood, tanstack-start, vike and waku. The evidence for each is either C3's own code (it copies or edits .ts files unconditionally for angular, hono, nuxt and waku, and qwik's c3.ts says "Qwik only has a typescript template"), or scaffolding the project exactly as C3 invokes the CLI: analog, qwik, redwood (create-rwsdk), tanstack-start and vike each produce a tsconfig.json and only TypeScript sources. create-vinext-app --help states it "always uses … TypeScript", and the opennext template is TypeScript.
  • ["js"]: pre-existing (its ./js path).
  • ["js", "ts"]: templates where the framework's own CLI offers the choice, through a prompt or flag that the e2e suite drives (docusaurus, solid, svelte, vue pages), C3's variant prompt (react pages), a user-chosen starter (gatsby), experimental create-next-app, and hello-world-assets-only, which ships no code.
  • Python is still only offered through an explicit copyFiles variant (./py on the hello-world family), so a template that does not declare one cannot produce it.

Python behaviour is unchanged, including the two cases covered by the e2e tests added in #11184:

$ node dist/cli.js ./p --category=demo --lang=python --no-deploy --no-git --no-open
# before and after, identically:
╰  ERROR  Error: No templates available for language "python" in the "demo" category.

$ node dist/cli.js ./h --category=hello-world --type=hello-world --lang=python --no-deploy --no-git --no-open
# before and after, identically:
│ type Worker only
│ lang Python (beta)

This is also compatible with the Python-only starters in #15636: they declare copyFiles.variants.python, so getTemplateLanguages returns ["python"] for them and they stay out of --lang ts. That PR touches the same region of templates.ts and will conflict textually.

Tests

filterTemplatesByLanguage is now exported so the new tests in src/__tests__/templates.test.ts can run it over the real template maps. They cover both directions: that a fixed-language template is kept for its own language, and that templates which cannot produce a language are still dropped, including the TypeScript-only frameworks under --lang js. A further test walks every template in all three maps, experimental ones included, and fails if a template without variants has no languages.

Against 9515011dc with only the new test file and the export keyword applied, so the import resolves:

 FAIL  src/__tests__/templates.test.ts > filterTemplatesByLanguage > should keep a TypeScript template that has no language variants
AssertionError: expected [ 'common', 'scheduled', 'queues' ] to include 'openapi'

 FAIL  src/__tests__/templates.test.ts > filterTemplatesByLanguage > should keep TypeScript frameworks that have no language variants
AssertionError: expected [ 'astro', 'react', 'vue' ] to deeply equal ArrayContaining{…}

- Expected
+ Received

- ArrayContaining [
-   "hono",
-   "next",
-   "nuxt",
-   "react-router",
-   "svelte",
-   "vike",
+ [
+   "astro",
+   "react",
+   "vue",
  ]

 Test Files  1 failed (1)
      Tests  2 failed | 22 passed (24)

On this branch:

 ✓ src/__tests__/templates.test.ts (24 tests) 22ms

 Test Files  1 passed (1)
      Tests  24 passed (24)

The four negative tests pass on both sides, which is what they are for.

Full create-cloudflare unit suite, vitest run --config ./vitest.config.mts:

# 9515011dc
 Test Files  2 failed | 19 passed (21)
      Tests  6 failed | 256 passed (262)

# this branch
 Test Files  2 failed | 19 passed (21)
      Tests  6 failed | 262 passed (268)

The same six tests fail on both sides — four in src/helpers/__tests__/args.test.ts and two printSummary snapshots in src/__tests__/dialog.test.ts. They are unrelated to this change and reproduce on an unmodified checkout; the local Node is 26.8.2 rather than the 22.22.1 the repo pins, which is the likely cause.

oxfmt --check, oxlint --deny-warnings --type-aware and tsc --noEmit are clean on the touched files.

The e2e tests in packages/create-cloudflare/e2e were not run — they scaffold real projects and install dependencies.


  • Tests
    • Tests included/updated
    • Automated tests not possible - manual testing has been completed as follows:
    • Additional testing not necessary because:
  • Public documentation
    • Cloudflare docs PR(s):
    • Documentation not necessary because: this restores the documented behaviour of --lang, which is described in --help as "The programming language of the template"; no user-facing option changes.

File and line references are against main @ 9515011dc5ecdc5abf3a0c685d80f78e307fb513.


Devin Review

…age variants

`templateSupportsLanguage` returned false for any template whose `copyFiles`
is a single path or absent, on the grounds that such a template declares no
variant key to match the language against. Passing `--lang` therefore hid
every template that has one fixed language rather than a js/ts choice, even
when that language was the one being asked for.

`create-cloudflare --lang ts` dropped `API starter (OpenAPI compliant)` from
the Application Starter list, and `--type=openapi --lang=ts` failed outright
with "Unknown application type provided: openapi". The same filter dropped 15
of the 18 framework starters, so `--framework=hono --lang=ts` failed with
"Unsupported framework: hono"; only astro, react and vue survived, because
those are the only frameworks that declare js/ts variants.

Templates that ship a single set of files now declare the languages they can
be created with, defaulting to JavaScript and TypeScript. Python filtering is
unchanged: it is only ever offered through an explicit `copyFiles` variant, so
a template without one is still left out of `--lang python` and the "No
templates available for language" error still fires for the demo category.

Fixes cloudflare#15649
@github-project-automation github-project-automation Bot moved this to Untriaged in workers-sdk Sep 16, 2026
@workers-devprod
workers-devprod requested review from a team and tpmmorris and removed request for a team September 16, 2026 13:56
@workers-devprod

Copy link
Copy Markdown
Contributor

Codeowners approval required for this PR:

  • @cloudflare/wrangler
Show detailed file reviewers
  • .changeset/eager-moons-declare.md: [@cloudflare/wrangler]
  • packages/create-cloudflare/src/tests/templates.test.ts: [@cloudflare/wrangler]
  • packages/create-cloudflare/src/templates.ts: [@cloudflare/wrangler]
  • packages/create-cloudflare/templates/openapi/c3.ts: [@cloudflare/wrangler]
  • packages/create-cloudflare/templates/pre-existing/c3.ts: [@cloudflare/wrangler]
  • packages/create-cloudflare/templates/react-router/c3.ts: [@cloudflare/wrangler]

devin-ai-integration[bot]

This comment was marked as resolved.

@pkg-pr-new

pkg-pr-new Bot commented Sep 16, 2026 •

Copy link
Copy Markdown
@cloudflare/autoconfig

npm i https://pkg.pr.new/cloudflare/workers-sdk/@cloudflare/autoconfig@15677

@cloudflare/build-output-utils

npm i https://pkg.pr.new/cloudflare/workers-sdk/@cloudflare/build-output-utils@15677

@cloudflare/codemods

npm i https://pkg.pr.new/cloudflare/workers-sdk/@cloudflare/codemods@15677

@cloudflare/config

npm i https://pkg.pr.new/cloudflare/workers-sdk/@cloudflare/config@15677

@cloudflare/containers-shared

npm i https://pkg.pr.new/cloudflare/workers-sdk/@cloudflare/containers-shared@15677

create-cloudflare

npm i https://pkg.pr.new/cloudflare/workers-sdk/create-cloudflare@15677

@cloudflare/deploy-helpers

npm i https://pkg.pr.new/cloudflare/workers-sdk/@cloudflare/deploy-helpers@15677

@cloudflare/kv-asset-handler

npm i https://pkg.pr.new/cloudflare/workers-sdk/@cloudflare/kv-asset-handler@15677

miniflare

npm i https://pkg.pr.new/cloudflare/workers-sdk/miniflare@15677

@cloudflare/pages-functions

npm i https://pkg.pr.new/cloudflare/workers-sdk/@cloudflare/pages-functions@15677

@cloudflare/pages-shared

npm i https://pkg.pr.new/cloudflare/workers-sdk/@cloudflare/pages-shared@15677

@cloudflare/runtime-types

npm i https://pkg.pr.new/cloudflare/workers-sdk/@cloudflare/runtime-types@15677

@cloudflare/unenv-preset

npm i https://pkg.pr.new/cloudflare/workers-sdk/@cloudflare/unenv-preset@15677

@cloudflare/vite-plugin

npm i https://pkg.pr.new/cloudflare/workers-sdk/@cloudflare/vite-plugin@15677

@cloudflare/vitest-plugin

npm i https://pkg.pr.new/cloudflare/workers-sdk/@cloudflare/vitest-plugin@15677

@cloudflare/workers-auth

npm i https://pkg.pr.new/cloudflare/workers-sdk/@cloudflare/workers-auth@15677

@cloudflare/workers-editor-shared

npm i https://pkg.pr.new/cloudflare/workers-sdk/@cloudflare/workers-editor-shared@15677

@cloudflare/workers-utils

npm i https://pkg.pr.new/cloudflare/workers-sdk/@cloudflare/workers-utils@15677

wrangler

npm i https://pkg.pr.new/cloudflare/workers-sdk/wrangler@15677

commit: dd984b7

@tpmmorris tpmmorris left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Please address Devin comments

@github-project-automation github-project-automation Bot moved this from Untriaged to In Review in workers-sdk Sep 17, 2026
…te instead of defaulting to both

--lang is not passed to a framework's own CLI, so defaulting a template
without variants to js and ts offered TypeScript-only frameworks under
--lang js: --framework qwik --lang js scaffolded a TypeScript project.

Drop the default. Every template without copyFiles variants now declares
the languages it can produce, and a test walks all three template maps
(experimental included) and fails if one does not. TypeScript only:
analog, angular, hono, next, nuxt, qwik, redwood, tanstack-start, vike
and waku. Both: templates whose framework CLI or C3 prompt offers the
choice (docusaurus, gatsby, react pages, solid, svelte, vue pages,
experimental next) and hello-world-assets-only, which ships no code.
@changeset-bot

changeset-bot Bot commented Sep 23, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: dd984b7

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
create-cloudflare Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@L4XB

L4XB commented Sep 23, 2026

Copy link
Copy Markdown
Contributor Author

@tpmmorris Addressed Devin's one finding in dd984b7: a template without language variants no longer defaults to both JavaScript and TypeScript, because that offered TypeScript-only frameworks such as Qwik under --lang js. Every such template now declares its languages from what its generator actually produces, a test enforces that across all template maps, and the changeset and PR description are updated to match. templates.test.ts passes (27 tests; the two new ones fail on the previous head), and tsc, oxlint and oxfmt are clean on the changed files. Details are in the thread.

@workers-devprod

workers-devprod commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Codeowners approval required for this PR:

  • ✅ @cloudflare/wrangler
Show detailed file reviewers

@L4XB

L4XB commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor Author

@tpmmorris the Devin finding is addressed in dd984b7, and Devin has marked it resolved.

  • Missing language metadata no longer defaults to both languages.
  • Every template without copyFiles variants now declares the languages it can produce:
    • TypeScript only: Qwik, Angular, Next and others.
    • Both: where the framework's CLI or the C3 prompt offers the choice.
  • A test walks all three template maps, experimental included, and fails if any template leaves its languages undeclared.

The one red check, Tests (Windows, fixtures), is unrelated to this PR: fixtures/no-bundle-import timed out in its 30 s beforeAll while starting its dev server, and this PR only touches create-cloudflare.

@tpmmorris tpmmorris left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

lgtm!

@workers-devprod workers-devprod left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Codeowners reviews satisfied

@github-project-automation github-project-automation Bot moved this from In Review to Approved in workers-sdk Sep 24, 2026
@tpmmorris
tpmmorris merged commit 884990d into cloudflare:main Sep 25, 2026
69 of 70 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

API template not appearing when passing --lang ts to create cloudflare

3 participants