Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ node_modules
*.vsix
*.env
.eslintcache
.idea
1 change: 1 addition & 0 deletions src/plugins/core/parse/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export * from './commentHttpRegionParser';
export * from './metaHttpRegionParser';
export * from './multipartMixedInterceptor';
export * from './outputRedirectionHttpRegionParser';
export * from './inputRedirectionHttpRegionParser';
export * from './requestBodyHttpRegionParser';
export * from './requestHttpRegionParser';
export * from './responseHttpRegionParser';
Expand Down
116 changes: 116 additions & 0 deletions src/plugins/core/parse/inputRedirectionHttpRegionParser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { fileProvider, log } from '../../../io';
import * as models from '../../../models';
import * as utils from '../../../utils';
import { transformToBufferOrString } from '../request';

export async function parseInputRedirection(
getLineReader: models.getHttpLineGenerator,
context: models.ParserContext
): Promise<models.HttpRegionParserResult> {
if (context.httpRegion.request) {
const lineReader = getLineReader();

const next = lineReader.next();
if (!next.done) {
const textLine = next.value.textLine;

console.log(`file Calling input redirection parser${textLine}`);

const match = /^<(?:(?<injectVariables>@)(?<encoding>\w+)?)?\s+(?<fileName>.+?)\s*$/u.exec(textLine);

if (match && match.groups?.fileName) {
console.log(match.groups.fileName.trim());
const fileName = `redirect-actual-${match.groups.fileName.trim()}`;
const force: boolean = true;

context.httpRegion.hooks.onRequest.addHook('inputRedirection', async (request, context) => {
try {
console.log(`file request body is ${request.body}`);
if (request.body) {
console.log('file Request body is present');
const body = await transformToBufferOrString(request.body, context);
const fileNameReplaced = utils.toString(
await utils.replaceVariables(fileName, models.VariableType.variable, context)
);
console.log(`File name replaced is ${fileNameReplaced}`);

if (fileNameReplaced) {
const file = await getInputRedirectionFileName(fileNameReplaced, force, context.httpFile.fileName);
console.log(`File name is ${file}`);
if (file) {
if (typeof body === 'string') {
await fileProvider.writeBuffer(file, Buffer.from(body));
} else {
await fileProvider.writeBuffer(file, body);
}
} else {
log.debug(`file ${fileName} not found`);
}
} else {
log.debug(`file ${fileName} not found`);
}
}
} catch (err) {
log.error(`input redirection failed for ${fileName}`, err);
}
});
return {
nextParserLine: next.value.line,
symbols: [
new models.HttpSymbol({
name: match.groups.key,
description: match.groups.value,
kind: models.HttpSymbolKind.response,
startLine: next.value.line,
startOffset: 0,
endLine: next.value.line,
endOffset: next.value.textLine.length,
children: [
new models.HttpSymbol({
name: 'filename',
description: fileName,
kind: models.HttpSymbolKind.path,
startLine: next.value.line,
startOffset: next.value.textLine.indexOf(fileName),
endLine: next.value.line,
endOffset: next.value.textLine.indexOf(fileName) + fileName.length,
}),
],
}),
],
};
}
}
}
return false;
}

async function getInputRedirectionFileName(fileName: string, force: boolean, baseName: models.PathLike) {
let file = await toAbsoluteFileName(fileName, baseName);

if (!force) {
if (await fileProvider.exists(file)) {
const dotIndex = fileName.lastIndexOf('.');
if (dotIndex > 0 && dotIndex < fileName.length - 2) {
const path = fileName.slice(0, dotIndex);
const extension = fileName.slice(dotIndex + 1);
let index = 1;

file = await toAbsoluteFileName(`${path}-${index}.${extension}`, baseName);
while (await fileProvider.exists(file)) {
file = await toAbsoluteFileName(`${path}-${index++}.${extension}`, baseName);
}
}
}
}
return file;
}
async function toAbsoluteFileName(fileName: string, baseName: models.PathLike) {
if (!(await fileProvider.isAbsolute(fileName))) {
const dirName = fileProvider.dirname(baseName);
if (dirName) {
return fileProvider.joinPath(dirName, fileName);
}
}
return fileName;
}
82 changes: 80 additions & 2 deletions src/plugins/core/parse/requestBodyHttpRegionParser.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import * as models from '../../../models';
import * as utils from '../../../utils';
import { fileProvider, log } from '../../../io';
import { transformToBufferOrString } from '../request';

