type-crafter 0.13.0 → 0.13.1
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 +126 -14
- package/dist/templates/rust/allOf-syntax.hbs +3 -3
- package/dist/templates/rust/object-syntax.hbs +1 -1
- package/dist/templates/rust/types-file-syntax.hbs +5 -1
- package/dist/types/index.d.ts +8 -0
- package/dist/utils/index.d.ts +4 -1
- package/dist/writer/helpers.d.ts +1 -0
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -21188,11 +21188,13 @@ function getReferencedTypeModules(_referencedTypes, _writtenAt) {
|
|
|
21188
21188
|
resolveFilePath(outputFile.filePath) !== resolveFilePath(writtenAt)) {
|
|
21189
21189
|
if (typeof referencedTypeModules[outputFile.modulePath] === 'undefined') {
|
|
21190
21190
|
const rawRelativePath = generateRelativePath(writtenAt, outputFile.modulePath);
|
|
21191
|
+
const moduleName = outputFile.modulePath.split('/').pop() ?? '';
|
|
21191
21192
|
referencedTypeModules[outputFile.modulePath] = {
|
|
21192
21193
|
modulePath: outputFile.modulePath,
|
|
21193
21194
|
moduleRelativePath: formatModulePath(rawRelativePath, writtenAt, modulePathConfig),
|
|
21194
21195
|
referencedTypes: [referenceType],
|
|
21195
|
-
moduleName
|
|
21196
|
+
moduleName,
|
|
21197
|
+
fileBasedModules: moduleName === (modulePathConfig?.moduleFileName ?? '')
|
|
21196
21198
|
};
|
|
21197
21199
|
}
|
|
21198
21200
|
else {
|
|
@@ -21234,6 +21236,20 @@ function toSnakeCaseHelper(input) {
|
|
|
21234
21236
|
}
|
|
21235
21237
|
return toSnakeCase(inputString);
|
|
21236
21238
|
}
|
|
21239
|
+
function toCamelCase(input) {
|
|
21240
|
+
const pascal = toPascalCase(input);
|
|
21241
|
+
return pascal.charAt(0).toLowerCase() + pascal.slice(1);
|
|
21242
|
+
}
|
|
21243
|
+
function formatCase(input, fontCase) {
|
|
21244
|
+
switch (fontCase) {
|
|
21245
|
+
case 'snake_case':
|
|
21246
|
+
return toSnakeCase(input);
|
|
21247
|
+
case 'PascalCase':
|
|
21248
|
+
return toPascalCase(input);
|
|
21249
|
+
case 'camelCase':
|
|
21250
|
+
return toCamelCase(input);
|
|
21251
|
+
}
|
|
21252
|
+
}
|
|
21237
21253
|
function refineJSONKey(input) {
|
|
21238
21254
|
if (typeof input === 'string' && input.includes('-')) {
|
|
21239
21255
|
return `'${input}'`;
|
|
@@ -21252,6 +21268,19 @@ function refineIndexKey(input) {
|
|
|
21252
21268
|
}
|
|
21253
21269
|
return input;
|
|
21254
21270
|
}
|
|
21271
|
+
function escapeReservedWord(input) {
|
|
21272
|
+
if (typeof input !== 'string') {
|
|
21273
|
+
return input;
|
|
21274
|
+
}
|
|
21275
|
+
const config = Runtime.getConfig().language.reservedKeywords;
|
|
21276
|
+
if (typeof config === 'undefined') {
|
|
21277
|
+
return input;
|
|
21278
|
+
}
|
|
21279
|
+
if (config.words.includes(input)) {
|
|
21280
|
+
return config.prefix + input;
|
|
21281
|
+
}
|
|
21282
|
+
return input;
|
|
21283
|
+
}
|
|
21255
21284
|
function registerTemplateHelpers() {
|
|
21256
21285
|
Handlebars.registerHelper('getOptionalKeys', getOptionalKeys);
|
|
21257
21286
|
Handlebars.registerHelper('getRequiredKeys', getRequiredKeys);
|
|
@@ -21267,6 +21296,7 @@ function registerTemplateHelpers() {
|
|
|
21267
21296
|
Handlebars.registerHelper('jsonKey', refineJSONKey);
|
|
21268
21297
|
Handlebars.registerHelper('variableName', refineVariableName);
|
|
21269
21298
|
Handlebars.registerHelper('indexKey', refineIndexKey);
|
|
21299
|
+
Handlebars.registerHelper('escapeReservedWord', escapeReservedWord);
|
|
21270
21300
|
Handlebars.registerHelper('stringify', (value) => JSON.stringify(value));
|
|
21271
21301
|
Handlebars.registerHelper('not', (value) => {
|
|
21272
21302
|
if (typeof value === 'boolean') {
|
|
@@ -21582,8 +21612,7 @@ async function generateObjectType(typeName, typeInfo, parentTypes) {
|
|
|
21582
21612
|
const referencedType = await generateReferencedType(propertyName, propertyDetails, parentTypes);
|
|
21583
21613
|
recursivePropertyName = referencedType.templateInput.typeName;
|
|
21584
21614
|
languageDataType = recursivePropertyName;
|
|
21585
|
-
references.push(
|
|
21586
|
-
primitives.push(...referencedType.primitives);
|
|
21615
|
+
references.push(recursivePropertyName);
|
|
21587
21616
|
isReferenced = true;
|
|
21588
21617
|
}
|
|
21589
21618
|
else if (enumValues !== null) {
|
|
@@ -21697,6 +21726,18 @@ async function generateArrayType(typeName, typeInfo, parentTypes) {
|
|
|
21697
21726
|
}
|
|
21698
21727
|
else {
|
|
21699
21728
|
arrayItemsType = await generateType(typeName + 'Item', typeInfo.items, parentTypes);
|
|
21729
|
+
// For referenced types (e.g. enums via $ref), use the type name as the item type
|
|
21730
|
+
// identifier, consistent with how inline enums are handled above.
|
|
21731
|
+
// Also only keep the direct reference — the referenced type handles its own imports.
|
|
21732
|
+
// Create new objects to avoid mutating cached data from generateReferencedType.
|
|
21733
|
+
if (typeInfo.items.$ref !== null) {
|
|
21734
|
+
const refItemTypeName = arrayItemsType.templateInput.typeName;
|
|
21735
|
+
arrayItemsType = {
|
|
21736
|
+
...arrayItemsType,
|
|
21737
|
+
templateInput: { ...arrayItemsType.templateInput, type: refItemTypeName },
|
|
21738
|
+
references: new Set([refItemTypeName])
|
|
21739
|
+
};
|
|
21740
|
+
}
|
|
21700
21741
|
}
|
|
21701
21742
|
if (typeof arrayItemsType.templateInput?.type === 'undefined') {
|
|
21702
21743
|
throw new InvalidSpecFileError('Invalid array type for: ' + typeName);
|
|
@@ -21962,28 +22003,41 @@ async function generator(specFileData) {
|
|
|
21962
22003
|
}
|
|
21963
22004
|
}
|
|
21964
22005
|
result.groupedTypes = groupedTypes;
|
|
22006
|
+
// remove self references from grouped types
|
|
22007
|
+
for (const groupName in result.groupedTypes) {
|
|
22008
|
+
for (const typeName in result.groupedTypes[groupName]) {
|
|
22009
|
+
result.groupedTypes[groupName][typeName].references.delete(typeName);
|
|
22010
|
+
}
|
|
22011
|
+
}
|
|
21965
22012
|
return result;
|
|
21966
22013
|
}
|
|
21967
22014
|
|
|
22015
|
+
function formatModuleName(name) {
|
|
22016
|
+
const moduleNameCase = Runtime.getConfig().language.modulePathConfig.moduleNameCase;
|
|
22017
|
+
return typeof moduleNameCase !== 'undefined' ? formatCase(name, moduleNameCase) : name;
|
|
22018
|
+
}
|
|
21968
22019
|
function generateTypesOutputFiles(types, groupName = null) {
|
|
21969
22020
|
const config = Runtime.getConfig();
|
|
21970
22021
|
const extension = config.output.fileExtension;
|
|
21971
22022
|
const outputDir = config.output.directory;
|
|
21972
22023
|
const moduleFileName = config.language.exporterModuleName;
|
|
21973
22024
|
const writerMode = groupName === null ? config.output.writerMode.types : config.output.writerMode.groupedTypes;
|
|
22025
|
+
const formattedGroupName = groupName !== null ? formatModuleName(groupName) : null;
|
|
21974
22026
|
const result = new Map();
|
|
21975
22027
|
for (const typeName in types) {
|
|
21976
22028
|
const typeProperties = types[typeName];
|
|
21977
22029
|
if (typeof typeProperties !== 'undefined') {
|
|
22030
|
+
const formattedTypeName = formatModuleName(typeName);
|
|
21978
22031
|
result.set(typeName, {
|
|
21979
22032
|
modulePath: outputDir +
|
|
21980
22033
|
'/' +
|
|
21981
|
-
(
|
|
21982
|
-
|
|
22034
|
+
(formattedGroupName
|
|
22035
|
+
? formattedGroupName + (writerMode === 'FolderWithFiles' ? '/' + moduleFileName : '')
|
|
22036
|
+
: moduleFileName),
|
|
21983
22037
|
filePath: outputDir +
|
|
21984
22038
|
(writerMode === 'Files' || writerMode === 'FolderWithFiles'
|
|
21985
|
-
? '/' + (
|
|
21986
|
-
: '/' + (
|
|
22039
|
+
? '/' + (formattedGroupName ?? '') + formattedTypeName
|
|
22040
|
+
: '/' + (formattedGroupName ?? 'types')),
|
|
21987
22041
|
extension
|
|
21988
22042
|
});
|
|
21989
22043
|
}
|
|
@@ -22041,7 +22095,7 @@ async function writeTypesToFiles(config, types, folderName = '') {
|
|
|
22041
22095
|
const typeNames = Object.keys(types);
|
|
22042
22096
|
for (const typeName in types) {
|
|
22043
22097
|
const typeData = types[typeName];
|
|
22044
|
-
const file = typeName + config.output.fileExtension;
|
|
22098
|
+
const file = formatModuleName(typeName) + config.output.fileExtension;
|
|
22045
22099
|
const references = filterReferences
|
|
22046
22100
|
? [...types[typeName].references].filter((x) => !typeNames.includes(x))
|
|
22047
22101
|
: [...types[typeName].references];
|
|
@@ -22125,11 +22179,12 @@ async function writeOutput(generationResult) {
|
|
|
22125
22179
|
if (config.output.writerMode.groupedTypes === 'FolderWithFiles') {
|
|
22126
22180
|
for (const groupName in generationResult.groupedTypes) {
|
|
22127
22181
|
let groupFilesWritten = null;
|
|
22128
|
-
|
|
22182
|
+
const formattedGroupName = formatModuleName(groupName);
|
|
22183
|
+
await createFolderWithBasePath(config.output.directory, formattedGroupName);
|
|
22129
22184
|
addValuesToMappedSet(writtenFiles, await getCompleteFolderPath(config.output.directory), [
|
|
22130
|
-
|
|
22185
|
+
formattedGroupName
|
|
22131
22186
|
]);
|
|
22132
|
-
groupFilesWritten = await writeTypesToFiles(config, generationResult.groupedTypes[groupName],
|
|
22187
|
+
groupFilesWritten = await writeTypesToFiles(config, generationResult.groupedTypes[groupName], formattedGroupName);
|
|
22133
22188
|
if (groupFilesWritten !== null) {
|
|
22134
22189
|
addValuesToMappedSet(writtenFiles, await getCompleteFolderPath(groupFilesWritten.folderName), groupFilesWritten.files);
|
|
22135
22190
|
}
|
|
@@ -22138,7 +22193,7 @@ async function writeOutput(generationResult) {
|
|
|
22138
22193
|
else if (config.output.writerMode.groupedTypes === 'SingleFile') {
|
|
22139
22194
|
for (const groupName in generationResult.groupedTypes) {
|
|
22140
22195
|
let groupFilesWritten = null;
|
|
22141
|
-
groupFilesWritten = await writeTypesToFile(config, generationResult.groupedTypes[groupName], groupName);
|
|
22196
|
+
groupFilesWritten = await writeTypesToFile(config, generationResult.groupedTypes[groupName], formatModuleName(groupName));
|
|
22142
22197
|
if (groupFilesWritten !== null) {
|
|
22143
22198
|
addValuesToMappedSet(writtenFiles, await getCompleteFolderPath(groupFilesWritten.folderName), groupFilesWritten.files);
|
|
22144
22199
|
}
|
|
@@ -22301,7 +22356,64 @@ async function config(inputFilePath, outputDirectory, typesWriterMode, groupedTy
|
|
|
22301
22356
|
parentRef: 'super',
|
|
22302
22357
|
selfRef: 'self',
|
|
22303
22358
|
moduleFileName: 'mod',
|
|
22304
|
-
fileBasedModules: true
|
|
22359
|
+
fileBasedModules: true,
|
|
22360
|
+
moduleNameCase: 'snake_case'
|
|
22361
|
+
},
|
|
22362
|
+
reservedKeywords: {
|
|
22363
|
+
prefix: 'r#',
|
|
22364
|
+
words: [
|
|
22365
|
+
'as',
|
|
22366
|
+
'break',
|
|
22367
|
+
'const',
|
|
22368
|
+
'continue',
|
|
22369
|
+
'crate',
|
|
22370
|
+
'else',
|
|
22371
|
+
'enum',
|
|
22372
|
+
'extern',
|
|
22373
|
+
'false',
|
|
22374
|
+
'fn',
|
|
22375
|
+
'for',
|
|
22376
|
+
'if',
|
|
22377
|
+
'impl',
|
|
22378
|
+
'in',
|
|
22379
|
+
'let',
|
|
22380
|
+
'loop',
|
|
22381
|
+
'match',
|
|
22382
|
+
'mod',
|
|
22383
|
+
'move',
|
|
22384
|
+
'mut',
|
|
22385
|
+
'pub',
|
|
22386
|
+
'ref',
|
|
22387
|
+
'return',
|
|
22388
|
+
'self',
|
|
22389
|
+
'Self',
|
|
22390
|
+
'static',
|
|
22391
|
+
'struct',
|
|
22392
|
+
'super',
|
|
22393
|
+
'trait',
|
|
22394
|
+
'true',
|
|
22395
|
+
'type',
|
|
22396
|
+
'unsafe',
|
|
22397
|
+
'use',
|
|
22398
|
+
'where',
|
|
22399
|
+
'while',
|
|
22400
|
+
'async',
|
|
22401
|
+
'await',
|
|
22402
|
+
'dyn',
|
|
22403
|
+
'abstract',
|
|
22404
|
+
'become',
|
|
22405
|
+
'box',
|
|
22406
|
+
'do',
|
|
22407
|
+
'final',
|
|
22408
|
+
'macro',
|
|
22409
|
+
'override',
|
|
22410
|
+
'priv',
|
|
22411
|
+
'typeof',
|
|
22412
|
+
'unsized',
|
|
22413
|
+
'virtual',
|
|
22414
|
+
'yield',
|
|
22415
|
+
'try'
|
|
22416
|
+
]
|
|
22305
22417
|
}
|
|
22306
22418
|
}
|
|
22307
22419
|
};
|
|
@@ -22374,7 +22486,7 @@ async function runner(language, inputFilePath, outputDirectory, _typesWriterMode
|
|
|
22374
22486
|
}
|
|
22375
22487
|
}
|
|
22376
22488
|
greeting();
|
|
22377
|
-
const program = new Command().version('0.13.
|
|
22489
|
+
const program = new Command().version('0.13.1');
|
|
22378
22490
|
program
|
|
22379
22491
|
.command('generate')
|
|
22380
22492
|
.description('Generate types for your language from a type spec file')
|
|
@@ -6,13 +6,13 @@ pub struct {{typeName}} {
|
|
|
6
6
|
{{#each compositions}}
|
|
7
7
|
{{#if (eq this.source 'referenced')}}
|
|
8
8
|
#[serde(flatten)]
|
|
9
|
-
pub {{toSnakeCase this.referencedType}}: {{this.referencedType}},
|
|
9
|
+
pub {{escapeReservedWord (toSnakeCase this.referencedType)}}: {{this.referencedType}},
|
|
10
10
|
{{else if (eq this.source 'inline')}}
|
|
11
11
|
{{#if (eq this.dataType 'object')}}
|
|
12
12
|
#[serde(flatten)]
|
|
13
|
-
pub {{toSnakeCase this.templateInput.typeName}}: {{this.templateInput.typeName}},
|
|
13
|
+
pub {{escapeReservedWord (toSnakeCase this.templateInput.typeName)}}: {{this.templateInput.typeName}},
|
|
14
14
|
{{else}}
|
|
15
|
-
pub {{toSnakeCase this.templateInput.typeName}}: {{{this.templateInput.type}}},
|
|
15
|
+
pub {{escapeReservedWord (toSnakeCase this.templateInput.typeName)}}: {{{this.templateInput.type}}},
|
|
16
16
|
{{/if}}
|
|
17
17
|
{{/if}}
|
|
18
18
|
{{/each}}
|
|
@@ -14,7 +14,7 @@ pub struct {{typeName}} {
|
|
|
14
14
|
{{#unless this.required}}
|
|
15
15
|
#[serde(skip_serializing_if = "Option::is_none")]
|
|
16
16
|
{{/unless}}
|
|
17
|
-
pub {{toSnakeCase @key}}: {{#unless this.required}}Option<{{/unless}}{{{this.type}}}{{#unless this.required}}>{{/unless}},
|
|
17
|
+
pub {{escapeReservedWord (toSnakeCase @key)}}: {{#unless this.required}}Option<{{/unless}}{{{this.type}}}{{#unless this.required}}>{{/unless}},
|
|
18
18
|
{{/each}}
|
|
19
19
|
{{#if additionalProperties}}
|
|
20
20
|
#[serde(flatten)]
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
use serde::{Serialize, Deserialize};
|
|
2
2
|
{{#each (getReferencedTypeModules referencedTypes writtenAt)}}
|
|
3
3
|
{{#each this.referencedTypes}}
|
|
4
|
-
|
|
4
|
+
{{#if ../fileBasedModules}}
|
|
5
|
+
use {{{../moduleRelativePath}}}::{{toSnakeCase this}}::{{this}};
|
|
6
|
+
{{else}}
|
|
7
|
+
use {{{../moduleRelativePath}}}::{{this}};
|
|
8
|
+
{{/if}}
|
|
5
9
|
{{/each}}
|
|
6
10
|
{{/each}}
|
|
7
11
|
|
package/dist/types/index.d.ts
CHANGED
|
@@ -25,17 +25,24 @@ export type Template = {
|
|
|
25
25
|
oneOfSyntax: string;
|
|
26
26
|
allOfSyntax: string;
|
|
27
27
|
};
|
|
28
|
+
export type FontCase = 'snake_case' | 'PascalCase' | 'camelCase';
|
|
28
29
|
export type ModulePathConfig = {
|
|
29
30
|
separator: string;
|
|
30
31
|
parentRef: string;
|
|
31
32
|
selfRef: string;
|
|
32
33
|
moduleFileName: string;
|
|
33
34
|
fileBasedModules: boolean;
|
|
35
|
+
moduleNameCase?: FontCase;
|
|
36
|
+
};
|
|
37
|
+
export type ReservedKeywordsConfig = {
|
|
38
|
+
words: string[];
|
|
39
|
+
prefix: string;
|
|
34
40
|
};
|
|
35
41
|
export type LanguageConfig = {
|
|
36
42
|
exporterModuleName: string;
|
|
37
43
|
typeMapper: LanguageTypeMapper;
|
|
38
44
|
modulePathConfig: ModulePathConfig;
|
|
45
|
+
reservedKeywords?: ReservedKeywordsConfig;
|
|
39
46
|
};
|
|
40
47
|
/**
|
|
41
48
|
* @description Mappers for all the types supported by OpenAPI 3.0.0
|
|
@@ -149,6 +156,7 @@ export type ReferencedModule = {
|
|
|
149
156
|
moduleRelativePath: string;
|
|
150
157
|
referencedTypes: string[];
|
|
151
158
|
moduleName: string;
|
|
159
|
+
fileBasedModules: boolean;
|
|
152
160
|
};
|
|
153
161
|
export type EnumTemplateInput = TypeDescriptors & {
|
|
154
162
|
typeName: string;
|
package/dist/utils/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ModulePathConfig, type TypeInfo, type TypeDataType } from '$types';
|
|
1
|
+
import { type ModulePathConfig, type FontCase, type TypeInfo, type TypeDataType } from '$types';
|
|
2
2
|
import { type JSONObject } from 'type-decoder';
|
|
3
3
|
export * from './file-system';
|
|
4
4
|
export * from './logger';
|
|
@@ -11,9 +11,12 @@ export declare function toPascalCase(input: string): string;
|
|
|
11
11
|
export declare function toPascalCaseHelper(input: unknown): string | unknown;
|
|
12
12
|
export declare function toSnakeCase(input: string): string;
|
|
13
13
|
export declare function toSnakeCaseHelper(input: unknown): string | unknown;
|
|
14
|
+
export declare function toCamelCase(input: string): string;
|
|
15
|
+
export declare function formatCase(input: string, fontCase: FontCase): string;
|
|
14
16
|
export declare function refineJSONKey(input: unknown): unknown;
|
|
15
17
|
export declare function refineVariableName(input: unknown): unknown;
|
|
16
18
|
export declare function refineIndexKey(input: unknown): unknown;
|
|
19
|
+
export declare function escapeReservedWord(input: unknown): unknown;
|
|
17
20
|
export declare function registerTemplateHelpers(): void;
|
|
18
21
|
export declare function readNestedValue(json: unknown, keyPath: string[]): JSONObject;
|
|
19
22
|
export declare function generateRelativePath(fromPath: string, toPath: string): string;
|
package/dist/writer/helpers.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import { type TypeFilePath, type Types } from '$types';
|
|
2
|
+
export declare function formatModuleName(name: string): string;
|
|
2
3
|
export declare function generateTypesOutputFiles(types: Types | null, groupName?: string | null): Map<string, TypeFilePath>;
|
|
3
4
|
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.13.
|
|
3
|
+
"version": "0.13.1",
|
|
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",
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
],
|
|
16
16
|
"scripts": {
|
|
17
17
|
"dev": "tsc --watch",
|
|
18
|
-
"format
|
|
19
|
-
"lint
|
|
18
|
+
"format": "npx prettier --write .",
|
|
19
|
+
"lint": "eslint src",
|
|
20
20
|
"clean:output": "rm -rf dist",
|
|
21
21
|
"build": "npm run clean:output && rollup --config rollup.config.js"
|
|
22
22
|
},
|