Remove linq from m4 and codegen (#4241)

* Remove from codegen

* Remove from m4

* Wip

* Tweaks

* Wip

* Wip

* fix

* fix
This commit is contained in:
Timothee Guerin 2021-07-30 13:04:46 -07:00 коммит произвёл GitHub
Родитель bc4b87e4b3
Коммит a73d85c7ab
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
25 изменённых файлов: 451 добавлений и 307 удалений

Просмотреть файл

@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "@autorest/codemodel",
"comment": "**Internal** Remove need for @azure-tools/linq library",
"type": "minor"
}
],
"packageName": "@autorest/codemodel",
"email": "tiguerin@microsoft.com"
}

Просмотреть файл

@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "@autorest/modelerfour",
"comment": "**Internal** Remove @azure-tools/linq library\"",
"type": "minor"
}
],
"packageName": "@autorest/modelerfour",
"email": "tiguerin@microsoft.com"
}

Просмотреть файл

@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "@azure-tools/codegen",
"comment": "**Internal** Remove @azure-tools/linq library\"",
"type": "minor"
}
],
"packageName": "@azure-tools/codegen",
"email": "tiguerin@microsoft.com"
}

Просмотреть файл

@ -45,7 +45,6 @@
"@azure-tools/async-io": "~3.0.0",
"@azure-tools/codegen": "~2.6.0",
"@azure-tools/datastore": "~4.4.0",
"@azure-tools/linq": "~3.1.0",
"@azure-tools/openapi": "~3.2.0",
"@azure-tools/tasks": "~3.0.0",
"@azure-tools/uri": "~3.1.1",

Просмотреть файл

