Skip to content

feat(cli): add --enum-style const to types and generate - #2070

Merged
ChiragAgg5k merged 2 commits into
mainfrom
feat/cli-types-const-enums
Oct 16, 2026
Merged

ChiragAgg5k merged 2 commits into
mainfrom
feat/cli-types-const-enums

Conversation

@ChiragAgg5k

@ChiragAgg5k ChiragAgg5k commented Oct 15, 2026 •

Copy link
Copy Markdown
Member

What

Adds an opt-in --enum-style enum|const flag to appwrite types (TypeScript only) and appwrite generate. The default stays enum, so existing output is byte-for-byte unchanged.

With --enum-style const, an enum column is emitted as an as const object plus a union type of the same name:

export const ItemsRunItemOrigin = {
    TEMPLATE: "template",
    CARRYOVER: "carryover",
    ADHOC: "adhoc"
} as const;

export type ItemsRunItemOrigin = (typeof ItemsRunItemOrigin)[keyof typeof ItemsRunItemOrigin];

Consumers keep both usages they had with enum: ItemsRunItemOrigin.CARRYOVER as a value and ItemsRunItemOrigin as a type. Plain string literals such as 'adhoc' are now assignable too.

Why

enum is not erasable syntax. A .ts file containing one fails tsc --erasableSyntaxOnly (TS1294) and Node's built-in type stripping refuses to load it (ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX). That hits appwrite types ./src/appwrite.ts and every appwrite generate output, since generate writes types.ts.

Design notes

  • .d.ts destinations. The issue's form cannot go into a declaration file: an ambient const may not carry an object initializer (TS1254). When the types destination ends in .d.ts, .d.mts or .d.cts (including the default appwrite.d.ts), the const style emits export declare const X: { readonly A: "a"; ... }; with the same union type. The default enum output in a .d.ts is left alone; tsc does not flag ambient enums under erasableSyntaxOnly.
  • generate is included. The generated databases.ts only uses the enum names as types, never their members, so swapping the declaration form changes nothing else. Both commands now render through the same typegen.TypeScript.DeclareEnum, which replaces the duplicated enum printer in generator/typescript.go. The default output is identical to before, and the existing golden files still match.
  • JavaScript is untouched. -l js already emits JSDoc string-union typedefs, not enums.
  • --enum-style const with a non-TypeScript -l is rejected (--enum-style is only supported for ts, not php), and so is an unknown value.

Reproduction

Against Appwrite Cloud staging: a tablesdb database audit277 with table Items and a required enum column runItemOrigin (template, carryover, adhoc), then appwrite pull tables --force. BEFORE is the released 28.6.0 binary, AFTER is built from this branch. tsc is typescript@5.9.3, run as tsc --noEmit --strict --erasableSyntaxOnly --skipLibCheck false --module nodenext.

Before (appwrite types -l ts ./before/appwrite.ts):

export enum ItemsRunItemOrigin {
    TEMPLATE = "template",
    CARRYOVER = "carryover",
    ADHOC = "adhoc"
}
before/appwrite.ts(6,13): error TS1294: This syntax is not allowed when 'erasableSyntaxOnly' is enabled.
$ node run-before.ts
SyntaxError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]: TypeScript enum is not supported in strip-only mode

After (appwrite types -l ts --enum-style const ./after/appwrite.ts):

export const ItemsRunItemOrigin = {
    TEMPLATE: "template",
    CARRYOVER: "carryover",
    ADHOC: "adhoc"
} as const;

export type ItemsRunItemOrigin = (typeof ItemsRunItemOrigin)[keyof typeof ItemsRunItemOrigin];

tsc exits 0. It also exits 0 on a consumer that uses ItemsRunItemOrigin.CARRYOVER, the literal 'adhoc' and item.runItemOrigin as ItemsRunItemOrigin. node run-after.ts prints carryover.

After, default destination (appwrite types -l ts --enum-style const ./after → appwrite.d.ts):

export declare const ItemsRunItemOrigin: {
    readonly TEMPLATE: "template";
    readonly CARRYOVER: "carryover";
    readonly ADHOC: "adhoc";
};

export type ItemsRunItemOrigin = (typeof ItemsRunItemOrigin)[keyof typeof ItemsRunItemOrigin];

