@omnifyjp/ts 5.8.33 → 5.8.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -107,6 +107,7 @@ function resolveFromConfig(configPath) {
107
107
  tsOutput,
108
108
  tsPlatform: tsConfig?.platform,
109
109
  tsAuth: tsConfig?.auth,
110
+ tsEnumStyle: tsConfig?.enumStyle,
110
111
  laravelEnabled,
111
112
  laravelOverrides,
112
113
  };
@@ -127,6 +128,7 @@ program
127
128
  let tsOutput;
128
129
  let tsPlatform;
129
130
  let tsAuth;
131
+ let tsEnumStyle;
130
132
  let laravelEnabled = false;
131
133
  let laravelOverrides;
132
134
  let configDir = process.cwd();
@@ -151,6 +153,7 @@ program
151
153
  tsOutput = opts.output ? resolve(opts.output) : resolved.tsOutput;
152
154
  tsPlatform = resolved.tsPlatform;
153
155
  tsAuth = resolved.tsAuth;
156
+ tsEnumStyle = resolved.tsEnumStyle;
154
157
  laravelEnabled = resolved.laravelEnabled;
155
158
  laravelOverrides = resolved.laravelOverrides;
156
159
  }
@@ -178,6 +181,7 @@ program
178
181
  const files = generateTypeScript(input, {
179
182
  platform: tsPlatform,
180
183
  auth: tsAuth,
184
+ enumStyle: tsEnumStyle,
181
185
  });
182
186
  mkdirSync(join(tsOutput, 'base'), { recursive: true });
183
187
  mkdirSync(join(tsOutput, 'enum'), { recursive: true });
