Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@luvio/generator-ts

Package Overview
Dependencies
Maintainers
0
Versions
69
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@luvio/generator-ts - npm Package Compare versions

Comparing version 5.11.0 to 5.12.0

dist/types/commands/__tests__/aura-command/basic.spec.d.ts

581

dist/generator-ts.js

@@ -218,2 +218,7 @@ /**

}
// default importStringifier implementation
function defaultImportStringifier(ir) {
const source = 'filename' in ir ? `file:${ir.filename}` : `module:${ir.module}`;
return `<<${source}:${ir.exportedSymbol}:${ir.isType})>>`;
}
/**

@@ -255,4 +260,4 @@ * A Code instance holds a collection of TypeScript code.

*
* @param newChunks
* @returns
* @param newChunks code to be appended
* @returns this
*/

@@ -287,22 +292,19 @@ push(...newChunks) {

equals(comparison) {
return (this.chunks.length === comparison.chunks.length &&
this.chunks.every((chunkA, i) => {
const chunkB = comparison.chunks[i];
if (isImportableReference(chunkA)) {
if (isImportableReference(chunkB)) {
// replace with generic deep equality function if ImportableReference grows or changes
return (chunkA.exportedSymbol === chunkB.exportedSymbol &&
(('filename' in chunkA &&
'filename' in chunkB &&
chunkA.filename === chunkB.filename) ||
('module' in chunkA &&
'module' in chunkB &&
chunkA.module === chunkB.module)) &&
chunkA.isType === chunkB.isType);
}
return false;
}
return chunkA === chunkB;
}));
return this.toString() === comparison.toString();
}
/**
* Returns the Code as a single string.
*
* @param options
* importStringifier - function to convert ImportableReferences to strings.
* Defaults to an internal function whose only guarantee is that equivalent
* ImportableReferencesit will result in equivalent strings.
* @returns string representation of the code
*/
toString(options = {}) {
const irToString = options.importStringifier || defaultImportStringifier;
return this.chunks
.map((chunk) => (isImportableReference(chunk) ? irToString(chunk) : chunk))
.join('');
}
}