tsc exits 0.

generate: appwrite generate -l typescript --server false with 28.6.0 fails tsc on types.ts(3,13): error TS1294. With --enum-style const from this branch, tsc exits 0 on all four generated files.

Without the flag, the AFTER binary's types output is identical to 28.6.0's apart from the invocation recorded in the header comment.

Tests

  • internal/typegen: new golden files ts.const.appwrite.ts (source) and ts.const.appwrite.d.ts (declaration). Also a check that Declaration alone leaves the existing ts.loose.appwrite.d.ts baseline unchanged.
  • internal/generator: new golden file server.const.types.ts for generate --enum-style const.
  • internal/cmd: the flag surface for both commands now includes --enum-style. Also covered: the enum default, rejection of unknown values, and rejection of const for non-TypeScript languages.
  • All three const golden files, plus the full generate output built from them, pass tsc 5.9.3 under --strict --erasableSyntaxOnly.
  • php example.php cli, gofmt -l clean, go build ./... && go vet ./... && go test ./... in examples/cli, and composer refactor:check all pass.

Fixes appwrite/sdk-for-cli#277

Closes #2071

TypeScript enums are not erasable syntax, so the .ts files that types and generate write are rejected by erasableSyntaxOnly and by Node's type stripping. The const style emits an as-const object plus a same-named union type, which keeps X.MEMBER and X-as-a-type working for consumers. A .d.ts destination gets a declared const instead, since an ambient const cannot carry an object initializer. The default stays enum so existing output does not change.

Fixes appwrite/sdk-for-cli#277
@hansi-codes

hansi-codes Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

🟢 Tier S · Ready to merge

The new option is threaded through both commands, and the implementation and generated output are covered by baseline tests.

Adds an opt-in --enum-style enum|const option to the CLI’s types and generate commands. The const style emits an as const object and a matching union type, with ambient declarations for .d.ts destinations; the default enum output remains unchanged.

Verdict New comments Fixed Still open
✅ Approved 0 0 0
📂 Walkthrough · 12
File Change
src/SDK/Language/CLI.php Registers the new enum-style implementation and its source, declaration, and generate test fixtures in generated CLI projects.
templates/cli/internal/cmd/generate.go Adds the enum-style flag to generate and passes its parsed value to the generator.
templates/cli/internal/cmd/types.go Adds the enum-style flag to types, validates its supported language and detects declaration-file destinations.
templates/cli/internal/cmd/typegen_commands_test.go Covers the flag surfaces, default style, and invalid style/language handling.
templates/cli/internal/generator/generator.go Adds enum style to generator options.
templates/cli/internal/generator/typescript.go Uses the shared TypeScript enum declaration renderer for generated SDK types.
templates/cli/internal/generator/generator_test.go Adds a baseline test for const-style generated types.
templates/cli/internal/generator/testdata/server.const.types.ts Adds the expected const-style generated types fixture.
templates/cli/internal/typegen/enum_style.go Defines enum styles, supported-style choices, and style parsing.
templates/cli/internal/typegen/typescript.go Renders enum, const-object, and ambient declaration forms through a shared declaration method.
templates/cli/internal/typegen/language_test.go Adds source and declaration const-style baselines and confirms the default declaration output is unchanged.
templates/cli/internal/typegen/testdata/ts.const.appwrite.ts and templates/cli/internal/typegen/testdata/ts.const.appwrite.d.ts Add source and declaration fixtures for const-style TypeScript enums.

Merged main (c6c2531); no changes to this PR's code since 40eeaa7 · Details · Comment @hansi-codes review to re-run, or mention @hansi-codes with a question.

@hansi-codes hansi-codes Bot 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.

🟢 Tier S · Looks good to merge. Summary

@ChiragAgg5k
ChiragAgg5k merged commit 22a1737 into main Oct 16, 2026
61 checks passed
@ChiragAgg5k
ChiragAgg5k deleted the feat/cli-types-const-enums branch October 16, 2026 08:05
@ChiragAgg5k ChiragAgg5k mentioned this pull request Oct 16, 2026
2 tasks done
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.

Add --enum-style const to CLI types and generate TypeScript enums

1 participant