Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@amritk/helpers

Package Overview
Dependencies
Maintainers
1
Versions
14
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@amritk/helpers - npm Package Compare versions

Comparing version
0.5.0
to
0.6.0
+5
-0
dist/generate-type-definition.d.ts

@@ -6,2 +6,7 @@ import type { JSONSchema } from 'json-schema-typed/draft-2020-12';

readonly readonly?: boolean;
/**
* Suffix appended to every generated type name derived from a `$ref`.
* Defaults to `''` (no suffix). Set to e.g. `'Object'` to emit `ContactObject`.
*/
readonly typeSuffix?: string;
};

@@ -8,0 +13,0 @@ /**

+10
-10

@@ -161,3 +161,3 @@ // src/has-ref.ts

// src/ref-to-name.ts
var kebabToPascal = (kebab) => {
var kebabToPascal = (kebab, suffix) => {
const words = kebab.split("-");

@@ -168,5 +168,5 @@ let pascalCase = "";

}
return pascalCase + "Object";
return pascalCase + suffix;
};
var refToName = (ref) => kebabToPascal(refToFilename(ref));
var refToName = (ref, suffix = "") => kebabToPascal(refToFilename(ref), suffix);

@@ -302,9 +302,9 @@ // src/safe-accessor.ts

}
return refToName(schema.$ref);
return refToName(schema.$ref, options.typeSuffix);
}
if (schema.$dynamicRef) {
if (schema.$dynamicRef === "#meta") {
return "Schema";
return `Schema${options.typeSuffix ?? ""}`;
}
return refToName(schema.$dynamicRef);
return refToName(schema.$dynamicRef, options.typeSuffix);
}

@@ -356,3 +356,3 @@ if (schema.const !== undefined) {

if (conditionalResult.thenRef) {
return `(${baseType}) & ${refToName(conditionalResult.thenRef)}`;
return `(${baseType}) & ${refToName(conditionalResult.thenRef, options.typeSuffix)}`;
}

@@ -550,3 +550,3 @@ return baseType;

if (isSchemaObject(entry) && entry.$ref) {
allOfIntersections.push(refToName(entry.$ref));
allOfIntersections.push(refToName(entry.$ref, options.typeSuffix));
}

@@ -556,3 +556,3 @@ }

if (isSchemaObject(schema) && typeof schema.$ref === "string" && schema.$ref.startsWith("#")) {
allOfIntersections.push(refToName(schema.$ref));
allOfIntersections.push(refToName(schema.$ref, options.typeSuffix));
}

@@ -567,3 +567,3 @@ let result = "";

if (conditionalThenRef) {
typeBody += " & " + refToName(conditionalThenRef);
typeBody += " & " + refToName(conditionalThenRef, options.typeSuffix);
}

@@ -570,0 +570,0 @@ for (const intersectionType of allOfIntersections) {

/**
* Converts a JSON Schema $ref to a type name.
* Derives the filename via `refToFilename` then converts to PascalCase with
* an "Object" suffix.
* Derives the filename via `refToFilename` then converts to PascalCase,
* appending an optional suffix.
*

@@ -9,11 +9,14 @@ * Handles all ref forms: internal `#/$defs/...`, `#/definitions/...`, and URI refs.

* @param ref - The $ref string
* @returns The type name in PascalCase with "Object" suffix
* @param suffix - Optional suffix appended to the PascalCase name. Defaults to
* `''` (no suffix). Pass e.g. `'Object'` to get `ContactObject`.
* @returns The type name in PascalCase with the suffix applied
*
* @example
* ```ts
* refToName('#/$defs/contact') // 'ContactObject'
* refToName('#/$defs/server-variable') // 'ServerVariableObject'
* refToName('http://asyncapi.com/definitions/3.1.0/channel.json') // 'ChannelObject'
* refToName('#/$defs/contact') // 'Contact'
* refToName('#/$defs/server-variable') // 'ServerVariable'
* refToName('#/$defs/contact', 'Object') // 'ContactObject'
* refToName('http://asyncapi.com/definitions/3.1.0/channel.json') // 'Channel'
* ```
*/
export declare const refToName: (ref: string) => string;
export declare const refToName: (ref: string, suffix?: string) => string;

@@ -43,3 +43,3 @@ // src/ref-to-filename.ts