@@ -451,8 +453,19 @@ /**

*/
class File extends Code {
class File {
constructor(filename) {
super();
this.filename = filename;
this.code = new Code();
}
/**
* Appends new chunks of code to this list. Parameters are handled as in
* Code.push().
*
* @param newChunks code to be appended
* @returns this
*/
push(...newChunks) {
this.code.push(...newChunks);
return this;
}
/**
* Returns the code for this File, with ImportableReferences resolved.

@@ -466,6 +479,6 @@ *

const imports = new Imports(this.filename);
const resolvedString = this.chunks
.map((chunk) => (isImportableReference(chunk) ? imports.localSymbolFor(chunk) : chunk))
.join('');
const code = imports.toString() + resolvedString;
const executableCode = this.code.toString({
importStringifier: (ir) => imports.localSymbolFor(ir),
});
const code = imports.toString() + executableCode;
return options.prettified ? prettier.format(code, { parser: 'typescript' }) : code;

@@ -494,171 +507,79 @@ }

function jsonSchemaFor(type, additionalProperties = false) {
/**
* Returns the JSON schema for a specified type.
*
* @param type the type
* @returns JSON schema for type
*/
function jsonSchemaFor(type) {
if (type.type === 'any') {
return code `true`;
}
let jsonSchemaBuilder;
if (type.inherits.length > 0) {
jsonSchemaBuilder = new AllOfJsonSchemaBuilder(type);
// arbitrary type with inheritance => allOf(the inherited types + the type w/o inheritance)
else if (type.inherits.length > 0) {
return code `{allOf:[${schemasFor(...type.inherits, Object.assign({}, type, { inherits: [] }))}]}`;
}
else if (type.type === 'union') {
jsonSchemaBuilder = new OneOfJsonSchemaBuilder(type, additionalProperties);
return code `{anyOf:[${schemasFor(...type.anyOf)}]}`;
}
else if (type.type === 'object') {
// discriminated object => anyOf the discriminated types
if (type.discriminator !== undefined) {
jsonSchemaBuilder = new DiscriminatedObjectJsonSchemaBuilder(type, additionalProperties);
return code `{anyOf:[${schemasFor(...type.discriminatorValueMapping.map((val) => val.type))}]}`;
}
else {
jsonSchemaBuilder = new ObjectJsonSchemaBuilder(type, additionalProperties);
}
return buildObjectSchema(type);
}
else if (type.type === 'array') {
jsonSchemaBuilder = new ArrayJsonSchemaBuilder(type, additionalProperties);
return code `{type:'array',items:${jsonSchemaFor(type.items)}}`;
}
else if (['string', 'date', 'time', 'datetime', 'datetime-only'].some((t) => t === type.type)) {
jsonSchemaBuilder = new StringJsonSchemaBuilder(type);
return code `{type:'string'}`;
}
else if (['double', 'number'].some((t) => t === type.type)) {
jsonSchemaBuilder = new NumberJsonSchemaBuilder(type);
return code `{type:'number'}`;
}
else if (type.type === 'boolean') {
jsonSchemaBuilder = new BooleanJsonSchemaBuilder(type);
return code `{type:'boolean'}`;
}
else if (type.type === 'integer') {
jsonSchemaBuilder = new IntegerJsonSchemaBuilder(type);
return code `{type:'integer'}`;
}
else if (type.type === 'not') {
// short-circuit not-any => false
if (type.not.type === 'any') {
return code `false`;
}
return code `{not:${jsonSchemaFor(type.not)}}`;
}
else {
throw new Error(`unsupported type ${type.type}`);
}
return jsonSchemaBuilder.build();
}
class StringJsonSchemaBuilder {
constructor(type) {
this.type = type;
}
build() {
const result = code `{type:'string'}`;
return result;
}
/**
* Translates a set of Types to the corresponding JSON schemas, removing duplicates.
*
* @param types Types
* @returns JSON schemas for the specified types, deduped
*/
function schemasFor(...types) {
return Code.join(types.reduce((schemas, type) => {
const schema = jsonSchemaFor(type);
if (!schemas.find((existing) => existing.equals(schema))) {
schemas.push(schema);
}
return schemas;
}, []), ',');
}
class BooleanJsonSchemaBuilder {
constructor(type) {
this.type = type;
}
build() {
const result = code `{type:'boolean'}`;
return result;
}
// constructs the JSON schema for a non-discriminated object type
function buildObjectSchema(type) {
const required = [];
const properties = Object.entries(type.properties).map(([propName, propType]) => {
const safeName = toTypeScriptSafeIdentifier(propName);
if (propType.required) {
required.push(`'${safeName}'`);
}
return code `${safeName}:${jsonSchemaFor(propType.type)}`;
});
return code `{type:'object',properties:{${Code.join(properties, ',')}},required:[${required.join(',')}],additionalProperties:${jsonSchemaFor(type.additionalProperties)}}`;
}
class NumberJsonSchemaBuilder {
constructor(type) {
this.type = type;
}
build() {
const result = code `{type:'number'}`;
return result;
}
}
class IntegerJsonSchemaBuilder {
constructor(type) {
this.type = type;
}
build() {
const result = code `{type:'integer'}`;
return result;
}
}
class AllOfJsonSchemaBuilder {
constructor(type) {
this.type = type;
}
build() {
const result = code `{`;
const jsonSchemas = this.type.inherits.reduce((schemas, type) => {
// in allOf context, sub types need to relax the additionalProperties member so that
// checks can succeed
const jsonSchema = jsonSchemaFor(type, true);
if (schemas.find((schema) => schema.equals(jsonSchema)) === undefined) {
schemas.push(jsonSchema);
}
return schemas;
}, []);
jsonSchemas.push(jsonSchemaFor(Object.assign({}, this.type, { inherits: [] }), true));
result.push(code `allOf:[${Code.join(jsonSchemas, ',')}]`);
result.push(`}`);
return result;
}
}
class ObjectJsonSchemaBuilder {
constructor(type, additionalProperties) {
this.type = type;
this.additionalProperties = additionalProperties;
}
build() {
const result = code `{type:'object'`;
const required = [];
result.push(`,properties:{`);
Object.entries(this.type.properties).forEach((entry, i) => {
const [propName, propType] = entry;
if (propType.required) {
required.push(`'${toTypeScriptSafeIdentifier(propName)}'`);
}
result.push(code `${i > 0 ? ',' : ''}${toTypeScriptSafeIdentifier(propName)}:${jsonSchemaFor(propType.type, this.additionalProperties)}`);
});
result.push(`},required:[${required.join(',')}],additionalProperties:${this.additionalProperties}`);
result.push(`}`);
return result;
}
}
class DiscriminatedObjectJsonSchemaBuilder {
constructor(type, additionalProperties) {
this.type = type;
this.additionalProperties = additionalProperties;
}
build() {
const result = code `{`;
const jsonSchemas = this.type.discriminatorValueMapping
.map((val) => val.type)
.reduce((schemas, type) => {
const jsonSchema = jsonSchemaFor(type, this.additionalProperties);
if (schemas.find((schema) => schema.equals(jsonSchema)) === undefined) {
schemas.push(jsonSchema);
}
return schemas;
}, []);
result.push(code `anyOf:[${Code.join(jsonSchemas, ',')}]`);
result.push(`}`);
return result;
}
}
class OneOfJsonSchemaBuilder {
constructor(type, additionalProperties) {
this.type = type;
this.additionalProperties = additionalProperties;
}
build() {
const result = code `{`;
const jsonSchemas = this.type.anyOf.reduce((schemas, type) => {
const jsonSchema = jsonSchemaFor(type, this.additionalProperties);
if (schemas.find((schema) => schema.equals(jsonSchema)) === undefined) {
schemas.push(jsonSchema);
}
return schemas;
}, []);
result.push(code `anyOf:[${Code.join(jsonSchemas, ',')}]`);
result.push(`}`);
return result;
}
}
class ArrayJsonSchemaBuilder {
constructor(type, additionalProperties) {
this.type = type;
this.additionalProperties = additionalProperties;
}
build() {
const result = code `{type:'array',`;
result.push(code `items:${jsonSchemaFor(this.type.items, this.additionalProperties)}`);
result.push(`}`);
return result;
}
}

@@ -688,2 +609,3 @@ function typeDefinitionFor$1(t, options = {}) {

t.type !== 'nil' &&
t.type !== 'not' &&
((_b = t.values) === null || _b === void 0 ? void 0 : _b.length) !== undefined) {

@@ -744,2 +666,6 @@ result.push(Code.join(t.values.map((val) => JSON.stringify(val)), '|'));

}
case 'not': {
// no good way to express "not something" in typescript at the moment, defer until someone asks for it
result.push(code `unknown`);
}
}

@@ -757,2 +683,3 @@ }

result.push(...buildPatternProperties(t, options));
result.push(...buildAdditionalProperties(t, options));
return result;

@@ -816,2 +743,21 @@ }

}
function buildAdditionalProperties(t, options) {
const result = [];
// No additional properties allowed, default to other parts of the type
if (t.additionalProperties.type === 'not' && t.additionalProperties.not.type === 'any') {
return result;
}
// Additional properties allowed, no schema specified, which means any value is allowed
// but the type is not known
if (t.additionalProperties.type === 'any') {
result.push(code `Record<string,unknown>`);
return result;
}
// Additional properties allowed and we have a schema
result.push(code `Record<string,${typeDefinitionFor$1(t.additionalProperties, {
...options,
useReferences: true,
})}>`);
return result;
}
const MATCH_ALL_PATTERN = '^.*$';

@@ -943,5 +889,3 @@ function isSupportedPattern(pattern) {

function buildConfigType(params) {
const { inputPayloadDef } = params;
const queryParams = params.queryParams || [];
const otherParams = params.otherParams || [];
const { inputPayloadDef, queryParams = [], otherParams = [], configSchemaType } = params;
const configType = {

@@ -952,2 +896,3 @@ type: 'object',

patternProperties: [],
additionalProperties: { type: 'not', inherits: [], not: { type: 'any', inherits: [] } },
getDiscriminatedParent: () => undefined,

@@ -957,3 +902,3 @@ discriminator: undefined,

};
[getQueryParameterMembers(...queryParams), getParameterMembers(...otherParams)].forEach((allParams) => allParams.forEach((param) => {
[...getQueryParameterMembers(...queryParams), ...getParameterMembers(...otherParams)].forEach((param) => {
configType.properties[toCamelCase(param.name)] = {

@@ -963,8 +908,15 @@ type: param.type,

};
}));
});
if (inputPayloadDef) {
configType.properties[inputPayloadDef.name] = {
type: inputPayloadDef.type,
required: true,
};
if (configSchemaType === 'flattened') {
// Input payload needs to be flattened for backwards compatibility with
// older versions of Luvio.
configType.inherits.push(inputPayloadDef.type);
}
else {
configType.properties[inputPayloadDef.name] = {
type: inputPayloadDef.type,
required: true,
};
}
}

@@ -989,2 +941,45 @@ return configType;

/**
* Validates an API operation against the given endpoint.
*
* This function checks two key aspects of an API operation:
* 1. Whether the `operationId` exists.
* 2. If only one request type is defined for the operation (only one is supported).
*
* @param {Operation} operation - The API operation to be validated.
* @param {EndPoint} endpoint - The endpoint to which the operation belongs.
*
* @throws {Error} If the `operationId` is missing.
* @throws {Error} If more than one request type is found in the operation.
*/
function validateOperation(operation, endpoint) {
const { operationId } = operation;
if (!operationId) {
throw new Error(`operationId missing from ${operation.method} ${endpoint.path} operation`);
}
if (operation.requests.length > 1) {
throw new Error(`Only 1 request type is currently supported. More than one found in ${operation.method} ${endpoint.path} operation`);
}
}
/**
* Retrieves the default response for a given API operation.
*
* This function searches for the response with status code '200' in the operation's responses.
* If a '200' response is not found, it attempts to find a response with a status code of 'default'.
*
* @param {Operation} operation - The API operation containing the list of responses to search through.
* @param {EndPoint} endpoint - The endpoint to which the operation belongs. Includes information such as the endpoint path.
*
* @returns {Response} The first response found with status code '200' or 'default'.
*
* @throws {Error} If no '200' or 'default' response is found in the operation.
*/
function getDefaultResponse(operation, endpoint) {
const response = operation.responses.find((resp) => resp.statusCode === '200') ||
operation.responses.find((resp) => resp.statusCode === 'default');
if (!response) {
throw new Error(`missing '200' response in ${operation.method} ${endpoint.path} operation`);
}
return response;
}
/**
* An implementation of OperationCommandService that consumes EndPoint and Operation from an APIService

@@ -1001,5 +996,5 @@ * and generates TypeScript type declarations in Files from a FileService.

const { operationId } = operation;
this.validateOperation(operation, endpoint);
validateOperation(operation, endpoint);
const request = operation.requests[0];
const response = this.getDefaultResponse(operation, endpoint);
const response = getDefaultResponse(operation, endpoint);
const server = this.getServer(endpoint, operation);

@@ -1029,2 +1024,7 @@ const commandName = `${toTypeScriptSafeIdentifier(operationId)}Command`;

}, code ``);
const processedUrl = this.processUrl({
...params,
request,
server,
});
file.push(code `export const ${schemaConfigConst}: ${JSON_SCHEMA} = ${configJsonSchema};`, code `type BaseType = ${this.commandBaseClass}<${typeDefinitionFor(this.services, outputType)}, ${commandNamedServices}>;`, code `type BaseConstructorType = typeof ${this.commandBaseClass}<${typeDefinitionFor(this.services, outputType)},${commandNamedServices}>;`, code `type BaseConstructorParams = ConstructorParameters<BaseConstructorType>;`, code `type ${commandClassTypeName} = new (config: ${commandConfigType}, ...args: BaseConstructorParams) => BaseType;`, code `export function ${builderFunctionName}(baseClass: BaseConstructorType): ${commandClassTypeName}{`, code `return class ${className} extends baseClass{`, code `constructor(private config: ${commandConfigType}, ...args: BaseConstructorParams){super(...args)}`, this.generateClassBody({

@@ -1036,2 +1036,3 @@ ...params,

outputType,
processedUrl,
}), '}};');

@@ -1057,19 +1058,2 @@ return {

}
validateOperation(operation, endpoint) {
const { operationId } = operation;
if (!operationId) {
throw new Error(`operationId missing from ${operation.method} ${endpoint.path} operation`);
}
if (operation.requests.length > 1) {
throw new Error(`Only 1 request type is currently supported. More than one found in ${operation.method} ${endpoint.path} operation`);
}
}
getDefaultResponse(operation, endpoint) {
const response = operation.responses.find((resp) => resp.statusCode === '200') ||
operation.responses.find((resp) => resp.statusCode === 'default');
if (!response) {
throw new Error(`missing '200' response in ${operation.method} ${endpoint.path} operation`);
}
return response;
}
getServer(endpoint, operation) {

@@ -1115,2 +1099,3 @@ // TODO - picking first server is probably not always correct

],
configSchemaType: operation.configSchemaType,
});

@@ -1128,9 +1113,9 @@ return configType;

return isNumericType(type)
? `this.config.${name}`
? `${name}`
: isStringType(type)
? `encodeURIComponent(this.config.${name})`
? `encodeURIComponent(${name})`
: isArrayType(type)
? type.items !== undefined && isStringType(type.items)
? `this.config.${name}.map(item=>encodeURIComponent(item)).join(',')`
: `this.config.${name}.join(',')`
? `${name}.map(item=>encodeURIComponent(item)).join(',')`
: `${name}.join(',')`
: undefined;

@@ -1178,3 +1163,6 @@ }

super(...arguments);
this.serviceDependencies = [
this.commandBaseClass = AURA_COMMAND_BASE_CLASS;
}
get serviceDependencies() {
return [
{

@@ -1187,3 +1175,2 @@ version: '1.0',

];
this.commandBaseClass = AURA_COMMAND_BASE_CLASS;
}

@@ -1199,36 +1186,57 @@ getInputPayloadParameterName(config) {

generateClassBody(config) {
var _a;
const { endpoint, operation, request, server, hasInputPayload } = config;
const auraControllerName = endpoint.auraController.name;
if (auraControllerName === undefined) {
// controller name is mandatory
throw new Error(`Missing Connect API family name or Aura controller name in extensions for ${operation.method} ${endpoint.path} operation`);
const { endpoint, operation } = config;
// I would prefer to organize this so this code becomes iterating through keys, and calling generators
return code `${this.generateAuraEndpoint(endpoint, operation)}${this.generateAuraParamsCode(config)}${this.generateAuraActionConfig()}`;
}
// TODO: Need to actually support overriding pieces of the actionConfig using annotations or the incoming config
generateAuraActionConfig() {
return code ``; // Default values are provided in AuraNetworkCommand class
}
generateAuraParamsCode(config) {
const { request, server, endpoint, hasInputPayload } = config;
const result = code `get auraParams():Record<string,unknown>{`;
// handle uri params, query params and input payload
const queryParameters = getQueryParameterMembers(request.queryParameters);
const uriParameters = getParameterMembers(server.uriParameters, endpoint.uriParameters, request.uriParameters);
const allParams = [...queryParameters, ...uriParameters]
.map(({ name }) => toCamelCase(name))
.join(',');
const inputPayloadDelimiter = allParams.length && hasInputPayload ? ',' : '';
if (allParams.length || hasInputPayload) {
// Create destructing assignment to be returned
// ex: const { param1, param2, ...body } = this.config;
result.push(code `const {
${allParams}
${inputPayloadDelimiter}
${this.generateInputPayloadParameter(config)}
} = this.config;`);
}
// make sure all parameters part of server+url specification are available, even if we don't use the
// processed url directly, these will be needed on Aura controller side
this.processUrl(config);
// generate endpoint
// the extensions member has been initialized as part of the processExtensions call
const auraMethodName = ((_a = operation.auraMethod) === null || _a === void 0 ? void 0 : _a.name) || operation.operationId;
const result = code ``;
result.push(code `endpoint = '${auraControllerName}.${auraMethodName}';`);
result.push(code `get auraParams(): Record<string, unknown>{`);
// handle uri params, query params and input payload
const queryParameters = getQueryParameterMembers(request === null || request === void 0 ? void 0 : request.queryParameters);
const uriParameters = getParameterMembers(server.uriParameters, endpoint.uriParameters, request === null || request === void 0 ? void 0 : request.uriParameters);
result.push(code `return {`);
[queryParameters, uriParameters].forEach((allParams) => {
allParams.forEach((param) => {
result.push(code `'${param.name}'${param.required ? '' : '?'}:this.config.${toCamelCase(param.name)},`);
});
});
result.push(code `return { ${allParams}`);
if (hasInputPayload) {
// the extensions member has been initialized as part of the processExtensions call
const inputPayload = this.getInputPayloadParameterName(config);
result.push(code `${inputPayload}:this.config.${inputPayload},`);
result.push(code `${inputPayloadDelimiter}${inputPayload}:body`);
}
result.push(`};`);
result.push(code `}`);
result.push(`};}`);
return result;
}
generateInputPayloadParameter(config) {
const { hasInputPayload, operation: { configSchemaType }, } = config;
if (hasInputPayload) {
if (configSchemaType === 'flattened') {
// Use rest operator when flattening,
// e.g. const { ...body } = this.config
return code `...body`;
}
else {
// Extract using input payload name otherwise,
// e.g. const { inputPayload: body } = this.config
return code `${this.getInputPayloadParameterName(config)}: body`;
}
}
}
generateAuraEndpoint(endpoint, operation) {
const auraControllerName = endpoint.auraController.name;
return code `endpoint='${auraControllerName}.${operation.auraMethod.name}';`;
}
}

@@ -1273,5 +1281,4 @@

}
generateUrl(config) {
const url = this.processUrl(config);
return code `let url:Parameters<${FETCH_SERVICE}>[0]=\`${url}\`;`;
generateUrl(processedUrl) {
return code `let url:Parameters<${FETCH_SERVICE}>[0]=\`${processedUrl}\`;`;
}

@@ -1283,2 +1290,3 @@ generateHeaders(config) {

let result = undefined;
let names = [];
if (hasHeaders) {

@@ -1293,3 +1301,3 @@ // TODO - resolve cookies?

.filter((hdr) => hdr.required)
.forEach((hdr) => result.push(`'${hdr.name}':this.config.${toCamelCase(hdr.name)},`));
.forEach((hdr) => result.push(`'${hdr.name}':${toCamelCase(hdr.name)},`));
result.push(`};`);

@@ -1300,6 +1308,7 @@ headers

const headerName = toCamelCase(hdr.name);
result.push(`if(this.config.${headerName}!==undefined){headers['${hdr.name}']=this.config.${headerName};}`);
result.push(`if(${headerName}!==undefined){headers['${hdr.name}']=${headerName};}`);
});
names = headers.map((header) => toCamelCase(header.name));
}
return result;
return { names, code: result };
}

@@ -1310,2 +1319,3 @@ generateQueryParams(config) {

let result = undefined;
let names = [];
const queryParameters = getQueryParameterMembers(request === null || request === void 0 ? void 0 : request.queryParameters);

@@ -1320,12 +1330,48 @@ if (queryParameters.length > 0) {

}
result.push(param.required ? '' : `if(this.config.${paramName}!==undefined){`, `queryParams.push('${param.name}='+${value});`, param.required ? '' : `}`);
result.push(param.required ? '' : `if(${paramName}!==undefined){`, `queryParams.push('${param.name}='+${value});`, param.required ? '' : `}`);
names.push(paramName);
});
result.push(`if(queryParams.length>0){url+='?'+queryParams.join('&');}`);
}
return { names, code: result };
}
generateAllParams(headers, queryParameters, config) {
const { hasInputPayload, request, server, endpoint } = config;
const uriParameters = getParameterMembers(server.uriParameters, endpoint.uriParameters, request === null || request === void 0 ? void 0 : request.uriParameters);
const result = new Code();
const allParams = [
...headers,
...queryParameters,
...uriParameters.map((param) => toCamelCase(param.name)),
];
if (hasInputPayload || allParams.length) {
result.push(code `const {
${allParams.join(',')}
${allParams.length && hasInputPayload ? ',' : ''}
${this.generateInputPayloadParameter(config)}
} = this.config;`);
}
return result;
}
generateClassBody(config) {
const { request, operation, hasInputPayload } = config;
const result = new Code().push(code `get fetchParams(): Parameters<${FETCH_SERVICE}>{`, code `${this.generateUrl(config)}${this.generateQueryParams(config)}${this.generateHeaders(config)}`);
const hasHeaders = getParameterMembers(request === null || request === void 0 ? void 0 : request.headers).length > 0 || hasInputPayload;
generateInputPayloadParameter(config) {
const { hasInputPayload, operation: { configSchemaType }, } = config;
if (hasInputPayload) {
if (configSchemaType === 'flattened') {
// Use rest operator when flattening,
// e.g. const { ...body } = this.config
return code `...body`;
}
else {
// Extract using input payload name otherwise,
// e.g. const { inputPayload: body } = this.config
return code `${this.getInputPayloadParameterName(config)}: body`;
}
}
}
generateFetchParams(config) {
const { operation, hasInputPayload, processedUrl } = config;
const headers = this.generateHeaders(config);
const queryParams = this.generateQueryParams(config);
const result = new Code().push(code `get fetchParams(): Parameters<${FETCH_SERVICE}>{`, code `${this.generateAllParams(headers.names, queryParams.names, config)}`, code `${this.generateUrl(processedUrl)}${queryParams.code}${headers.code}`);
const hasHeaders = headers.names.length > 0 || hasInputPayload;
result.push(code `const params:Parameters<${FETCH_SERVICE}>[1]={`, code `method:'${operation.method.toUpperCase()}',`, code `cache:'no-cache',`);

@@ -1336,3 +1382,3 @@ if (hasHeaders) {

if (hasInputPayload) {
result.push(`,body:JSON.stringify(this.config.${INPUT_PAYLOAD_MEMBER_NAME})`);
result.push(`,body:JSON.stringify(body)`);
}

@@ -1343,4 +1389,47 @@ result.push(`};`);

}
generateClassBody(config) {
return code `${this.generateFetchParams(config)}`;
}
}
const AURA_CACHE_CONTROL_COMMAND_BASE_CLASS = {
module: '@luvio/command-aura-resource-cache-control/v1',
exportedSymbol: 'AuraCacheControlCommand',
isType: true,
};
const NAMED_CACHE_CONTROL_SERVICE = {
module: '@luvio/service-cache-control/v1',
exportedSymbol: 'NamedCacheControlService',
isType: true,
};
const CACHE_CONTROL_SERVICE_DESCRIPTOR = {
module: '@luvio/service-cache-control/v1',
exportedSymbol: 'CacheControlServiceDescriptor',
isType: true,
};
class AuraResourceCacheControlCommandGenerator extends AuraCommandGenerator {
constructor() {
super(...arguments);
this.commandBaseClass = AURA_CACHE_CONTROL_COMMAND_BASE_CLASS;
}
get serviceDependencies() {
return [
...super.serviceDependencies,
{
version: '1.0',
descriptor: CACHE_CONTROL_SERVICE_DESCRIPTOR,
namedService: NAMED_CACHE_CONTROL_SERVICE,
name: 'cacheControl',
},
];
}
generateBuildCacheControlMetadata(operation) {
return code `buildCacheControlMetadata(_networkResult:NetworkData){return{type:'max-age',maxAge:${operation.cacheStrategy.config.maxAge},generatedTime:Date.now()/1000}as const;}`;
}
generateClassBody(config) {
const { operation } = config;
return code `${super.generateClassBody(config)}${this.generateBuildCacheControlMetadata(operation)}`;
}
}
function operationCommandGeneratorService(services) {

@@ -1350,3 +1439,7 @@ let commands = [];

for (const operation of endpoint.operations) {
const commandGenerator = new (endpoint.type === 'aura' ? AuraCommandGenerator : HttpCommandGenerator)(services);
const commandGenerator = new (endpoint.type === 'aura'
? operation.cacheStrategy.type === 'none'
? AuraCommandGenerator
: AuraResourceCacheControlCommandGenerator
: HttpCommandGenerator)(services);
commands.push({

@@ -1353,0 +1446,0 @@ ...commandGenerator.build({ endpoint, operation }),

@@ -5,3 +5,4 @@ import { CommandGenerator } from './command-generator';

export declare class AuraCommandGenerator extends CommandGenerator {
serviceDependencies: {
commandBaseClass: ImportableReference;
get serviceDependencies(): {
version: "1.0";

@@ -12,3 +13,2 @@ descriptor: ImportableReference;

}[];
commandBaseClass: ImportableReference;
getInputPayloadParameterName(config: {

@@ -25,3 +25,19 @@ endpoint: EndPoint;

outputType: Type | undefined;
processedUrl: string;
}): Code;
generateAuraActionConfig(): Code;
generateAuraParamsCode(config: {
endpoint: AuraEndPoint;
operation: AuraOperation;
request: Request;
server: Server;
hasInputPayload: boolean;
outputType: Type | undefined;
}): Code;
generateInputPayloadParameter(config: {
hasInputPayload: boolean;
endpoint: EndPoint;
operation: AuraMutationOperation;
}): Code | undefined;
generateAuraEndpoint(endpoint: AuraEndPoint, operation: AuraOperation): Code;
}
import type { NamedLoggerService, ServiceVersion } from '@luvio/utils';
import type { EndPoint, ObjectType, Operation, Parameter, Payload, Request, Server, Type, QueryParameter, TypeOfParameter } from '@luvio/model';
import type { EndPoint, ObjectType, Operation, Parameter, Payload, Request, Server, Type, QueryParameter, TypeOfParameter, ConfigSchemaType } from '@luvio/model';
import type { NamedAPIService } from '../api';

@@ -72,2 +72,3 @@ import type { ImportableReference, Code, NamedFileService } from '../files';

otherParams?: Record<string, Parameter>[];
configSchemaType?: ConfigSchemaType;
}): ObjectType;

@@ -83,2 +84,30 @@ /**

/**
* Validates an API operation against the given endpoint.
*
* This function checks two key aspects of an API operation:
* 1. Whether the `operationId` exists.
* 2. If only one request type is defined for the operation (only one is supported).
*
* @param {Operation} operation - The API operation to be validated.
* @param {EndPoint} endpoint - The endpoint to which the operation belongs.
*
* @throws {Error} If the `operationId` is missing.
* @throws {Error} If more than one request type is found in the operation.
*/
export declare function validateOperation(operation: Operation, endpoint: EndPoint): void;
/**
* Retrieves the default response for a given API operation.
*
* This function searches for the response with status code '200' in the operation's responses.
* If a '200' response is not found, it attempts to find a response with a status code of 'default'.
*
* @param {Operation} operation - The API operation containing the list of responses to search through.
* @param {EndPoint} endpoint - The endpoint to which the operation belongs. Includes information such as the endpoint path.
*
* @returns {Response} The first response found with status code '200' or 'default'.
*
* @throws {Error} If no '200' or 'default' response is found in the operation.
*/
export declare function getDefaultResponse(operation: Operation, endpoint: EndPoint): import("@luvio/model").Response<Type>;
/**
* An implementation of OperationCommandService that consumes EndPoint and Operation from an APIService

@@ -94,4 +123,2 @@ * and generates TypeScript type declarations in Files from a FileService.

}): CommandInfo;
private validateOperation;
private getDefaultResponse;
abstract getInputPayloadParameterName(config: {

@@ -108,2 +135,3 @@ endpoint: EndPoint;

outputType: Type | undefined;
processedUrl: string;
}): Code;

@@ -110,0 +138,0 @@ abstract get serviceDependencies(): ServiceInfo[];

@@ -17,19 +17,41 @@ import { Code } from '../files';

commandBaseClass: ImportableReference;
generateUrl(config: {
generateUrl(processedUrl: string): Code;
generateHeaders(config: {
endpoint: EndPoint;
operation: Operation;
request: Request;
hasInputPayload: boolean;
}): {
names: string[];
code: Code | undefined;
};
generateQueryParams(config: {
endpoint: EndPoint;
operation: Operation;
request: Request;
}): {
names: string[];
code: Code | undefined;
};
generateAllParams(headers: string[], queryParameters: string[], config: {
endpoint: EndPoint;
operation: Operation;
request: Request;
server: Server;
hasInputPayload: boolean;
}): Code;
generateHeaders(config: {
generateInputPayloadParameter(config: {
hasInputPayload: boolean;
endpoint: EndPoint;
operation: Operation;
request: Request;
hasInputPayload: boolean;
}): Code | undefined;
generateQueryParams(config: {
generateFetchParams(config: {
endpoint: EndPoint;
operation: Operation;
request: Request;
}): Code | undefined;
server: Server;
hasInputPayload: boolean;
outputType: Type | undefined;
processedUrl: string;
}): Code;
generateClassBody(config: {

@@ -42,3 +64,4 @@ endpoint: EndPoint;

outputType: Type | undefined;
processedUrl: string;
}): Code;
}

@@ -47,4 +47,4 @@ export type ImportableReference = ({

*
* @param newChunks
* @returns
* @param newChunks code to be appended
* @returns this
*/

@@ -60,2 +60,14 @@ push(...newChunks: any[]): this;

equals(comparison: Code): boolean;
/**
* Returns the Code as a single string.
*
* @param options
* importStringifier - function to convert ImportableReferences to strings.
* Defaults to an internal function whose only guarantee is that equivalent
* ImportableReferencesit will result in equivalent strings.
* @returns string representation of the code
*/
toString(options?: {
importStringifier?: (reference: ImportableReference) => string;
}): string;
}

@@ -62,0 +74,0 @@ /**

@@ -29,6 +29,15 @@ import { Code } from './code';

*/
export declare class File extends Code {
export declare class File {
readonly filename: string;
code: Code;
constructor(filename: string);
/**
* Appends new chunks of code to this list. Parameters are handled as in
* Code.push().
*
* @param newChunks code to be appended
* @returns this
*/
push(...newChunks: any[]): this;
/**
* Returns the code for this File, with ImportableReferences resolved.

@@ -35,0 +44,0 @@ *

@@ -0,3 +1,9 @@

import { type Type } from '@luvio/model';
import { Code } from '../files';
import type { Type } from '@luvio/model';
export declare function jsonSchemaFor(type: Type, additionalProperties?: boolean): Code;
/**
* Returns the JSON schema for a specified type.
*
* @param type the type
* @returns JSON schema for type
*/
export declare function jsonSchemaFor(type: Type): Code;
{
"name": "@luvio/generator-ts",
"version": "5.11.0",
"version": "5.12.0",
"description": "Luvio TypeScript code generation",

@@ -25,10 +25,10 @@ "repository": {

"dependencies": {
"@luvio/model": "5.11.0",
"@luvio/model": "5.12.0",
"prettier": "^2.7.1"
},
"devDependencies": {
"@luvio/service-aura-network": "5.11.0",
"@luvio/service-broker": "5.11.0",
"@luvio/service-fetch-network": "5.11.0",
"@luvio/utils": "5.11.0",
"@luvio/service-aura-network": "5.12.0",
"@luvio/service-broker": "5.12.0",
"@luvio/service-fetch-network": "5.12.0",
"@luvio/utils": "5.12.0",
"memfs": "^3.4.13"

@@ -35,0 +35,0 @@ },

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc