Repository: conwnet/github1s
File: extensions/github1s/src/helpers/util.ts (TypeScript)

Code before:
	for (let i = 0; i < 32; i++) {
		text += possible.charAt(Math.floor(Math.random() * possible.length));
	}
	return text;
};

export const getWebviewOptions = (
	extensionUri: vscode.Uri
): vscode.WebviewOptions => {
	return {
		// Enable javascript in the webview
		enableScripts: true,
		// And restrict the webview to only loading content from our extension's `assets` directory.
		localResourceRoots: [vscode.Uri.joinPath(extensionUri, 'assets')],
	};
};

export const encodeFilePath = (filePath: string): string => {
	return filePath
		.split('/')
		.map((segment) => encodeURIComponent(segment))
		.join('/');
};

// parse the querystring simply: 'a=1&b=2&c=3'
export const parseQuery = (query: string): { [key: string]: string } => {
	const pairs = (query || '').split('&').filter(Boolean);
	return pairs.reduce((prev, item) => {
		const [key, value] = item.split('=');
		return { ...prev, [key]: value };
	}, {});
};


Review comment (bug):
I suggest we use https://github.com/ljharb/qs or https://github.com/sindresorhus/query-string to handle the query parsing since there might be problems with escaped character and other edge cases.

Code after:
/**
 * @file common util
 * @author netcon
 */

import * as vscode from 'vscode';

export const noop = () => {};

export const trimStart = (str: string, chars: string = ' '): string => {
	let index = 0;
	while (chars.indexOf(str[index]) !== -1) {
		index++;
	}
	return str.slice(index);
};

export const trimEnd = (str: string, chars: string = ' '): string => {
	let length = str.length;
	while (length && chars.indexOf(str[length - 1]) !== -1) {
		length--;
	}
	return str.slice(0, length);
};

export const joinPath = (...segments: string[]): string => {
	if (!segments.length) {
		return '';
	}

	return segments.reduce((prev, segment) => {
		return trimEnd(prev, '/') + '/' + trimStart(segment, '/');
	});
};

export const dirname = (path: string): string => {
	const trimmedPath = trimEnd(path, '/');
	return trimmedPath.substr(0, trimmedPath.lastIndexOf('/')) || '';
};

export const basename = (path: string): string => {
	const trimmedPath = trimEnd(path, '/');
	return trimmedPath.substr(trimmedPath.lastIndexOf('/') + 1) || '';
};

export const uniqueId = ((id) => () => id++)(1);

export const prop = (obj: object, path: (string | number)[] = []): any => {
	let cur = obj;
	path.forEach((key) => (cur = cur ? cur[key] : undefined));
	return cur;
};

export const getNonce = (): string => {
	let text: string = '';
	const possible =
		'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
	for (let i = 0; i < 32; i++) {
		text += possible.charAt(Math.floor(Math.random() * possible.length));
	}
	return text;
};

export const getWebviewOptions = (
	extensionUri: vscode.Uri
): vscode.WebviewOptions => {
	return {
		// Enable javascript in the webview
		enableScripts: true,
		// And restrict the webview to only loading content from our extension's `assets` directory.
		localResourceRoots: [vscode.Uri.joinPath(extensionUri, 'assets')],
	};
};

export const encodeFilePath = (filePath: string): string => {
	return filePath
		.split('/')
		.map((segment) => encodeURIComponent(segment))
		.join('/');
};