type-crafter 0.5.0 → 0.6.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.
@@ -1,5 +1,6 @@
1
- import { type ResolveReferenceData } from '$types';
2
- export declare function resolveReference(reference: string): Promise<ResolveReferenceData>;
1
+ import { type ResolvedTypeReferenceData, type ResolvedGroupReferenceData } from '$types';
2
+ export declare function resolveTypeReference(reference: string): Promise<ResolvedTypeReferenceData>;
3
+ export declare function resolveGroupReference(reference: string): Promise<ResolvedGroupReferenceData>;
3
4
  export declare function fillPatterns(input: string, patterns: Array<{
4
5
  regex: RegExp;
5
6
  value: string;
package/dist/index.js CHANGED
@@ -3488,7 +3488,9 @@ function decodeGroupedTypes(rawInput) {
3488
3488
  const result = {};
3489
3489
  for (const key in rawInput) {
3490
3490
  const value = rawInput[key];
3491
- const decodedValue = decodeTypes(value);
3491
+ const decodedRefValue = decodeGroupRef(value);
3492
+ const decodedTypes = decodeTypes(value);
3493
+ const decodedValue = decodedRefValue ?? decodedTypes;
3492
3494
  if (decodedValue !== null) {
3493
3495
  result[key] = decodedValue;
3494
3496
  }
@@ -3500,6 +3502,20 @@ function decodeGroupedTypes(rawInput) {
3500
3502
  }
3501
3503
  return null;
3502
3504
  }
3505
+ function valueIsGroupRef(value) {
3506
+ return isJSON(value) && typeof value.$ref === 'string';
3507
+ }
3508
+ function decodeGroupRef(rawInput) {
3509
+ if (isJSON(rawInput)) {
3510
+ const ref = decodeString(rawInput.$ref);
3511
+ if (ref !== null) {
3512
+ return {
3513
+ $ref: ref
3514
+ };
3515
+ }
3516
+ }
3517
+ return null;
3518
+ }
3503
3519
  function decodeTypes(rawInput) {
3504
3520
  if (isJSON(rawInput)) {
3505
3521
  const result = {};
@@ -12008,6 +12024,12 @@ function getCachedReferenceType(referencePath) {
12008
12024
  function cacheReferenceType(referencePath, generatedData) {
12009
12025
  cachedReferencedTypes.set(referencePath, generatedData);
12010
12026
  }
12027
+ function getInputFilePath(absolutePath = true) {
12028
+ if (config$2 === null) {
12029
+ throw new RuntimeError('Spec file path not set!');
12030
+ }
12031
+ return absolutePath ? resolveFilePath(config$2.input) : config$2.input;
12032
+ }
12011
12033
  var Runtime = {
12012
12034
  getConfig,
12013
12035
  setConfig,
@@ -12023,7 +12045,8 @@ var Runtime = {
12023
12045
  getOneOfTemplate,
12024
12046
  getCachedReferencedTypes,
12025
12047
  getCachedReferenceType,
12026
- cacheReferenceType
12048
+ cacheReferenceType,
12049
+ getInputFilePath
12027
12050
  };
12028
12051
 
12029
12052
  const ALIAS = Symbol.for('yaml.alias');
@@ -19479,6 +19502,24 @@ function toPascalCaseHelper(input) {
19479
19502
  }
19480
19503
  return toPascalCase(inputString);
19481
19504
  }
19505
+ function refineJSONKey(input) {
19506
+ if (typeof input === 'string' && input.includes('-')) {
19507
+ return `'${input}'`;
19508
+ }
19509
+ return input;
19510
+ }
19511
+ function refineVariableName(input) {
19512
+ if (typeof input === 'string') {
19513
+ return toPascalCase(input);
19514
+ }
19515
+ return input;
19516
+ }
19517
+ function refineIndexKey(input) {
19518
+ if (typeof input === 'string') {
19519
+ return `'${input}'`;
19520
+ }
19521
+ return input;
19522
+ }
19482
19523
  function registerTemplateHelpers() {
19483
19524
  Handlebars.registerHelper('getOptionalKeys', getOptionalKeys);
19484
19525
  Handlebars.registerHelper('getRequiredKeys', getRequiredKeys);
@@ -19488,6 +19529,9 @@ function registerTemplateHelpers() {
19488
19529
  Handlebars.registerHelper('toPascalCase', toPascalCaseHelper);
19489
19530
  Handlebars.registerHelper('isNonEmptyArray', (value) => Array.isArray(value) && value.length === 0);
19490
19531
  Handlebars.registerHelper('eq', (value1, value2) => value1 === value2);
19532
+ Handlebars.registerHelper('jsonKey', refineJSONKey);
19533
+ Handlebars.registerHelper('variableName', refineVariableName);
19534
+ Handlebars.registerHelper('indexKey', refineIndexKey);
19491
19535
  }
19492
19536
  function readNestedValue(json, keyPath) {
19493
19537
  if (!isJSON(json)) {
@@ -19526,10 +19570,10 @@ function stripPrefix(value, prefix) {
19526
19570
  }
19527
19571
  // #endregion
19528
19572
 
19529
- async function resolveReference(reference) {
19530
- let referenceType = 'unknown';
19531
- const referenceParts = reference.split('/');
19532
- const referenceName = referenceParts[referenceParts.length - 1];
19573
+ function getReferenceMeta(reference) {
19574
+ const slashedParts = reference.split('/');
19575
+ const hashSlashParts = reference.split('#');
19576
+ let referenceType;
19533
19577
  if (reference.startsWith('#')) {
19534
19578
  referenceType = 'local';
19535
19579
  }
@@ -19539,32 +19583,61 @@ async function resolveReference(reference) {
19539
19583
  else {
19540
19584
  referenceType = 'remote';
19541
19585
  }
19542
- let result = null;
19543
- let referenceFileName;
19544
- if (referenceType === 'local') {
19545
- const specFileData = Runtime.getSpecFileData();
19546
- const referenceKeyPath = referenceParts.slice(1);
19547
- result = decodeTypeInfo(readNestedValue(specFileData, referenceKeyPath));
19586
+ let completeSource = hashSlashParts.at(0);
19587
+ const sourceFile = hashSlashParts.at(0)?.split('/').at(-1);
19588
+ const path = hashSlashParts.at(1)?.slice(1);
19589
+ const name = slashedParts[slashedParts.length - 1];
19590
+ if (typeof completeSource === 'undefined' ||
19591
+ typeof path === 'undefined' ||
19592
+ typeof sourceFile === 'undefined') {
19593
+ throw new InvalidSpecFileError('Invalid reference at: ' + reference);
19548
19594
  }
19549
- else if (referenceType === 'url') {
19550
- throw new UnsupportedFeatureError('URL references are not supported yet');
19595
+ if (referenceType === 'remote' &&
19596
+ resolveFilePath(completeSource) === Runtime.getInputFilePath()) {
19597
+ completeSource = resolveFilePath(completeSource);
19598
+ referenceType = 'local';
19551
19599
  }
19552
- else if (referenceType === 'remote') {
19553
- const indexOfExtension = reference.indexOf('.yaml');
19554
- const referenceFilePath = reference.slice(0, indexOfExtension + 5);
19555
- const typeDataPath = reference.slice(indexOfExtension + 6);
19556
- referenceFileName = referenceParts.find((part) => part.endsWith('.yaml'));
19557
- const referencedFileData = await readYaml(referenceFilePath);
19558
- const jsonValue = readNestedValue(referencedFileData, typeDataPath.split('/'));
19559
- result = decodeTypeInfo(jsonValue);
19600
+ return {
19601
+ completeSource,
19602
+ sourceFile,
19603
+ path,
19604
+ type: referenceType,
19605
+ name
19606
+ };
19607
+ }
19608
+ async function getReferencedData(refMeta) {
19609
+ let refFileData;
19610
+ if (refMeta.type === 'local') {
19611
+ refFileData = Runtime.getSpecFileData();
19612
+ }
19613
+ else if (refMeta.type === 'remote') {
19614
+ refFileData = await readYaml(refMeta.completeSource);
19560
19615
  }
19561
19616
  else {
19617
+ throw new UnsupportedFeatureError('URL references are not supported yet');
19618
+ }
19619
+ if (typeof refFileData === 'undefined') {
19620
+ throw new InvalidSpecFileError('Invalid reference at: ' + refMeta.completeSource);
19621
+ }
19622
+ return readNestedValue(refFileData, refMeta.path.split('/'));
19623
+ }
19624
+ async function resolveTypeReference(reference) {
19625
+ const refMeta = getReferenceMeta(reference);
19626
+ const refData = await getReferencedData(refMeta);
19627
+ const result = decodeTypeInfo(refData);
19628
+ if (result === null) {
19562
19629
  throw new InvalidSpecFileError('Invalid reference at: ' + reference);
19563
19630
  }
19631
+ return { typeInfo: result, ...refMeta };
19632
+ }
19633
+ async function resolveGroupReference(reference) {
19634
+ const refMeta = getReferenceMeta(reference);
19635
+ const refData = await getReferencedData(refMeta);
19636
+ const result = decodeTypes(refData);
19564
19637
  if (result === null) {
19565
19638
  throw new InvalidSpecFileError('Invalid reference at: ' + reference);
19566
19639
  }
19567
- return { typeInfo: result, referenceName, sourceFile: referenceFileName };
19640
+ return { groupedTypes: result, ...refMeta };
19568
19641
  }
19569
19642
  function fillPatterns(input, patterns) {
19570
19643
  let result = input;
@@ -19574,6 +19647,12 @@ function fillPatterns(input, patterns) {
19574
19647
  return result;
19575
19648
  }
19576
19649
 
19650
+ /**
19651
+ * @description Generates the primitive type for the unit attribute in the spec.
19652
+ * @param typeName { string }
19653
+ * @param typeInfo { TypeInfo }
19654
+ * @returns {GeneratedType<VariableTemplateInput>}
19655
+ */
19577
19656
  function getPrimitiveType(typeName, typeInfo) {
19578
19657
  if (typeInfo.type === null) {
19579
19658
  throw new InvalidSpecFileError('Invalid type for: ' + typeName);
@@ -19609,7 +19688,7 @@ function getPrimitiveType(typeName, typeInfo) {
19609
19688
  result.primitives.add(languageDataType);
19610
19689
  return result;
19611
19690
  }
19612
- async function generateObjectType(typeName, typeInfo) {
19691
+ async function generateObjectType(typeName, typeInfo, parentTypes) {
19613
19692
  const templateInput = {
19614
19693
  typeName,
19615
19694
  type: typeName,
@@ -19622,13 +19701,14 @@ async function generateObjectType(typeName, typeInfo) {
19622
19701
  let dynamicGeneratedType = '';
19623
19702
  const primitives = [];
19624
19703
  const references = [];
19704
+ // Generating types for properties
19625
19705
  for (const propertyName in typeInfo.properties) {
19626
19706
  const propertyDetails = typeInfo.properties[propertyName];
19627
19707
  const propertyType = propertyDetails.type;
19628
19708
  const reference = propertyDetails.$ref ?? null;
19629
19709
  const enumValues = propertyDetails.enum ?? null;
19630
19710
  // Throwing error in case neither property type nor reference to a different type is present
19631
- if (propertyType === null && reference === null) {
19711
+ if (propertyType === null && reference === null && propertyDetails.oneOf === null) {
19632
19712
  throw new InvalidSpecFileError('Invalid property type for: ' + typeName + '.' + propertyName);
19633
19713
  }
19634
19714
  const primitiveType = propertyType ?? 'object';
@@ -19637,7 +19717,7 @@ async function generateObjectType(typeName, typeInfo) {
19637
19717
  let languageDataType = null;
19638
19718
  let isReferenced = false;
19639
19719
  if (reference !== null) {
19640
- const referencedType = await generateReferencedType(propertyName, propertyDetails);
19720
+ const referencedType = await generateReferencedType(propertyName, propertyDetails, parentTypes);
19641
19721
  recursivePropertyName = referencedType.templateInput.typeName;
19642
19722
  languageDataType = recursivePropertyName;
19643
19723
  references.push(...referencedType.references);
@@ -19650,7 +19730,7 @@ async function generateObjectType(typeName, typeInfo) {
19650
19730
  languageDataType = enumName;
19651
19731
  }
19652
19732
  else if (propertyType === 'array') {
19653
- const arrayDataGenOutput = await generateArrayType(propertyName, propertyDetails);
19733
+ const arrayDataGenOutput = await generateArrayType(propertyName, propertyDetails, parentTypes);
19654
19734
  primitives.push(...arrayDataGenOutput.primitives);
19655
19735
  references.push(...arrayDataGenOutput.references);
19656
19736
  languageDataType = arrayDataGenOutput.templateInput.type;
@@ -19658,16 +19738,17 @@ async function generateObjectType(typeName, typeInfo) {
19658
19738
  }
19659
19739
  else if (propertyType === 'object') {
19660
19740
  recursivePropertyName = toPascalCase(propertyName);
19661
- recursiveTypeGenOutput = await generateObjectType(recursivePropertyName, typeInfo.properties[propertyName]);
19741
+ recursiveTypeGenOutput = await generateObjectType(recursivePropertyName, typeInfo.properties[propertyName], parentTypes);
19662
19742
  languageDataType = recursivePropertyName;
19663
19743
  references.push(...recursiveTypeGenOutput.references);
19664
19744
  primitives.push(...recursiveTypeGenOutput.primitives);
19665
19745
  }
19666
19746
  else {
19667
- const primitiveTypeGenOutput = getPrimitiveType(propertyName, propertyDetails);
19747
+ const primitiveTypeGenOutput = await generateType(typeName + toPascalCase(propertyName), propertyDetails, parentTypes);
19668
19748
  languageDataType = primitiveTypeGenOutput.templateInput.type;
19669
19749
  primitives.push(...primitiveTypeGenOutput.primitives);
19670
19750
  references.push(...primitiveTypeGenOutput.references);
19751
+ dynamicGeneratedType = primitiveTypeGenOutput.content;
19671
19752
  }
19672
19753
  if (languageDataType === null) {
19673
19754
  throw new InvalidSpecFileError(`Invalid language data type for: ${typeName}.${propertyName}`);
@@ -19696,6 +19777,12 @@ async function generateObjectType(typeName, typeInfo) {
19696
19777
  };
19697
19778
  return result;
19698
19779
  }
19780
+ /**
19781
+ * @description Generated ENUM type for the unit attribute in the spec.
19782
+ * @param typeName
19783
+ * @param typeInfo
19784
+ * @returns {GeneratedType<EnumTemplateInput>}
19785
+ */
19699
19786
  function generateEnumType(typeName, typeInfo) {
19700
19787
  if (typeInfo.enum === null || typeInfo.enum.length === 0 || typeInfo.type === null) {
19701
19788
  throw new InvalidSpecFileError('Invalid enum type for: ' + typeName);
@@ -19717,11 +19804,11 @@ function generateEnumType(typeName, typeInfo) {
19717
19804
  result.content = Runtime.getEnumTemplate()(templateInput);
19718
19805
  return result;
19719
19806
  }
19720
- async function generateArrayType(typeName, typeInfo) {
19807
+ async function generateArrayType(typeName, typeInfo, parentTypes) {
19721
19808
  if (typeInfo.items === null) {
19722
19809
  throw new InvalidSpecFileError('Invalid array type for: ' + typeName);
19723
19810
  }
19724
- const arrayItemsType = await generateType(typeName, typeInfo.items);
19811
+ const arrayItemsType = await generateType(typeName + 'Item', typeInfo.items, parentTypes);
19725
19812
  if (typeof arrayItemsType.templateInput?.type === 'undefined') {
19726
19813
  throw new InvalidSpecFileError('Invalid array type for: ' + typeName);
19727
19814
  }
@@ -19766,7 +19853,7 @@ function generateVariableType(typeName, typeInfo) {
19766
19853
  templateInput
19767
19854
  };
19768
19855
  }
19769
- async function generateReferencedType(typeName, typeInfo) {
19856
+ async function generateReferencedType(typeName, typeInfo, parentTypes) {
19770
19857
  if (typeInfo.$ref === null) {
19771
19858
  throw new InvalidSpecFileError('Invalid referenced type for: ' + typeName);
19772
19859
  }
@@ -19774,18 +19861,18 @@ async function generateReferencedType(typeName, typeInfo) {
19774
19861
  if (cachedReferencedType !== null) {
19775
19862
  return cachedReferencedType.templateData;
19776
19863
  }
19777
- const referencedTypeInfo = await resolveReference(typeInfo.$ref);
19778
- const referencedGeneratedType = await generateType(referencedTypeInfo.referenceName, referencedTypeInfo.typeInfo);
19864
+ const referencedTypeInfo = await resolveTypeReference(typeInfo.$ref);
19865
+ const referencedGeneratedType = await generateType(referencedTypeInfo.name, referencedTypeInfo.typeInfo, parentTypes);
19779
19866
  const result = {
19780
19867
  content: referencedGeneratedType.content,
19781
- references: new Set([...referencedGeneratedType.references, referencedTypeInfo.referenceName]),
19868
+ references: new Set([...referencedGeneratedType.references, referencedTypeInfo.name]),
19782
19869
  primitives: referencedGeneratedType.primitives,
19783
19870
  templateInput: referencedGeneratedType.templateInput
19784
19871
  };
19785
19872
  Runtime.cacheReferenceType(typeInfo.$ref, { ...referencedTypeInfo, templateData: result });
19786
19873
  return result;
19787
19874
  }
19788
- async function generateOneOfTypes(typeName, typeInfo) {
19875
+ async function generateOneOfTypes(typeName, typeInfo, parentTypes) {
19789
19876
  if (typeInfo.oneOf === null || typeInfo.oneOf.length === 0) {
19790
19877
  throw new InvalidSpecFileError('Invalid oneOf type for: ' + typeName);
19791
19878
  }
@@ -19806,16 +19893,16 @@ async function generateOneOfTypes(typeName, typeInfo) {
19806
19893
  for (let index = 0; index < typeInfo.oneOf.length; index++) {
19807
19894
  const oneOfItem = typeInfo.oneOf[index];
19808
19895
  if (oneOfItem.$ref !== null) {
19809
- const referenceData = await resolveReference(oneOfItem.$ref);
19896
+ const referenceData = await resolveTypeReference(oneOfItem.$ref);
19810
19897
  const composition = {
19811
19898
  source: 'referenced',
19812
- referencedType: referenceData.referenceName
19899
+ referencedType: referenceData.name
19813
19900
  };
19814
19901
  templateInput.compositions.push(composition);
19815
- result.references.add(referenceData.referenceName);
19902
+ result.references.add(referenceData.name);
19816
19903
  }
19817
19904
  else {
19818
- const generatedType = await generateType(typeName + (index + 1), oneOfItem);
19905
+ const generatedType = await generateType(typeName + (index + 1), oneOfItem, parentTypes);
19819
19906
  if (generatedType === null) {
19820
19907
  throw new InvalidSpecFileError('Invalid oneOf type for: ' + typeName);
19821
19908
  }
@@ -19837,21 +19924,41 @@ async function generateOneOfTypes(typeName, typeInfo) {
19837
19924
  result.content = Runtime.getOneOfTemplate()(templateInput);
19838
19925
  return result;
19839
19926
  }
19840
- async function generateType(typeName, typeInfo) {
19927
+ function returnCyclicReference(typeName) {
19928
+ const templateInput = {
19929
+ typeName,
19930
+ type: typeName,
19931
+ composerType: typeName,
19932
+ description: '',
19933
+ example: '',
19934
+ summary: ''
19935
+ };
19936
+ return {
19937
+ content: '',
19938
+ references: new Set(),
19939
+ primitives: new Set(),
19940
+ templateInput
19941
+ };
19942
+ }
19943
+ async function generateType(typeName, typeInfo, parentTypes) {
19944
+ if (parentTypes.includes(typeName)) {
19945
+ return returnCyclicReference(typeName);
19946
+ }
19947
+ parentTypes = [...parentTypes, typeName];
19841
19948
  if (typeInfo.type === 'object') {
19842
- return await generateObjectType(typeName, typeInfo);
19949
+ return await generateObjectType(typeName, typeInfo, parentTypes);
19843
19950
  }
19844
19951
  if (typeInfo.enum !== null) {
19845
19952
  return generateEnumType(typeName, typeInfo);
19846
19953
  }
19847
19954
  if (typeInfo.oneOf !== null) {
19848
- return await generateOneOfTypes(typeName, typeInfo);
19955
+ return await generateOneOfTypes(typeName, typeInfo, parentTypes);
19849
19956
  }
19850
19957
  if (typeInfo.type === 'array') {
19851
- return await generateArrayType(typeName, typeInfo);
19958
+ return await generateArrayType(typeName, typeInfo, parentTypes);
19852
19959
  }
19853
19960
  if (typeInfo.$ref !== null) {
19854
- return await generateReferencedType(typeName, typeInfo);
19961
+ return await generateReferencedType(typeName, typeInfo, parentTypes);
19855
19962
  }
19856
19963
  return generateVariableType(typeName, typeInfo);
19857
19964
  }
@@ -19859,7 +19966,11 @@ async function generateTypes(types) {
19859
19966
  const result = {};
19860
19967
  for (const type in types) {
19861
19968
  const typeInfo = types[type];
19862
- result[type] = await generateType(type, typeInfo);
19969
+ const generatedData = await generateType(type, typeInfo, []);
19970
+ // Not storing top level referenced types as they are already generated somewhere else
19971
+ if (typeInfo.$ref === null) {
19972
+ result[type] = generatedData;
19973
+ }
19863
19974
  }
19864
19975
  return result;
19865
19976
  }
@@ -19872,18 +19983,34 @@ async function generator(specFileData) {
19872
19983
  if (specFileData.types !== null) {
19873
19984
  result.types = await generateTypes(specFileData.types);
19874
19985
  }
19986
+ // remove self references
19987
+ for (const typeName in result.types) {
19988
+ const typeData = result.types[typeName];
19989
+ typeData.references.delete(typeName);
19990
+ }
19875
19991
  // generating grouped types
19876
19992
  const groupedTypes = {};
19993
+ const referencedGroups = [];
19877
19994
  for (const groupName in specFileData.groupedTypes) {
19878
- groupedTypes[groupName] = await generateTypes(specFileData.groupedTypes[groupName]);
19995
+ const groupData = specFileData.groupedTypes[groupName];
19996
+ if (!valueIsGroupRef(groupData)) {
19997
+ groupedTypes[groupName] = await generateTypes(groupData);
19998
+ }
19999
+ else {
20000
+ const groupRefData = await resolveGroupReference(groupData.$ref);
20001
+ referencedGroups.push(groupRefData);
20002
+ }
20003
+ }
20004
+ for (const refGroup of referencedGroups) {
20005
+ groupedTypes[refGroup.name] = await generateTypes(refGroup.groupedTypes);
19879
20006
  }
19880
20007
  // storing remote referenced to output
19881
20008
  for (const generatedRefData of Runtime.getCachedReferencedTypes().values()) {
19882
- if (typeof generatedRefData.sourceFile === 'string') {
20009
+ if (typeof generatedRefData.sourceFile === 'string' && generatedRefData.type !== 'local') {
19883
20010
  const refGroupName = toPascalCase(generatedRefData.sourceFile.replace('.yaml', ''));
19884
20011
  groupedTypes[refGroupName] = {
19885
20012
  ...groupedTypes[refGroupName],
19886
- [generatedRefData.referenceName]: generatedRefData.templateData
20013
+ [generatedRefData.name]: generatedRefData.templateData
19887
20014
  };
19888
20015
  }
19889
20016
  }
@@ -19922,25 +20049,33 @@ function generateExpectedOutputFile() {
19922
20049
  result = new Map([...generateTypesOutputFiles(specData.types)]);
19923
20050
  for (const groupName in specData.groupedTypes) {
19924
20051
  const group = specData.groupedTypes[groupName];
19925
- result = new Map([...result, ...generateTypesOutputFiles(group, groupName)]);
20052
+ // No File/Folder will be created for referenced groups
20053
+ if (!valueIsGroupRef(group)) {
20054
+ result = new Map([...result, ...generateTypesOutputFiles(group, groupName)]);
20055
+ }
19926
20056
  }
19927
20057
  // Generating expect writing types for referenced types
19928
20058
  let referredGroups = {};
19929
20059
  for (const generatedRefData of Runtime.getCachedReferencedTypes().values()) {
19930
- if (typeof generatedRefData.sourceFile !== 'undefined') {
20060
+ if (typeof generatedRefData.sourceFile !== 'undefined' &&
20061
+ generatedRefData.completeSource !== Runtime.getInputFilePath() // Preventing new file creation for remote references from base file
20062
+ ) {
19931
20063
  const groupName = toPascalCase(generatedRefData.sourceFile.replace('.yaml', ''));
19932
20064
  referredGroups = {
19933
20065
  ...referredGroups,
19934
20066
  [groupName]: {
19935
20067
  ...referredGroups[groupName],
19936
- [generatedRefData.referenceName]: generatedRefData.typeInfo
20068
+ [generatedRefData.name]: generatedRefData.typeInfo
19937
20069
  }
19938
20070
  };
19939
20071
  }
19940
20072
  }
19941
20073
  for (const groupName in referredGroups) {
19942
20074
  const group = referredGroups[groupName];
19943
- result = new Map([...result, ...generateTypesOutputFiles(group, groupName)]);
20075
+ // No File/Folder will be created for referenced groups
20076
+ if (!valueIsGroupRef(group)) {
20077
+ result = new Map([...result, ...generateTypesOutputFiles(group, groupName)]);
20078
+ }
19944
20079
  }
19945
20080
  return result;
19946
20081
  }
@@ -19951,11 +20086,19 @@ async function writeTypesToFiles(config, types, folderName = '') {
19951
20086
  folderName: config.output.directory + '/' + folderName,
19952
20087
  files: []
19953
20088
  };
20089
+ // Filtering references for writing types to files; Done for types.writerMode: Files
20090
+ // Maybe a hack. But it works for now
20091
+ // Fix this later
20092
+ const filterReferences = folderName !== '';
20093
+ const typeNames = Object.keys(types);
19954
20094
  for (const typeName in types) {
19955
20095
  const typeData = types[typeName];
19956
20096
  const file = typeName + config.output.fileExtension;
20097
+ const references = filterReferences
20098
+ ? [...types[typeName].references].filter((x) => !typeNames.includes(x))
20099
+ : [...types[typeName].references];
19957
20100
  const templateInput = {
19958
- referencedTypes: [...typeData.references],
20101
+ referencedTypes: references,
19959
20102
  primitives: [...typeData.primitives],
19960
20103
  typesContent: typeData.content,
19961
20104
  writtenAt: await getExpectedWrittenPath(result.folderName, file)
@@ -19976,9 +20119,12 @@ async function writeTypesToFile(config, types, fileName = 'types') {
19976
20119
  typesContent: '',
19977
20120
  writtenAt: ''
19978
20121
  };
20122
+ const typeNames = Object.keys(types);
19979
20123
  for (const typeName in types) {
19980
20124
  templateInput.primitives.push(...types[typeName].primitives);
19981
- templateInput.referencedTypes.push(...types[typeName].references);
20125
+ // Removing references that are already written to file
20126
+ const _references = [...types[typeName].references].filter((x) => !typeNames.includes(x));
20127
+ templateInput.referencedTypes.push(..._references);
19982
20128
  templateInput.typesContent += types[typeName].content + '\n';
19983
20129
  }
19984
20130
  // remove duplicates
@@ -20080,7 +20226,7 @@ async function config$1(inputFilePath, outputDirectory, typesWriterMode, grouped
20080
20226
  typeMapper: {
20081
20227
  string: { default: 'string', date: 'Date' },
20082
20228
  number: { default: 'number' },
20083
- integer: { default: 'integer' },
20229
+ integer: { default: 'number' },
20084
20230
  boolean: 'boolean',
20085
20231
  array: '~ItemType~[]',
20086
20232
  object: 'type',
@@ -20122,7 +20268,7 @@ async function config(inputFilePath, outputDirectory, typesWriterMode, groupedTy
20122
20268
  typeMapper: {
20123
20269
  string: { default: 'string', date: 'Date' },
20124
20270
  number: { default: 'number' },
20125
- integer: { default: 'integer' },
20271
+ integer: { default: 'number' },
20126
20272
  boolean: 'boolean',
20127
20273
  array: '~ItemType~[]',
20128
20274
  object: 'type',
@@ -20179,15 +20325,15 @@ async function runner(language, inputFilePath, outputDirectory, _typesWriterMode
20179
20325
  }
20180
20326
  }
20181
20327
  greeting();
20182
- const program = new Command().version('0.5.0');
20328
+ const program = new Command().version('0.6.0');
20183
20329
  program
20184
20330
  .command('generate')
20185
20331
  .description('Generate types for your language from a type spec file')
20186
20332
  .argument('<outputLanguage>', 'Language to generate types for')
20187
20333
  .argument('<inputFilePath>', 'Path to the input spec file')
20188
20334
  .argument('<outputDirectory>', 'Path to the output file')
20189
- .argument('[typesWriterMode]', 'Writer mode for types', 'SingleFile')
20190
- .argument('[groupedTypesWriterMode]', 'Writer mode for grouped types', 'SingleFile')
20335
+ .argument('[typesWriterMode]', 'Writer mode for types', 'Files')
20336
+ .argument('[groupedTypesWriterMode]', 'Writer mode for grouped types', 'FolderWithFiles')
20191
20337
  .action(runner);
20192
20338
  program.parse();
20193
20339
 
package/dist/runtime.d.ts CHANGED
@@ -14,6 +14,7 @@ declare function getExpectedOutputFiles(): Map<string, TypeFilePath>;
14
14
  declare function getCachedReferencedTypes(): Map<string, GeneratedReferencedType>;
15
15
  declare function getCachedReferenceType(referencePath: string): GeneratedReferencedType | null;
16
16
  declare function cacheReferenceType(referencePath: string, generatedData: GeneratedReferencedType): void;
17
+ declare function getInputFilePath(absolutePath?: boolean): string;
17
18
  declare const _default: {
18
19
  getConfig: typeof getConfig;
19
20
  setConfig: typeof setConfig;
@@ -30,5 +31,6 @@ declare const _default: {
30
31
  getCachedReferencedTypes: typeof getCachedReferencedTypes;
31
32
  getCachedReferenceType: typeof getCachedReferenceType;
32
33
  cacheReferenceType: typeof cacheReferenceType;
34
+ getInputFilePath: typeof getInputFilePath;
33
35
  };
34
36
  export default _default;
@@ -19,6 +19,6 @@ export type {{typeName}} = {
19
19
  * @example {{{this.example}}}
20
20
  {{/if}}
21
21
  */
22
- {{@key}}: {{{this.type}}}{{#unless this.required}} | null{{/unless}};
22
+ {{{jsonKey @key}}}: {{{this.type}}}{{#unless this.required}} | null{{/unless}};
23
23
  {{/each}}
24
24
  };
@@ -13,7 +13,7 @@ export type {{typeName}} =
13
13
  {{/each}}
14
14
  }
15
15
  {{else}}
16
- {{this.templateInput.dataType}}
16
+ {{this.templateInput.type}}
17
17
  {{/if}}
18
18
  {{/if}}
19
19
  {{/each}};
@@ -19,20 +19,20 @@ export type {{typeName}} = {
19
19
  * @example {{{this.example}}}
20
20
  {{/if}}
21
21
  */
22
- {{@key}}: {{{this.type}}}{{#unless this.required}} | null{{/unless}};
22
+ {{{jsonKey @key}}}: {{{this.type}}}{{#unless this.required}} | null{{/unless}};
23
23
  {{/each}}
24
24
  };
25
25
 
26
26
  export function decode{{typeName}}(rawInput: unknown): {{typeName}} | null {
27
27
  if (isJSON(rawInput)) {
28
28
  {{#each properties}}
29
- const {{@key}} = {{#if (eq this.primitiveType 'array') }} decodeArray(rawInput.{{@key}}, decode{{{toPascalCase this.composerType}}}){{else}} decode{{{toPascalCase this.type}}}(rawInput.{{@key}}){{/if}};
29
+ const decoded{{variableName @key}} = {{#if (eq this.primitiveType 'array') }} decodeArray(rawInput[{{{indexKey @key}}}], decode{{{toPascalCase this.composerType}}}){{else}} decode{{{toPascalCase this.type}}}(rawInput[{{{indexKey @key}}}]){{/if}};
30
30
  {{/each}}
31
31
 
32
32
  {{#if (areRequiredKeysPresent properties)}}
33
33
  if (
34
34
  {{#each (getRequiredKeys properties)}}
35
- {{this}} === null{{#unless @last}} ||{{/unless}}
35
+ decoded{{toPascalCase this}} === null{{#unless @last}} ||{{/unless}}
36
36
  {{/each}}
37
37
  ) {
38
38
  return null;
@@ -41,7 +41,7 @@ export function decode{{typeName}}(rawInput: unknown): {{typeName}} | null {
41
41
 
42
42
  return {
43
43
  {{#each properties}}
44
- {{@key}},
44
+ {{{jsonKey @key}}}: decoded{{{variableName @key}}},
45
45
  {{/each}}
46
46
  };
47
47
  }
@@ -7,7 +7,7 @@ export type {{typeName}} =
7
7
  {{else if (eq this.dataType 'object')}}
8
8
  C{{this.templateInput.typeName}}
9
9
  {{else}}
10
- {{this.templateInput.dataType}}
10
+ {{this.templateInput.type}}
11
11
  {{/if}}
12
12
  {{/if}}
13
13
  {{/each}};
@@ -19,12 +19,12 @@ export function decode{{typeName}}(rawInput: unknown): {{typeName}} | null {
19
19
  decodeC{{referencedType}}(rawInput)
20
20
  {{else if (eq this.dataType 'object')}}
21
21
  decodeC{{this.templateInput.typeName}}(rawInput)
22
- {{else if (eq this.templateInput.primitiveType 'array')}}
23
- decodeArray(rawInput, decode{{{toPascalCase this.templateInput.itemType}}})
22
+ {{else if (eq this.dataType 'array')}}
23
+ decodeArray(rawInput, decode{{{toPascalCase this.templateInput.composerType}}})
24
24
  {{else if this.templateInput.values}}
25
25
  decode{{this.templateInput.typeName}}(rawInput)
26
26
  {{else}}
27
- decode{{{toPascalCase this.templateInput.dataType}}}(rawInput)
27
+ decode{{{toPascalCase this.templateInput.type}}}(rawInput)
28
28
  {{/if}}{{#unless @last}}??{{/unless}}
29
29
  {{/each}};
30
30
  return result;
@@ -1,7 +1,9 @@
1
- import type { EnumTemplateInput, GroupedTypesWriterMode, ObjectTemplateInputProperties, SpecFileData, TypeInfo, TypesWriterMode } from '.';
1
+ import type { GroupRef, EnumTemplateInput, GroupedTypesWriterMode, ObjectTemplateInputProperties, SpecFileData, TypeInfo, Types, TypesWriterMode, GroupTypesData } from '.';
2
2
  export declare function decodeGroupedTypesWriterMode(rawInput: unknown): GroupedTypesWriterMode | null;
3
3
  export declare function decodeTypesWriterMode(rawInput: unknown): TypesWriterMode | null;
4
4
  export declare function decodeSpecFileData(rawInput: unknown): SpecFileData | null;
5
+ export declare function valueIsGroupRef(value: GroupTypesData): value is GroupRef;
6
+ export declare function decodeTypes(rawInput: unknown): Types | null;
5
7
  export declare function decodeTypeInfo(rawInput: unknown): TypeInfo | null;
6
8
  export declare function decodeObjectTemplateInputProperties(rawInput: unknown): ObjectTemplateInputProperties | null;
7
9
  export declare function decodeEnumTemplateInput(rawInput: unknown): EnumTemplateInput | null;
@@ -36,12 +36,21 @@ export type FormatType = {
36
36
  default: string;
37
37
  [format: string]: string | undefined;
38
38
  };
39
- export type ResolveReferenceData = {
39
+ export type ReferenceType = 'local' | 'remote' | 'url';
40
+ export type ReferenceMeta = {
41
+ completeSource: string;
42
+ sourceFile: string;
43
+ path: string;
44
+ type: ReferenceType;
45
+ name: string;
46
+ };
47
+ export type ResolvedTypeReferenceData = ReferenceMeta & {
40
48
  typeInfo: TypeInfo;
41
- referenceName: string;
42
- sourceFile?: string;
43
49
  };
44
- export type GeneratedReferencedType = ResolveReferenceData & {
50
+ export type ResolvedGroupReferenceData = ReferenceMeta & {
51
+ groupedTypes: Types;
52
+ };
53
+ export type GeneratedReferencedType = ResolvedTypeReferenceData & {
45
54
  templateData: GeneratedType<TemplateInput>;
46
55
  };
47
56
  export type SpecFileData = {
@@ -54,7 +63,11 @@ export type SpecInfo = {
54
63
  title: string;
55
64
  };
56
65
  type GroupName = string;
57
- export type GroupedTypes = Record<GroupName, Types>;
66
+ export type GroupedTypes = Record<GroupName, GroupTypesData>;
67
+ export type GroupTypesData = Types | GroupRef;
68
+ export type GroupRef = {
69
+ $ref: string;
70
+ };
58
71
  type TypeName = string;
59
72
  export type Types = Record<TypeName, TypeInfo>;
60
73
  export type TypeInfo = TypeDescriptors & {
@@ -8,6 +8,9 @@ export declare function getReferencedTypes(object: unknown): string[];
8
8
  export declare function getReferencedTypeModules(_referencedTypes: unknown, _writtenAt: string): unknown[];
9
9
  export declare function toPascalCase(input: string): string;
10
10
  export declare function toPascalCaseHelper(input: unknown): string | unknown;
11
+ export declare function refineJSONKey(input: unknown): unknown;
12
+ export declare function refineVariableName(input: unknown): unknown;
13
+ export declare function refineIndexKey(input: unknown): unknown;
11
14
  export declare function registerTemplateHelpers(): void;
12
15
  export declare function readNestedValue(json: unknown, keyPath: string[]): JSONObject;
13
16
  export declare function generateRelativePath(fromPath: string, toPath: string): string;
@@ -1,3 +1,3 @@
1
- import type { TypeFilePath, Types } from '$types';
1
+ import { type TypeFilePath, type Types } from '$types';
2
2
  export declare function generateTypesOutputFiles(types: Types | null, groupName?: string | null): Map<string, TypeFilePath>;
3
3
  export declare function generateExpectedOutputFile(): Map<string, TypeFilePath>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "type-crafter",
3
- "version": "0.5.0",
3
+ "version": "0.6.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",