// src/ref-to-name.ts
var kebabToPascal = (kebab) => {
var kebabToPascal = (kebab, suffix) => {
const words = kebab.split("-");

@@ -50,7 +50,7 @@ let pascalCase = "";

}
return pascalCase + "Object";
return pascalCase + suffix;
};
var refToName = (ref) => kebabToPascal(refToFilename(ref));
var refToName = (ref, suffix = "") => kebabToPascal(refToFilename(ref), suffix);
export {
refToName
};
{
"name": "@amritk/helpers",
"version": "0.5.0",
"version": "0.6.0",
"description": "Shared utilities for the mjst code generation ecosystem.",

@@ -5,0 +5,0 @@ "type": "module",

@@ -167,5 +167,5 @@ import type { JSONSchema } from 'json-schema-typed/draft-2020-12'

const result = generateTypeDefinition(schema, 'GenericObject')
const result = generateTypeDefinition(schema, 'Generic')
expect(result).toStrictEqual('export type GenericObject = {\n' + ' metadata?: object;\n' + '};')
expect(result).toStrictEqual('export type Generic = {\n' + ' metadata?: object;\n' + '};')
})

@@ -224,5 +224,5 @@

const result = generateTypeDefinition(schema, 'EmptyObject')
const result = generateTypeDefinition(schema, 'Empty')
expect(result).toStrictEqual('export type EmptyObject = {\n' + '\n' + '};')
expect(result).toStrictEqual('export type Empty = {\n' + '\n' + '};')
})

@@ -580,14 +580,14 @@

const result = generateTypeDefinition(info, 'InfoObject')
const result = generateTypeDefinition(info, 'Info')
expect(result).toStrictEqual(
'/**\n' +
'* InfoObject\n' +
'* Info\n' +
'*\n' +
'* https://spec.openapis.org/oas/v3.1#info-object\n' +
'*/\n' +
'export type InfoObject = {\n' +
'export type Info = {\n' +
' title: string;\n' +
' summary?: string;\n' +
' contact?: ContactObject;\n' +
' contact?: Contact;\n' +
' version: string;\n' +

@@ -617,9 +617,9 @@ '};',

const result = generateTypeDefinition(components, 'ComponentsObject')
const result = generateTypeDefinition(components, 'Components')
expect(result).toStrictEqual(
'export type ComponentsObject = {\n' +
' responses?: Record<string, ResponseObject>;\n' +
' parameters?: Record<string, ParameterObject>;\n' +
' pathItems?: Record<string, PathItemObject>;\n' +
'export type Components = {\n' +
' responses?: Record<string, Response>;\n' +
' parameters?: Record<string, Parameter>;\n' +
' pathItems?: Record<string, PathItem>;\n' +
'};',

@@ -629,3 +629,3 @@ )

it('generates type for object with paths property as Record<string, PathItemObject>', () => {
it('generates type for object with paths property as Record<string, PathItem>', () => {
const document: JSONSchema.Object = {

@@ -655,4 +655,4 @@ $comment: 'https://spec.openapis.org/oas/v3.1#openapi-object',

' openapi: string;\n' +
' info: InfoObject;\n' +
' paths?: Record<string, PathItemObject>;\n' +
' info: Info;\n' +
' paths?: Record<string, PathItem>;\n' +
'};',

@@ -711,8 +711,8 @@ )

' openapi: string;\n' +
' info: InfoObject;\n' +
' info: Info;\n' +
' jsonSchemaDialect?: string;\n' +
' servers?: ServerObject[];\n' +
' paths?: Record<string, PathItemObject>;\n' +
' webhooks?: Record<string, PathItemObject>;\n' +
' components?: ComponentsObject;\n' +
' servers?: Server[];\n' +
' paths?: Record<string, PathItem>;\n' +
' webhooks?: Record<string, PathItem>;\n' +
' components?: Components;\n' +
'};',

@@ -733,11 +733,11 @@ )

const result = generateTypeDefinition(paths, 'PathsObject')
const result = generateTypeDefinition(paths, 'Paths')
expect(result).toStrictEqual(
'/**\n' +
'* PathsObject\n' +
'* Paths\n' +
'*\n' +
'* https://spec.openapis.org/oas/v3.1#paths-object\n' +
'*/\n' +
'export type PathsObject = Record<string, PathItemObject>;',
'export type Paths = Record<string, PathItem>;',
)

@@ -754,3 +754,3 @@ })

}
const result = generateTypeDefinition(schema, 'InfoExtensionsObject')
const result = generateTypeDefinition(schema, 'InfoExtensions')
expect(result).toContain("'x-linkedin'?: string;")

@@ -779,7 +779,5 @@ expect(result).toContain('name?: string;')

const result = generateTypeDefinition(schema, 'TypeHttpObject')
const result = generateTypeDefinition(schema, 'TypeHttp')
expect(result).toStrictEqual(
'export type TypeHttpObject = {\n' + ' type: "http";\n' + ' scheme: string;\n' + '};',
)
expect(result).toStrictEqual('export type TypeHttp = {\n' + ' type: "http";\n' + ' scheme: string;\n' + '};')
})

@@ -805,6 +803,6 @@

const result = generateTypeDefinition(schema, 'TypeHttpObject')
const result = generateTypeDefinition(schema, 'TypeHttp')
expect(result).toStrictEqual(
'export type TypeHttpObject = {\n' + ' type: "http";\n' + ' bearerFormat: string;\n' + '};',
'export type TypeHttp = {\n' + ' type: "http";\n' + ' bearerFormat: string;\n' + '};',
)

@@ -837,5 +835,5 @@ })

const result = generateTypeDefinition(schema, 'TypeHttpObject')
const result = generateTypeDefinition(schema, 'TypeHttp')
expect(result).toContain('* TypeHttpObject')
expect(result).toContain('* TypeHttp')
expect(result).toContain('* https://spec.openapis.org/oas/v3.1#security-scheme-object')

@@ -862,9 +860,9 @@ expect(result).toContain('type: "http";')

const result = generateTypeDefinition(securityScheme, 'SecuritySchemeObject')
const result = generateTypeDefinition(securityScheme, 'SecurityScheme')
expect(result).toStrictEqual(
'export type SecuritySchemeObject = {\n' +
'export type SecurityScheme = {\n' +
' type: "apiKey" | "http" | "oauth2";\n' +
' description?: string;\n' +
'} & TypeApikeyObject & TypeHttpObject & TypeOauth2Object;',
'} & TypeApikey & TypeHttp & TypeOauth2;',
)

@@ -886,8 +884,8 @@ })

const result = generateTypeDefinition(securityScheme, 'SecuritySchemeObject')
const result = generateTypeDefinition(securityScheme, 'SecurityScheme')
expect(result).toContain('* SecuritySchemeObject')
expect(result).toContain('* SecurityScheme')
expect(result).toContain('* https://spec.openapis.org/oas/v3.1#security-scheme-object')
expect(result).toContain('type: "apiKey" | "http" | "oauth2";')
expect(result).toContain('} & TypeApikeyObject & TypeHttpObject;')
expect(result).toContain('} & TypeApikey & TypeHttp;')
})

@@ -902,5 +900,5 @@

const result = generateTypeDefinition(schema, 'SpecificationExtensionsObject')
const result = generateTypeDefinition(schema, 'SpecificationExtensions')
expect(result).toStrictEqual('export type SpecificationExtensionsObject = Record<`x-${string}`, unknown>;')
expect(result).toStrictEqual('export type SpecificationExtensions = Record<`x-${string}`, unknown>;')
})

@@ -917,5 +915,5 @@

const result = generateTypeDefinition(schema, 'RestrictedObject')
const result = generateTypeDefinition(schema, 'Restricted')
expect(result).toStrictEqual('export type RestrictedObject = Record<`x-${string}`, never>;')
expect(result).toStrictEqual('export type Restricted = Record<`x-${string}`, never>;')
})

@@ -949,3 +947,3 @@

expect(result).toContain('content?: SchemaObject')
expect(result).toContain('content?: Schema')
})

@@ -1078,8 +1076,8 @@

const result = generateTypeDefinition(schema, 'CallbackObject')
const result = generateTypeDefinition(schema, 'Callback')
expect(result).toContain('/**')
expect(result).toContain('* CallbackObject')
expect(result).toContain('* Callback')
expect(result).toContain('* https://spec.openapis.org/oas/v3.1#callback-object')
expect(result).toContain('[key: string]: PathItemObject')
expect(result).toContain('[key: string]: PathItem')
})

@@ -1172,3 +1170,3 @@

expect(result).toBe('export type Parameters = (ParameterObject | ReferenceObject)[];')
expect(result).toBe('export type Parameters = (Parameter | Reference)[];')
})

@@ -1187,3 +1185,3 @@

expect(result).toContain('* https://spec.openapis.org/oas/v3.1#contact-object')
expect(result).toContain('export type Contacts = ServerObject[];')
expect(result).toContain('export type Contacts = Server[];')
})

@@ -1202,3 +1200,3 @@

expect(result).toContain('A list of parameters applicable to the operation.')
expect(result).toContain('export type Parameters = ParameterObject[];')
expect(result).toContain('export type Parameters = Parameter[];')
})

@@ -1212,5 +1210,5 @@

const result = generateTypeDefinition(schema, 'MaximumObject')
const result = generateTypeDefinition(schema, 'Maximum')
expect(result).toBe('export type MaximumObject = unknown;')
expect(result).toBe('export type Maximum = unknown;')
})

@@ -1227,3 +1225,3 @@

const result = generateTypeDefinition(schema, 'PlainCommentObject')
const result = generateTypeDefinition(schema, 'PlainComment')

@@ -1340,2 +1338,23 @@ expect(result).toMatch(/\* A plain-text description with no URL\.\n\*\//)

})
describe('typeSuffix', () => {
const schema: JSONSchema = {
type: 'object',
properties: {
contact: { $ref: '#/$defs/contact' },
},
required: ['contact'],
}
it('appends the suffix to ref-derived type names', () => {
const result = generateTypeDefinition(schema, 'Document', { typeSuffix: 'Object' })
expect(result).toContain('contact: ContactObject;')
})
it('emits no suffix by default', () => {
const result = generateTypeDefinition(schema, 'Document')
expect(result).toContain('contact: Contact;')
expect(result).not.toContain('ContactObject')
})
})
})

@@ -17,2 +17,7 @@ import type { JSONSchema } from 'json-schema-typed/draft-2020-12'

readonly readonly?: boolean
/**
* Suffix appended to every generated type name derived from a `$ref`.
* Defaults to `''` (no suffix). Set to e.g. `'Object'` to emit `ContactObject`.
*/
readonly typeSuffix?: string
}

@@ -168,3 +173,3 @@

}
return refToName(schema.$ref)
return refToName(schema.$ref, options.typeSuffix)
}

@@ -176,5 +181,5 @@

if (schema.$dynamicRef === '#meta') {
return 'Schema'
return `Schema${options.typeSuffix ?? ''}`
}
return refToName(schema.$dynamicRef)
return refToName(schema.$dynamicRef, options.typeSuffix)
}

@@ -241,3 +246,3 @@

if (conditionalResult.thenRef) {
return `(${baseType}) & ${refToName(conditionalResult.thenRef)}`
return `(${baseType}) & ${refToName(conditionalResult.thenRef, options.typeSuffix)}`
}

@@ -500,3 +505,3 @@ return baseType

if (isSchemaObject(entry) && entry.$ref) {
allOfIntersections.push(refToName(entry.$ref))
allOfIntersections.push(refToName(entry.$ref, options.typeSuffix))
}

@@ -509,3 +514,3 @@ }

if (isSchemaObject(schema) && typeof schema.$ref === 'string' && schema.$ref.startsWith('#')) {
allOfIntersections.push(refToName(schema.$ref))
allOfIntersections.push(refToName(schema.$ref, options.typeSuffix))
}

@@ -521,3 +526,3 @@

if (conditionalThenRef) {
typeBody += ' & ' + refToName(conditionalThenRef)
typeBody += ' & ' + refToName(conditionalThenRef, options.typeSuffix)
}

@@ -524,0 +529,0 @@

@@ -7,32 +7,32 @@ import { describe, expect, it } from 'vitest'

it('converts simple ref to PascalCase', () => {
expect(refToName('#/$defs/contact')).toBe('ContactObject')
expect(refToName('#/$defs/contact')).toBe('Contact')
})
it('converts kebab-case ref to PascalCase', () => {
expect(refToName('#/$defs/server-variable')).toBe('ServerVariableObject')
expect(refToName('#/$defs/server-variable')).toBe('ServerVariable')
})
it('converts multi-word kebab-case ref to PascalCase', () => {
expect(refToName('#/$defs/external-documentation')).toBe('ExternalDocumentationObject')
expect(refToName('#/$defs/external-documentation')).toBe('ExternalDocumentation')
})
it('handles refs with multiple path segments', () => {
expect(refToName('#/components/schemas/user-profile')).toBe('UserProfileObject')
expect(refToName('#/components/schemas/user-profile')).toBe('UserProfile')
})
it('handles single word refs', () => {
expect(refToName('#/$defs/info')).toBe('InfoObject')
expect(refToName('#/$defs/info')).toBe('Info')
})
it('handles refs with numbers', () => {
expect(refToName('#/$defs/oauth2-flow')).toBe('Oauth2FlowObject')
expect(refToName('#/$defs/oauth2-flow')).toBe('Oauth2Flow')
})
it('converts uppercase acronym keys to PascalCase via kebab normalization', () => {
expect(refToName('#/$defs/APIKey')).toBe('ApiKeyObject')
expect(refToName('#/$defs/APIKey')).toBe('ApiKey')
})
it('derives type name from a URI ref', () => {
expect(refToName('http://asyncapi.com/definitions/3.1.0/channel.json')).toBe('ChannelObject')
expect(refToName('http://asyncapi.com/definitions/3.1.0/info.json')).toBe('InfoObject')
expect(refToName('http://asyncapi.com/definitions/3.1.0/channel.json')).toBe('Channel')
expect(refToName('http://asyncapi.com/definitions/3.1.0/info.json')).toBe('Info')
})

@@ -42,3 +42,3 @@

expect(refToName('http://asyncapi.com/bindings/sns/0.1.0/channel.json#/definitions/queue')).toBe(
'BindingsSns010ChannelQueueObject',
'BindingsSns010ChannelQueue',
)

@@ -48,4 +48,13 @@ })

it('handles draft-07 schema URI', () => {
expect(refToName('http://json-schema.org/draft-07/schema')).toBe('Draft07SchemaObject')
expect(refToName('http://json-schema.org/draft-07/schema')).toBe('Draft07Schema')
})
it('appends the suffix when one is provided', () => {
expect(refToName('#/$defs/contact', 'Object')).toBe('ContactObject')
expect(refToName('#/$defs/server-variable', 'Object')).toBe('ServerVariableObject')
})
it('treats an empty suffix the same as omitting it', () => {
expect(refToName('#/$defs/contact', '')).toBe('Contact')
})
})
import { refToFilename } from './ref-to-filename'
/**
* Converts a kebab-case filename to PascalCase with an "Object" suffix.
* Converts a kebab-case filename to PascalCase, appending an optional suffix.
*
* @example
* ```ts
* kebabToPascal('server-variable') // 'ServerVariableObject'
* kebabToPascal('channel') // 'ChannelObject'
* kebabToPascal('server-variable') // 'ServerVariable'
* kebabToPascal('channel') // 'Channel'
* kebabToPascal('channel', 'Object') // 'ChannelObject'
* ```
*/
const kebabToPascal = (kebab: string): string => {
const kebabToPascal = (kebab: string, suffix: string): string => {
const words = kebab.split('-')

@@ -18,3 +19,3 @@ let pascalCase = ''

}
return pascalCase + 'Object'
return pascalCase + suffix
}

@@ -24,4 +25,4 @@

* Converts a JSON Schema $ref to a type name.
* Derives the filename via `refToFilename` then converts to PascalCase with
* an "Object" suffix.
* Derives the filename via `refToFilename` then converts to PascalCase,
* appending an optional suffix.
*

@@ -31,11 +32,14 @@ * Handles all ref forms: internal `#/$defs/...`, `#/definitions/...`, and URI refs.

* @param ref - The $ref string
* @returns The type name in PascalCase with "Object" suffix
* @param suffix - Optional suffix appended to the PascalCase name. Defaults to
* `''` (no suffix). Pass e.g. `'Object'` to get `ContactObject`.
* @returns The type name in PascalCase with the suffix applied
*
* @example
* ```ts
* refToName('#/$defs/contact') // 'ContactObject'
* refToName('#/$defs/server-variable') // 'ServerVariableObject'
* refToName('http://asyncapi.com/definitions/3.1.0/channel.json') // 'ChannelObject'
* refToName('#/$defs/contact') // 'Contact'
* refToName('#/$defs/server-variable') // 'ServerVariable'
* refToName('#/$defs/contact', 'Object') // 'ContactObject'
* refToName('http://asyncapi.com/definitions/3.1.0/channel.json') // 'Channel'
* ```
*/
export const refToName = (ref: string): string => kebabToPascal(refToFilename(ref))
export const refToName = (ref: string, suffix = ''): string => kebabToPascal(refToFilename(ref), suffix)