@ -16,7 +16,6 @@ import {
SchemaContext,
} from "@autorest/codemodel";
import { Session } from "@autorest/extension-base";
import { values, items, length, Dictionary, refCount, clone } from "@azure-tools/linq";
import { pascalCase, camelCase } from "@azure-tools/codegen";
import { ModelerFourOptions } from "../modeler/modelerfour-options";
@ -26,7 +25,7 @@ const xmsParameterGrouping = "x-ms-parameter-grouping";
export class Grouper {
codeModel: CodeModel;
options: ModelerFourOptions = {};
groups: Dictionary<GroupSchema> = {};
groups: Record<string, GroupSchema> = {};
constructor(protected session: Session<CodeModel>) {
this.codeModel = session.model; // shadow(session.model, filename);
@ -42,7 +41,7 @@ export class Grouper {
if (this.options["group-parameters"] === true) {
for (const group of this.codeModel.operationGroups) {
for (const operation of group.operations) {
for (const request of values(operation.requests)) {
for (const request of operation.requests ?? []) {
this.processParameterGroup(group, operation, request);
request.updateSignatureParameters();
}
@ -101,7 +100,7 @@ export class Grouper {
const schema = this.groups[groupName];
// see if the group has this parameter.
const existingProperty = values(schema.properties).first(
const existingProperty = schema.properties?.find(
(each) => each.language.default.name === parameter.language.default.name,
);
if (existingProperty) {
@ -144,7 +143,7 @@ export class Grouper {
// remove the grouping extension from the original parameter.
if (parameter.extensions) {
delete parameter.extensions[xmsParameterGrouping];
if (length(parameter.extensions) === 0) {
if (parameter.extensions.length === 0) {
delete parameter["extensions"];
}
}

Просмотреть файл

@ -1,6 +1,5 @@
import { Session } from "@autorest/extension-base";
import * as OpenAPI from "@azure-tools/openapi";
import { values, length, ToDictionary, Dictionary } from "@azure-tools/linq";
import {
ChoiceSchema,
XmlSerlializationFormat,
@ -10,9 +9,15 @@ import {
ChoiceValue,
SetType,
} from "@autorest/codemodel";
import { StringFormat, JsonType, ParameterLocation, includeXDashKeys } from "@azure-tools/openapi";
import {
StringFormat,
JsonType,
ParameterLocation,
includeXDashKeys,
includeXDashProperties,
} from "@azure-tools/openapi";
import { getPascalIdentifier } from "@azure-tools/codegen";
import { keyBy } from "lodash";
export interface XMSEnum {
modelAsString?: boolean;
values: [{ value: any; description?: string; name?: string }];
@ -195,10 +200,16 @@ export class Interpretations {
const hasAdditionalProps =
typeof schema.additionalProperties === "boolean"
? schema.additionalProperties
: length(schema.additionalProperties) !== 0;
: Object.keys(schema.additionalProperties ?? {}).length !== 0;
const allOfCount = schema.allOf?.length ?? 0;
const anyOfCount = schema.anyOf?.length ?? 0;
const oneOfCount = schema.oneOf?.length ?? 0;
const propertyCount = Object.keys(schema.properties ?? {}).length;
return (
schema.type === JsonType.Object &&
length(schema.allOf) + length(schema.anyOf) + length(schema.oneOf) + length(schema.properties) === 0 &&
allOfCount + anyOfCount + oneOfCount + propertyCount === 0 &&
!hasAdditionalProps &&
!schema.discriminator
);
@ -240,23 +251,20 @@ export class Interpretations {
}
getApiVersions(schema: OpenAPI.Schema | OpenAPI.HttpOperation | OpenAPI.PathItem): Array<ApiVersion> | undefined {
if (schema["x-ms-metadata"] && schema["x-ms-metadata"]["apiVersions"]) {
const v = values(<Array<string>>schema["x-ms-metadata"]["apiVersions"])
.select((each) =>
SetType(ApiVersion, {
version: each.replace(/^-/, "").replace(/\+$/, ""),
range: each.startsWith("-") ? <any>"-" : each.endsWith("+") ? "+" : undefined,
}),
)
.toArray();
const v = (schema["x-ms-metadata"]["apiVersions"] ?? []).map((each: string) =>
SetType(ApiVersion, {
version: each.replace(/^-/, "").replace(/\+$/, ""),
range: each.startsWith("-") ? <any>"-" : each.endsWith("+") ? "+" : undefined,
}),
);
return v;
}
return undefined;
}
getApiVersionValues(node: OpenAPI.Schema | OpenAPI.HttpOperation | OpenAPI.PathItem): Array<string> {
if (node["x-ms-metadata"] && node["x-ms-metadata"]["apiVersions"]) {
return values(<Array<string>>node["x-ms-metadata"]["apiVersions"])
.distinct()
.toArray();
return [...new Set<string>((node["x-ms-metadata"]["apiVersions"] as any) ?? [])];
}
return [];
}
@ -308,9 +316,9 @@ export class Interpretations {
}
// synthesize from tags.
if (original.tags && length(original.tags) > 0) {
if (original.tags && original.tags.length > 0) {
const newOperationId =
length(original.tags) === 1 ? `${original.tags[0]}` : `${original.tags[0]}_${original.tags[1]}`;
original.tags.length === 1 ? `${original.tags[0]}` : `${original.tags[0]}_${original.tags[1]}`;
this.session.warning(
`Generating 'operationId' to '${newOperationId}' for '${httpMethod}' operation on path '${path}' `,
@ -405,7 +413,10 @@ export class Interpretations {
return new ChoiceSchema(name, this.getDescription("MISSING-SERVER-VARIABLE-ENUM-DESCRIPTION", somethingWithEnum));
}
getExtensionProperties(dictionary: Dictionary<any>, additional?: Dictionary<any>): Dictionary<any> | undefined {
getExtensionProperties(
dictionary: Record<string, any>,
additional?: Record<string, any>,
): Record<string, any> | undefined {
const main = Interpretations.getExtensionProperties(dictionary);
if (additional) {
const more = Interpretations.getExtensionProperties(additional);
@ -415,15 +426,18 @@ export class Interpretations {
}
return main;
}
getClientDefault(dictionary: Dictionary<any>, additional?: Dictionary<any>): string | number | boolean | undefined {
getClientDefault(
dictionary: Record<string, any>,
additional?: Record<string, any>,
): string | number | boolean | undefined {
return dictionary?.["x-ms-client-default"] || additional?.["x-ms-client-default"] || undefined;
}
static getExtensionProperties(dictionary: Dictionary<any>): Dictionary<any> | undefined {
const result = ToDictionary(includeXDashKeys(dictionary), (each) => dictionary[each]);
static getExtensionProperties(dictionary: Record<string, any>): Record<string, any> | undefined {
const result: Record<string, any> = includeXDashProperties(dictionary);
for (const each of removeKnownParameters) {
delete result[each];
}
return length(result) === 0 ? undefined : result;
return Object.keys(result).length === 0 ? undefined : result;
}
}

Просмотреть файл

@ -10,8 +10,8 @@ import {
MediaType,
omitXDashProperties,
} from "@azure-tools/openapi";
import { uniq, every } from "lodash";
import * as OpenAPI from "@azure-tools/openapi";
import { items, values, Dictionary, length } from "@azure-tools/linq";
import {
HttpMethod,
HttpModel,
@ -80,6 +80,7 @@ import { isContentTypeParameterDefined } from "./utils";
import { BodyProcessor } from "./body-processor";
import { isSchemaAnEnum, isSchemaBinary } from "./schema-utils";
import { SecurityProcessor } from "./security-processor";
import { isDefined } from "../utils";
/** adds only if the item is not in the collection already
*
@ -151,7 +152,7 @@ export class ModelerFour {
this.processSchemaImpl(schema, name),
);
private options: ModelerFourOptions = {};
private uniqueNames: Dictionary<any> = {};
private uniqueNames: Record<string, any> = {};
private bodyProcessor: BodyProcessor;
private securityProcessor: SecurityProcessor;
private ignoreHeaders: Set<string> = new Set();
@ -215,10 +216,11 @@ export class ModelerFour {
}
// see how many api versions there are for all the operations
const allApiVersions = values(this.inputOperations)
.selectMany((each) => <Array<string>>this.interpret.xmsMetaFallback(each.operation, each.pathItem, "apiVersions"))
.distinct()
.toArray();
const allApiVersions = uniq(
this.inputOperations.flatMap(
(each) => <Array<string>>this.interpret.xmsMetaFallback(each.operation, each.pathItem, "apiVersions"),
),
);
switch (allApiVersions.length) {
case 0:
this.useModelNamespace = false;
@ -231,11 +233,9 @@ export class ModelerFour {
}
// multiple api versions in play.
const multiVersionPerOperation = values(this.inputOperations)
.select((each) =>
length(<Array<string>>this.interpret.xmsMetaFallback(each.operation, each.pathItem, "apiVersions")),
)
.any((each) => each > 1);
const multiVersionPerOperation = this.inputOperations
.map((each) => this.interpret.xmsMetaFallback(each.operation, each.pathItem, "apiVersions").length)
.find((each) => each > 1);
if (!multiVersionPerOperation) {
// operations have one single api version each
this.apiVersionParameter = apiVersionParameter || "constant";
@ -313,13 +313,13 @@ export class ModelerFour {
return (source ?? []).map((each) => dereference(this.input, each).instance);
}
resolveDictionary<T>(source?: Dictionary<Refable<T>>) {
return items(source)
.linq.select((each) => ({
key: each.key,
value: dereference(this.input, each.value).instance,
resolveDictionary<T>(source?: Record<string, Refable<T>>) {
return Object.entries(source ?? {})
.map(([key, value]) => ({
key,
value: dereference(this.input, value).instance,
}))
.where((each) => each.value !== undefined);
.filter(isDefined);
}
location(obj: any): string {
@ -661,7 +661,7 @@ export class ModelerFour {
case JsonType.Integer:
return this.processIntegerSchema("integer", schema);
case undefined:
if (length(schema.enum) > 0 && values(schema.enum).all((each) => typeof each === "string")) {
if (schema.enum && schema.enum.length > 0 && every(schema.enum, (x) => typeof x === "string")) {
this.session.warning(
`The enum schema '${schema?.["x-ms-metadata"]?.name}' with an undefined type and enum values is ambiguous. This has been auto-corrected to 'type:string'`,
["Modeler", "MissingType"],
@ -855,7 +855,7 @@ export class ModelerFour {
// cache this now before we accidentally recurse on this type.
this.schemaCache.set(schema, objectSchema);
for (const { key: propertyName, value: propertyDeclaration } of items(schema.properties)) {
for (const [propertyName, propertyDeclaration] of Object.entries(schema.properties ?? {})) {
const property = this.resolve(propertyDeclaration);
this.use(<OpenAPI.Refable<OpenAPI.Schema>>propertyDeclaration, (pSchemaName, pSchema) => {
const pType = this.processSchema(pSchemaName || `type·for·${propertyName}`, pSchema);
@ -892,11 +892,12 @@ export class ModelerFour {
const dictionaryDef = schema.additionalProperties;
// is this more than a straightforward object?
const parentCount = length(schema.allOf);
const isMoreThanObject = parentCount + length(schema.anyOf) + length(schema.oneOf) > 0 || !!dictionaryDef;
const parentCount = schema.allOf?.length ?? 0;
const isMoreThanObject =
parentCount + (schema.anyOf?.length ?? 0) + (schema.oneOf?.length ?? 0) > 0 || !!dictionaryDef;
// do we have properties at all?
const hasProperties = length(schema.properties) > 0;
const hasProperties = schema.properties && Object.keys(schema.properties).length > 0;
if (!isMoreThanObject && !hasProperties) {
// it's an empty object?
@ -912,37 +913,27 @@ export class ModelerFour {
const objectSchema = this.createObjectSchema(name, schema);
let i = 0;
const parents: Array<ComplexSchema> = <any>values(schema.allOf)
.select((sch) =>
this.use(sch, (n, s) => {
return this.processSchema(n || `${name}.allOf.${i++}`, s);
}),
)
.toArray();
const orTypes = values(schema.anyOf)
.select((sch) =>
this.use(sch, (n, s) => {
return this.processSchema(n || `${name}.anyOf.${i++}`, s);
}),
)
.toArray();
const xorTypes = values(schema.oneOf)
.select((sch) =>
this.use(sch, (n, s) => {
return this.processSchema(n || `${name}.oneOf.${i++}`, s);
}),
)
.toArray();
const parents: Array<ComplexSchema> = Object.values(schema.allOf ?? {}).map((sch) =>
this.use(sch, (n, s) => {
return this.processSchema(n || `${name}.allOf.${i++}`, s);
}),
);
const orTypes = Object.values(schema.anyOf ?? {}).map((sch) =>
this.use(sch, (n, s) => {
return this.processSchema(n || `${name}.anyOf.${i++}`, s);
}),
);
const xorTypes = Object.values(schema.oneOf ?? {}).map((sch) =>
this.use(sch, (n, s) => {
return this.processSchema(n || `${name}.oneOf.${i++}`, s);
}),
);
// add it to the upcoming and schema set
// andTypes.unshift(objectSchema);
// set the apiversion namespace
const m = minimum(
values(objectSchema.apiVersions)
.select((each) => each.version)
.toArray(),
);
const m = minimum((objectSchema.apiVersions ?? []).map((each) => each.version));
objectSchema.language.default.namespace = this.useModelNamespace ? pascalCase(`Api ${m}`, false) : "";
// tell it should be internal if possible
@ -1299,7 +1290,7 @@ export class ModelerFour {
throw new Error(`Unrecognized schema type:'${schema.type}' / format: ${schema.format} ${JSON.stringify(schema)} `);
}
filterMediaTypes(oai3Content: Dictionary<MediaType> | undefined) {
filterMediaTypes(oai3Content: Record<string, MediaType> | undefined) {
const mediaTypeGroups = this.bodyProcessor.groupMediaTypes(oai3Content);
// filter out invalid combinations
@ -1481,7 +1472,7 @@ export class ModelerFour {
const bodyName = body.instance?.["x-ms-requestBody-name"] ?? "data";
const requestSchema = values(kmtBinary).first((each) => !!each.schema.instance)?.schema;
const requestSchema = kmtBinary.find((x) => !!x.schema.instance)?.schema;
const pSchema =
kmt === KnownMediaType.Text
@ -1555,7 +1546,7 @@ export class ModelerFour {
);
}
const requestSchema = values(kmtObject).first((each) => !!each.schema.instance)?.schema;
const requestSchema = kmtObject.find((each) => !!each.schema.instance)?.schema;
if (kmt === KnownMediaType.Multipart || kmt === KnownMediaType.Form) {
if (!requestSchema || !requestSchema.instance) {
@ -1566,7 +1557,7 @@ export class ModelerFour {
// multipart/form-data parameters be modeled as object schema properties
// but we must turn them back into operation parameters so that code
// generators will generate them as method parameters.
for (const { key: propertyName, value: propertyDeclaration } of items(requestSchema.instance.properties)) {
for (const [propertyName, propertyDeclaration] of Object.entries(requestSchema.instance.properties ?? {})) {
const property = this.resolve(propertyDeclaration);
this.use(<OpenAPI.Refable<OpenAPI.Schema>>propertyDeclaration, (pSchemaName, pSchema) => {
const pType = this.processSchema(pSchemaName || `type·for·${propertyName}`, pSchema);
@ -1691,7 +1682,7 @@ export class ModelerFour {
let baseUri = "";
// create $host parameters from servers information.
// $host is comprised of []
const servers = values(httpOperation.servers).toArray();
const servers = httpOperation.servers ?? [];
switch (servers.length) {
case 0:
@ -1710,7 +1701,7 @@ export class ModelerFour {
const uri =
server.url.endsWith("/") && path.startsWith("/") ? server.url.substr(0, server.url.length - 1) : server.url;
if (length(server.variables) === 0) {
if (server.variables === undefined || Object.keys(server.variables).length === 0) {
// scenario 1 : single static value
// check if we have the $host parameter foor this uri yet.
@ -1742,7 +1733,7 @@ export class ModelerFour {
} else {
// scenario 3 : single parameterized value
for (const { key: variableName, value: variable } of items(server.variables).where((each) => !!each.key)) {
for (const [variableName, variable] of Object.entries(server.variables ?? {}).filter(([key]) => !!key)) {
const sch = this.getServerVariableSchema(variableName, variable);
const clientdefault = variable.default ? variable.default : undefined;
@ -1797,7 +1788,7 @@ export class ModelerFour {
break;
default: {
if (values(servers).any((each) => length(each.variables) > 0)) {
if (servers.find((each) => Object.keys(each.variables ?? {}).length > 0)) {
// scenario 4 : multiple parameterized value - not valid.
throw new Error(
`Operation ${pathItem?.["x-ms-metadata"]?.path} has multiple server information with parameterized values.`,
@ -2074,7 +2065,7 @@ export class ModelerFour {
const knownMediaTypes = this.filterMediaTypes(response.content);
if (length(knownMediaTypes) === 0) {
if (knownMediaTypes.size === 0) {
// it has no actual response *payload*
// so we just want to create a simple response .
const rsp = new Response({
@ -2093,14 +2084,13 @@ export class ModelerFour {
operation.addResponse(rsp);
}
} else {
for (const { key: knownMediaType, value: mediatypes } of items(knownMediaTypes)) {
const allMt = mediatypes.map((each) => each.mediaType);
for (const [knownMediaType, mediatypes] of knownMediaTypes.entries()) {
const allMt = mediatypes.map((each: any) => each.mediaType);
for (const mediaType of allMt) {
acceptTypes.add(mediaType);
}
const headers = this.processResponseHeaders(response.headers);
if (knownMediaType === KnownMediaType.Binary) {
// binary response needs different response type.
const rsp = new BinaryResponse({
@ -2182,9 +2172,9 @@ export class ModelerFour {
const mediaTypes = Array.from(acceptTypes);
if (this.options["always-create-accept-parameter"] === true && acceptTypes.size > 0) {
const acceptSchema = this.getAcceptParameterSchema(mediaTypes);
if (!values(operation.parameters).first(isAcceptHeaderParam)) {
for (const request of values(operation.requests)) {
if (values(request.parameters).first(isAcceptHeaderParam)) {
if (!operation.parameters?.find(isAcceptHeaderParam)) {
for (const request of operation.requests ?? []) {
if (request.parameters?.find(isAcceptHeaderParam)) {
// Already has an accept parameter, move on to the next.
continue;
}
@ -2209,7 +2199,7 @@ export class ModelerFour {
}
}
private processResponseHeaders(responseHeaders: Dictionary<Refable<OpenAPI.Header>> | undefined): HttpHeader[] {
private processResponseHeaders(responseHeaders: Record<string, Refable<OpenAPI.Header>> | undefined): HttpHeader[] {
const headers: HttpHeader[] = [];
for (const { key: headerName, value: header } of this.resolveDictionary(responseHeaders)) {
this.use(header.schema, (_name, sch) => {
@ -2304,7 +2294,7 @@ export class ModelerFour {
this.processSerializedObject(KnownMediaType.Multipart, kmtMultipart, operation, requestBody);
}
// ensure the protocol information is set on the requests
for (const request of values(operation.requests)) {
for (const request of operation.requests ?? []) {
is(request.protocol.http);
request.protocol.http.method = httpMethod;
request.protocol.http.path = path;
@ -2412,10 +2402,10 @@ export class ModelerFour {
schema.children?.all?.forEach((c) => innerApplySchemaUsage(c, schemaUsage));
schema.children?.immediate?.forEach((c) => innerApplySchemaUsage(c, schemaUsage));
items(schema.discriminator?.all).forEach(({ key: k, value: d }) => {
Object.values(schema.discriminator?.all ?? {}).forEach((d) => {
innerApplySchemaUsage(d, schemaUsage);
});
values(schema.discriminator?.immediate).forEach((d) => {
Object.values(schema.discriminator?.immediate ?? {}).forEach((d) => {
innerApplySchemaUsage(d, schemaUsage);
});
}

Просмотреть файл

@ -1,5 +1,4 @@
import { Languages } from "@autorest/codemodel";
import { length, Dictionary } from "@azure-tools/linq";
import { removeSequentialDuplicates, fixLeadingNumber, deconstruct, Style, Styler } from "@azure-tools/codegen";
import { Session } from "@autorest/extension-base";
@ -7,8 +6,8 @@ export function getNameOptions(typeName: string, components: Array<string>) {
const result = new Set<string>();
// add a variant for each incrementally inclusive parent naming scheme.
for (let i = 0; i < length(components); i++) {
const subset = Style.pascal([...removeSequentialDuplicates(components.slice(-1 * i, length(components)))]);
for (let i = 0; i < components.length; i++) {
const subset = Style.pascal([...removeSequentialDuplicates(components.slice(-1 * i, components.length))]);
result.add(subset);
}
@ -41,7 +40,7 @@ export function setName(
thing: Nameable,
styler: Styler,
defaultValue: string,
overrides: Dictionary<string>,
overrides: Record<string, string>,
options?: SetNameOptions,
) {
setNameAllowEmpty(thing, styler, defaultValue, overrides, options);
@ -54,7 +53,7 @@ export function setNameAllowEmpty(
thing: Nameable,
styler: Styler,
defaultValue: string,
overrides: Dictionary<string>,
overrides: Record<string, string>,
options?: SetNameOptions,
) {
options = { ...setNameDefaultOptions, ...options };

Просмотреть файл

@ -16,10 +16,10 @@ import {
SealedChoiceSchema,
} from "@autorest/codemodel";
import { Session } from "@autorest/extension-base";
import { values, length, Dictionary, items } from "@azure-tools/linq";
import { selectName, Style } from "@azure-tools/codegen";
import { ModelerFourOptions } from "../modeler/modelerfour-options";
import { getNameOptions, isUnassigned, ScopeNamer, setName, setNameAllowEmpty } from "./naming-utils";
import { partition } from "lodash";
export class PreNamer {
codeModel: CodeModel;
@ -38,7 +38,7 @@ export class PreNamer {
client: Style.pascal,
local: Style.camel,
global: Style.pascal,
override: <Dictionary<string>>{},
override: <Record<string, string>>{},
};
enum = 0;
@ -271,14 +271,14 @@ export class PreNamer {
private setResponseHeaderNames(response: Response) {
if (response.protocol.http) {
for (const { value: header } of items(response.protocol.http.headers)) {
for (const header of Object.values(response.protocol.http.headers ?? {})) {
setName(header as { language: Languages }, this.format.responseHeader, "", this.format.override);
}
}
}
fixParameterCollisions() {
for (const operation of values(this.codeModel.operationGroups).selectMany((each) => each.operations)) {
for (const operation of values(this.codeModel.operationGroups).flatMap((each) => each.operations)) {
for (const request of values(operation.requests)) {
const parameters = values(operation.signatureParameters).concat(values(request.signatureParameters));
@ -312,10 +312,13 @@ export class PreNamer {
}
fixCollisions(schema: ObjectSchema) {
for (const each of values(schema.parents?.immediate).where((each) => isObjectSchema(each))) {
for (const each of values(schema.parents?.immediate).filter((each) => isObjectSchema(each))) {
this.fixCollisions(<ObjectSchema>each);
}
const [owned, flattened] = values(schema.properties).bifurcate((each) => length(each.flattenedNames) === 0);
const [owned, flattened] = partition(
schema.properties ?? [],
(each) => each.flattenedNames === undefined || each.flattenedNames.length === 0,
);
const inherited = [...getAllParentProperties(schema)];
const all = [...owned, ...inherited, ...flattened];
@ -346,3 +349,7 @@ export class PreNamer {
}
}
}
function values<T>(item: T[] | undefined): T[] {
return Object.values(item ?? []);
}

Просмотреть файл

@ -1,5 +1,4 @@
import { Session } from "@autorest/extension-base";
import { length } from "@azure-tools/linq";
import oai3, { dereference, Dereferenced, JsonType, Schema } from "@azure-tools/openapi";
import { groupBy } from "lodash";
import { ModelerFourOptions } from "modeler/modelerfour-options";
@ -212,13 +211,15 @@ export class DuplicateSchemaMerger {
case JsonType.Object:
// empty objects don't worry.
if (length(schema.properties) === 0 && length(schema.allOf) === 0) {
if (Object.keys(schema.properties ?? {}).length === 0 && Object.keys(schema.allOf ?? {}).length === 0) {
return false;
}
return true;
default:
return length(schema.properties) > 0 || length(schema.allOf) > 0 ? true : false;
return Object.keys(schema.properties ?? {}).length > 0 || Object.keys(schema.allOf ?? {}).length > 0
? true
: false;
}
}
}

Просмотреть файл

@ -1,5 +1,4 @@
import { Session } from "@autorest/extension-base";
import { values, items, length } from "@azure-tools/linq";
import {
Model as oai3,
Refable,
@ -79,10 +78,10 @@ export class QualityPreChecker {
}
getProperties(schema: Schema) {
return items(schema.properties).select((each) => ({
key: each.key,
name: <string>this.interpret.getPreferredName(each.value, each.key),
property: this.resolve(each.value).instance,
return Object.entries(schema.properties ?? {}).map(([key, value]) => ({
key: key,
name: <string>this.interpret.getPreferredName(value, key),
property: this.resolve(value).instance,
}));
//return items(schema.properties).toMap(each => <string>this.interpret.getPreferredName(each.value, each.key), each => this.resolve(each.value).instance);
}
@ -91,7 +90,7 @@ export class QualityPreChecker {
tag: string,
schemas: Array<Refable<Schema>> | undefined,
): Iterable<{ name: string; schema: Schema; tag: string }> {
return values(schemas).select((a) => {
return Object.values(schemas ?? []).map((a) => {
const { instance: schema, name } = this.resolve(a);
return {
name: this.interpret.getName(name, schema),
@ -121,7 +120,7 @@ export class QualityPreChecker {
completed.add(schema);
if (schema.allOf && schema.properties) {
const myProperties = this.getProperties(schema).toArray();
const myProperties = this.getProperties(schema);
for (const { name: parentName, schema: parentSchema } of this.getAllParents(schemaName, schema)) {
this.checkForHiddenProperties(parentName, parentSchema, completed);
@ -207,15 +206,15 @@ export class QualityPreChecker {
fixUpSchemasThatUseAllOfInsteadOfJustRef() {
const schemas = this.input.components?.schemas;
if (schemas) {
for (const { key, instance: schema, name, fromRef } of items(schemas).select((s) => ({
key: s.key,
...this.resolve(s.value),
for (const { key, instance: schema } of Object.entries(schemas).map(([key, value]) => ({
key: key,
...this.resolve(value),
}))) {
// we're looking for schemas that offer no possible value
// because they just use allOf instead of $ref
if (!schema.type || schema.type === JsonType.Object) {
if (length(schema.allOf) === 1) {
if (length(schema.properties) > 0) {
if (Object.keys(schema.allOf ?? {}).length === 1) {
if (Object.keys(schema.properties ?? {}).length > 0) {
continue;
}
if (schema.additionalProperties) {
@ -251,7 +250,7 @@ export class QualityPreChecker {
}
fixUpObjectsWithoutType() {
for (const { instance: schema, name, fromRef } of values(this.input.components?.schemas).select((s) =>
for (const { instance: schema, name, fromRef } of Object.values(this.input.components?.schemas ?? {}).map((s) =>
this.resolve(s),
)) {
if (<any>schema.type === "file" || <any>schema.format === "file" || <any>schema.format === "binary") {
@ -317,7 +316,11 @@ export class QualityPreChecker {
}
isEmptyObjectSchema(schema: Schema): boolean {
if (length(schema.properties) > 0 || length(schema.allOf) > 0 || schema.additionalProperties === true) {
if (
Object.keys(schema.properties ?? {}).length > 0 ||
Object.keys(schema.allOf ?? {}).length > 0 ||
schema.additionalProperties === true
) {
return false;
}
@ -332,12 +335,12 @@ export class QualityPreChecker {
fixUpSchemasWithEmptyObjectParent() {
const schemas = this.input.components?.schemas;
if (schemas) {
for (const { key, instance: schema, name, fromRef } of items(schemas).select((s) => ({
key: s.key,
...this.resolve(s.value),
for (const { key, instance: schema, name, fromRef } of Object.entries(schemas).map(([key, value]) => ({
key: key,
...this.resolve(value),
}))) {
if (schema.type === JsonType.Object) {
if (length(schema.allOf) > 1) {
if (Object.keys(schema.allOf ?? {}).length > 1) {
const schemaName = schema["x-ms-metadata"]?.name || name;
schema.allOf = schema.allOf?.filter((p) => {
const parent = this.resolve(p).instance;
@ -370,14 +373,14 @@ export class QualityPreChecker {
this.checkForDuplicateSchemas();
let onlyOnce = new WeakSet<Schema>();
for (const { instance: schema, name, fromRef } of values(this.input.components?.schemas).select((s) =>
for (const { instance: schema, name, fromRef } of Object.values(this.input.components?.schemas ?? {}).map((s) =>
this.resolve(s),
)) {
this.checkForHiddenProperties(this.interpret.getName(name, schema), schema, onlyOnce);
}
onlyOnce = new WeakSet<Schema>();
for (const { instance: schema, name, fromRef } of values(this.input.components?.schemas).select((s) =>
for (const { instance: schema, name, fromRef } of Object.values(this.input.components?.schemas ?? {}).map((s) =>
this.resolve(s),
)) {
this.checkForDuplicateParents(this.interpret.getName(name, schema), schema, onlyOnce);

Просмотреть файл

@ -1,6 +1,5 @@
import { clone } from "@azure-tools/linq";
import * as oai3 from "@azure-tools/openapi";
import { cloneDeep } from "lodash";
export const InitialTestSpec = Object.freeze({
info: {
title: "Test OpenAPI 3 Specification",
@ -24,7 +23,7 @@ export type TestSpecCustomizer = (spec: any) => any;
export function createTestSpec(...customizers: Array<TestSpecCustomizer>): any {
return customizers.reduce<any>(
(spec: any, customizer: TestSpecCustomizer) => customizer(spec),
clone(InitialTestSpec),
cloneDeep(InitialTestSpec),
);
}

Просмотреть файл

@ -55,7 +55,6 @@
},
"dependencies": {
"@azure-tools/async-io": "~3.0.0",
"@azure-tools/linq": "~3.1.0",
"js-yaml": "~4.0.0",
"semver": "^5.5.1"
}

Просмотреть файл

@ -1,15 +1,14 @@
import { fixLeadingNumber, removeSequentialDuplicates } from "../text-manipulation";
import { Dictionary, values } from "@azure-tools/linq";
export type Styler = (
identifier: string | Array<string>,
removeDuplicates: boolean | undefined,
overrides: Dictionary<string> | undefined,
overrides: Record<string, string> | undefined,
) => string;
type StylerWithUppercasePreservation = (
identifier: string | Array<string>,
removeDuplicates: boolean | undefined,
overrides: Dictionary<string> | undefined,
overrides: Record<string, string> | undefined,
maxUppercasePreserve: number | undefined,
) => string;
@ -40,7 +39,7 @@ function IsFullyUpperCase(identifier: string, maxUppercasePreserve: number) {
function deconstruct(identifier: string | Array<string>, maxUppercasePreserve: number): Array<string> {
if (Array.isArray(identifier)) {
return [...values(identifier).selectMany((each) => deconstruct(each, maxUppercasePreserve))];
return [...identifier.flatMap((each) => deconstruct(each, maxUppercasePreserve))];
}
return `${identifier}`
@ -71,7 +70,7 @@ function wrap(
function applyFormat(
normalizedContent: Array<string>,
overrides: Dictionary<string> = {},
overrides: Record<string, string> = {},
separator = "",
formatter: (s: string, i: number) => string = (s, i) => s,
) {
@ -83,7 +82,7 @@ function applyFormat(
function normalize(
identifier: string | Array<string>,
removeDuplicates = true,
overrides: Dictionary<string> = {},
overrides: Record<string, string> = {},
maxUppercasePreserve = 0,
): Array<string> {
if (!identifier || identifier.length === 0) {
@ -136,7 +135,7 @@ export class Style {
static kebab(
identifier: string | Array<string>,
removeDuplicates = true,
overrides: Dictionary<string> = {},
overrides: Record<string, string> = {},
maxUppercasePreserve = 0,
): string {
return (
@ -151,7 +150,7 @@ export class Style {
static space(
identifier: string | Array<string>,
removeDuplicates = true,
overrides: Dictionary<string> = {},
overrides: Record<string, string> = {},
maxUppercasePreserve = 0,
): string {
return (
@ -166,7 +165,7 @@ export class Style {
static snake(
identifier: string | Array<string>,
removeDuplicates = true,
overrides: Dictionary<string> = {},
overrides: Record<string, string> = {},
maxUppercasePreserve = 0,
): string {
return (
@ -181,7 +180,7 @@ export class Style {
static upper(
identifier: string | Array<string>,
removeDuplicates = true,
overrides: Dictionary<string> = {},
overrides: Record<string, string> = {},
maxUppercasePreserve = 0,
): string {
return (
@ -195,7 +194,7 @@ export class Style {
static pascal(
identifier: string | Array<string>,
removeDuplicates = true,
overrides: Dictionary<string> = {},
overrides: Record<string, string> = {},
maxUppercasePreserve = 0,
): string {
return (
@ -209,7 +208,7 @@ export class Style {
static camel(
identifier: string | Array<string>,
removeDuplicates = true,
overrides: Dictionary<string> = {},
overrides: Record<string, string> = {},
maxUppercasePreserve = 0,
): string {
return (

Просмотреть файл

@ -3,8 +3,6 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { keys, items } from "@azure-tools/linq";
export type Primitive = string | number | boolean | bigint | symbol | undefined | null;
export type XDeepPartial<T> = DeepPartial<T>;
@ -55,7 +53,7 @@ function applyTo(source: any, target: any, exclusions: Set<string>, cache = new
throw new Error("Circular refrenced models are not permitted in apply() initializers.");
}
for (const i of <any>keys(source)) {
for (const i of Object.keys(source ?? {})) {
if (exclusions.has(i)) {
continue;
}
@ -79,13 +77,13 @@ function applyTo(source: any, target: any, exclusions: Set<string>, cache = new
target[i] = source[i];
continue;
/* bad idea? :
/* bad idea? :
this recursively cloned the contents of the intializer
but this has the effect of breaking referencs where I wanted
but this has the effect of breaking referencs where I wanted
them.
// copy toarray
// copy toarray
if (Array.isArray(source[i])) {
cache.add(source);
applyTo(source[i], target[i] = [], cache);

Просмотреть файл

@ -1,15 +1,8 @@
import { items, clone, values, keys, Dictionary } from "@azure-tools/linq";
import { typeOf, isPrimitive } from "./type";
import { typeOf } from "./type";
const sourceMarker = "_#source#_";
const mapMarker = "_#map#_";
const getMap = "_#get-map#_";
const getPosition = "_#get-position#_";
const getActualValue = "_#get-value#_";
const noSource = {
$f: "none",
$p: "none",
};
export function getMappings(instance: any) {
return instance[getMap];
@ -19,7 +12,7 @@ export function enableSourceTracking<T extends object>(
instance: T,
enforce = true,
path = "$",
map = new Dictionary<any>(),
map: Record<string, any> = {},
cache = new Map<string, any>(),
): T {
let proxy = cache.get(path);

Просмотреть файл

@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
import { Text, TextPossibilities } from "./file-generator";
import { Dictionary, values } from "@azure-tools/linq";
let indentation = " ";
@ -43,11 +42,11 @@ Array.prototype.joinWith = function <T>(selector: (t: T) => string, separator?:
/** todo: can we remove this? */
/* eslint-disable */
if (!Array.prototype.hasOwnProperty('last')) {
Object.defineProperty(Array.prototype, 'last', {
if (!Array.prototype.hasOwnProperty("last")) {
Object.defineProperty(Array.prototype, "last", {
get() {
return this[this.length - 1];
}
},
});
}
@ -64,11 +63,11 @@ String.prototype.uncapitalize = function (): string {
};
/** Trims the string and removes multi leading spaces? */
String.prototype.slim = function (): string {
return this.trim().replace(/([^ ]) +/g, '$1 ');
return this.trim().replace(/([^ ]) +/g, "$1 ");
};
export function join<T>(items: Array<T>, separator: string) {
return items.filter(v => v ? true : false).join(separator);
return items.filter((v) => (v ? true : false)).join(separator);
}
export function joinComma<T>(items: Array<T>, mapFn: (item: T) => string) {
@ -84,11 +83,11 @@ export function sortByName(a: IHasName, b: IHasName): number {
}
export function setIndentation(spaces: number) {
indentation = ' '.repeat(spaces);
indentation = " ".repeat(spaces);
}
export function trimDots(content: string) {
return content.replace(/^[.\s]*(.*?)[.\s]*$/g, '$1');
return content.replace(/^[.\s]*(.*?)[.\s]*$/g, "$1");
}
export function toMap<T>(source: Array<T>, eachFn: (item: T) => string): Map<string, Array<T>> {
@ -118,13 +117,13 @@ export function indent(content: string, factor: number = 1): string {
export function comment(content: string, prefix = lineCommentPrefix, factor = 0, maxLength = 120) {
const result = new Array<string>();
let line = '';
let line = "";
prefix = indent(prefix, factor);
content = content.trim();
if (content) {
for (const word of content.replace(/\n+/g, ' » ').split(/\s+/g)) {
if (word === '»') {
for (const word of content.replace(/\n+/g, " » ").split(/\s+/g)) {
if (word === "»") {
result.push(line);
line = prefix;
continue;
@ -132,7 +131,7 @@ export function comment(content: string, prefix = lineCommentPrefix, factor = 0,
if (maxLength < line.length) {
result.push(line);
line = '';
line = "";
}
if (!line) {
@ -147,7 +146,7 @@ export function comment(content: string, prefix = lineCommentPrefix, factor = 0,
return result.join(EOL);
}
return '';
return "";
}
export function docComment(content: string, prefix = docCommentPrefix, factor = 0, maxLength = 120) {
@ -155,59 +154,107 @@ export function docComment(content: string, prefix = docCommentPrefix, factor =
}
export function dotCombine(prefix: string, content: string) {
return trimDots([trimDots(prefix), trimDots(content)].join('.'));
return trimDots([trimDots(prefix), trimDots(content)].join("."));
}
export function map<T, U>(dictionary: Dictionary<T>, callbackfn: (key: string, value: T) => U, thisArg?: any): Array<U> {
export function map<T, U>(
dictionary: Record<string, T>,
callbackfn: (key: string, value: T) => U,
thisArg?: any,
): Array<U> {
return Object.getOwnPropertyNames(dictionary).map((key) => callbackfn(key, dictionary[key]));
}
export function ToMap<T>(dictionary: Dictionary<T>): Map<string, T> {
export function ToMap<T>(dictionary: Record<string, T>): Map<string, T> {
const result = new Map<string, T>();
Object.getOwnPropertyNames(dictionary).map(key => result.set(key, dictionary[key]));
Object.getOwnPropertyNames(dictionary).map((key) => result.set(key, dictionary[key]));
return result;
}
export function __selectMany<T>(multiArray: Array<Array<T>>): Array<T> {
const result = new Array<T>();
multiArray.map(v => result.push(...v));
multiArray.map((v) => result.push(...v));
return result;
}
export function pall<T, U>(array: Array<T>, callbackfn: (value: T, index: number, array: Array<T>) => Promise<U>, thisArg?: any): Promise<Array<U>> {
export function pall<T, U>(
array: Array<T>,
callbackfn: (value: T, index: number, array: Array<T>) => Promise<U>,
thisArg?: any,
): Promise<Array<U>> {
return Promise.all(array.map(callbackfn));
}
export function deconstruct(identifier: string | Array<string>): Array<string> {
if (Array.isArray(identifier)) {
return [...values(identifier).selectMany(deconstruct)];
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());
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());
}
export function isCapitalized(identifier: string): boolean {
return /^[A-Z]/.test(identifier);
}
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 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];
export function* convert(num: number): Iterable<string> {
if (!num) {
yield 'zero';
yield "zero";
return;
}
if (num > 1e+30) {
yield 'lots';
if (num > 1e30) {
yield "lots";
return;
}
@ -218,13 +265,12 @@ export function* convert(num: number): Iterable<string> {
yield* convert(Math.floor(num / c));
yield magnitude[i];
num = num % c;
}
}
}
if (num > 99) {
yield ones[Math.floor(num / 100)];
yield 'hundred';
yield "hundred";
num %= 100;
}
if (num > 19) {
@ -243,10 +289,14 @@ export function fixLeadingNumber(identifier: Array<string>): Array<string> {
return identifier;
}
export function removeProhibitedPrefix(identifier: string, prohibitedPrefix: string, skipIdentifiers?: Array<string>): string {
export function removeProhibitedPrefix(
identifier: string,
prohibitedPrefix: string,
skipIdentifiers?: Array<string>,
): string {
if (identifier.toLowerCase().startsWith(prohibitedPrefix.toLowerCase())) {
const regex = new RegExp(`(^${prohibitedPrefix})(.*)`, 'i');
let newIdentifier = identifier.replace(regex, '$2');
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.
@ -254,21 +304,24 @@ export function removeProhibitedPrefix(identifier: string, prohibitedPrefix: str
}
newIdentifier = isCapitalized(identifier) ? newIdentifier.capitalize() : newIdentifier.uncapitalize();
return (skipIdentifiers !== undefined) ? skipIdentifiers.includes(newIdentifier) ? identifier : newIdentifier : newIdentifier;
return skipIdentifiers !== undefined
? skipIdentifiers.includes(newIdentifier)
? identifier
: newIdentifier
: newIdentifier;
}
return identifier;
}
export function isEqual(s1: string, s2: string): boolean {
// 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' });
return s2 !== undefined && !!s1 && !s1.localeCompare(s2, undefined, { sensitivity: "base" });
}
export function removeSequentialDuplicates(identifier: Iterable<string>) {
const ids = [...identifier].filter(each => !!each);
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);
@ -282,26 +335,28 @@ export function removeSequentialDuplicates(identifier: Iterable<string>) {
}
export function pascalCase(identifier: string | Array<string>, removeDuplicates = true): string {
return identifier === undefined ? '' : typeof identifier === 'string' ?
pascalCase(fixLeadingNumber(deconstruct(identifier)), removeDuplicates) :
(removeDuplicates ? [...removeSequentialDuplicates(identifier)] : identifier).map(each => each.capitalize()).join('');
return identifier === undefined
? ""
: typeof identifier === "string"
? pascalCase(fixLeadingNumber(deconstruct(identifier)), removeDuplicates)
: (removeDuplicates ? [...removeSequentialDuplicates(identifier)] : identifier)
.map((each) => each.capitalize())
.join("");
}
export function camelCase(identifier: string | Array<string>): string {
if (typeof (identifier) === 'string') {
if (typeof identifier === "string") {
return camelCase(fixLeadingNumber(deconstruct(identifier)));
}
switch (identifier.length) {
case 0:
return '';
return "";
case 1:
return identifier[0].uncapitalize();
}
return `${identifier[0].uncapitalize()}${pascalCase(identifier.slice(1))}`;
}
export function getPascalIdentifier(name: string): string {
return pascalCase(fixLeadingNumber(deconstruct(name)));
}
@ -311,33 +366,35 @@ export function escapeString(text: string | undefined): string {
const q = JSON.stringify(text);
return q.substr(1, q.length - 2);
}
return '';
return "";
}
/** emits c# to get the name of a property - uses nameof when it can, and uses a literal when it's an array value. */
export function nameof(text: string): string {
if (text.indexOf('[') > -1) {
return `$"${text.replace(/\[(.*)\]/, '[{$1}]')}"`;
if (text.indexOf("[") > -1) {
return `$"${text.replace(/\[(.*)\]/, "[{$1}]")}"`;
}
return `nameof(${text})`;
}
export function* getRegions(source: string, prefix: string = "#", postfix: string = "") {
source = source.replace(/\r?\n|\r/g, "«");
export function* getRegions(source: string, prefix: string = '#', postfix: string = '') {
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');
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)) {
while ((match = rx.exec(source))) {
if (match[1]) {
// we have text before this region.
yield {
name: '',
start: '',
content: match[1].replace(/«/g, '\n'),
end: ''
name: "",
start: "",
content: match[1].replace(/«/g, "\n"),
end: "",
};
}
@ -345,8 +402,8 @@ export function* getRegions(source: string, prefix: string = '#', postfix: strin
yield {
name: match[3],
start: match[2],
content: match[4].replace(/«/g, '\n'),
end: match[5]
content: match[4].replace(/«/g, "\n"),
end: match[5],
};
finalPosition = rx.lastIndex;
}
@ -354,17 +411,27 @@ export function* getRegions(source: string, prefix: string = '#', postfix: strin
if (finalPosition < source.length) {
// we have text after the last region.
yield {
name: '',
start: '',
content: source.substring(finalPosition).replace(/«/g, '\n'),
end: '',
name: "",
start: "",
content: source.substring(finalPosition).replace(/«/g, "\n"),
end: "",
};
}
}
export function setRegion(source: string, region: string, content: TextPossibilities, prepend = true, prefix: string = '#', postfix: string = '') {
export function setRegion(
source: string,
region: string,
content: TextPossibilities,
prepend = true,
prefix: string = "#",
postfix: string = "",
) {
const result = new Array<string>();
const ct = new Text(content).text.replace(/\r?\n|\r/g, '«').replace(/^«*/, '').replace(/«*$/, '');
const ct = new 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) {
@ -372,12 +439,11 @@ export function setRegion(source: string, region: string, content: TextPossibili
// (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, '«');
result.push(each.start, ct, each.end, "«");
found = true;
}
}
else {
result.push(each.start, each.content, each.end, '«');
} else {
result.push(each.start, each.content, each.end, "«");
}
}
if (!found) {
@ -387,21 +453,40 @@ export function setRegion(source: string, region: string, content: TextPossibili
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');
return result
.join("«")
.replace(/\r?\n|\r/g, "«")
.replace(/^«*/, "")
.replace(/«*$/, "")
.replace(/«««*/g, "««")
.replace(/«/g, "\n");
}
// Note: Where is this used?
export function _setRegion(source: string, region: string, content: TextPossibilities, prepend = true, prefix: string = '#', postfix: string = '') {
const ct = new Text(content).text.replace(/\r?\n|\r/g, '«').replace(/^«*/, '').replace(/«*$/, '');
export function _setRegion(
source: string,
region: string,
content: TextPossibilities,
prepend = true,
prefix: string = "#",
postfix: string = "",
) {
const ct = new Text(content).text
.replace(/\r?\n|\r/g, "«")
.replace(/^«*/, "")
.replace(/«*$/, "");
source = source.replace(/\r?\n|\r/g, '«');
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');
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, `«$${ct}$2`);
} else {
source = source.replace(rx, '');
source = source.replace(rx, "");
}
} else {
if (ct.length > 0) {
@ -409,7 +494,7 @@ export function _setRegion(source: string, region: string, content: TextPossibil
source = prepend ? text + source : source + text;
}
}
source = source.replace(/«««*/g, '««').replace(/«/g, '\n');
source = source.replace(/«««*/g, "««").replace(/«/g, "\n");
return source;
}
@ -423,7 +508,7 @@ export function selectName(nameOptions: Array<string>, reservedNames: Set<string
}
}
// hmm, none of the names were suitable.
// 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 {
@ -439,4 +524,3 @@ export function selectName(nameOptions: Array<string>, reservedNames: Set<string
// after an unreasonalbe search, return something invalid
return `InvalidPropertyName${nameOptions[0]}`;
}

Просмотреть файл

@ -3,7 +3,6 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { values, Dictionary, items } from "@azure-tools/linq";
import * as aio from "@azure-tools/async-io";
import { join } from "path";
@ -17,7 +16,7 @@ function getAllPropertyNames(obj: any) {
}
});
/* eslint-disable */
} while (obj = Object.getPrototypeOf(obj));
} while ((obj = Object.getPrototypeOf(obj)));
return props;
}
@ -26,27 +25,40 @@ export function fail(text: string): never {
throw new Error(text);
}
export function applyOverrides(content: string, overrides: Dictionary<string>): string {
for (const { key: from, value: to } of items(overrides)) {
content = content.replace(new RegExp(from, 'g'), to);
export function applyOverrides(content: string, overrides: Record<string, string>): string {
for (const [from, to] of Object.entries(overrides)) {
content = content.replace(new RegExp(from, "g"), to);
}
return content;
}
export async function copyResources(sourceFolder: string, fileWriter: (filename: string, content: string) => Promise<void>, overrides: Dictionary<string> = {}, contentManipulator: (content: string) => Promise<string> = async (i) => { return i; }) {
export async function copyResources(
sourceFolder: string,
fileWriter: (filename: string, content: string) => Promise<void>,
overrides: Record<string, string> = {},
contentManipulator: (content: string) => Promise<string> = async (i) => {
return i;
},
) {
const done = new Array<Promise<void>>();
try {
const files = await aio.readdir(sourceFolder);
for (const file of values(files)) {
for (const file of files) {
const fullPath = join(sourceFolder, file);
if (await aio.isDirectory(fullPath)) {
done.push(copyResources(fullPath, async (f, c) => fileWriter(`${file}/${f}`, c), overrides, contentManipulator));
done.push(
copyResources(fullPath, async (f, c) => fileWriter(`${file}/${f}`, c), overrides, contentManipulator),
);
continue;
}
if (await aio.isFile(fullPath)) {
done.push(aio.readFile(fullPath).then(contentManipulator).then(async (content) => fileWriter(file, applyOverrides(content, overrides))
));
done.push(
aio
.readFile(fullPath)
.then(contentManipulator)
.then(async (content) => fileWriter(file, applyOverrides(content, overrides))),
);
}
}
} catch {
@ -55,12 +67,15 @@ export async function copyResources(sourceFolder: string, fileWriter: (filename:
await Promise.all(done);
}
export async function copyBinaryResources(sourceFolder: string, fileWriter: (filename: string, content: string) => Promise<void>) {
export async function copyBinaryResources(
sourceFolder: string,
fileWriter: (filename: string, content: string) => Promise<void>,
) {
const done = new Array<Promise<void>>();
try {
const files = await aio.readdir(sourceFolder);
for (const file of values(files)) {
for (const file of files) {
const fullPath = join(sourceFolder, file);
if (await aio.isDirectory(fullPath)) {
done.push(copyBinaryResources(fullPath, async (f, c) => fileWriter(`${file}/${f}`, c)));
@ -81,5 +96,18 @@ function quartet() {
}
export function guid() {
return (quartet() + quartet() + '-' + quartet() + '-4' + quartet().substr(0, 3) + '-' + quartet() + '-' + quartet() + quartet() + quartet()).toLowerCase();
return (
quartet() +
quartet() +
"-" +
quartet() +
"-4" +
quartet().substr(0, 3) +
"-" +
quartet() +
"-" +
quartet() +
quartet() +
quartet()
).toLowerCase();
}

Просмотреть файл

@ -4,7 +4,6 @@ import { Info } from "./info";
import { OperationGroup } from "./operation";
import { DeepPartial, enableSourceTracking } from "@azure-tools/codegen";
import { Parameter } from "./parameter";
import { ValueOrFactory, realize, sort } from "@azure-tools/linq";
import { Security } from "./security";
/** the model that contains all the information required to generate a service api */
@ -76,10 +75,21 @@ export class CodeModel extends Metadata implements CodeModel {
}
return p;
} finally {
this.globalParameters = sort.numericly.ascendingInvalidLast(
this.globals,
(each) => each.extensions?.["x-ms-priority"],
);
this.globalParameters = sortAscendingInvalidLast(this.globals, (each) => each.extensions?.["x-ms-priority"]);
}
}
}
export type ValueOrFactory<T> = T | (() => T);
function realize<T>(f: ValueOrFactory<T>): T {
return f instanceof Function ? f() : f;
}
function sortAscendingInvalidLast<T>(input: Array<T>, accessor: (each: T) => number | undefined): Array<T> {
return input.sort((a, b) => {
const pA = accessor(a) ?? Number.MAX_VALUE;
const pB = accessor(b) ?? Number.MAX_VALUE;
return pA - pB;
});
}

Просмотреть файл

@ -1,5 +1,3 @@
import { Dictionary } from "@azure-tools/linq";
/** A dictionary of open-ended 'x-*' extensions propogated from the original source document.
*
* @note - any unrecognized non-schema extensions found in the source model will be copied here verbatim
@ -10,5 +8,5 @@ export interface Extensions {
*
* @notes - undefined means that there are no extensions present on the node.
*/
extensions?: Dictionary<any>;
extensions?: Record<string, any>;
}

Просмотреть файл

@ -1,4 +1,3 @@
import { Dictionary } from "@azure-tools/linq";
import { Extensions } from "./extensions";
import { Languages } from "./languages";
import { Protocols } from "./protocols";
@ -30,7 +29,7 @@ export class Metadata extends Initializer implements Metadata {
}
/** the bare-minimum fields for per-language metadata on a given aspect */
export interface Language extends Dictionary<any> {
export interface Language extends Record<string, any> {
/** name used in actual implementation */
name: string;
@ -44,7 +43,7 @@ export interface CSharpLanguage {}
export class CSharpLanguage implements CSharpLanguage {}
/** the bare-minimum fields for per-protocol metadata on a given aspect */
export interface Protocol extends Dictionary<any> {}
export interface Protocol extends Record<string, any> {}
export class Protocol extends Initializer implements Protocol {
constructor(objectInitializer?: DeepPartial<Protocol>) {

Просмотреть файл

@ -3,7 +3,6 @@ import { Response } from "./response";
import { Metadata } from "./metadata";
import { Aspect } from "./aspect";
import { ApiVersion } from "./api-version";
import { Dictionary, values } from "@azure-tools/linq";
import { DeepPartial } from "@azure-tools/codegen";
import { SchemaType } from "./schema-type";
@ -25,7 +24,7 @@ export interface Operation extends Aspect {
exceptions?: Array<Response>;
/** the apiVersion to use for a given profile name */
profile?: Dictionary<ApiVersion>;
profile?: Record<string, ApiVersion>;
}
export interface Request extends Metadata {
@ -50,15 +49,13 @@ export class Request extends Metadata implements Request {
updateSignatureParameters() {
if (this.parameters) {
this.signatureParameters = values(this.parameters)
.where(
(each) =>
each.schema.type !== SchemaType.Constant &&
each.implementation !== ImplementationLocation.Client &&
!each.groupedBy &&
!each.flattened,
)
.toArray();
this.signatureParameters = (this.parameters ?? []).filter(
(each) =>
each.schema.type !== SchemaType.Constant &&
each.implementation !== ImplementationLocation.Client &&
!each.groupedBy &&
!each.flattened,
);
}
}
}
@ -82,15 +79,13 @@ export class Operation extends Aspect implements Operation {
updateSignatureParameters() {
if (this.parameters) {
this.signatureParameters = values(this.parameters)
.where(
(each) =>
each.schema.type !== SchemaType.Constant &&
each.implementation !== ImplementationLocation.Client &&
!each.groupedBy &&
!each.flattened,
)
.toArray();
this.signatureParameters = (this.parameters ?? []).filter(
(each) =>
each.schema.type !== SchemaType.Constant &&
each.implementation !== ImplementationLocation.Client &&
!each.groupedBy &&
!each.flattened,
);
}
}

Просмотреть файл

@ -1,12 +1,11 @@
import { Aspect } from "./aspect";
import { SerializationFormats } from "./formats";
import { AllSchemaTypes, SchemaType } from "./schema-type";
import { AllSchemaTypes } from "./schema-type";
import { DeepPartial } from "@azure-tools/codegen";
import { Dictionary } from "@azure-tools/linq";
import { Extensions } from "./extensions";
import { Languages } from "./languages";
export interface SerializationFormat extends Extensions, Dictionary<any> {}
export interface SerializationFormat extends Extensions, Record<string, any> {}
/** The Schema Object allows the definition of input and output data types. */
export interface Schema extends Aspect {

Просмотреть файл

@ -2,7 +2,6 @@ import { SchemaType } from "../schema-type";
import { Schema, ComplexSchema } from "../schema";
import { DeepPartial } from "@azure-tools/codegen";
import { Property } from "../property";
import { Dictionary, values } from "@azure-tools/linq";
import { Parameter } from "../parameter";
import { SchemaUsage } from "./usage";
@ -19,8 +18,8 @@ export class Relations {
export interface Discriminator {
property: Property;
immediate: Dictionary<ComplexSchema>;
all: Dictionary<ComplexSchema>;
immediate: Record<string, ComplexSchema>;
all: Record<string, ComplexSchema>;
}
export class Discriminator implements Discriminator {
@ -101,15 +100,15 @@ export function isObjectSchema(schema: Schema): schema is ObjectSchema {
// gs01: todo/Note -- these two need to be commented out to run the schema generation script
export function* getAllProperties(schema: ObjectSchema): Iterable<Property> {
for (const parent of values(schema.parents?.immediate)) {
for (const parent of schema.parents?.immediate ?? []) {
if (isObjectSchema(parent)) {
yield* getAllProperties(parent);
}
}
yield* values(schema.properties);
yield* schema.properties ?? [];
}
export function* getAllParentProperties(schema: ObjectSchema): Iterable<Property> {
for (const parent of values(schema.parents?.immediate)) {
for (const parent of schema.parents?.immediate ?? []) {
if (isObjectSchema(parent)) {
yield* getAllProperties(parent);
}

Просмотреть файл

@ -3,7 +3,6 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Dictionary } from "@azure-tools/linq";
import { Initializer, DeepPartial } from "@azure-tools/codegen";
import { Extensions } from "../common/extensions";
import { uri } from "../common/uri";
@ -24,7 +23,7 @@ export interface AuthorizationCodeOAuthFlow extends Extensions {
authorizationUrl: uri; // uriref
tokenUrl: uri; // uriref
refreshUrl?: uri; // uriref
scopes: Dictionary<string>;
scopes: Record<string, string>;
}
export interface BearerHTTPSecurityScheme extends Extensions {
@ -37,13 +36,13 @@ export interface BearerHTTPSecurityScheme extends Extensions {
export interface ClientCredentialsFlow extends Extensions {
tokenUrl: uri; // uriref
refreshUrl?: uri; // uriref
scopes: Dictionary<string>;
scopes: Record<string, string>;
}
export interface ImplicitOAuthFlow extends Extensions {
authorizationUrl: uri; // uriref
refreshUrl?: uri; // uriref
scopes: Dictionary<string>;
scopes: Record<string, string>;
}
export interface NonBearerHTTPSecurityScheme extends Extensions {
@ -99,7 +98,7 @@ export class BearerHTTPSecurityScheme extends Initializer implements BearerHTTPS
}
export class ImplicitOAuthFlow extends Initializer implements ImplicitOAuthFlow {
scopes = new Dictionary<string>();
scopes: Record<string, string> = {};
constructor(public authorizationUrl: string, initializer?: DeepPartial<ImplicitOAuthFlow>) {
super();
@ -147,11 +146,11 @@ export class OpenIdConnectSecurityScheme extends Initializer implements OpenIdCo
export interface PasswordOAuthFlow extends Extensions {
tokenUrl: uri; // uriref
refreshUrl?: uri; // uriref
scopes: Dictionary<string>;
scopes: Record<string, string>;
}
export class PasswordOAuthFlow extends Initializer implements PasswordOAuthFlow {
scopes = new Dictionary<string>();
scopes: Record<string, string> = {};
constructor(public tokenUrl: string, initializer?: DeepPartial<PasswordOAuthFlow>) {
super();
@ -160,7 +159,7 @@ export class PasswordOAuthFlow extends Initializer implements PasswordOAuthFlow
}
export class AuthorizationCodeOAuthFlow extends Initializer implements AuthorizationCodeOAuthFlow {
scopes = new Dictionary<string>();
scopes: Record<string, string> = {};
constructor(
public authorizationUrl: string,
tokenUrl: string,
@ -171,7 +170,7 @@ export class AuthorizationCodeOAuthFlow extends Initializer implements Authoriza
}
}
export class ClientCredentialsFlow extends Initializer implements ClientCredentialsFlow {
scopes = new Dictionary<string>();
scopes: Record<string, string> = {};
constructor(public tokenUrl: string, initializer?: DeepPartial<ClientCredentialsFlow>) {
super();
this.apply(initializer);
@ -182,4 +181,4 @@ export class ClientCredentialsFlow extends Initializer implements ClientCredenti
* @description common ways of serializing simple parameters
* @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#style-values
*/
export interface SecurityRequirement extends Dictionary<string> {}
export interface SecurityRequirement extends Record<string, string> {}