export async function parseRequestBody(
getLineReader: models.getHttpLineGenerator,
Expand All @@ -10,8 +12,16 @@ export async function parseRequestBody(
if (context.httpRegion.request) {
const requestBody = getRequestBody(context);
const next = lineReader.next();

if (!next.done) {
if (requestBody.rawBody.length > 0 || !utils.isStringEmpty(next.value.textLine)) {
const textLine = next.value.textLine;

const match =
/^<(?:(?<injectVariables>@)(?<encoding>\w+)?)?\s+(?<fileName>.+?)\s+>>(?<force>!)?\s+(?<outputFile>.+?)\s*$/u.exec(
textLine
);

if (requestBody.rawBody.length > 0 || !utils.isStringEmpty(textLine)) {
const symbols: Array<models.HttpSymbol> = [];

if (!requestBody.symbol || requestBody.symbol.endLine !== next.value.line - 1) {
Expand All @@ -23,7 +33,7 @@ export async function parseRequestBody(
startOffset: 0,
endLine: next.value.line,
endOffset: next.value.textLine.length,
children: utils.parseHandlebarsSymbols(next.value.textLine, next.value.line),
children: utils.parseHandlebarsSymbols(textLine, next.value.line),
});
symbols.push(requestBody.symbol);
} else {
Expand All @@ -32,6 +42,44 @@ export async function parseRequestBody(
requestBody.symbol.children?.push?.(...utils.parseHandlebarsSymbols(next.value.textLine, next.value.line));
}

if (match && match.groups?.outputFile) {
console.log(match.groups.outputFile.trim());
const fileName = match.groups.outputFile.trim();
const force: boolean = !!match.groups.force;

context.httpRegion.hooks.onRequest.addHook('inputRedirection', async (request, context) => {
try {
console.log(`request body is ${request.body}`);
if (request.body) {
console.log('Request body is present');
const body = await transformToBufferOrString(request.body, context);
const fileNameReplaced = utils.toString(
await utils.replaceVariables(fileName, models.VariableType.variable, context)
);
console.log(`File name replaced is ${fileNameReplaced}`);

if (fileNameReplaced) {
const file = await getInputRedirectionFileName(fileNameReplaced, force, context.httpFile.fileName);
console.log(`File name is ${file}`);
if (file) {
if (typeof body === 'string') {
await fileProvider.writeBuffer(file, Buffer.from(body));
} else {
await fileProvider.writeBuffer(file, body);
}
} else {
log.debug(`file ${fileName} not found`);
}
} else {
log.debug(`file ${fileName} not found`);
}
}
} catch (err) {
log.error(`input redirection failed for ${fileName}`, err);
}
});
}

const fileImport = utils.parseFileImport(next.value.textLine);
if (fileImport) {
requestBody.rawBody.push(fileImport);
Expand Down Expand Up @@ -70,3 +118,33 @@ export function getRequestBody(context: models.ParserContext) {
}
return result;
}

async function getInputRedirectionFileName(fileName: string, force: boolean, baseName: models.PathLike) {
let file = await toAbsoluteFileName(fileName, baseName);

if (!force) {
if (await fileProvider.exists(file)) {
const dotIndex = fileName.lastIndexOf('.');
if (dotIndex > 0 && dotIndex < fileName.length - 2) {
const path = fileName.slice(0, dotIndex);
const extension = fileName.slice(dotIndex + 1);
let index = 1;

file = await toAbsoluteFileName(`${path}-${index}.${extension}`, baseName);
while (await fileProvider.exists(file)) {
file = await toAbsoluteFileName(`${path}-${index++}.${extension}`, baseName);
}
}
}
}
return file;
}
async function toAbsoluteFileName(fileName: string, baseName: models.PathLike) {
if (!(await fileProvider.isAbsolute(fileName))) {
const dirName = fileProvider.dirname(baseName);
if (dirName) {
return fileProvider.joinPath(dirName, fileName);
}
}
return fileName;
}
1 change: 0 additions & 1 deletion src/plugins/core/registerCorePlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ function initParseHook(api: models.HttpyacHooksApi) {
api.hooks.parse.addHook('responseRef', parse.parseResponseRef);
api.hooks.parse.addHook('response', parse.parseResponse);
api.hooks.parse.addHook('requestBody', parse.parseRequestBody);

api.hooks.parse.addInterceptor(new parse.MultipartMixedInterceptor());
}
function initParseEndHook(api: models.HttpyacHooksApi) {
Expand Down
7 changes: 5 additions & 2 deletions src/utils/parserUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -542,8 +542,11 @@ export async function parseInlineResponse(
}

export function parseFileImport(text: string) {
const fileImport = /^<(?:(?<injectVariables>@)(?<encoding>\w+)?)?\s+(?<fileName>.+?)\s*$/u.exec(text);
if (fileImport && fileImport.length === 4 && fileImport.groups) {
const fileImport =
/^<(?:(?<injectVariables>@)(?<encoding>\w+)?)?\s+(?<fileName>.+?)\s+>>(?<force>!)?\s+(?<outputFile>.+?)\s*$/u.exec(
text
);
if (fileImport && fileImport.length === 6 && fileImport.groups) {
return {
fileName: fileImport.groups.fileName.trim(),
injectVariables: !!fileImport.groups.injectVariables,
Expand Down