type-crafter 0.1.0 → 0.2.0

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/index.js CHANGED
@@ -5,6 +5,7 @@ import path$1 from 'path';
5
5
  import require$$3 from 'fs';
6
6
  import require$$4 from 'process';
7
7
  import fs$1 from 'fs/promises';
8
+ import { fileURLToPath } from 'url';
8
9
 
9
10
  function getDefaultExportFromCjs (x) {
10
11
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
@@ -10857,11 +10858,15 @@ function decodeObjectTemplateInputProperty(rawInput) {
10857
10858
  const required = decodeBoolean(rawInput.required);
10858
10859
  const _type = decodeString(rawInput.type);
10859
10860
  const referenced = decodeBoolean(rawInput.referenced);
10860
- if (required !== null && _type !== null && referenced !== null) {
10861
+ const primitiveType = decodeString(rawInput.primitiveType);
10862
+ const composerType = decodeString(rawInput.composerType);
10863
+ if (required !== null && _type !== null && referenced !== null && primitiveType !== null) {
10861
10864
  return {
10862
10865
  type: _type,
10863
10866
  required,
10864
- referenced
10867
+ referenced,
10868
+ primitiveType,
10869
+ composerType
10865
10870
  };
10866
10871
  }
10867
10872
  }
@@ -19194,20 +19199,20 @@ function handleErrors(error) {
19194
19199
  }
19195
19200
  }
19196
19201
 
19197
- let config$1 = null;
19202
+ let config$2 = null;
19198
19203
  let specFileData = null;
19199
19204
  let objectSyntaxTemplate = null;
19200
19205
  let exporterModuleSyntaxTemplate = null;
19201
19206
  let typesFileSyntaxTemplate = null;
19202
19207
  let expectedOutputFiles = null;
19203
19208
  function setConfig(newConfig) {
19204
- config$1 = newConfig;
19209
+ config$2 = newConfig;
19205
19210
  }
19206
19211
  function getConfig() {
19207
- if (config$1 === null) {
19212
+ if (config$2 === null) {
19208
19213
  throw new RuntimeError('Failed to load configuration!');
19209
19214
  }
19210
- return config$1;
19215
+ return config$2;
19211
19216
  }
19212
19217
  function setSpecFileData(newSpecFileData) {
19213
19218
  specFileData = newSpecFileData;
@@ -19264,13 +19269,19 @@ var Runtime = {
19264
19269
  compileTemplates
19265
19270
  };
19266
19271
 
19267
- function resolveFilePath(filePath) {
19272
+ function getSourceFileDirectory() {
19273
+ const fileName = fileURLToPath(import.meta.url);
19274
+ return path$1.dirname(fileName);
19275
+ }
19276
+ function resolveFilePath(filePath, useCurrentDirectory = true) {
19268
19277
  const isAbsolutePath = path$1.isAbsolute(filePath);
19269
- const normalizedPath = isAbsolutePath ? filePath : path$1.join(process.cwd(), filePath);
19278
+ const normalizedPath = isAbsolutePath
19279
+ ? filePath
19280
+ : path$1.join(useCurrentDirectory ? process.cwd() : getSourceFileDirectory(), filePath);
19270
19281
  return path$1.resolve(normalizedPath);
19271
19282
  }
19272
- async function readFile(filePath) {
19273
- const data = await fs$1.readFile(resolveFilePath(filePath), 'utf-8');
19283
+ async function readFile(filePath, useCurrentWorkingDirectory = true) {
19284
+ const data = await fs$1.readFile(resolveFilePath(filePath, useCurrentWorkingDirectory), 'utf-8');
19274
19285
  return data;
19275
19286
  }
19276
19287
  async function createFolderWithBasePath(basePath, folderName) {
@@ -19284,7 +19295,12 @@ async function createFolder(folderPath) {
19284
19295
  await fs$1.mkdir(folderPath, { recursive: true });
19285
19296
  }
19286
19297
  async function deleteFolder(folderPath) {
19287
- await fs$1.rmdir(folderPath, { recursive: true });
19298
+ try {
19299
+ await fs$1.rm(folderPath, { recursive: true });
19300
+ }
19301
+ catch (e) {
19302
+ console.log("Couldn't delete folder: ", folderPath);
19303
+ }
19288
19304
  }
19289
19305
  async function getCompleteFolderPath(folderName) {
19290
19306
  const isAbsolutePath = path$1.isAbsolute(folderName);
@@ -19328,6 +19344,19 @@ function getOptionalKeys(object) {
19328
19344
  }
19329
19345
  return nullableKeys;
19330
19346
  }
19347
+ function getRequiredKeys(object) {
19348
+ const requiredKeys = [];
19349
+ const properties = decodeObjectTemplateInputProperties(object);
19350
+ if (properties !== null) {
19351
+ for (const propertyName in properties) {
19352
+ const property = properties[propertyName];
19353
+ if (property.required) {
19354
+ requiredKeys.push(propertyName);
19355
+ }
19356
+ }
19357
+ }
19358
+ return requiredKeys;
19359
+ }
19331
19360
  function getReferencedTypes(object) {
19332
19361
  const referencedTypes = [];
19333
19362
  const properties = decodeObjectTemplateInputProperties(object);
@@ -19379,8 +19408,13 @@ function toPascalCase(input) {
19379
19408
  }
19380
19409
  function registerTemplateHelpers() {
19381
19410
  Handlebars.registerHelper('getOptionalKeys', getOptionalKeys);
19411
+ Handlebars.registerHelper('getRequiredKeys', getRequiredKeys);
19412
+ Handlebars.registerHelper('areRequiredKeysPresent', (object) => getRequiredKeys(object).length > 0);
19382
19413
  Handlebars.registerHelper('getReferencedTypes', getReferencedTypes);
19383
19414
  Handlebars.registerHelper('getReferencedTypeModules', getReferencedTypeModules);
19415
+ Handlebars.registerHelper('toPascalCase', toPascalCase);
19416
+ Handlebars.registerHelper('isNonEmptyArray', (value) => Array.isArray(value) && value.length === 0);
19417
+ Handlebars.registerHelper('eq', (value1, value2) => value1 === value2);
19384
19418
  }
19385
19419
  function readNestedValue(json, keyPath) {
19386
19420
  let result = json;
@@ -19455,13 +19489,21 @@ function getReferenceName(reference) {
19455
19489
  const referenceParts = reference.split('/');
19456
19490
  return referenceParts[referenceParts.length - 1];
19457
19491
  }
19492
+ function resolveAndGetReferenceName(reference) {
19493
+ resolveReference(reference);
19494
+ return getReferenceName(reference);
19495
+ }
19458
19496
  function getLanguageDataType(dataType, format, items) {
19459
19497
  const typeMapper = Runtime.getConfig().language.typeMapper ?? null;
19460
19498
  const mappedType = typeMapper !== null ? typeMapper[dataType] : null;
19461
19499
  const itemsType =
19462
19500
  // eslint-disable-next-line
19463
- items !== null && items.type !== null
19464
- ? getLanguageDataType(items.type, items.format, items.items)
19501
+ items !== null
19502
+ ? items.type !== null
19503
+ ? getLanguageDataType(items.type, items.format, items.items)
19504
+ : items.$ref !== null
19505
+ ? resolveAndGetReferenceName(items.$ref)
19506
+ : null
19465
19507
  : null;
19466
19508
  const fillerPatterns = [];
19467
19509
  if (itemsType !== null) {
@@ -19499,6 +19541,8 @@ function generateType(typeName, typeInfo, groupedTypes = false) {
19499
19541
  if (propertyType === null && reference === null) {
19500
19542
  throw new InvalidSpecFileError('Invalid property type for: ' + typeName + '.' + propertyName);
19501
19543
  }
19544
+ const primitiveType = propertyType ?? 'object';
19545
+ let composerType = null;
19502
19546
  let recursivePropertyName;
19503
19547
  let languageDataType = null;
19504
19548
  let isReferenced = false;
@@ -19522,7 +19566,12 @@ function generateType(typeName, typeInfo, groupedTypes = false) {
19522
19566
  }
19523
19567
  else if (propertyType !== null) {
19524
19568
  languageDataType = getLanguageDataType(propertyType, propertyFormat, propertyItems);
19525
- result.primitives.add(languageDataType);
19569
+ result.primitives.add(propertyItems !== null ? 'Array' : languageDataType);
19570
+ if (propertyItems !== null) {
19571
+ const itemsType = getReferenceName(propertyItems.$ref ?? '');
19572
+ result.references.add(itemsType);
19573
+ composerType = itemsType;
19574
+ }
19526
19575
  }
19527
19576
  if (languageDataType === null) {
19528
19577
  throw new InvalidSpecFileError(`Invalid language data type for: ${typeName}.${propertyName}`);
@@ -19532,7 +19581,9 @@ function generateType(typeName, typeInfo, groupedTypes = false) {
19532
19581
  [propertyName]: {
19533
19582
  type: languageDataType,
19534
19583
  required: typeInfo.required?.includes(propertyName) ?? false,
19535
- referenced: isReferenced
19584
+ referenced: isReferenced,
19585
+ primitiveType,
19586
+ composerType
19536
19587
  }
19537
19588
  };
19538
19589
  }
@@ -19704,12 +19755,51 @@ async function writeOutput(generationResult) {
19704
19755
  });
19705
19756
  }
19706
19757
 
19707
- async function config(inputFilePath, outputDirectory, typesWriterMode, groupedTypesWriterMode) {
19758
+ async function config$1(inputFilePath, outputDirectory, typesWriterMode, groupedTypesWriterMode) {
19759
+ const devMode = 'PRODUCTION'.includes('DEVELOPMENT');
19708
19760
  // PRODUCTION will be replaced with PRODUCTION when package is built.
19709
- const directoryPrefix = 'PRODUCTION'.includes('DEVELOPMENT') ? 'src/' : 'dist/';
19710
- const objectSyntax = await readFile(directoryPrefix + 'templates/typescript/object-syntax.hbs');
19711
- const exporterModuleSyntax = await readFile(directoryPrefix + 'templates/typescript/exporter-module-syntax.hbs');
19712
- const typesFileSyntax = await readFile(directoryPrefix + 'templates/typescript/types-file-syntax.hbs');
19761
+ const directoryPrefix = devMode ? 'src/' : './';
19762
+ const objectSyntax = await readFile(directoryPrefix + 'templates/typescript/object-syntax.hbs', devMode);
19763
+ const exporterModuleSyntax = await readFile(directoryPrefix + 'templates/typescript/exporter-module-syntax.hbs', devMode);
19764
+ const typesFileSyntax = await readFile(directoryPrefix + 'templates/typescript/types-file-syntax.hbs', devMode);
19765
+ const config = {
19766
+ input: inputFilePath,
19767
+ output: {
19768
+ cleanWrite: true,
19769
+ fileExtension: '.ts',
19770
+ directory: outputDirectory,
19771
+ writerMode: {
19772
+ groupedTypes: groupedTypesWriterMode,
19773
+ types: typesWriterMode
19774
+ }
19775
+ },
19776
+ template: {
19777
+ objectSyntax,
19778
+ exporterModuleSyntax,
19779
+ typesFileSyntax
19780
+ },
19781
+ language: {
19782
+ exporterModuleName: 'index',
19783
+ typeMapper: {
19784
+ string: { default: 'string', date: 'Date' },
19785
+ number: { default: 'number' },
19786
+ integer: { default: 'integer' },
19787
+ boolean: 'boolean',
19788
+ array: '~ItemType~[]',
19789
+ object: 'type',
19790
+ unknown: 'unknown'
19791
+ }
19792
+ }
19793
+ };
19794
+ return config;
19795
+ }
19796
+
19797
+ async function config(inputFilePath, outputDirectory, typesWriterMode, groupedTypesWriterMode) {
19798
+ const devMode = 'PRODUCTION'.includes('DEVELOPMENT');
19799
+ const directoryPrefix = devMode ? 'src/' : './';
19800
+ const objectSyntax = await readFile(directoryPrefix + 'templates/typescript-with-decoders/object-syntax.hbs', devMode);
19801
+ const exporterModuleSyntax = await readFile(directoryPrefix + 'templates/typescript/exporter-module-syntax.hbs', devMode);
19802
+ const typesFileSyntax = await readFile(directoryPrefix + 'templates/typescript-with-decoders/types-file-syntax.hbs', devMode);
19713
19803
  const config = {
19714
19804
  input: inputFilePath,
19715
19805
  output: {
@@ -19770,6 +19860,9 @@ async function runner(language, inputFilePath, outputDirectory, _typesWriterMode
19770
19860
  let generatorConfig = null;
19771
19861
  switch (language.toLowerCase()) {
19772
19862
  case 'typescript':
19863
+ generatorConfig = await config$1(inputFilePath, outputDirectory, typesWriterMode, groupedTypesWriterMode);
19864
+ break;
19865
+ case 'typescript-with-decoders':
19773
19866
  generatorConfig = await config(inputFilePath, outputDirectory, typesWriterMode, groupedTypesWriterMode);
19774
19867
  break;
19775
19868
  default:
@@ -19786,7 +19879,7 @@ async function runner(language, inputFilePath, outputDirectory, _typesWriterMode
19786
19879
  }
19787
19880
  }
19788
19881
  greeting();
19789
- const program = new Command().version('0.1.0');
19882
+ const program = new Command().version('0.2.0');
19790
19883
  program
19791
19884
  .command('generate')
19792
19885
  .description('Generate types for your language from a type spec file')
@@ -1 +1,2 @@
1
1
  export * as typescript from './typescript';
2
+ export * as typescriptWithDecoders from './typescript-with-decoders';
@@ -0,0 +1,2 @@
1
+ import type { Configuration, GroupedTypesWriterMode, TypesWriterMode } from '$types';
2
+ export declare function config(inputFilePath: string, outputDirectory: string, typesWriterMode: TypesWriterMode, groupedTypesWriterMode: GroupedTypesWriterMode): Promise<Configuration>;
@@ -0,0 +1,30 @@
1
+ export type {{typeName}} = {
2
+ {{#each properties}}
3
+ {{@key}}: {{{this.type}}}{{#unless this.required}} | null{{/unless}};
4
+ {{/each}}
5
+ };
6
+
7
+ export function decode{{typeName}}(rawInput: unknown): {{typeName}} | null {
8
+ if (isJSON(rawInput)) {
9
+ {{#each properties}}
10
+ const {{@key}} = {{#if (eq this.primitiveType 'array') }} decodeArray(rawInput.{{@key}}, decode{{{toPascalCase this.composerType}}}){{else}} decode{{{toPascalCase this.type}}}(rawInput.{{@key}}){{/if}};
11
+ {{/each}}
12
+
13
+ {{#if (areRequiredKeysPresent properties)}}
14
+ if (
15
+ {{#each (getRequiredKeys properties)}}
16
+ {{this}} === null{{#unless @last}} ||{{/unless}}
17
+ {{/each}}
18
+ ) {
19
+ return null;
20
+ }
21
+ {{/if}}
22
+
23
+ return {
24
+ {{#each properties}}
25
+ {{@key}},
26
+ {{/each}}
27
+ };
28
+ }
29
+ return null;
30
+ }
@@ -0,0 +1,7 @@
1
+ {{#each (getReferencedTypeModules referencedTypes writtenAt)}}
2
+ import { {{#each this.referencedTypes}}type {{this}}, decode{{this}}{{#unless @last}}, {{/unless}} {{/each}} } from '{{this.moduleRelativePath}}';
3
+ {{/each}}
4
+ import { isJSON, {{#each primitives}}decode{{{toPascalCase this}}}{{#unless @last}}, {{/unless}}{{/each}} } from 'type-decoder';
5
+
6
+ {{{typesContent}}}
7
+
@@ -67,6 +67,8 @@ export type ObjectTemplateInputProperty = {
67
67
  type: string;
68
68
  required: boolean;
69
69
  referenced: boolean;
70
+ primitiveType: string;
71
+ composerType: string | null;
70
72
  };
71
73
  export type ExporterModuleTemplateInput = {
72
74
  modules: string[];
@@ -1,5 +1,5 @@
1
- export declare function resolveFilePath(filePath: string): string;
2
- export declare function readFile(filePath: string): Promise<string>;
1
+ export declare function resolveFilePath(filePath: string, useCurrentDirectory?: boolean): string;
2
+ export declare function readFile(filePath: string, useCurrentWorkingDirectory?: boolean): Promise<string>;
3
3
  export declare function createFolderWithBasePath(basePath: string, folderName: string): Promise<void>;
4
4
  export declare function createFolder(folderPath: string): Promise<void>;
5
5
  export declare function deleteFolder(folderPath: string): Promise<void>;
@@ -3,6 +3,7 @@ export * from './file-system';
3
3
  export * from './logger';
4
4
  export declare function addValuesToMappedSet(map: Map<string, Set<string>>, key: string, values: string[]): void;
5
5
  export declare function getOptionalKeys(object: unknown): string[];
6
+ export declare function getRequiredKeys(object: unknown): string[];
6
7
  export declare function getReferencedTypes(object: unknown): string[];
7
8
  export declare function getReferencedTypeModules(_referencedTypes: unknown, _writtenAt: string): unknown[];
8
9
  export declare function toPascalCase(input: string): string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "type-crafter",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "A tool to generate types from a yaml schema for any language",
5
5
  "main": "./dist/index.js",
6
6
  "type": "module",