@@ -15,8 +15,23 @@ export declare function schemaToEnum(schema: SchemaDefinition, options: Generato
15
15
  export declare function generateEnums(schemas: Record<string, SchemaDefinition>, options: GeneratorOptions): TSEnum[];
16
16
  /** Generate enums from plugin enums (customTypes.enums in schemas.json). */
17
17
  export declare function generatePluginEnums(pluginEnums: Record<string, string[]>, _options: GeneratorOptions): TSEnum[];
18
- /** Format a TypeScript enum with helpers (Values array, type guard, label getter). */
19
- export declare function formatEnum(enumDef: TSEnum): string;
18
+ /** Format a TypeScript enum with helpers (Values array, type guard, label getter).
19
+ *
20
+ * Two emission shapes (issue #103 Issue 1):
21
+ *
22
+ * - `'enum'` (DEFAULT): native `export enum X { ... }` — backwards-
23
+ * compatible with every project that depended on TS enum semantics
24
+ * (declaration merging via namespace, etc.) before v5.8.34.
25
+ *
26
+ * - `'const'`: `export const X = {...} as const; export type X = ...` —
27
+ * compiles under TS 5.5+ `erasableSyntaxOnly` (Vite 7 default).
28
+ * Call-site ergonomics identical to enum: `X.User === 'user'` works,
29
+ * string union narrowing works, all helper signatures unchanged.
30
+ *
31
+ * Pass `style` to pick. Default preserves the pre-v5.8.34 behavior so an
32
+ * upgrade without config change doesn't break consumer code.
33
+ */
34
+ export declare function formatEnum(enumDef: TSEnum, style?: 'enum' | 'const'): string;
20
35
  /** Format a TypeScript type alias with helpers. */
21
36
  export declare function formatTypeAlias(alias: TSTypeAlias): string;
22
37
  /** Result of extracting inline enums. */
@@ -97,16 +97,45 @@ function lowerFirst(str) {
97
97
  function escapeString(str) {
98
98
  return str.replace(/\\/g, '\\\\').replace(/'/g, "\\'");
99
99
  }
100
- /** Format a TypeScript enum with helpers (Values array, type guard, label getter). */
101
- export function formatEnum(enumDef) {
100
+ /** Format a TypeScript enum with helpers (Values array, type guard, label getter).
101
+ *
102
+ * Two emission shapes (issue #103 Issue 1):
103
+ *
104
+ * - `'enum'` (DEFAULT): native `export enum X { ... }` — backwards-
105
+ * compatible with every project that depended on TS enum semantics
106
+ * (declaration merging via namespace, etc.) before v5.8.34.
107
+ *
108
+ * - `'const'`: `export const X = {...} as const; export type X = ...` —
109
+ * compiles under TS 5.5+ `erasableSyntaxOnly` (Vite 7 default).
110
+ * Call-site ergonomics identical to enum: `X.User === 'user'` works,
111
+ * string union narrowing works, all helper signatures unchanged.
112
+ *
113
+ * Pass `style` to pick. Default preserves the pre-v5.8.34 behavior so an
114
+ * upgrade without config change doesn't break consumer code.
115
+ */
116
+ export function formatEnum(enumDef, style = 'enum') {
102
117
  const { name, values, comment } = enumDef;
103
118
  const parts = [];
104
119
  if (comment) {
105
120
  parts.push(`/**\n * ${comment}\n */\n`);
106
121
  }
107
- // Enum definition
108
- const enumValues = values.map(v => ` ${v.name} = '${v.value}',`).join('\n');
109
- parts.push(`export enum ${name} {\n${enumValues}\n}\n\n`);
122
+ if (style === 'const') {
123
+ // Const object works under erasableSyntaxOnly. Identical access at
124
+ // call sites: `X.User === 'user'` (literal string equality).
125
+ const enumValues = values.map(v => ` ${v.name}: '${v.value}',`).join('\n');
126
+ parts.push(`export const ${name} = {\n${enumValues}\n} as const;\n\n`);
127
+ // Type alias — string union derived from the const object's values.
128
+ // The `keyof typeof` extraction is the canonical TS pattern for this.
129
+ parts.push(`export type ${name} = typeof ${name}[keyof typeof ${name}];\n\n`);
130
+ }
131
+ else {
132
+ // Native `enum` — pre-v5.8.34 default. Some downstream projects
133
+ // depend on declaration-merging or other TS-enum-specific semantics
134
+ // that the const-object pattern can't replicate, so we keep this
135
+ // available as the safe upgrade path.
136
+ const enumValues = values.map(v => ` ${v.name} = '${v.value}',`).join('\n');
137
+ parts.push(`export enum ${name} {\n${enumValues}\n}\n\n`);
138
+ }
110
139
  // Values array
111
140
  parts.push(`/** All ${name} values */\n`);
112
141
  parts.push(`export const ${name}Values = Object.values(${name}) as ${name}[];\n\n`);
@@ -18,6 +18,8 @@ import type { SchemasJson, TypeScriptFile } from './types.js';
18
18
  export interface GenerateExtraConfig {
19
19
  platform?: 'web' | 'expo';
20
20
  auth?: 'cookie' | 'secureStore';
21
+ /** Enum emission style — see GeneratorOptions.enumStyle. Issue #103. */
22
+ enumStyle?: 'enum' | 'const';
21
23
  }
22
24
  /**
23
25
  * Generate all TypeScript files from schemas.json input.
package/dist/generator.js CHANGED
@@ -42,6 +42,7 @@ function buildOptions(input, extra) {
42
42
  customTypes: input.customTypes,
43
43
  platform: extra?.platform,
44
44
  auth: extra?.auth,
45
+ enumStyle: extra?.enumStyle,
45
46
  };
46
47
  }
47
48
  /** Generate a base interface file for a schema. */
@@ -106,10 +107,15 @@ function generateBaseInterfaceFile(schemaName, schemas, options) {
106
107
  // would be empty noise.
107
108
  const formShape = buildFormShape(schema, schemas, options);
108
109
  if (formShape.fields.length > 0) {
109
- // The builders depend on `Locale` (from common.ts) and the shared
110
- // `buildI18nPayload` / `emptyLocaleMap` helpers (from payload-helpers.ts).
111
- // Inject the imports near the top of the file.
112
- insertPayloadImports(parts);
110
+ // The builders only reference `Locale` / `buildI18nPayload` /
111
+ // `emptyLocaleMap` for translatable fields. When the schema has no
112
+ // translatable field, those imports would be unused trip TS6133
113
+ // (declared but never read) under noUnusedLocals. Pilot #103 Issue 2
114
+ // — emit imports conditionally on actual i18n usage.
115
+ const hasTranslatableField = formShape.fields.some(f => f.translatable);
116
+ if (hasTranslatableField) {
117
+ insertPayloadImports(parts);
118
+ }
113
119
  parts.push(formatPayloadBuilderSection(formShape, options.defaultLocale));
114
120
  }
115
121
  return {
@@ -139,9 +145,9 @@ function insertPayloadImports(parts) {
139
145
  parts.splice(1, 0, importBlock);
140
146
  }
141
147
  /** Generate an enum file. */
142
- function generateEnumFile(enumDef, isPlugin) {
148
+ function generateEnumFile(enumDef, isPlugin, options) {
143
149
  const parts = [generateBaseHeader()];
144
- parts.push(formatEnum(enumDef));
150
+ parts.push(formatEnum(enumDef, options.enumStyle));
145
151
  parts.push('\n');
146
152
  return {
147
153
  filePath: `${enumDef.name}.ts`,
@@ -451,12 +457,12 @@ export function generateTypeScript(input, extra) {
451
457
  // Schema enums (e.g., PostStatus)
452
458
  const schemaEnums = generateEnums(schemas, options);
453
459
  for (const enumDef of schemaEnums) {
454
- files.push(generateEnumFile(enumDef, false));
460
+ files.push(generateEnumFile(enumDef, false, options));
455
461
  }
456
462
  // Plugin enums (e.g., Prefecture, BankAccountType from customTypes.enums)
457
463
  const pluginEnums = generatePluginEnums(input.customTypes.enums, options);
458
464
  for (const enumDef of pluginEnums) {
459
- files.push(generateEnumFile(enumDef, true));
465
+ files.push(generateEnumFile(enumDef, true, options));
460
466
  }
461
467
  // Inline enums from properties (type aliases or full enums)
462
468
  const inlineEnums = extractInlineEnums(schemas, options);
@@ -464,7 +470,7 @@ export function generateTypeScript(input, extra) {
464
470
  for (const item of inlineEnums) {
465
471
  if (item.enum) {
466
472
  schemaEnums.push(item.enum);
467
- files.push(generateEnumFile(item.enum, false));
473
+ files.push(generateEnumFile(item.enum, false, options));
468
474
  }
469
475
  else if (item.typeAlias) {
470
476
  inlineTypeAliases.push(item.typeAlias);
package/dist/types.d.ts CHANGED
@@ -448,4 +448,25 @@ export interface GeneratorOptions {
448
448
  readonly platform?: 'web' | 'expo';
449
449
  /** Auth strategy: 'cookie' (default) or 'secureStore' (Expo). Issue #63. */
450
450
  readonly auth?: 'cookie' | 'secureStore';
451
+ /**
452
+ * Enum emission style. Issue #103 Issue 1.
453
+ *
454
+ * - `'enum'` (default): emit `export enum X { ... }` — TypeScript native
455
+ * syntax. Compatible with projects predating TS 5.5 / projects that
456
+ * declaration-merge enums via namespace. INCOMPATIBLE with the
457
+ * `erasableSyntaxOnly` strict-mode option (TS 5.5+ default in Vite 7
458
+ * starters), which rejects enums because they emit runtime code that
459
+ * type-only-stripping tools (esbuild/deno/bun) can't erase.
460
+ *
461
+ * - `'const'`: emit `export const X = {...} as const; export type X = ...`
462
+ * — works under all strict modes. Identical call-site ergonomics
463
+ * (`X.User === 'user'`, type narrowing, helper functions). Pilot
464
+ * downstream uses this when their tsconfig enables erasableSyntaxOnly.
465
+ *
466
+ * Default `'enum'` preserves backwards compatibility for projects
467
+ * upgrading omnify without changing their omnify.yaml — set
468
+ * `enumStyle: 'const'` explicitly to opt into the strict-mode-friendly
469
+ * output.
470
+ */
471
+ readonly enumStyle?: 'enum' | 'const';
451
472
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omnifyjp/ts",
3
- "version": "5.8.33",
3
+ "version": "5.8.35",
4
4
  "description": "TypeScript model type generator from Omnify schemas.json",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",