@azure-tools/codegen
Version:
Autorest Code generator common and base classes
439 lines • 14.8 kB
JavaScript
;
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.selectName = exports._setRegion = exports.setRegion = exports.getRegions = exports.nameof = exports.escapeString = exports.getPascalIdentifier = exports.camelCase = exports.pascalCase = exports.removeSequentialDuplicates = exports.isEqual = exports.removeProhibitedPrefix = exports.fixLeadingNumber = exports.convert = exports.isCapitalized = exports.deconstruct = exports.pall = exports.__selectMany = exports.ToMap = exports.map = exports.dotCombine = exports.docComment = exports.comment = exports.indent = exports.fixEOL = exports.toMap = exports.trimDots = exports.setIndentation = exports.sortByName = exports.joinComma = exports.join = exports.uncapitalize = exports.capitalize = exports.CommaChar = exports.EOL = exports.docCommentPrefix = exports.lineCommentPrefix = void 0;
const file_generator_1 = require("./file-generator");
let indentation = " ";
exports.lineCommentPrefix = "//";
exports.docCommentPrefix = "///";
exports.EOL = "\n";
exports.CommaChar = ", ";
const acronyms = new Set([
"ip",
"os",
"ms",
"vm", // 'ssl', 'https', 'http', ''
]);
function capitalize(str) {
if (acronyms.has(str)) {
return str.toUpperCase();
}
return str ? `${str.charAt(0).toUpperCase()}${str.slice(1)}` : str;
}
exports.capitalize = capitalize;
function uncapitalize(str) {
return str ? `${str.charAt(0).toLowerCase()}${str.slice(1)}` : str;
}
exports.uncapitalize = uncapitalize;
function join(items, separator) {
return items.filter((v) => (v ? true : false)).join(separator);
}
exports.join = join;
function joinComma(items, mapFn) {
return join(items.map(mapFn), exports.CommaChar);
}
exports.joinComma = joinComma;
function sortByName(a, b) {
return a.name < b.name ? -1 : a.name > b.name ? 1 : 0;
}
exports.sortByName = sortByName;
function setIndentation(spaces) {
indentation = " ".repeat(spaces);
}
exports.setIndentation = setIndentation;
function trimDots(content) {
return content.replace(/^[.\s]*(.*?)[.\s]*$/g, "$1");
}
exports.trimDots = trimDots;
function toMap(source, eachFn) {
const result = new Map();
for (const each of source) {
const key = eachFn(each);
let values = result.get(key);
if (!values) {
values = new Array();
result.set(key, values);
}
values.push(each);
}
return result;
}
exports.toMap = toMap;
function fixEOL(content) {
return content.replace(/\r\n/g, exports.EOL);
}
exports.fixEOL = fixEOL;
function indent(content, factor = 1) {
const i = indentation.repeat(factor);
content = i + fixEOL(content.trim());
return content.split(/\n/g).join(`${exports.EOL}${i}`);
}
exports.indent = indent;
function comment(content, prefix = exports.lineCommentPrefix, factor = 0, maxLength = 120) {
const result = new Array();
let line = "";
prefix = indent(prefix, factor);
content = content.trim();
if (content) {
for (const word of content.replace(/\n+/g, " » ").split(/\s+/g)) {
if (word === "»") {
result.push(line);
line = prefix;
continue;
}
if (maxLength < line.length) {
result.push(line);
line = "";
}
if (!line) {
line = prefix;
}
line += ` ${word}`;
}
if (line) {
result.push(line);
}
return result.join(exports.EOL);
}
return "";
}
exports.comment = comment;
function docComment(content, prefix = exports.docCommentPrefix, factor = 0, maxLength = 120) {
return comment(content, prefix, factor, maxLength);
}
exports.docComment = docComment;
function dotCombine(prefix, content) {
return trimDots([trimDots(prefix), trimDots(content)].join("."));
}
exports.dotCombine = dotCombine;
function map(dictionary, callbackfn, thisArg) {
return Object.getOwnPropertyNames(dictionary).map((key) => callbackfn(key, dictionary[key]));
}
exports.map = map;
function ToMap(dictionary) {
const result = new Map();
Object.getOwnPropertyNames(dictionary).map((key) => result.set(key, dictionary[key]));
return result;
}
exports.ToMap = ToMap;
function __selectMany(multiArray) {
const result = new Array();
multiArray.map((v) => result.push(...v));
return result;
}
exports.__selectMany = __selectMany;
function pall(array, callbackfn, thisArg) {
return Promise.all(array.map(callbackfn));
}
exports.pall = pall;
function deconstruct(identifier) {
if (Array.isArray(identifier)) {
return identifier.flatMap(deconstruct);
}
return `${identifier}`
.replace(/([a-z]+)([A-Z])/g, "$1 $2")
.replace(/(\d+)([a-z|A-Z]+)/g, "$1 $2")
.replace(/\b([A-Z]+)([A-Z])([a-z])/, "$1 $2$3")
.split(/[\W|_]+/)
.map((each) => each.toLowerCase());
}
exports.deconstruct = deconstruct;
function isCapitalized(identifier) {
return /^[A-Z]/.test(identifier);
}
exports.isCapitalized = isCapitalized;
const ones = [
"",
"one",
"two",
"three",
"four",
"five",
"six",
"seven",
"eight",
"nine",
"ten",
"eleven",
"twelve",
"thirteen",
"fourteen",
"fifteen",
"sixteen",
"seventeen",
"eighteen",
"nineteen",
];
const teens = [
"ten",
"eleven",
"twelve",
"thirteen",
"fourteen",
"fifteen",
"sixteen",
"seventeen",
"eighteen",
"nineteen",
];
const tens = ["", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"];
const magnitude = [
"thousand",
"million",
"billion",
"trillion",
"quadrillion",
"quintillion",
"septillion",
"octillion",
];
const magvalues = [10 ** 3, 10 ** 6, 10 ** 9, 10 ** 12, 10 ** 15, 10 ** 18, 10 ** 21, 10 ** 24, 10 ** 27];
function* convert(num) {
if (!num) {
yield "zero";
return;
}
if (num > 1e30) {
yield "lots";
return;
}
if (num > 999) {
for (let i = magvalues.length; i > -1; i--) {
const c = magvalues[i];
if (num > c) {
yield* convert(Math.floor(num / c));
yield magnitude[i];
num = num % c;
}
}
}
if (num > 99) {
yield ones[Math.floor(num / 100)];
yield "hundred";
num %= 100;
}
if (num > 19) {
yield tens[Math.floor(num / 10)];
num %= 10;
}
if (num) {
yield ones[num];
}
}
exports.convert = convert;
function fixLeadingNumber(identifier) {
if (identifier.length > 0 && /^\d+/.exec(identifier[0])) {
return [...convert(parseInt(identifier[0])), ...identifier.slice(1)];
}
return identifier;
}
exports.fixLeadingNumber = fixLeadingNumber;
function removeProhibitedPrefix(identifier, prohibitedPrefix, skipIdentifiers) {
if (identifier.toLowerCase().startsWith(prohibitedPrefix.toLowerCase())) {
const regex = new RegExp(`(^${prohibitedPrefix})(.*)`, "i");
let newIdentifier = identifier.replace(regex, "$2");
if (newIdentifier.length < 2) {
// if it results in an empty string or a single letter string
// then, it is not really a word.
return identifier;
}
newIdentifier = isCapitalized(identifier) ? capitalize(newIdentifier) : uncapitalize(newIdentifier);
return skipIdentifiers !== undefined
? skipIdentifiers.includes(newIdentifier)
? identifier
: newIdentifier
: newIdentifier;
}
return identifier;
}
exports.removeProhibitedPrefix = removeProhibitedPrefix;
function isEqual(s1, s2) {
// when s2 is undefined and s1 is the string 'undefined', it returns 0, making this true.
// To prevent that, first we need to check if s2 is undefined.
return s2 !== undefined && !!s1 && !s1.localeCompare(s2, undefined, { sensitivity: "base" });
}
exports.isEqual = isEqual;
function removeSequentialDuplicates(identifier) {
const ids = [...identifier].filter((each) => !!each);
for (let i = 0; i < ids.length; i++) {
while (isEqual(ids[i], ids[i - 1])) {
ids.splice(i, 1);
}
while (isEqual(ids[i], ids[i - 2]) && isEqual(ids[i + 1], ids[i - 1])) {
ids.splice(i, 2);
}
}
return ids;
}
exports.removeSequentialDuplicates = removeSequentialDuplicates;
function pascalCase(identifier, removeDuplicates = true) {
return identifier === undefined
? ""
: typeof identifier === "string"
? pascalCase(fixLeadingNumber(deconstruct(identifier)), removeDuplicates)
: (removeDuplicates ? [...removeSequentialDuplicates(identifier)] : identifier)
.map((each) => capitalize(each))
.join("");
}
exports.pascalCase = pascalCase;
function camelCase(identifier) {
if (typeof identifier === "string") {
return camelCase(fixLeadingNumber(deconstruct(identifier)));
}
switch (identifier.length) {
case 0:
return "";
case 1:
return uncapitalize(identifier[0]);
}
return `${uncapitalize(identifier[0])}${pascalCase(identifier.slice(1))}`;
}
exports.camelCase = camelCase;
function getPascalIdentifier(name) {
return pascalCase(fixLeadingNumber(deconstruct(name)));
}
exports.getPascalIdentifier = getPascalIdentifier;
function escapeString(text) {
if (text) {
const q = JSON.stringify(text);
return q.slice(1, -1);
}
return "";
}
exports.escapeString = escapeString;
/** emits c# to get the name of a property - uses nameof when it can, and uses a literal when it's an array value. */
function nameof(text) {
if (text.indexOf("[") > -1) {
return `$"${text.replace(/\[(.*)\]/, "[{$1}]")}"`;
}
return `nameof(${text})`;
}
exports.nameof = nameof;
function* getRegions(source, prefix = "#", postfix = "") {
source = source.replace(/\r?\n|\r/g, "«");
const rx = new RegExp(`(.*?)«?(\\s*${prefix}\\s*region\\s*(.*?)\\s*${postfix})\\s*«(.*?)«(\\s*${prefix}\\s*endregion\\s*${postfix})\\s*?«`, "g");
let match;
let finalPosition = 0;
/* eslint-disable */
while ((match = rx.exec(source))) {
if (match[1]) {
// we have text before this region.
yield {
name: "",
start: "",
content: match[1].replace(/«/g, "\n"),
end: "",
};
}
// this region
yield {
name: match[3],
start: match[2],
content: match[4].replace(/«/g, "\n"),
end: match[5],
};
finalPosition = rx.lastIndex;
}
if (finalPosition < source.length) {
// we have text after the last region.
yield {
name: "",
start: "",
content: source.substring(finalPosition).replace(/«/g, "\n"),
end: "",
};
}
}
exports.getRegions = getRegions;
function setRegion(source, region, content, prepend = true, prefix = "#", postfix = "") {
const result = new Array();
const ct = new file_generator_1.Text(content).text
.replace(/\r?\n|\r/g, "«")
.replace(/^«*/, "")
.replace(/«*$/, "");
let found = false;
for (const each of getRegions(source, prefix, postfix)) {
if (each.name === region) {
// found the region, replace it.
// (this also makes sure that we only have one region by that name when replacing/deleting)
if (!found && ct) {
// well, only if it has content, otherwise, we're deleting it.
result.push(each.start, ct, each.end, "«");
found = true;
}
}
else {
result.push(each.start, each.content, each.end, "«");
}
}
if (!found) {
if (prepend) {
result.splice(0, 0, `${prefix} region ${region} ${postfix}`, ct, `${prefix} endregion ${postfix}«`);
}
else {
result.push(`${prefix} region ${region} ${postfix}`, ct, `${prefix} endregion ${postfix}«`);
}
}
return result
.join("«")
.replace(/\r?\n|\r/g, "«")
.replace(/^«*/, "")
.replace(/«*$/, "")
.replace(/«««*/g, "««")
.replace(/«/g, "\n");
}
exports.setRegion = setRegion;
// Note: Where is this used?
function _setRegion(source, region, content, prepend = true, prefix = "#", postfix = "") {
const ct = new file_generator_1.Text(content).text
.replace(/\r?\n|\r/g, "«")
.replace(/^«*/, "")
.replace(/«*$/, "");
source = source.replace(/\r?\n|\r/g, "«");
const rx = new RegExp(`«(\\s*${prefix}\\s*region\\s*${region}\\s*${postfix})\\s*«.*?(«\\s*${prefix}\\s*endregion\\s*${postfix}«?)`, "g");
if (rx.test(source)) {
if (ct.length > 0) {
source = source.replace(rx, `«$1«${ct}$2`);
}
else {
source = source.replace(rx, "");
}
}
else {
if (ct.length > 0) {
const text = `«${prefix} region ${region} ${postfix}«${ct}«${prefix} endregion ${postfix}«`;
source = prepend ? text + source : source + text;
}
}
source = source.replace(/«««*/g, "««").replace(/«/g, "\n");
return source;
}
exports._setRegion = _setRegion;
function selectName(nameOptions, reservedNames) {
// we're here because the original name is in conflict.
// so we start with the alternatives (skip the 0th!) NOT
for (const each of nameOptions) {
if (!reservedNames.has(each)) {
reservedNames.add(each);
return each;
}
}
// hmm, none of the names were suitable.
// use the first one, and tack on a number until we have a free value
let i = 1;
do {
const name = `${nameOptions[0]}${i}`;
if (!reservedNames.has(name)) {
reservedNames.add(name);
return name;
}
i++;
} while (i < 100);
// after an unreasonalbe search, return something invalid
return `InvalidPropertyName${nameOptions[0]}`;
}
exports.selectName = selectName;
//# sourceMappingURL=text-manipulation.js.map