From eca2fb41960b50c3e481ed889cebe701225d0733 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Tue, 28 Nov 2023 14:01:51 -0800 Subject: [PATCH 01/10] Absolute path --- .../compiler/src/core/schema-validator.ts | 51 +++++++++++++++---- packages/openapi3/src/lib.ts | 1 + 2 files changed, 41 insertions(+), 11 deletions(-) diff --git a/packages/compiler/src/core/schema-validator.ts b/packages/compiler/src/core/schema-validator.ts index 52e9ba9b8a..d7cf7266bc 100644 --- a/packages/compiler/src/core/schema-validator.ts +++ b/packages/compiler/src/core/schema-validator.ts @@ -1,7 +1,9 @@ -import Ajv, { DefinedError, Options } from "ajv"; +import Ajv, { ErrorObject, Options } from "ajv"; import { getLocationInYamlScript } from "../yaml/diagnostics.js"; import { YamlScript } from "../yaml/types.js"; import { compilerAssert } from "./diagnostics.js"; +import { createDiagnostic } from "./messages.js"; +import { isPathAbsolute } from "./path-utils.js"; import { Diagnostic, JSONSchemaType, JSONSchemaValidator, NoTarget, SourceFile } from "./types.js"; export interface JSONSchemaValidatorOptions { @@ -13,12 +15,18 @@ export function createJSONSchemaValidator( schema: JSONSchemaType, options: JSONSchemaValidatorOptions = { strict: true } ): JSONSchemaValidator { - const ajv = new (Ajv as any)({ + const ajv: import("ajv").default = new (Ajv as any)({ strict: options.strict, coerceTypes: options.coerceTypes, allErrors: true, } satisfies Options); + ajv.addFormat("absolute-path", { + type: "string", + validate: (path) => { + return !path.startsWith(".") && isPathAbsolute(path); + }, + }); return { validate }; function validate( @@ -34,7 +42,7 @@ export function createJSONSchemaValidator( const diagnostics = []; for (const error of validate.errors ?? []) { - const diagnostic = ajvErrorToDiagnostic(error, target); + const diagnostic = ajvErrorToDiagnostic(config, error, target); diagnostics.push(diagnostic); } @@ -45,9 +53,24 @@ export function createJSONSchemaValidator( const IGNORED_AJV_PARAMS = new Set(["type", "errors"]); function ajvErrorToDiagnostic( - error: DefinedError, + obj: unknown, + error: ErrorObject, unknown>, target: YamlScript | SourceFile | typeof NoTarget ): Diagnostic { + const tspTarget = + target === NoTarget + ? target + : "kind" in target + ? getLocationInYamlScript(target, getErrorPath(error), "key") + : { file: target, pos: 0, end: 0 }; + if (error.params.format === "absolute-path") { + return createDiagnostic({ + code: "config-path-absolute", + format: { path: getErrorValue(obj, error) as any }, + target: tspTarget, + }); + } + const messageLines = [`Schema violation: ${error.message} (${error.instancePath || "/"})`]; for (const [name, value] of Object.entries(error.params).filter( ([name]) => !IGNORED_AJV_PARAMS.has(name) @@ -61,16 +84,11 @@ function ajvErrorToDiagnostic( code: "invalid-schema", message, severity: "error", - target: - target === NoTarget - ? target - : "kind" in target - ? getLocationInYamlScript(target, getErrorPath(error), "key") - : { file: target, pos: 0, end: 0 }, + target: tspTarget, }; } -function getErrorPath(error: DefinedError): string[] { +function getErrorPath(error: ErrorObject, unknown>): string[] { const instancePath = parseJsonPointer(error.instancePath); switch (error.keyword) { case "additionalProperties": @@ -79,6 +97,17 @@ function getErrorPath(error: DefinedError): string[] { return instancePath; } } +function getErrorValue( + obj: any, + error: ErrorObject, unknown> +): unknown { + const path = getErrorPath(error); + let current = obj; + for (const segment of path) { + current = current[segment]; + } + return current; +} /** * Converts a json pointer into a array of reference tokens diff --git a/packages/openapi3/src/lib.ts b/packages/openapi3/src/lib.ts index feca60d2f3..d55c5fd3fc 100644 --- a/packages/openapi3/src/lib.ts +++ b/packages/openapi3/src/lib.ts @@ -70,6 +70,7 @@ const EmitterOptionsSchema: JSONSchemaType = { "output-file": { type: "string", nullable: true, + format: "absolute-path", description: [ "Name of the output file.", " Output file will interpolate the following values:", From d2c4c064f688ebb36f082abb82fffc542fa88ab2 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Wed, 29 Nov 2023 10:11:27 -0800 Subject: [PATCH 02/10] Show errors in the right place --- .../compiler/src/config/config-to-options.ts | 3 +- packages/compiler/src/core/options.ts | 9 ++-- packages/compiler/src/core/program.ts | 10 ++++- .../compiler/src/core/schema-validator.ts | 44 ++++++++++++++----- packages/compiler/src/core/types.ts | 11 ++++- packages/compiler/src/yaml/types.ts | 8 ++++ .../samples/src/sample-snapshot-testing.ts | 2 +- 7 files changed, 68 insertions(+), 19 deletions(-) diff --git a/packages/compiler/src/config/config-to-options.ts b/packages/compiler/src/config/config-to-options.ts index 5ad6c58c54..de61f1245e 100644 --- a/packages/compiler/src/config/config-to-options.ts +++ b/packages/compiler/src/config/config-to-options.ts @@ -93,7 +93,8 @@ export function resolveOptionsFromConfig(config: TypeSpecConfig, options: Config const resolvedOptions: CompilerOptions = omitUndefined({ outputDir: expandedConfig.outputDir, - config: config.filename, + configPath: config.filename, + config: config, additionalImports: expandedConfig["imports"], warningAsError: expandedConfig.warnAsError, trace: expandedConfig.trace, diff --git a/packages/compiler/src/core/options.ts b/packages/compiler/src/core/options.ts index 470475d82f..4fec94e7e8 100644 --- a/packages/compiler/src/core/options.ts +++ b/packages/compiler/src/core/options.ts @@ -1,4 +1,4 @@ -import { EmitterOptions } from "../config/types.js"; +import { EmitterOptions, TypeSpecConfig } from "../config/types.js"; import { LinterRuleSet, ParseOptions } from "./types.js"; export interface CompilerOptions { @@ -11,9 +11,9 @@ export interface CompilerOptions { outputDir?: string; /** - * Path to config YAML file or folder in which to search for default tspconfig.yaml file. + * Path to config YAML file used, this is also where the project root should be. */ - config?: string; + configPath?: string; /** * @deprecated use outputDir. @@ -63,4 +63,7 @@ export interface CompilerOptions { /** Ruleset to enable for linting. */ linterRuleSet?: LinterRuleSet; + + /** @internal */ + config?: TypeSpecConfig; } diff --git a/packages/compiler/src/core/program.ts b/packages/compiler/src/core/program.ts index 0a6e804267..6f159addc6 100644 --- a/packages/compiler/src/core/program.ts +++ b/packages/compiler/src/core/program.ts @@ -318,7 +318,7 @@ export async function compile( getGlobalNamespaceType, resolveTypeReference, getSourceFileLocationContext, - projectRoot: getDirectoryPath(options.config ?? resolvedMain ?? ""), + projectRoot: getDirectoryPath(options.configPath ?? resolvedMain ?? ""), }; trace("compiler.options", JSON.stringify(options, null, 2)); @@ -753,7 +753,13 @@ export async function compile( if (libDefinition?.emitter?.options) { const diagnostics = libDefinition?.emitterOptionValidator?.validate( emitterOptions, - NoTarget + options.config?.file + ? { + kind: "path-target", + path: ["options", emitterNameOrPath], + script: options.config.file, + } + : NoTarget ); if (diagnostics && diagnostics.length > 0) { program.reportDiagnostics(diagnostics); diff --git a/packages/compiler/src/core/schema-validator.ts b/packages/compiler/src/core/schema-validator.ts index d7cf7266bc..155966b89e 100644 --- a/packages/compiler/src/core/schema-validator.ts +++ b/packages/compiler/src/core/schema-validator.ts @@ -1,10 +1,17 @@ import Ajv, { ErrorObject, Options } from "ajv"; import { getLocationInYamlScript } from "../yaml/diagnostics.js"; -import { YamlScript } from "../yaml/types.js"; +import { YamlPathTarget, YamlScript } from "../yaml/types.js"; import { compilerAssert } from "./diagnostics.js"; import { createDiagnostic } from "./messages.js"; import { isPathAbsolute } from "./path-utils.js"; -import { Diagnostic, JSONSchemaType, JSONSchemaValidator, NoTarget, SourceFile } from "./types.js"; +import { + Diagnostic, + DiagnosticTarget, + JSONSchemaType, + JSONSchemaValidator, + NoTarget, + SourceFile, +} from "./types.js"; export interface JSONSchemaValidatorOptions { coerceTypes?: boolean; @@ -31,7 +38,7 @@ export function createJSONSchemaValidator( function validate( config: unknown, - target: YamlScript | SourceFile | typeof NoTarget + target: YamlScript | YamlPathTarget | SourceFile | typeof NoTarget ): Diagnostic[] { const validate = ajv.compile(schema); const valid = validate(config); @@ -55,14 +62,9 @@ const IGNORED_AJV_PARAMS = new Set(["type", "errors"]); function ajvErrorToDiagnostic( obj: unknown, error: ErrorObject, unknown>, - target: YamlScript | SourceFile | typeof NoTarget + target: YamlScript | YamlPathTarget | SourceFile | typeof NoTarget ): Diagnostic { - const tspTarget = - target === NoTarget - ? target - : "kind" in target - ? getLocationInYamlScript(target, getErrorPath(error), "key") - : { file: target, pos: 0, end: 0 }; + const tspTarget = resolveTarget(error, target); if (error.params.format === "absolute-path") { return createDiagnostic({ code: "config-path-absolute", @@ -88,6 +90,28 @@ function ajvErrorToDiagnostic( }; } +function resolveTarget( + error: ErrorObject, unknown>, + target: YamlScript | YamlPathTarget | SourceFile | typeof NoTarget +): DiagnosticTarget | typeof NoTarget { + if (target === NoTarget) { + return NoTarget; + } + if (!("kind" in target)) { + return { file: target, pos: 0, end: 0 }; + } + switch (target.kind) { + case "yaml-script": + return getLocationInYamlScript(target, getErrorPath(error), "key"); + case "path-target": + return getLocationInYamlScript( + target.script, + [...target.path, ...getErrorPath(error)], + "key" + ); + } +} + function getErrorPath(error: ErrorObject, unknown>): string[] { const instancePath = parseJsonPointer(error.instancePath); switch (error.keyword) { diff --git a/packages/compiler/src/core/types.ts b/packages/compiler/src/core/types.ts index 026fa47a51..4a92d48345 100644 --- a/packages/compiler/src/core/types.ts +++ b/packages/compiler/src/core/types.ts @@ -1,7 +1,7 @@ import type { JSONSchemaType as AjvJSONSchemaType } from "ajv"; import { TypeEmitter } from "../emitter-framework/type-emitter.js"; import { AssetEmitter } from "../emitter-framework/types.js"; -import { YamlScript } from "../yaml/types.js"; +import { YamlPathTarget, YamlScript } from "../yaml/types.js"; import { ModuleResolutionResult } from "./module-resolver.js"; import { Program } from "./program.js"; @@ -1963,6 +1963,9 @@ export type TypeOfDiagnostics> = T extends Diagnost export type JSONSchemaType = AjvJSONSchemaType; +/** + * @internal + */ export interface JSONSchemaValidator { /** * Validate the configuration against its JSON Schema. @@ -1971,7 +1974,10 @@ export interface JSONSchemaValidator { * @param target Source file target to use for diagnostics. * @returns Diagnostics produced by schema validation of the configuration. */ - validate(config: unknown, target: YamlScript | SourceFile | typeof NoTarget): Diagnostic[]; + validate( + config: unknown, + target: YamlScript | YamlPathTarget | SourceFile | typeof NoTarget + ): Diagnostic[]; } /** @deprecated Use TypeSpecLibraryDef */ @@ -2092,6 +2098,7 @@ export interface TypeSpecLibrary< > extends TypeSpecLibraryDef { /** * JSON Schema validator for emitter options + * @internal */ readonly emitterOptionValidator?: JSONSchemaValidator; diff --git a/packages/compiler/src/yaml/types.ts b/packages/compiler/src/yaml/types.ts index 6fe808c26a..a13f45f23e 100644 --- a/packages/compiler/src/yaml/types.ts +++ b/packages/compiler/src/yaml/types.ts @@ -11,4 +11,12 @@ export interface YamlScript { readonly doc: Document.Parsed; } +/** + * Represent the location of a value in a yaml script. + */ +export interface YamlPathTarget { + kind: "path-target"; + script: YamlScript; + path: string[]; +} export type YamlDiagnosticTargetType = "value" | "key"; diff --git a/packages/samples/src/sample-snapshot-testing.ts b/packages/samples/src/sample-snapshot-testing.ts index aff140112b..a7e6fdd052 100644 --- a/packages/samples/src/sample-snapshot-testing.ts +++ b/packages/samples/src/sample-snapshot-testing.ts @@ -104,7 +104,7 @@ function defineSampleSnaphotTest( const emit = options.emit; if (emit === undefined || emit.length === 0) { fail( - `No emitters configured for sample "${sample.name}". Make sure the config at: "${options.config}" is correct.` + `No emitters configured for sample "${sample.name}". Make sure the config at: "${options.configPath}" is correct.` ); } From 33af5e94d51db31ca67ce017c496283e9e0ff7c6 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Wed, 29 Nov 2023 10:24:10 -0800 Subject: [PATCH 03/10] Changelog --- .../feature-absolute-path_2023-11-29-18-24.json | 10 ++++++++++ .../feature-absolute-path_2023-11-29-18-24.json | 10 ++++++++++ 2 files changed, 20 insertions(+) create mode 100644 common/changes/@typespec/compiler/feature-absolute-path_2023-11-29-18-24.json create mode 100644 common/changes/@typespec/openapi3/feature-absolute-path_2023-11-29-18-24.json diff --git a/common/changes/@typespec/compiler/feature-absolute-path_2023-11-29-18-24.json b/common/changes/@typespec/compiler/feature-absolute-path_2023-11-29-18-24.json new file mode 100644 index 0000000000..bc12592689 --- /dev/null +++ b/common/changes/@typespec/compiler/feature-absolute-path_2023-11-29-18-24.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@typespec/compiler", + "comment": "Emitter API: Added `absolute-path` as a known format for emitter options which will validate the value passed by the user resolve to an absolute path.", + "type": "none" + } + ], + "packageName": "@typespec/compiler" +} \ No newline at end of file diff --git a/common/changes/@typespec/openapi3/feature-absolute-path_2023-11-29-18-24.json b/common/changes/@typespec/openapi3/feature-absolute-path_2023-11-29-18-24.json new file mode 100644 index 0000000000..b9099b1780 --- /dev/null +++ b/common/changes/@typespec/openapi3/feature-absolute-path_2023-11-29-18-24.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@typespec/openapi3", + "comment": "`output-file` expect an absolute path to be passed. Use `{project-root}`, `{emitter-output-dir}` or `{cwd}` instead.", + "type": "none" + } + ], + "packageName": "@typespec/openapi3" +} \ No newline at end of file From c27b7729d3176d1ff739ce830b5a1370a7066cef Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Wed, 29 Nov 2023 10:32:21 -0800 Subject: [PATCH 04/10] Docs --- docs/extending-typespec/emitters-basics.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/docs/extending-typespec/emitters-basics.md b/docs/extending-typespec/emitters-basics.md index 68c629270d..b223c6da8e 100644 --- a/docs/extending-typespec/emitters-basics.md +++ b/docs/extending-typespec/emitters-basics.md @@ -72,6 +72,24 @@ export async function $onEmit(context: EmitContext) { } ``` +### Emitter options known format: + +### `absolute-path` + +Specify that the value for this option should resolve to an absolute path. e.g. `"{project-root}/dir"`. + +:::important +It is recommended that all options that involve path use this. Using relative path can be confusing for users on as it is not clear what the relative path is relative to. And more importantly relative path if not careful are resolved relative to the `cwd` in node file system which result in spec only compiling from the the project root. +::: + +Example: + +```js +{ + "asset-dir": { type: "string", format: "absolute-path", nullable: true }, +} +``` + ### Configuration options convention - Name options `kebab-case`. So it can be inline with the rest of the cli From b7281502fc9c83b8ff142bfec7295d5d4972c9a2 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Wed, 29 Nov 2023 11:00:32 -0800 Subject: [PATCH 05/10] revert breaking change --- .../feature-absolute-path_2023-11-29-18-24.json | 10 ---------- packages/openapi3/src/lib.ts | 1 - 2 files changed, 11 deletions(-) delete mode 100644 common/changes/@typespec/openapi3/feature-absolute-path_2023-11-29-18-24.json diff --git a/common/changes/@typespec/openapi3/feature-absolute-path_2023-11-29-18-24.json b/common/changes/@typespec/openapi3/feature-absolute-path_2023-11-29-18-24.json deleted file mode 100644 index b9099b1780..0000000000 --- a/common/changes/@typespec/openapi3/feature-absolute-path_2023-11-29-18-24.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "changes": [ - { - "packageName": "@typespec/openapi3", - "comment": "`output-file` expect an absolute path to be passed. Use `{project-root}`, `{emitter-output-dir}` or `{cwd}` instead.", - "type": "none" - } - ], - "packageName": "@typespec/openapi3" -} \ No newline at end of file diff --git a/packages/openapi3/src/lib.ts b/packages/openapi3/src/lib.ts index d55c5fd3fc..feca60d2f3 100644 --- a/packages/openapi3/src/lib.ts +++ b/packages/openapi3/src/lib.ts @@ -70,7 +70,6 @@ const EmitterOptionsSchema: JSONSchemaType = { "output-file": { type: "string", nullable: true, - format: "absolute-path", description: [ "Name of the output file.", " Output file will interpolate the following values:", From fc4fe1db1240b6d5206cf637f013659ac329b0f8 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Wed, 29 Nov 2023 12:38:27 -0800 Subject: [PATCH 06/10] add tests --- .../test/core/emitter-options.test.ts | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 packages/compiler/test/core/emitter-options.test.ts diff --git a/packages/compiler/test/core/emitter-options.test.ts b/packages/compiler/test/core/emitter-options.test.ts new file mode 100644 index 0000000000..1cc4d1d614 --- /dev/null +++ b/packages/compiler/test/core/emitter-options.test.ts @@ -0,0 +1,120 @@ +import { ok, strictEqual } from "assert"; +import { Diagnostic, EmitContext, createTypeSpecLibrary } from "../../src/index.js"; +import { expectDiagnosticEmpty, expectDiagnostics } from "../../src/testing/expect.js"; +import { createTestHost } from "../../src/testing/test-host.js"; + +const fakeEmitter = createTypeSpecLibrary({ + name: "fake-emitter", + diagnostics: {}, + emitter: { + options: { + type: "object", + properties: { + "asset-dir": { type: "string", format: "absolute-path", nullable: true }, + "max-files": { type: "number", nullable: true }, + }, + additionalProperties: false, + }, + }, +}); + +describe("compiler: emitter options", () => { + async function runWithEmitterOptions( + options: Record + ): Promise<[EmitContext | undefined, readonly Diagnostic[]]> { + let emitContext: EmitContext | undefined; + const host = await createTestHost(); + host.addTypeSpecFile("main.tsp", ""); + host.addTypeSpecFile( + "node_modules/fake-emitter/package.json", + JSON.stringify({ + main: "index.js", + }) + ); + host.addJsFile("node_modules/fake-emitter/index.js", { + $lib: fakeEmitter, + $onEmit: (ctx: EmitContext) => { + emitContext = ctx; + }, + }); + + const diagnostics = await host.diagnose("main.tsp", { + emit: ["fake-emitter"], + options: { + "fake-emitter": options, + }, + }); + return [emitContext, diagnostics]; + } + + async function diagnoseEmitterOptions( + options: Record + ): Promise { + const [_, diagnostics] = await runWithEmitterOptions(options); + return diagnostics; + } + + async function getEmitContext(options: Record): Promise { + const [context, diagnostics] = await runWithEmitterOptions(options); + expectDiagnosticEmpty(diagnostics); + ok(context, "Emit context should have been set."); + return context; + } + + it("pass options", async () => { + const context = await getEmitContext({ + "emitter-output-dir": "/out", + "asset-dir": "/assets", + "max-files": 10, + }); + + strictEqual(context.emitterOutputDir, "/out"); + strictEqual(context.options["asset-dir"], "/assets"); + strictEqual(context.options["max-files"], 10); + }); + + it("emit diagnostic if passing unknown option", async () => { + const diagnostics = await diagnoseEmitterOptions({ + "invalid-option": "abc", + }); + expectDiagnostics(diagnostics, { + code: "invalid-schema", + message: [ + "Schema violation: must NOT have additional properties (/)", + " additionalProperty: invalid-option", + ].join("\n"), + }); + }); + + it("emit diagnostic if passing invalid option type", async () => { + const diagnostics = await diagnoseEmitterOptions({ + "max-files": "not a number", + }); + expectDiagnostics(diagnostics, { + code: "invalid-schema", + message: "Schema violation: must be number (/max-files)", + }); + }); + + describe("format: absolute-path", () => { + it("emit diagnostic if passing relative path starting with `./`", async () => { + const diagnostics = await diagnoseEmitterOptions({ + "asset-dir": "./assets", + }); + expectDiagnostics(diagnostics, { + code: "config-path-absolute", + message: `Path "./assets" cannot be relative. Use {cwd} or {project-root} to specify what the path should be relative to.`, + }); + }); + + it("emit diagnostic if passing relative path if starting with the file/dir name", async () => { + const diagnostics = await diagnoseEmitterOptions({ + "asset-dir": "assets", + }); + expectDiagnostics(diagnostics, { + code: "config-path-absolute", + message: `Path "assets" cannot be relative. Use {cwd} or {project-root} to specify what the path should be relative to.`, + }); + }); + }); +}); From c6ff72801120733a7ebc960cf7aa092cef13fe88 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Wed, 29 Nov 2023 13:05:57 -0800 Subject: [PATCH 07/10] fix test --- packages/compiler/test/cli.test.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/compiler/test/cli.test.ts b/packages/compiler/test/cli.test.ts index 69569fccdd..203e71320d 100644 --- a/packages/compiler/test/cli.test.ts +++ b/packages/compiler/test/cli.test.ts @@ -1,4 +1,4 @@ -import { deepStrictEqual, strictEqual } from "assert"; +import { deepStrictEqual, ok, strictEqual } from "assert"; import { stringify } from "yaml"; import { TypeSpecRawConfig } from "../src/config/types.js"; import { CompileCliArgs, getCompilerOptions } from "../src/core/cli/actions/compile/args.js"; @@ -31,7 +31,9 @@ describe("compiler: cli", () => { env ); expectDiagnosticEmpty(diagnostics); - return options; + ok(options, "Options should have been set."); + const { config, ...rest } = options; + return rest; } it("no args and config: return empty options with output-dir at {cwd}/tsp-output", async () => { @@ -188,7 +190,7 @@ describe("compiler: cli", () => { interface TestUnifiedOptions< K extends keyof CompileCliArgs & keyof TypeSpecRawConfig, - T extends keyof CompilerOptions, + T extends Exclude, > { default: CompileCliArgs[K]; set: { in: CompileCliArgs[K]; alt: CompileCliArgs[K]; expected: CompilerOptions[T] }[]; @@ -196,7 +198,7 @@ describe("compiler: cli", () => { function testUnifiedOptions< K extends keyof CompileCliArgs & keyof TypeSpecRawConfig, - T extends keyof CompilerOptions, + T extends Exclude, >(name: K, resolvedName: T, data: TestUnifiedOptions) { describe(name, () => { it("default", async () => { From 8ff8c2c0f8dce699856da5759e3dc19baca0b4b2 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Wed, 29 Nov 2023 13:22:35 -0800 Subject: [PATCH 08/10] fix --- .../compiler/test/config/resolve-compiler-option.test.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/compiler/test/config/resolve-compiler-option.test.ts b/packages/compiler/test/config/resolve-compiler-option.test.ts index c05c19e848..ad1e411fe7 100644 --- a/packages/compiler/test/config/resolve-compiler-option.test.ts +++ b/packages/compiler/test/config/resolve-compiler-option.test.ts @@ -16,11 +16,12 @@ describe("compiler: resolve compiler options", () => { describe("specifying explicit config file", () => { const resolveOptions = async (path: string) => { const fullPath = resolvePath(scenarioRoot, path); - return await resolveCompilerOptions(NodeHost, { + const [{ config, ...options }, diagnostics] = await resolveCompilerOptions(NodeHost, { cwd: normalizePath(process.cwd()), entrypoint: fullPath, // not really used here configPath: fullPath, }); + return [options, diagnostics] as const; }; it("loads config at the given path", async () => { @@ -28,7 +29,7 @@ describe("compiler: resolve compiler options", () => { expectDiagnosticEmpty(diagnostics); deepStrictEqual(options, { - config: resolvePath(scenarioRoot, "custom/myConfig.yaml"), + configPath: resolvePath(scenarioRoot, "custom/myConfig.yaml"), emit: ["openapi"], options: {}, outputDir: tspOutputPath, From d6dbbda2a7a7fa8691060c8d81b5d16f9eae2563 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Thu, 30 Nov 2023 09:06:34 -0800 Subject: [PATCH 09/10] Revert --- packages/compiler/src/core/options.ts | 4 ++-- packages/compiler/src/core/program.ts | 6 +++--- packages/compiler/test/cli.test.ts | 6 +++--- .../test/config/resolve-compiler-option.test.ts | 13 ++++++++----- packages/samples/src/sample-snapshot-testing.ts | 2 +- 5 files changed, 17 insertions(+), 14 deletions(-) diff --git a/packages/compiler/src/core/options.ts b/packages/compiler/src/core/options.ts index 4fec94e7e8..ddc2bdc5ff 100644 --- a/packages/compiler/src/core/options.ts +++ b/packages/compiler/src/core/options.ts @@ -13,7 +13,7 @@ export interface CompilerOptions { /** * Path to config YAML file used, this is also where the project root should be. */ - configPath?: string; + config?: string; /** * @deprecated use outputDir. @@ -65,5 +65,5 @@ export interface CompilerOptions { linterRuleSet?: LinterRuleSet; /** @internal */ - config?: TypeSpecConfig; + readonly configFile?: TypeSpecConfig; } diff --git a/packages/compiler/src/core/program.ts b/packages/compiler/src/core/program.ts index 6f159addc6..44bc1229f9 100644 --- a/packages/compiler/src/core/program.ts +++ b/packages/compiler/src/core/program.ts @@ -318,7 +318,7 @@ export async function compile( getGlobalNamespaceType, resolveTypeReference, getSourceFileLocationContext, - projectRoot: getDirectoryPath(options.configPath ?? resolvedMain ?? ""), + projectRoot: getDirectoryPath(options.config ?? resolvedMain ?? ""), }; trace("compiler.options", JSON.stringify(options, null, 2)); @@ -753,11 +753,11 @@ export async function compile( if (libDefinition?.emitter?.options) { const diagnostics = libDefinition?.emitterOptionValidator?.validate( emitterOptions, - options.config?.file + options.configFile?.file ? { kind: "path-target", path: ["options", emitterNameOrPath], - script: options.config.file, + script: options.configFile.file, } : NoTarget ); diff --git a/packages/compiler/test/cli.test.ts b/packages/compiler/test/cli.test.ts index 203e71320d..c734e62242 100644 --- a/packages/compiler/test/cli.test.ts +++ b/packages/compiler/test/cli.test.ts @@ -32,7 +32,7 @@ describe("compiler: cli", () => { ); expectDiagnosticEmpty(diagnostics); ok(options, "Options should have been set."); - const { config, ...rest } = options; + const { configFile: config, ...rest } = options; return rest; } @@ -190,7 +190,7 @@ describe("compiler: cli", () => { interface TestUnifiedOptions< K extends keyof CompileCliArgs & keyof TypeSpecRawConfig, - T extends Exclude, + T extends Exclude, > { default: CompileCliArgs[K]; set: { in: CompileCliArgs[K]; alt: CompileCliArgs[K]; expected: CompilerOptions[T] }[]; @@ -198,7 +198,7 @@ describe("compiler: cli", () => { function testUnifiedOptions< K extends keyof CompileCliArgs & keyof TypeSpecRawConfig, - T extends Exclude, + T extends Exclude, >(name: K, resolvedName: T, data: TestUnifiedOptions) { describe(name, () => { it("default", async () => { diff --git a/packages/compiler/test/config/resolve-compiler-option.test.ts b/packages/compiler/test/config/resolve-compiler-option.test.ts index ad1e411fe7..9fbfe073a6 100644 --- a/packages/compiler/test/config/resolve-compiler-option.test.ts +++ b/packages/compiler/test/config/resolve-compiler-option.test.ts @@ -16,11 +16,14 @@ describe("compiler: resolve compiler options", () => { describe("specifying explicit config file", () => { const resolveOptions = async (path: string) => { const fullPath = resolvePath(scenarioRoot, path); - const [{ config, ...options }, diagnostics] = await resolveCompilerOptions(NodeHost, { - cwd: normalizePath(process.cwd()), - entrypoint: fullPath, // not really used here - configPath: fullPath, - }); + const [{ configFile: config, ...options }, diagnostics] = await resolveCompilerOptions( + NodeHost, + { + cwd: normalizePath(process.cwd()), + entrypoint: fullPath, // not really used here + configPath: fullPath, + } + ); return [options, diagnostics] as const; }; diff --git a/packages/samples/src/sample-snapshot-testing.ts b/packages/samples/src/sample-snapshot-testing.ts index a7e6fdd052..aff140112b 100644 --- a/packages/samples/src/sample-snapshot-testing.ts +++ b/packages/samples/src/sample-snapshot-testing.ts @@ -104,7 +104,7 @@ function defineSampleSnaphotTest( const emit = options.emit; if (emit === undefined || emit.length === 0) { fail( - `No emitters configured for sample "${sample.name}". Make sure the config at: "${options.configPath}" is correct.` + `No emitters configured for sample "${sample.name}". Make sure the config at: "${options.config}" is correct.` ); } From c82a12f27944006b1be6175ce526d49b8a2b45d7 Mon Sep 17 00:00:00 2001 From: Timothee Guerin Date: Thu, 30 Nov 2023 09:11:59 -0800 Subject: [PATCH 10/10] . --- packages/compiler/src/config/config-to-options.ts | 4 ++-- packages/compiler/test/config/resolve-compiler-option.test.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/compiler/src/config/config-to-options.ts b/packages/compiler/src/config/config-to-options.ts index de61f1245e..ff261a863c 100644 --- a/packages/compiler/src/config/config-to-options.ts +++ b/packages/compiler/src/config/config-to-options.ts @@ -93,8 +93,8 @@ export function resolveOptionsFromConfig(config: TypeSpecConfig, options: Config const resolvedOptions: CompilerOptions = omitUndefined({ outputDir: expandedConfig.outputDir, - configPath: config.filename, - config: config, + config: config.filename, + configFile: config, additionalImports: expandedConfig["imports"], warningAsError: expandedConfig.warnAsError, trace: expandedConfig.trace, diff --git a/packages/compiler/test/config/resolve-compiler-option.test.ts b/packages/compiler/test/config/resolve-compiler-option.test.ts index 9fbfe073a6..33fda9d1f9 100644 --- a/packages/compiler/test/config/resolve-compiler-option.test.ts +++ b/packages/compiler/test/config/resolve-compiler-option.test.ts @@ -32,7 +32,7 @@ describe("compiler: resolve compiler options", () => { expectDiagnosticEmpty(diagnostics); deepStrictEqual(options, { - configPath: resolvePath(scenarioRoot, "custom/myConfig.yaml"), + config: resolvePath(scenarioRoot, "custom/myConfig.yaml"), emit: ["openapi"], options: {}, outputDir: tspOutputPath,