Tweak OpenAPI include/exclude `x-dash` utils types (#4218)

This commit is contained in:
Timothee Guerin 2021-07-16 13:55:41 -07:00 коммит произвёл GitHub
Родитель fbb7d48054
Коммит 59be4e234e
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
15 изменённых файлов: 144 добавлений и 130 удалений

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

@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "@autorest/core",
"comment": "",
"type": "none"
}
],
"packageName": "@autorest/core",
"email": "tiguerin@microsoft.com"
}

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

@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "@autorest/modelerfour",
"comment": "",
"type": "none"
}
],
"packageName": "@autorest/modelerfour",
"email": "tiguerin@microsoft.com"
}

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

@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "@azure-tools/codegen",
"comment": "**Remove** include/exclude x-dash properties utils. Use @azure-tools/openapi instead for this functionality",
"type": "minor"
}
],
"packageName": "@azure-tools/codegen",
"email": "tiguerin@microsoft.com"
}

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

@ -0,0 +1,11 @@
{
"changes": [
{
"packageName": "@azure-tools/openapi",
"comment": "**Update** include/exclude x-dash properties utils types",
"type": "minor"
}
],
"packageName": "@azure-tools/openapi",
"email": "tiguerin@microsoft.com"
}

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

@ -1,6 +1,5 @@
import oai3 from "@azure-tools/openapi";
import { SemanticErrorCodes } from "../types";
import { validateDiscriminator } from "./discriminator-validator";
import { validateRefsSiblings } from "./refs-siblings-validator";
const baseModel: oai3.Model = {

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

@ -1,5 +1,5 @@
import { walk } from "@azure-tools/json";
import oai3, { excludeXDash, omitXDashProperties } from "@azure-tools/openapi";
import oai3 from "@azure-tools/openapi";
import { SemanticError, SemanticErrorCodes } from "../types";
/**

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

@ -3,7 +3,7 @@ import assert from "assert";
import { AutoRest } from "../src/lib/autorest-core";
import { RealFileSystem } from "@azure-tools/datastore";
import { Channel, Message } from "../src/lib/message";
import { CreateFolderUri, ResolveUri } from "@azure-tools/uri";
import { createFolderUri, resolveUri } from "@azure-tools/uri";
import { AppRoot } from "../src/lib/constants";
import { AutorestConfiguration } from "@autorest/configuration";
@ -70,90 +70,11 @@ describe("EndToEnd", () => {
it("other configuration scenario", async () => {
const autoRest = new AutoRest(
new RealFileSystem(),
ResolveUri(CreateFolderUri(AppRoot), "test/resources/literate-example/readme-complicated.md"),
resolveUri(createFolderUri(AppRoot), "test/resources/literate-example/readme-complicated.md"),
);
// PumpMessagesToConsole(autoRest);
const context = await autoRest.view;
assert.strictEqual(context.config["shouldwork" as keyof AutorestConfiguration], true);
});
// todo: skipping because testing is broken?
it.skip("complicated configuration scenario", async () => {
const autoRest = new AutoRest(
new RealFileSystem(),
ResolveUri(CreateFolderUri(AppRoot), "test/resources/literate-example/readme-complicated.md"),
);
// PumpMessagesToConsole(autoRest);
autoRest.AddConfiguration({
"cmd-line-true": true,
"cmd-line-false": false,
"cmd-line-complex": {
true: true,
false: false,
},
});
const config = await autoRest.view;
assert.strictEqual(config.config.inputFileUris.length, 1);
const messages: Array<Message> = [];
autoRest.Message.Subscribe((_, m) => {
if (m.Channel === Channel.Warning) {
messages.push(m);
}
});
assert.equal(await autoRest.Process().finish, true);
assert.notEqual(messages.length, 0);
});
// testing end-to-end for non-arm type validation rules. Since all validation rules are currently defaulted to
// ARM, non-ARM documents should show 0 validation messages
// TODO: fix this test when validation rules are properly categorized
it.skip("non-arm type spec testing", async () => {
const autoRest = new AutoRest(
new RealFileSystem(),
ResolveUri(CreateFolderUri(AppRoot), "test/resources/validation-options/readme.md"),
);
autoRest.AddConfiguration({
"openapi-type": "default",
"azure-validator": true,
});
const config = await autoRest.view;
const messages: Array<Message> = [];
autoRest.Message.Subscribe((_, m) => {
messages.push(m);
});
assert.equal(await autoRest.Process().finish, true);
assert.notEqual(messages.length, 0);
// flag any fatal errors
assert.equal(messages.filter((m) => m.Channel === Channel.Fatal).length, 0);
});
// todo: skipping because testing is broken?
it.skip("arm type spec testing", async () => {
const autoRest = new AutoRest(
new RealFileSystem(),
ResolveUri(CreateFolderUri(AppRoot), "test/resources/validation-options/readme.md"),
);
autoRest.AddConfiguration({
"openapi-type": "arm",
"azure-validator": true,
});
const config = await autoRest.view;
const messages: Array<Message> = [];
autoRest.Message.Subscribe((_, m) => {
messages.push(m);
});
// PumpMessagesToConsole(autoRest);
assert.equal(await autoRest.Process().finish, true);
// flag any fatal errors
assert.equal(messages.filter((m) => m.Channel === Channel.Fatal).length, 0);
assert.notEqual(messages.length, 0);
});
});

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

@ -1,6 +1,6 @@
import { Session } from "@autorest/extension-base";
import * as OpenAPI from "@azure-tools/openapi";
import { values, length, items, ToDictionary, Dictionary } from "@azure-tools/linq";
import { values, length, ToDictionary, Dictionary } from "@azure-tools/linq";
import {
ChoiceSchema,
XmlSerlializationFormat,
@ -10,7 +10,7 @@ import {
ChoiceValue,
SetType,
} from "@autorest/codemodel";
import { StringFormat, JsonType, ParameterLocation } from "@azure-tools/openapi";
import { StringFormat, JsonType, ParameterLocation, includeXDashKeys } from "@azure-tools/openapi";
import { getPascalIdentifier } from "@azure-tools/codegen";
export interface XMSEnum {
@ -420,7 +420,7 @@ export class Interpretations {
}
static getExtensionProperties(dictionary: Dictionary<any>): Dictionary<any> | undefined {
const result = ToDictionary(OpenAPI.includeXDash(dictionary), (each) => dictionary[each]);
const result = ToDictionary(includeXDashKeys(dictionary), (each) => dictionary[each]);
for (const each of removeKnownParameters) {
delete result[each];
}

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

@ -8,10 +8,10 @@ import {
StringFormat,
NumberFormat,
MediaType,
filterOutXDash,
omitXDashProperties,
} from "@azure-tools/openapi";
import * as OpenAPI from "@azure-tools/openapi";
import { items, values, Dictionary, length, keys } from "@azure-tools/linq";
import { items, values, Dictionary, length } from "@azure-tools/linq";
import {
HttpMethod,
HttpModel,
@ -167,7 +167,7 @@ export class ModelerFour {
contact: i.contact,
license: i.license,
termsOfService: i.termsOfService,
externalDocs: filterOutXDash<ExternalDocumentation>(this.input.externalDocs as any),
externalDocs: omitXDashProperties<ExternalDocumentation>(this.input.externalDocs as any),
extensions: Interpretations.getExtensionProperties(i),
},
extensions: Interpretations.getExtensionProperties(this.input),

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

@ -5,8 +5,8 @@
"directories": {
"doc": "docs"
},
"main": "dist/exports.js",
"typings": "dist/exports.d.ts",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"engines": {
"node": ">=12.0.0"
},

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

@ -1,12 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Dictionary } from "@azure-tools/linq";
export function includeXDash<T>(dictionary: Dictionary<T>) {
return Object.keys(dictionary).filter((v, i, a) => v.startsWith("x-"));
}
export function excludeXDash<T>(dictionary: Dictionary<T>) {
return Object.keys(dictionary).filter((v, i, a) => !v.startsWith("x-"));
}

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

@ -2,7 +2,6 @@ export * from "./exec";
export * from "./file-generator";
export * from "./initializer";
export * from "./intersect";
export * from "./dictionary-filter";
export * from "./pluralization";
export * from "./text-manipulation";
export * from "./utility";

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

@ -0,0 +1,65 @@
import { omitXDashKeys, includeXDashKeys, includeXDashProperties, omitXDashProperties } from "./utils";
describe("OpenAPI utils", () => {
it("includeXDashKeys returns x- properties keys", () => {
// Type validation
const result: ("x-foo" | "x-other")[] = includeXDashKeys({
"foo": 1,
"bar": 2,
"x-foo": 3,
"x-other": 4,
});
expect(result).toEqual(["x-foo", "x-other"]);
});
it("omitXDashKeys returns non x- properties keys", () => {
// Type validation
const result: ("foo" | "bar")[] = omitXDashKeys({
"foo": 1,
"bar": 2,
"x-foo": 3,
"x-other": 4,
});
expect(result).toEqual(["foo", "bar"]);
});
it("includeXDashProperties returns x- properties", () => {
const result = includeXDashProperties({
"foo": 1,
"bar": 2,
"x-foo": 3,
"x-other": 4,
});
// Type validation
expect<{ "x-foo": number; "x-other": number }>(result).toEqual({
"x-foo": 3,
"x-other": 4,
});
});
it("includeXDashProperties returns undefined if undefined is passed", () => {
const result = includeXDashProperties(undefined);
// Type validation
expect<undefined>(result).toEqual(undefined);
});
it("omitXDashProperties returns x- properties", () => {
// Type validation
const result = omitXDashProperties({
"foo": 1,
"bar": 2,
"x-foo": 3,
"x-other": 4,
});
expect<{ foo: number; bar: number }>(result).toEqual({
foo: 1,
bar: 2,
});
});
it("omitXDashProperties returns undefined if undefined is passed", () => {
const result = omitXDashProperties(undefined);
// Type validation
expect<undefined>(result).toEqual(undefined);
});
});

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

@ -4,54 +4,55 @@ import { Dereferenced, ExtensionKey, PathReference, Refable } from "./common";
* Only return properties starting with x-
* @param dictionary
*/
export const includeXDash = (dictionary: Record<string, unknown>): ExtensionKey[] => {
return Object.keys(dictionary).filter((v, i, a) => v.startsWith("x-")) as any;
};
export function includeXDashKeys<T extends Record<string | ExtensionKey, any>>(
dictionary: T,
): Extract<keyof T, ExtensionKey>[] {
return Object.keys(dictionary).filter((v) => v.startsWith("x-")) as any;
}
/**
* Only return properties NOT starting with x-
* @param dictionary
*/
export const excludeXDash = <T extends {}>(dictionary: T): string[] => {
return Object.keys(dictionary).filter((v, i, a) => !v.startsWith("x-"));
};
export function omitXDashKeys<T extends {}>(dictionary: T): Exclude<keyof T, ExtensionKey>[] {
return Object.keys(dictionary).filter((v) => !v.startsWith("x-")) as any;
}
export function includeXDashProperties<T extends { [key: string]: unknown }>(obj: T | undefined): T | undefined {
if (!obj) {
return undefined;
export function includeXDashProperties<T extends Record<string | ExtensionKey, any> | undefined>(
obj: T,
): T extends undefined ? undefined : Pick<T, Extract<keyof T, ExtensionKey>> {
if (obj === undefined) {
return undefined as any;
}
const result: any = {};
for (const key of includeXDash(obj)) {
for (const key of includeXDashKeys(obj)) {
result[key] = obj[key];
}
return result;
}
export function omitXDashProperties<T extends {}>(obj: T | undefined): T | undefined {
if (!obj) {
return undefined;
export function omitXDashProperties<T extends {} | undefined>(
obj: T,
): T extends undefined ? undefined : Pick<T, Exclude<keyof T, ExtensionKey>> {
if (obj === undefined) {
return undefined as any;
}
const result: any = {};
for (const key of excludeXDash(obj)) {
for (const key of omitXDashKeys(obj)) {
result[key] = (obj as any)[key];
}
return result;
}
/**
* @deprecated use omitXDashProperties
*/
export const filterOutXDash = omitXDashProperties;
/**
* Identifies if a given refable is a reference or an instance
* @param item Check if item is a reference.
*/
export const isReference = <T>(item: Refable<T>): item is PathReference => {
export function isReference<T>(item: Refable<T>): item is PathReference {
return item && (<PathReference>item).$ref ? true : false;
};
}
/**
* Gets an object instance for the item, regardless if it's a reference or not.
@ -59,7 +60,7 @@ export const isReference = <T>(item: Refable<T>): item is PathReference => {
* @param item Reference item.
* @param stack Stack for circular dependencies.
*/
export const dereference = <T>(document: any, item: Refable<T>, stack: string[] = []): Dereferenced<T> => {
export function dereference<T>(document: any, item: Refable<T>, stack: string[] = []): Dereferenced<T> {
let name: string | undefined;
if (isReference(item)) {
@ -86,4 +87,4 @@ export const dereference = <T>(document: any, item: Refable<T>, stack: string[]
return { instance: node, name: name || "", fromRef: true };
}
return { instance: item, name: "", fromRef: false };
};
}

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

@ -1,3 +0,0 @@
it("works", () => {
expect("hello").not.toEqual("world");
});