зеркало из https://github.com/Azure/autorest.git
Remove linq from m4 and codegen (#4241)
* Remove from codegen * Remove from m4 * Wip * Tweaks * Wip * Wip * fix * fix
This commit is contained in:
Родитель
bc4b87e4b3
Коммит
a73d85c7ab
|
@ -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, `«$1«${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> {}
|
||||
|
|
Загрузка…
Ссылка в новой задаче